tab completion

This commit is contained in:
Chris Wanstrath 2025-09-20 20:42:42 -07:00
parent 51d319a8b9
commit 258c804593
8 changed files with 51 additions and 25 deletions

24
src/js/completion.ts Normal file
View File

@ -0,0 +1,24 @@
////
// tab completion
import { cmdInput } from "./dom.js"
import { commands } from "./commands.js"
export function initCompletion() {
cmdInput.addEventListener("keydown", handleCompletion)
}
function handleCompletion(e: KeyboardEvent) {
if (e.key !== "Tab") return
e.preventDefault()
const input = cmdInput.value
for (const command of commands) {
console.log(input, command)
if (command.startsWith(input)) {
cmdInput.value = command
return
}
}
}

View File

@ -3,7 +3,7 @@
// elements we know will be there... right?
export const cmdLine = $("command-line") as HTMLDivElement
export const cmdTextbox = $("command-textbox") as HTMLTextAreaElement
export const cmdInput = $("command-textbox") as HTMLTextAreaElement
export const scrollback = $("scrollback") as HTMLUListElement
// finds an element by ID

View File

@ -1,7 +1,7 @@
////
// We try to keep the command textbox focused at all times.
import { cmdTextbox } from "./dom.js"
import { cmdInput } from "./dom.js"
export function initFocus() {
window.addEventListener("click", focusHandler)
@ -9,7 +9,7 @@ export function initFocus() {
}
export function focusTextbox() {
cmdTextbox.focus()
cmdInput.focus()
}
// clicking anywhere outside of a link should focus the prompt, unless the user is
@ -19,7 +19,7 @@ export function focusHandler(e: MouseEvent) {
// who knows where they clicked... just focus the textbox
if (!(target instanceof HTMLElement)) {
cmdTextbox.focus()
cmdInput.focus()
return
}
@ -32,7 +32,7 @@ export function focusHandler(e: MouseEvent) {
const selection = window.getSelection() || ""
if (selection.toString() === "")
cmdTextbox.focus()
cmdInput.focus()
e.preventDefault()
return true

View File

@ -1,14 +1,14 @@
////
// Command input history storage and navigation.
import { cmdTextbox } from "./dom.js"
import { cmdInput } from "./dom.js"
const history: string[] = ["one", "two", "three"]
let idx = -1
let savedInput = ""
export function initHistory() {
cmdTextbox.addEventListener("keydown", navigateHistory)
cmdInput.addEventListener("keydown", navigateHistory)
}
export function addToHistory(input: string) {
@ -30,9 +30,9 @@ function navigateHistory(e: KeyboardEvent) {
if (idx >= history.length - 1) return
if (idx === -1)
savedInput = cmdTextbox.value
savedInput = cmdInput.value
cmdTextbox.value = history[++idx] || ""
cmdInput.value = history[++idx] || ""
if (idx >= history.length) idx = history.length - 1
} else if (e.key === "ArrowDown" || (e.ctrlKey && e.key === "n")) {
@ -40,12 +40,12 @@ function navigateHistory(e: KeyboardEvent) {
console.log(idx, savedInput)
if (idx <= 0) {
cmdTextbox.value = savedInput
cmdInput.value = savedInput
idx = -1
return
}
cmdTextbox.value = history[--idx] || ""
cmdInput.value = history[--idx] || ""
if (idx < -1) idx = -1
} else if (idx !== -1) {

View File

@ -1,35 +1,35 @@
////
// Terminal input is handled by a <textarea> and friends.
import { cmdTextbox, cmdLine } from "./dom.js"
import { cmdInput, cmdLine } from "./dom.js"
import { runCommand } from "./shell.js"
import { resetHistory } from "./history.js"
export function initInput() {
cmdTextbox.addEventListener("keydown", inputHandler)
cmdInput.addEventListener("keydown", inputHandler)
}
function inputHandler(event: KeyboardEvent) {
const target = event.target as HTMLElement
if (target?.id !== cmdTextbox.id) return
if (target?.id !== cmdInput.id) return
if (event.key === "Escape" || (event.ctrlKey && event.key === "c")) {
cmdTextbox.value = ""
cmdInput.value = ""
resetHistory()
} else if (event.key === "Tab") {
event.preventDefault()
} else if (event.shiftKey && event.key === "Enter") {
cmdTextbox.rows += 1
cmdInput.rows += 1
cmdLine.dataset.extended = "true"
} else if (event.key === "Enter") {
event.preventDefault()
runCommand(cmdTextbox.value)
runCommand(cmdInput.value)
clearInput()
}
}
function clearInput() {
cmdTextbox.value = ""
cmdTextbox.rows = 1
cmdInput.value = ""
cmdInput.rows = 1
cmdLine.dataset.extended = "false"
}

View File

@ -1,14 +1,16 @@
import { initResize } from "./resize.js"
import { initInput } from "./input.js"
import { initCompletion } from "./completion.js"
import { initFocus } from "./focus.js"
import { initHistory } from "./history.js"
import { initInput } from "./input.js"
import { initResize } from "./resize.js"
import { startVramCounter } from "./vram.js"
import { startConnection } from "./websocket.js"
initCompletion()
initFocus()
initResize()
initInput()
initHistory()
initInput()
initResize()
startConnection()
startVramCounter()

View File

@ -44,5 +44,4 @@ export function addOutput(id: string, output: string) {
item.dataset.id = id
scrollback.append(item)
}

View File

@ -18,7 +18,8 @@ export function runCommand(input: string) {
if (browserCommands[cmd]) {
const result = browserCommands[cmd]()
if (result) addOutput(id, result)
if (typeof result === "string")
addOutput(id, result)
setStatus(id, "ok")
} else {
send({ id, type: "input", data: input })