crap
This commit is contained in:
		| @@ -1,39 +1,61 @@ | ||||
| p { | ||||
|   line-height: 0.3; | ||||
| /* Remove the p styling since we're using div now */ | ||||
| div { | ||||
|     line-height: 1.2; | ||||
|     margin: 0; | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| html, body { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   padding: 0; | ||||
|   margin: 0; | ||||
| html, | ||||
| body { | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     padding: 0; | ||||
|     margin: 0; | ||||
| } | ||||
|  | ||||
| button { | ||||
|   font-family: monospace; | ||||
|   background-color: #48156e; | ||||
|   color: #e6e8ff; | ||||
|   border: 0px; | ||||
|   border-radius: 2px; | ||||
| button, .button { | ||||
|     font-family: monospace; | ||||
|     background-color: #48156e; | ||||
|     color: #e6e8ff; | ||||
|     border: 0px; | ||||
|     border-radius: 2px; | ||||
|     padding: 8px 12px; | ||||
|     cursor: pointer; | ||||
| } | ||||
|  | ||||
| button:hover, .button:hover { | ||||
|     background-color: #5a1a82; | ||||
| } | ||||
|  | ||||
| .left { | ||||
|   height: 100%; | ||||
|   width: 70%; | ||||
|   padding: 10px; | ||||
|   background-color: #0d0a12; | ||||
|   color: #e6e8ff; | ||||
|   position: absolute; | ||||
|   overflow: scroll; | ||||
|     height: 100%; | ||||
|     width: 70%; | ||||
|     padding: 10px; | ||||
|     background-color: #0d0a12; | ||||
|     color: #e6e8ff; | ||||
|     position: absolute; | ||||
|     overflow: scroll; | ||||
| } | ||||
|  | ||||
| .right { | ||||
|   height: 100%; | ||||
|   width: 30%; | ||||
|   padding: 10px; | ||||
|   background-color: #191324; | ||||
|   color: #e6e8ff; | ||||
|   position: absolute; | ||||
|   right: 0; | ||||
|     height: 100%; | ||||
|     width: 30%; | ||||
|     padding: 10px; | ||||
|     background-color: #191324; | ||||
|     color: #e6e8ff; | ||||
|     position: absolute; | ||||
|     right: 0; | ||||
| } | ||||
|  | ||||
| /* Remove focus outline on the editor */ | ||||
| #editor { | ||||
|     outline: none; | ||||
|     font-family: monospace; | ||||
|     white-space: pre-wrap; | ||||
|     spellcheck: false; /* Disable spellcheck squiggly lines */ | ||||
| } | ||||
|  | ||||
| #console { | ||||
|     font-family: monospace; | ||||
|     white-space: pre-wrap; | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
|     <div class="right"> | ||||
|       <button onclick="runCode()">Run</button> | ||||
|       <input type="file" id="fileInput" hidden accept=".grnd"> | ||||
|       <button for="fileInput" id="buttonTrigger">Choose File</button> | ||||
|       <label for="fileInput" id="buttonTrigger" class="button">Choose File</label> | ||||
|       <br> | ||||
|       <code id="console">Output will be shown here, click the run button to run your code!</code> | ||||
|     </div> | ||||
|   | ||||
							
								
								
									
										409
									
								
								client/index.js
									
									
									
									
									
								
							
							
						
						
									
										409
									
								
								client/index.js
									
									
									
									
									
								
							| @@ -1,166 +1,339 @@ | ||||
| let textbox; | ||||
| let textconsole; | ||||
| let text = '# welcome to gride! start typing to code a program in Ground!\n'; | ||||
|  | ||||
| let text = "# welcome to gride!\n# type your code here and click run!\n"; | ||||
| let filebutton; | ||||
| let fileinput; | ||||
| let firstRun = true; | ||||
|  | ||||
| function renderHighlightedText() { | ||||
|   let renderedText = ""; | ||||
|   const lines = text.split("\n"); | ||||
|   for (const line of lines) { | ||||
|     iscomment = false; | ||||
|     renderedText += "<p>"; | ||||
|     const tokens = line.split(" "); | ||||
|     for (const token of tokens) { | ||||
|       renderedText += highlightToken(token) + " "; | ||||
|     } | ||||
|     renderedText += "</p>"; | ||||
|     instring = false; | ||||
|   } | ||||
|   textbox.innerHTML = renderedText; | ||||
| // Function to save cursor position | ||||
| function saveCursorPosition() { | ||||
|   const selection = window.getSelection(); | ||||
|   if (selection.rangeCount === 0) return null; | ||||
|  | ||||
|   const range = selection.getRangeAt(0); | ||||
|   const preCaretRange = range.cloneRange(); | ||||
|   preCaretRange.selectNodeContents(textbox); | ||||
|   preCaretRange.setEnd(range.startContainer, range.startOffset); | ||||
|  | ||||
|   return preCaretRange.toString().length; | ||||
| } | ||||
|  | ||||
| // Function to restore cursor position | ||||
| function restoreCursorPosition(savedPos) { | ||||
|   if (savedPos === null || !textbox) return; | ||||
|  | ||||
|   const textNodes = []; | ||||
|   const walker = document.createTreeWalker( | ||||
|     textbox, | ||||
|     NodeFilter.SHOW_TEXT, | ||||
|     null, | ||||
|     false, | ||||
|   ); | ||||
|  | ||||
|   let node; | ||||
|   while ((node = walker.nextNode())) { | ||||
|     textNodes.push(node); | ||||
|   } | ||||
|  | ||||
|   let currentPos = 0; | ||||
|   for (const textNode of textNodes) { | ||||
|     const nodeLength = textNode.textContent.length; | ||||
|     if (currentPos + nodeLength >= savedPos) { | ||||
|       const range = document.createRange(); | ||||
|       const selection = window.getSelection(); | ||||
|  | ||||
|       try { | ||||
|         range.setStart(textNode, Math.min(savedPos - currentPos, nodeLength)); | ||||
|         range.collapse(true); | ||||
|         selection.removeAllRanges(); | ||||
|         selection.addRange(range); | ||||
|       } catch (e) { | ||||
|         // If positioning fails, just focus the element | ||||
|         textbox.focus(); | ||||
|       } | ||||
|       return; | ||||
|     } | ||||
|     currentPos += nodeLength; | ||||
|   } | ||||
|  | ||||
|   // If we couldn't find the exact position, focus at the end | ||||
|   const range = document.createRange(); | ||||
|   const selection = window.getSelection(); | ||||
|   try { | ||||
|     range.selectNodeContents(textbox); | ||||
|     range.collapse(false); | ||||
|     selection.removeAllRanges(); | ||||
|     selection.addRange(range); | ||||
|   } catch (e) { | ||||
|     textbox.focus(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function renderHighlightedText() { | ||||
|   if (!textbox) return; | ||||
|  | ||||
|   // Save cursor position before updating | ||||
|   const cursorPos = saveCursorPosition(); | ||||
|  | ||||
|   let renderedText = ""; | ||||
|   const lines = text.split("\n"); | ||||
|  | ||||
|   for (let i = 0; i < lines.length; i++) { | ||||
|     const line = lines[i]; | ||||
|     if (line.trim() === "") { | ||||
|       renderedText += "<div> </div>"; // Preserve empty lines | ||||
|     } else { | ||||
|       const commentIndex = line.indexOf("#"); | ||||
|       if (commentIndex !== -1) { | ||||
|         const beforeComment = line.substring(0, commentIndex); | ||||
|         const comment = line.substring(commentIndex); | ||||
|         renderedText += `<div>${highlightTokens(beforeComment)}<span style="color: ${colours.comment}">${comment}</span></div>`; | ||||
|       } else { | ||||
|         renderedText += `<div>${highlightTokens(line)}</div>`; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   textbox.innerHTML = renderedText; | ||||
|  | ||||
|   // Restore cursor position after a brief delay to let the DOM update | ||||
|   setTimeout(() => { | ||||
|     restoreCursorPosition(cursorPos); | ||||
|   }, 0); | ||||
| } | ||||
|  | ||||
| function getTextFromEditor() { | ||||
|   let newText = ""; | ||||
|   for (let i = 0; i < textbox.childNodes.length; i++) { | ||||
|     const div = textbox.childNodes[i]; | ||||
|     if (div.nodeType === Node.ELEMENT_NODE && div.tagName === 'DIV') { | ||||
|       let line = ""; | ||||
|       for (let j = 0; j < div.childNodes.length; j++) { | ||||
|         line += div.childNodes[j].textContent; | ||||
|       } | ||||
|       newText += line + (i < textbox.childNodes.length - 1 ? "\n" : ""); | ||||
|     } else if (div.nodeType === Node.TEXT_NODE) { | ||||
|       newText += div.textContent; | ||||
|     } | ||||
|   } | ||||
|   return newText; | ||||
| } | ||||
|  | ||||
| // Wait for the window to load before doing anything | ||||
| window.addEventListener("load", function() { | ||||
|  | ||||
| window.addEventListener("load", function () { | ||||
|   // Get all the elements | ||||
|   textbox = document.getElementById("editor"); | ||||
|   textconsole = document.getElementById("console"); | ||||
|   filebutton = document.getElementById("buttonTrigger"); | ||||
|   fileinput = document.getElementById("fileInput"); | ||||
|  | ||||
|   // Check if elements exist | ||||
|   if (!textbox || !textconsole || !filebutton || !fileinput) { | ||||
|     console.error("Some required elements not found!"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   textbox.innerText = text; | ||||
|   filebutton = document.getElementById('buttonTrigger'); | ||||
|   fileinput = document.getElementById('fileInput'); | ||||
|  | ||||
|   // Initial render | ||||
|   renderHighlightedText(); | ||||
|  | ||||
|   // Set up watchers for everything | ||||
|   filebutton.addEventListener('click', () => { | ||||
|   filebutton.addEventListener("click", () => { | ||||
|     fileinput.click(); | ||||
|   }) | ||||
|   }); | ||||
|  | ||||
|   fileinput.addEventListener('change', () => { | ||||
|   fileinput.addEventListener("change", () => { | ||||
|     const file = fileinput.files[0]; | ||||
|     if (file) { | ||||
|       const reader = new FileReader(); | ||||
|       reader.onload = function(e) { | ||||
|       reader.onload = function (e) { | ||||
|         text = e.target.result; | ||||
|         textbox.innerText = text; | ||||
|         renderHighlightedText(); | ||||
|       }; | ||||
|       reader.readAsText(file); | ||||
|     } else { | ||||
|       console.log("what"); | ||||
|       console.log("No file selected"); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   // When we press a key, start doing stuff | ||||
|   textbox.addEventListener("input", () => { | ||||
|     text = getTextFromEditor(); | ||||
|     renderHighlightedText(); | ||||
|   }); | ||||
|  | ||||
|   // Handle tab key to insert 4 spaces | ||||
|   textbox.addEventListener("keydown", (e) => { | ||||
|     if (e.key === "Tab") { | ||||
|       e.preventDefault(); | ||||
|  | ||||
|       // Insert 4 spaces at cursor position | ||||
|       const selection = window.getSelection(); | ||||
|       const range = selection.getRangeAt(0); | ||||
|  | ||||
|       // Create a text node with 4 spaces | ||||
|       const textNode = document.createTextNode("    "); | ||||
|       range.insertNode(textNode); | ||||
|  | ||||
|       // Move cursor to after the inserted spaces | ||||
|       range.setStartAfter(textNode); | ||||
|       range.collapse(true); | ||||
|       selection.removeAllRanges(); | ||||
|       selection.addRange(range); | ||||
|  | ||||
|       // Update our text variable and re-render | ||||
|       text = getTextFromEditor(); | ||||
|       renderHighlightedText(); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   // Handle paste events | ||||
|   textbox.addEventListener("paste", (e) => { | ||||
|     e.preventDefault(); | ||||
|     const paste = (e.clipboardData || window.clipboardData).getData("text"); | ||||
|     document.execCommand("insertText", false, paste); | ||||
|     text = getTextFromEditor(); | ||||
|     renderHighlightedText(); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| const keywords = ["if", "jump", "end", "input", "stdin", "print", "stdout", "println", "stdlnout", "set", "gettype", "exists", "setlist", "setlistat", "getlistat", "getlistsize", "listappend", "getstrsize", "getstrcharat", "add", "subtract", "multiply", "divide", "equal", "inequal", "not", "greater", "lesser", "stoi", "stod", "tostring", "fun", "return", "endfun", "pusharg", "call", "struct", "endstruct", "init", "use", "extern", "catch"]; | ||||
| const keywords = [ | ||||
|   "if", | ||||
|   "jump", | ||||
|   "end", | ||||
|   "input", | ||||
|   "stdin", | ||||
|   "print", | ||||
|   "stdout", | ||||
|   "println", | ||||
|   "stdlnout", | ||||
|   "set", | ||||
|   "gettype", | ||||
|   "exists", | ||||
|   "setlist", | ||||
|   "setlistat", | ||||
|   "getlistat", | ||||
|   "getlistsize", | ||||
|   "listappend", | ||||
|   "getstrsize", | ||||
|   "getstrcharat", | ||||
|   "add", | ||||
|   "subtract", | ||||
|   "multiply", | ||||
|   "divide", | ||||
|   "equal", | ||||
|   "inequal", | ||||
|   "not", | ||||
|   "greater", | ||||
|   "lesser", | ||||
|   "stoi", | ||||
|   "stod", | ||||
|   "tostring", | ||||
|   "fun", | ||||
|   "return", | ||||
|   "endfun", | ||||
|   "pusharg", | ||||
|   "call", | ||||
|   "struct", | ||||
|   "endstruct", | ||||
|   "init", | ||||
|   "use", | ||||
|   "extern", | ||||
|   "catch", | ||||
| ]; | ||||
|  | ||||
| const colours = { | ||||
|   keyword: "#42fff2", | ||||
|   comment: "#383838", | ||||
|   number: "#42ffb7", | ||||
|   number: "#42ff62", | ||||
|   string: "#42ff62", | ||||
|   valref: "#9544c7", | ||||
|   dirref: "#f587ff", | ||||
|   lineref: "#9bf542", | ||||
|   label: "#fff67d", | ||||
|   function: "#ffa640", | ||||
|   typeref: "#ff40ac" | ||||
| } | ||||
|   typeref: "#ff40ac", | ||||
| }; | ||||
|  | ||||
| let instring = false; | ||||
| let iscomment = false; | ||||
|  | ||||
| // Function to handle highlighting tokens that have been typed | ||||
| function highlightToken(token) { | ||||
|  | ||||
|   if (instring) { | ||||
|     if (token[token.length - 1] == '"' || token[token.length - 1] == '"') { | ||||
|       instring = false; | ||||
| function highlightTokens(line) { | ||||
|   const tokens = line.split(/(\s+|"[^"]*"|'[^']*')/).filter(Boolean); | ||||
|   let instring = false; | ||||
|   return tokens.map(token => { | ||||
|     if (token.startsWith('"') || token.startsWith("'")) { | ||||
|       instring = !instring; | ||||
|       return `<span style="color: ${colours.string}">${token}</span>`; | ||||
|     } | ||||
|     return `<span style="color: ${colours.string}">${token}</span>` | ||||
|   } | ||||
|  | ||||
|   // Comments | ||||
|   if (iscomment) { | ||||
|     return `<span style="color: ${colours.comment}"> ${token}</span>"` | ||||
|   } | ||||
|  | ||||
|   if (token[0] == '#') { | ||||
|     iscomment = true; | ||||
|     return `<span style="color: ${colours.comment}> ${token}</span>"` | ||||
|   } | ||||
|  | ||||
|   // Keywords | ||||
|   if (keywords.includes(token)) { | ||||
|     return `<span style="color: ${colours.keyword}">${token}</span>`; | ||||
|   } | ||||
|  | ||||
|   // Direct references | ||||
|   if (token[0] == '&') { | ||||
|     return `<span style="color: ${colours.dirref}">${token}</span>`; | ||||
|   } | ||||
|  | ||||
|   // Value references | ||||
|   if (token[0] == '$') { | ||||
|     return `<span style="color: ${colours.valref}">${token}</span>`; | ||||
|   } | ||||
|  | ||||
|   // Strings and characters | ||||
|   if (token[0] == '"' || token[0] == "'") { | ||||
|     if (!(token[token.length - 1] == '"' || token[token.length - 1] == '"')) { | ||||
|       instring = true; | ||||
|     if (instring) { | ||||
|       return `<span style="color: ${colours.string}">${token}</span>`; | ||||
|     } | ||||
|     return `<span style="color: ${colours.string}">${token}</span>`; | ||||
|   } | ||||
|  | ||||
|   return `<span>${token}</span>`; | ||||
| } | ||||
|  | ||||
| // When we press a key, start doing stuff | ||||
| textbox.addEventListener('input', () => { | ||||
|   text = textbox.innerText; | ||||
|   renderHighlightedText(); | ||||
| }); | ||||
|  | ||||
|  | ||||
| // Old code | ||||
| /* | ||||
| onkeydown = (event) => { | ||||
|   if (event.key == "Enter") { | ||||
|     //text += "</p>\n<p>"; | ||||
|     text += "\n" | ||||
|   } else if (event.key == "Tab") { | ||||
|     text += "    "; | ||||
|   } else if (event.key == "Backspace") { | ||||
|     text = text.slice(0, -1) | ||||
|   } else if (!(event.key == "Control" || event.key == "Alt" || event.key == "Meta" || event.key == "Shift" || event.key == "Escape")) { | ||||
|     text += event.key; | ||||
|   } | ||||
|   let renderedText = ""; | ||||
|   const lines = text.split("\n"); | ||||
|   for (const line of lines) { | ||||
|     renderedText += "<p>"; | ||||
|     const tokens = line.split(" "); | ||||
|     for (const token of tokens) { | ||||
|       renderedText += highlightToken(token) + " "; | ||||
|     if (keywords.includes(token)) { | ||||
|       return `<span style="color: ${colours.keyword}">${token}</span>`; | ||||
|     } | ||||
|     renderedText += "</p>"; | ||||
|     instring = false; | ||||
|     iscomment = false; | ||||
|   } | ||||
|   textbox.innerHTML = renderedText; | ||||
|     if (!isNaN(token) && token.trim() !== "") { | ||||
|       return `<span style="color: ${colours.number}">${token}</span>`; | ||||
|     } | ||||
|     if (token.startsWith('&')) { | ||||
|       return `<span style="color: ${colours.dirref}">${token}</span>`; | ||||
|     } | ||||
|     if (token.startsWith('$')) { | ||||
|       return `<span style="color: ${colours.valref}">${token}</span>`; | ||||
|     } | ||||
|     if (token.startsWith('-')) { | ||||
|       return `<span style="color: ${colours.typeref}">${token}</span>`; | ||||
|     } | ||||
|     if (token.startsWith('!')) { | ||||
|       return `<span style="color: ${colours.function}">${token}</span>`; | ||||
|     } | ||||
|     if (token.startsWith('%')) { | ||||
|       return `<span style="color: ${colours.lineref}">${token}</span>`; | ||||
|     } | ||||
|     if (token.startsWith('@')) { | ||||
|       return `<span style="color: ${colours.label}">${token}</span>`; | ||||
|     } | ||||
|     return token; | ||||
|   }).join(''); | ||||
| } | ||||
| */ | ||||
|  | ||||
| // Function to run code on the server | ||||
| async function runCode() { | ||||
|   console.log(text.split("<p>").join("").split("</p>").join("")); | ||||
|   const result = await fetch("http://localhost:5000/runProgram", { | ||||
|     "method": "POST", | ||||
|     //"mode": "no-cors", | ||||
|     "body": text.split("<p>").join("").split("</p>").join("") | ||||
|   }); | ||||
|   const data = await result.json(); | ||||
|   // Ensure everything's seperated | ||||
|   textconsole.innerHTML = "<p>" + data.stdout.split("\n").join("</p><p>") + "</p>"; | ||||
|   if (!textconsole) { | ||||
|     console.error("Console element not found!"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // Make sure we have the latest text | ||||
|   // The `text` variable is now the single source of truth. | ||||
|  | ||||
|   if (firstRun) { | ||||
|     textconsole.innerHTML = ""; | ||||
|     firstRun = false; | ||||
|   } | ||||
|  | ||||
|   console.log("Running code:", text); | ||||
|  | ||||
|   try { | ||||
|     const result = await fetch("/runProgram", { | ||||
|       method: "POST", | ||||
|       headers: { | ||||
|         "Content-Type": "text/plain", | ||||
|       }, | ||||
|       body: text, | ||||
|     }); | ||||
|  | ||||
|     if (!result.ok) { | ||||
|       throw new Error(`HTTP error! status: ${result.status}`); | ||||
|     } | ||||
|  | ||||
|     const data = await result.json(); | ||||
|     const output = data.stdout.split('\n').join('</div><div>'); | ||||
|     const timestamp = new Date().toLocaleTimeString(); | ||||
|     textconsole.innerHTML += `<div>[${timestamp}]</div><div>${output}</div>`; | ||||
|     textconsole.scrollTop = textconsole.scrollHeight; // Scroll to bottom | ||||
|   } catch (error) { | ||||
|     console.error("Error running code:", error); | ||||
|     textconsole.innerHTML = | ||||
|       "<div style='color: #ff4444'>Error: " + error.message + "</div>"; | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user