0

I'm trying to create a code editor for a programming language that I made. I'm using a contenteditable <pre> for the code so that I can style it using JavaScript. However, when I style it, the cursor position goes to the start. I would prefer if it didn't. I would also prefer if I didn't have to use any libraries like JQuery or Codemirror. Here is my code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>SCLIL editor</title>
    <style>
      * {
        margin: 0;
      }

      html,
      body {
        width: 100%;
        height: 100%;
      }
      
      pre {
        min-height: 100%;
        outline: 0;
        padding: 10px;
        background-color: #333;
        color: #fff;
      }
    </style>
  </head>
  <body>
    <pre contenteditable>
with background-colour=white
with foreground-colour=red
with font-style=bold,italic
say What is your name?

with foreground-colour=green
with space-after=true
with var=name
ask >

say Your name is $name.

with var=names-exists
file-exists names.txt

function write-to-names
  with var=names
  read-file names.txt

  with var=names
  append-line $name

  with var=names
  write-to-file names.txt
  :function.done

if names-exists=true
  do write-to-names
  
  :if.done

if names-exists=false
  with to-write=$null
  with var=$to-write
  write-to-file names.txt

  do write-to-names

  :if.done

say Exit?

with space-after=true
with var=exit
ask >

with var=exit
is-yes-like $exit

if exit=true
  exit
  :if.done

say Time to add some numbers.
say What is the first number?

with space-after=true
with var=first
ask >

say What is the second number?

with space-after=true
with var=second
ask >

say What is the third number?

with space-after=true
with var=third
ask >

with var=sum
sum $first $second $third

say The result is $sum.</pre
    >
    <script>
      String.prototype.r = function (k, v) {
        return this.split(k).join(v);
      };

      String.prototype.k = function (k, c, it = false, b = false) {
        let nt = this.split("\n");
        this.split("\n").forEach((line, i) => {
          let nl = line.split(" ");
          line.split(" ").forEach((word, i) => {
            if (word == k) {
              nl[i] = `${it ? "<i>" : ""}${
                b ? "<b>" : ""
              }<span style="color: ${c}">${k}</span>${b ? "</b>" : ""}${
                i ? "</i>" : ""
              }`;
            }
          });
          nt[i] = nl.join(" ");
        });
        return nt.join("\n");
      };

      setInterval(() => {
        const pre = document.querySelector("pre"),
          code = pre.innerText
            .r("&", "&amp;")
            .r("<", "&lt;")
            .r(">", "&gt;")
            .k("say", "#ed7d31")
            .k("ask", "#70ad47")
            .k("with", "#7030a0")
            .k("function", "#7030a0")
            .k("if", "#7030a0")
            .k("do", "#7030a0")
            .k("file-exists", "#c00000")
            .k("read-file", "#c00000")
            .k("write-to-file", "#c00000")
            .k("append-line", "#4472c4")
            .k(":function.done", "#00b0f0", true)
            .k(":if.done", "#00b0f0", true)
            .k("is-yes-like", "yellow")
            .k("sum", "yellow")
            .k("exit", "#ffc000", false, true);
        pre.focus();
        const sn = getSelection().anchorNode,
          sp = getSelection().anchorOffset,
          en = getSelection().focusNode,
          ep = getSelection().focusOffset;
        pre.innerHTML = code;
        getSelection().setBaseAndExtent(sn, sp, en, ep);
      });
    </script>
  </body>
</html>
  • Here is similar question with answer: https://stackoverflow.com/questions/13518512/i-have-a-div-with-contenteditable-true-and-need-to-color-the-numbers-entered – Dmytro Mysak Mar 18 '22 at 10:15
  • @DmytroMysak Unfortunately, the answer doesn't work because in my program, the children of the pre are not one letter each, some of them are 4 letters, some are 5, some can even be 10, so instead of e.g. focusing on the *letter* at index 1, it focuses on the *child* at index 1, which yield very different results. – Yugoslav Empire Apr 10 '22 at 10:17

0 Answers0