From f8a90e39e0fe11a2175bd5ced561c1a82e42025b Mon Sep 17 00:00:00 2001 From: Kyler Olsen Date: Wed, 29 Nov 2023 13:55:52 -0700 Subject: [PATCH] Started syntax highlighting --- editor.css | 81 ++++++++++++++++++++++++++++++++++++++++++++ editor.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ test-server.py | 11 ++++++ test.html | 41 +++++++++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 editor.css create mode 100644 editor.js create mode 100644 test-server.py create mode 100644 test.html diff --git a/editor.css b/editor.css new file mode 100644 index 0000000..8502075 --- /dev/null +++ b/editor.css @@ -0,0 +1,81 @@ +/* +Kyler Olsen +November 2023 +*/ + +.code { + position: relative; +} + +.code > pre { + padding: 5px; + position: absolute; + top: 0; + left: 0; + overflow: auto; + display: block; + width: 100%; +} + +.code > pre > code { + display: block; + min-height: 1rem; +} + +.view-code { + background-color: #002240; + color: #ffffff; +} + +.edit-code { + color: transparent; + /* border: 1px dotted #4242de; */ +} + +.idle-light .view-code { background-color: #ffffff; color: #000000; } +.idle-light .edit-code { caret-color: #000000; } +.idle-light .token { color: #000000 } +.idle-light .comment { color: #dd0000 } +.idle-light .output { color: #000000 } +.idle-light .error { color: #000000 } +.idle-light .literal { color: #000000 } +.idle-light .literal.number { color: #000000 } +.idle-light .literal.string { color: #00aa00 } +.idle-light .literal.string .format { color: #00aa00 } +.idle-light .escape { color: #000000 } +.idle-light .name { color: #000000 } +.idle-light .name.variable { color: #000000 } +.idle-light .name.constant{ color: #000000 } +.idle-light .name.function { color: #0000ff } +.idle-light .name.class { color: #0000ff } +.idle-light .name.attribute { color: #000000 } +.idle-light .name.property { color: #000000 } +.idle-light .keyword { color: #ff7700 } +.idle-light .keyword.operator { color: #ff7700 } +.idle-light .builtin { color: #900090 } +.idle-light .operator { color: #000000 } +.idle-light .punctuation { color: #000000 } + +.idle-dark .view-code { background-color: #002240; color: #ffffff; } +.idle-dark .edit-code { caret-color: #ffffff; } +.idle-dark .token { color: #ffffff } +.idle-dark .comment { color: #dd0000 } +.idle-dark .output { color: #ffffff } +.idle-dark .error { color: #ffffff } +.idle-dark .literal { color: #ffffff } +.idle-dark .literal.number { color: #ffffff } +.idle-dark .literal.string { color: #02ff02 } +.idle-dark .literal.string .format { color: #02ff02 } +.idle-dark .escape { color: #ffffff } +.idle-dark .name { color: #ffffff } +.idle-dark .name.variable { color: #ffffff } +.idle-dark .name.constant{ color: #ffffff } +.idle-dark .name.function { color: #5e5eff } +.idle-dark .name.class { color: #5e5eff } +.idle-dark .name.attribute { color: #ffffff } +.idle-dark .name.property { color: #ffffff } +.idle-dark .keyword { color: #ff8000 } +.idle-dark .keyword.operator { color: #ff8000 } +.idle-dark .builtin { color: #ff00ff } +.idle-dark .operator { color: #ffffff } +.idle-dark .punctuation { color: #ffffff } diff --git a/editor.js b/editor.js new file mode 100644 index 0000000..abc486b --- /dev/null +++ b/editor.js @@ -0,0 +1,91 @@ +// Kyler Olsen +// November 2023 + +class PythonEditor{ + constructor(ele) { + this.element = ele; + + this.element.addEventListener("input", this.textInput.bind(this)); + this.element.addEventListener("keydown", this.handleKeyDown.bind(this)); + + this.view_code = document.createElement("code"); + this.edit_code = document.createElement("code"); + this.view_pre = document.createElement("pre"); + this.edit_pre = document.createElement("pre"); + + this.edit_code.contentEditable = true; + this.edit_code.spellcheck = false; + this.view_pre.classList.add("view-code"); + this.edit_pre.classList.add("edit-code"); + + this.view_pre.appendChild(this.view_code); + this.edit_pre.appendChild(this.edit_code); + this.element.appendChild(this.view_pre); + this.element.appendChild(this.edit_pre); + } + + textInput(e) { + let text = this.edit_code.innerHTML; + syntax_highlight(text).forEach(ele => this.view_code.appendChild(ele)); + } + + handleKeyDown(e) { + if (e.key === "Tab") { + e.preventDefault(); + insertTab(e.target); + } + } +} + +function insertTab() { + const selection = window.getSelection(); + + if (selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + const startOffset = range.startOffset; + const lineStart = range.startContainer.textContent.lastIndexOf('\n', startOffset - 1) + 1; + const spacesToAdd = 4 - ((startOffset - lineStart) % 4); + const tabSpaces = ' '.repeat(spacesToAdd); + + const tabNode = document.createTextNode(tabSpaces); + range.deleteContents(); + range.insertNode(tabNode); + range.setStartAfter(tabNode); + range.setEndAfter(tabNode); + selection.removeAllRanges(); + selection.addRange(range); + } +} + +function syntax_highlight(text) { + const whitespace = " \n\t"; + const string_start = `'"`; + + const elements = []; + var char = text.substr(0, 1); text = text.substr(1); + + while (text.length) { + const element = document.createElement("span"); + var token_type = ""; + + if (whitespace.includes(char)) + token_type = "whitespace"; + else if (string_start.includes(char)) + token_type = "string"; + + while (text.length) { + if (token_type == "whitespace" && !whitespace.includes(char)) + break; + element.innerText.concat(char); + char = text.substr(0, 1); text = text.substr(1); + } + + elements.push(element); + } + + return elements; +} + +document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll(".code").forEach(ele => new PythonEditor(ele)) +}); diff --git a/test-server.py b/test-server.py new file mode 100644 index 0000000..88ff5b7 --- /dev/null +++ b/test-server.py @@ -0,0 +1,11 @@ +from http.server import SimpleHTTPRequestHandler + +class MyHandler(SimpleHTTPRequestHandler): + extensions_map = { + **SimpleHTTPRequestHandler.extensions_map, + '.mjs': 'application/javascript', + } + +if __name__ == "__main__": + from http.server import test + test(HandlerClass=MyHandler, port=8090) diff --git a/test.html b/test.html new file mode 100644 index 0000000..63c9e43 --- /dev/null +++ b/test.html @@ -0,0 +1,41 @@ + + + + + + + + + Test + + + + + + + + + +
+
+
+
+ + + +