JSFiddle - React, Tailwind, and code Playground

by Lazaro Contreras

HTML

<div class='numberLine'>
  <p></p>
</div>
<div class='container' contenteditable='true' spellcheck="false">

</div>
<div class='container2' contenteditable='true' spellcheck="false">

</div>

CSS

* {
  margin: 0;
  padding: 0;
  outline: none;
  font-size: 17px;
  font-family: Consolas;
  box-sizing: border-box;
}

html, body{
    background: #0F172A;
}

div.container {
  left: 50px;
  color: white;
  width: calc(100vw - 50px);
  height: 100vh;
  padding: 0px 10px;
  position: absolute;
}

div.container2 {
  left: 50px;
  width: calc(100vw - 50px);
  height: 100vh;
  padding: 0px 10px;
  position: absolute;
  /*opacity: 0;*/
  background: transparent;
  color: transparent;
  caret-color: white;
}

div.numberLine{
  left: 0;
  color: gray;
  width: 50px;
  height: 100vh;
  /*padding: 10px;*/
  text-align: right;
  position: absolute;
  counter-reset: numberLine;
}

div.numberLine p::after {
  content: '';
  width: 100vw;
  height: 20px;
  left: 0px;
  position: absolute;
  background: #1E293E50;
  z-index: -1;
}

div.numberLine p:nth-child(2n)::after {
  background: none;/*#33415350;*/
}

div.numberLine p::before {
  counter-increment: numberLine;
  content: counter(numberLine);
}

rsv {
  color: #2563EB;
}

car {
  color: #F59E0B;
}

dig {
  color: #EF4444;
}

JavaScript

let reservadas = ['abstract', 'enum', 'long', 'stackalloc', 'as', 'event', 'namespace', 'static', 'base', 'explicit', 'new', 'string', 'bool', 'extern', 'null', 'struct', 'break', 'false', 'object', 'switch', 'byte', 'finally', 'operator', 'this', 'case', 'Fixed', 'out', 'throw', 'catch', 'float', 'override', 'true', 'char', 'for', 'params', 'try', 'checked', 'foreach', 'private', 'typeof', 'class', 'goto', 'protected', 'uint', 'const', 'if', 'public', 'ulong', 'continue', 'implicit', 'readonly', 'unchecked', 'decimal', 'in', 'ref', 'unsafe', 'default', 'int', 'return', 'ushort', 'delegate', 'interface', 'sbyte', 'using', 'do', 'internal', 'sealed', 'virtual', 'double', 'is', 'short', 'void', 'else', 'lock', 'sizeof', 'while', 'var'];

let numberLine = document.querySelector('.numberLine');
let container = document.querySelector('.container');
let container2 = document.querySelector('.container2');

container2.onkeyup = () => {
  let lines = container2.innerText.split(/\n{1,2}/g);
  let linesLenght = lines.lenght;
  lines.join('').trim() == '' ? lines.splice(-1, 1) : null;
  numberLine.innerHTML = lines.map((e, i) => `<p></p>`).join('');

  reservadas.forEach(r =>
    lines.forEach((l, i) => {
      lines[i] = l.replace(new RegExp(`\\b${r}\\b`, 'g'), `<rsv>${r}</rsv>`)
      .replace(new RegExp(`\\b(\\d{1,})\\b`, 'g'), `<dig>$1</dig>`)
      .replace(new RegExp(`(\\"[^\\"]{0,}\\")`, 'g'), `<car>$1</car>`);
    })
  );
  console.log(lines.join('<br>'))
  container.innerHTML = lines.join('<br>');
};