Last active
December 5, 2023 23:40
-
-
Save franklindyer/57dc609020e969689d2acd9eef6f6f51 to your computer and use it in GitHub Desktop.
Simple REPLs in HTML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<head> | |
<style> | |
div.repl { | |
background-color: black; | |
color: white; | |
font-family: Courier; | |
overflow-y: scroll; | |
height: 200px; | |
padding: 5px; | |
margin: 5px; | |
width: 80%; | |
} | |
div.repl-output { | |
flex-direction: column-reverse; | |
} | |
div.repl-input-wrapper { | |
display: inline; | |
white-space: nowrap; | |
} | |
input.repl-input { | |
background-color: inherit; | |
color: inherit; | |
font-family: inherit; | |
font-size: inherit; | |
border: none; | |
outline: none; | |
resize: none; | |
overflow-x: scroll; | |
line-height: 1; | |
width: 100% | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
historyREPLs = {} | |
// Scroll a given REPL to the bottom. | |
function resetScrollREPL(n) { | |
let divrepl = document.getElementById(`repl-${n}`) | |
divrepl.scrollTop = divrepl.scrollHeight | |
} | |
// Insert a line of output to a given REPL. | |
function putLineToREPL(linestr, n) { | |
let divout = document.getElementById(`repl-output-${n}`) | |
let ind = divout.children.length | |
let newline = document.createElement("div") | |
newline.dataset.index = ind | |
newline.innerText = linestr | |
divout.appendChild(newline) | |
resetScrollREPL(n) | |
} | |
// Create all of the components necessary for a REPL. | |
function buildREPL(n, inittext, prompt) { | |
let repl = document.getElementById(`repl-${n}`) | |
repl.innerHTML = ` | |
<div id="repl-output-${n}" class="repl-output"> | |
<div data-index="0">${inittext}</div> | |
</div> | |
<div class="repl-input-wrapper"> | |
${prompt} | |
<input id="repl-input-${n}" class="repl-input" type="text"></input> | |
</div> | |
` | |
} | |
// Associate a handler function with a REPL, making it responsive. | |
// Handler function should take two inputs: int ID of REPL, and str input. | |
function registerREPL(handler, n) { | |
historyREPLs[n] = [0, []] | |
let replin = document.getElementById(`repl-input-${n}`) | |
replin.addEventListener('keydown', (e) => { | |
if (e.key === 'Enter') { | |
handler(n, replin.value) | |
historyREPLs[n][1].unshift(replin.value) | |
historyREPLs[n][0] = 0 | |
replin.value = '' | |
} else if (e.key === 'ArrowUp') { | |
if (historyREPLs[n][0] < historyREPLs[n][1].length) { | |
historyREPLs[n][0] += 1 | |
replin.value = historyREPLs[n][1][historyREPLs[n][0]-1] | |
} | |
} else if (e.key === 'ArrowDown') { | |
if (historyREPLs[n][0] > 0) { | |
historyREPLs[n][0] += -1 | |
if (historyREPLs[n][0] == 0) { | |
replin.value = '' | |
} else { | |
replin.value = historyREPLs[n][1][historyREPLs[n][0]-1] | |
} | |
} | |
} | |
}) | |
} | |
</script> | |
<div id="repl-1" class="repl"></div> | |
<div id="repl-2" class="repl"></div> | |
<script> | |
buildREPL(1, "This is an echoing REPL.", "Echo>") | |
registerREPL((n, strin) => { | |
putLineToREPL(`You said: ${strin}`, n) | |
}, 1) | |
buildREPL(2, "This is a JS REPL.", "JS>") | |
registerREPL((n, strin) => { | |
putLineToREPL(`JS> ${strin}`, n) | |
try { | |
putLineToREPL(eval(strin), n) | |
} catch (err) { | |
putLineToREPL(err, n) | |
} | |
}, 2) | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment