Skip to content

Instantly share code, notes, and snippets.

@franklindyer
Last active December 5, 2023 23:40
Show Gist options
  • Save franklindyer/57dc609020e969689d2acd9eef6f6f51 to your computer and use it in GitHub Desktop.
Save franklindyer/57dc609020e969689d2acd9eef6f6f51 to your computer and use it in GitHub Desktop.
Simple REPLs in HTML
<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