2025-01-06 00:18:13 -05:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
import init, * as talc from "./pkg/talc_web.js";
|
|
|
|
await init();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* DOM
|
|
|
|
*/
|
|
|
|
|
|
|
|
const $ = (q) => document.querySelector(q);
|
|
|
|
|
|
|
|
function newEl(tag, attrs, children) {
|
|
|
|
const el = document.createElement(tag);
|
|
|
|
for (const attr in attrs) {
|
|
|
|
el.setAttribute(attr, attrs[attr]);
|
|
|
|
}
|
|
|
|
for (const child of children) {
|
|
|
|
if (typeof(child) === "string") {
|
|
|
|
el.appendChild(document.createTextNode(child));
|
|
|
|
} else {
|
|
|
|
el.appendChild(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return el;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* History
|
|
|
|
*/
|
|
|
|
|
|
|
|
let historyEntries = [""];
|
|
|
|
let historyIndex = 0;
|
|
|
|
let currentLine = "";
|
|
|
|
|
|
|
|
function prevHistory() {
|
|
|
|
const inputEl = $("#input");
|
|
|
|
if (historyIndex === 0) {
|
|
|
|
currentLine = inputEl.innerText;
|
|
|
|
}
|
|
|
|
historyIndex = Math.min(historyIndex+1, historyEntries.length);
|
|
|
|
const text = historyEntries[historyEntries.length - historyIndex];
|
|
|
|
inputEl.innerText = text;
|
|
|
|
|
|
|
|
document.getSelection().setPosition(inputEl, inputEl.childNodes.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
function nextHistory() {
|
|
|
|
const inputEl = $("#input");
|
|
|
|
historyIndex = Math.max(historyIndex-1, 0);
|
|
|
|
let text;
|
|
|
|
if (historyIndex === 0) {
|
|
|
|
text = currentLine;
|
|
|
|
} else {
|
|
|
|
text = historyEntries[historyEntries.length - historyIndex];
|
|
|
|
}
|
|
|
|
inputEl.innerText = text;
|
|
|
|
|
|
|
|
document.getSelection().setPosition(inputEl, inputEl.childNodes.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* REPL
|
|
|
|
*/
|
|
|
|
|
|
|
|
function nextLine() {
|
|
|
|
const newPrompt = newEl("div", {"class": "prompt"}, []);
|
|
|
|
newPrompt.innerHTML = $("#prompt").innerHTML;
|
|
|
|
|
|
|
|
const newInput = newEl("div", {}, []);
|
|
|
|
newInput.innerHTML = $("#input").innerHTML;
|
|
|
|
|
|
|
|
$("#history").appendChild(newEl(
|
|
|
|
"div",
|
|
|
|
{"class": "input_line"},
|
|
|
|
[newPrompt, newInput]
|
|
|
|
));
|
|
|
|
|
|
|
|
$("#input").innerHTML = "";
|
|
|
|
|
|
|
|
currentLine = "";
|
|
|
|
historyIndex = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function execLine() {
|
|
|
|
const inputLine = $("#input").innerText;
|
|
|
|
nextLine();
|
|
|
|
historyEntries.push(inputLine);
|
|
|
|
|
|
|
|
try {
|
|
|
|
const fixedInput = inputLine.replaceAll("\u00a0", " ");
|
|
|
|
const out = talc.eval_line(fixedInput);
|
|
|
|
if (out !== undefined) {
|
|
|
|
$("#history").appendChild(newEl("div", {}, [out]));
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
$("#history").appendChild(newEl("div", {}, [
|
|
|
|
newEl("span", {"class": "error"}, ["Error: "]),
|
|
|
|
newEl("pre", {"class": "err_msg"}, [e.toString()])
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Input
|
|
|
|
*/
|
|
|
|
|
|
|
|
function handleCtrlKey(event) {
|
|
|
|
switch (event.code) {
|
|
|
|
case "KeyL":
|
|
|
|
event.preventDefault();
|
|
|
|
$("#history").innerHTML = "";
|
|
|
|
break;
|
|
|
|
case "KeyC":
|
|
|
|
event.preventDefault();
|
|
|
|
nextLine();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function keyPressed(event) {
|
2025-01-18 19:06:58 -05:00
|
|
|
if (event.key === "Enter" && !event.shiftKey && !event.altKey) {
|
2025-01-06 00:18:13 -05:00
|
|
|
event.preventDefault();
|
|
|
|
execLine()
|
2025-01-18 19:06:58 -05:00
|
|
|
} else if (event.ctrlKey && !event.altKey) {
|
2025-01-06 00:18:13 -05:00
|
|
|
handleCtrlKey(event);
|
2025-01-18 19:06:58 -05:00
|
|
|
} else if (event.key === "ArrowUp" && !event.altKey) {
|
2025-01-06 00:18:13 -05:00
|
|
|
event.preventDefault();
|
|
|
|
prevHistory();
|
2025-01-18 19:06:58 -05:00
|
|
|
} else if (event.key === "ArrowDown" && !event.altKey) {
|
2025-01-06 00:18:13 -05:00
|
|
|
event.preventDefault();
|
|
|
|
nextHistory();
|
|
|
|
}
|
|
|
|
|
|
|
|
window.scrollTo(0, document.body.scrollHeight);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Listeners
|
|
|
|
*/
|
|
|
|
|
|
|
|
$("#input").addEventListener("keydown", keyPressed);
|
|
|
|
$("#input").focus();
|
|
|
|
|
|
|
|
$("#terminal").addEventListener("click", (event) => {
|
|
|
|
if (event.target.id === "terminal" || event.target.id === "input") {
|
|
|
|
$("#input").focus();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Query parameter
|
|
|
|
*/
|
|
|
|
|
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
|
|
const initialLine = urlParams.get("eval");
|
|
|
|
|
|
|
|
if (initialLine !== null) {
|
|
|
|
$("#input").innerText = initialLine;
|
|
|
|
execLine();
|
|
|
|
}
|