the prompt and command input works but the history does not

This commit is contained in:
2025-02-18 17:36:54 -05:00
parent 578aebcae1
commit 129d0ff6b4
7 changed files with 150 additions and 122 deletions

View File

@ -1,28 +1,47 @@
import type { JSX } from "react"
import { bold } from "../color"
import { get_working_dir_name_full, set_working_dir, SetDirStatus } from "../fs/fn"
type args = string[]
type command = JSX.Element | boolean
import create from "../../elements/create"
function parse_ls(entries: JSX.Element[]) {
return <div className="horizontal-display">
type Term = HTMLElement
type Args = string[]
</div>
function strout(term: Term, s: string) {
const p = create("p")
p.innerText = s
term.appendChild(p)
}
function cd(args: args): command {
function clear(term: Term, args: Args): boolean {
Array.from(term.children).forEach(node => {
if (node.tagName === "DIV") {
if (node.className === "shell-prompt") {
const input = node.getElementsByClassName("shell-ps1")[0] as HTMLInputElement
if (input.disabled || input.value === "clear") {
node.remove()
}
} else {
node.remove()
}
} else if (node.tagName === "P") {
node.remove()
}
})
return true
}
function cd(term: Term, args: Args): boolean {
const new_dir_status = set_working_dir(args[1])
if (new_dir_status === SetDirStatus.NotADirectory) {
return <p>{"cd: \""}{bold(args[1])}{"\" is not a directory"}</p>
// return <p>{"cd: \""}{bold(args[1])}{"\" is not a directory"}</p>
} else if (new_dir_status === SetDirStatus.NotFound) {
return <p>{"cd: The directory \""}{bold(args[1])}{"\" does not exist"}</p>
// return <p>{"cd: The directory \""}{bold(args[1])}{"\" does not exist"}</p>
}
return true
}
function ls(args: args): command {
function ls(term: Term, args: Args): boolean {
// if (args[1] === undefined) {
// for (const dir_name in working_dir) {
@ -32,22 +51,26 @@ function ls(args: args): command {
return true
}
function pwd(args: args): command {
return <p>{`${get_working_dir_name_full()}`}</p>
}
function cat(args: args): command {
function pwd(term: Term, args: Args): boolean {
strout(term, get_working_dir_name_full())
return true
}
interface commands_list {
[index: string]: (args: args) => command
function cat(term: Term, args: Args): boolean {
return true
}
const commands: commands_list = {
type Command = (term: Term, args: Args) => boolean
interface CommandsList {
[index: string]: Command,
}
const commands: CommandsList = {
["clear"]: clear,
["cd"]: cd,
["ls"]: ls,
["pwd"]: pwd,
["cat"]: cat,
}
export default commands
export default commands
export { type Command }

View File

@ -0,0 +1,14 @@
function trim(stdin: string): string {
const trimmed_str: string[] = []
stdin.split(" ").forEach(s => { if (s !== "") { trimmed_str.push(s) } })
return trimmed_str.join(" ")
}
function to_args(trimmed_str: string): string[] {
return trimmed_str.split(" ")
}
export {
trim,
to_args
}

View File

@ -1,37 +1,37 @@
import type { JSX } from "react";
import commands from "./list";
import { bold } from "../color";
import { to_args, trim } from "./parse";
function trim(stdin: string): string {
const trimmed_str: string[] = []
stdin.split(" ").forEach(s => { if (s !== "") { trimmed_str.push(s) } })
return trimmed_str.join(" ")
}
import commands, { type Command } from "./list";
import create from "../../elements/create";
import history from "../history";
function to_args(trimmed_str: string): string[] {
return trimmed_str.split(" ")
}
type Term = HTMLElement
function valid_command(args: string[]): JSX.Element | undefined {
function valid_command(term: Term, args: string[]) {
for (const command_in_list in commands) {
const command = args[0]
if (command === command_in_list) {
return commands[command_in_list](args)
return (commands[command_in_list] as Command)(term, args)
}
}
return
}
function unknown_command(cmd_name: string) {
return <p>{"shell: Unknown command: "}{bold(cmd_name)}</p>
const unknown_element = create("p")
unknown_element.innerText = "shell: Unknown command: "
unknown_element.appendChild(bold(cmd_name))
return unknown_element
}
export default function run(stdin: string) {
export default function run(term: Term, stdin: string) {
const args = to_args(trim(stdin))
const command = valid_command(args)
const valid = valid_command(term, args)
const command = args[0] as string
if (args[0] !== "" && !command) {
return unknown_command(args[0])
if (command !== "" && !valid) {
return unknown_command(command)
}
return command ? command : <></>
history.add(args.join(" "))
return false
}

View File

@ -1,35 +0,0 @@
import Display from "./prompt"
import run from "./command/run"
const enum Key {
Enter = "Enter",
ArrowUp = "ArrowUp",
ArrowDown = "ArrowDown",
Tab = "Tab"
}
function keyboard_events(terminal_window: HTMLElement, new_elements_f: newElement) {
const terminal_event = (keyboard_event: KeyboardEvent) => {
if (keyboard_event.key === Key.Enter) {
keyboard_event.preventDefault()
const current_prompt = get_current_prompt()
if (current_prompt) {
const prompt = new_prompt()
const output = run(current_prompt.value)
new_elements_f([output, prompt])
terminal_window.removeEventListener("keydown", terminal_event)
}
} else if (keyboard_event.key === Key.ArrowUp) {
keyboard_event.preventDefault()
} else if (keyboard_event.key === Key.ArrowDown) {
keyboard_event.preventDefault()
} else if (keyboard_event.key === Key.Tab) {
keyboard_event.preventDefault()
}
}
terminal_window.addEventListener("keydown", terminal_event)
}
export {
keyboard_events,
}

View File

@ -2,7 +2,7 @@ import { Entry, EntryType, fs, type FsEntrySignature } from "./fs"
let working_dir = ["/", "home", "user"]
function get_working_dir_name(): string {
function get_working_dir_name() {
return working_dir[working_dir.length-1]
}
@ -29,7 +29,7 @@ function iter_fs_to_goal(w_dir_clone: string[]): FsIterEntry {
for (const w_dir of w_dir_clone) {
if (w_dir === "/") { continue }
if (next_iter.inner) {
if (next_iter && next_iter.inner) {
const found = next_iter.inner.find(entry => entry.name === w_dir)
if (!found) {

View File

@ -1,23 +0,0 @@
import { get_working_dir_name } from "./fs/fn"
import { cyan, green } from "./color"
const userAgent = navigator.userAgent
const browser_name_fallible = userAgent.match(/Firefox.\d+[\d.\d]+|Chrome.\d+[\d.\d]+/gm)?.map(f => f.split("/")[0])
let browser_name = "unknown"
if (browser_name_fallible) {
browser_name = browser_name_fallible[0] === "Firefox" ? "gecko" : "chromium"
}
function working_dir() {
const name = get_working_dir_name()
return name === "user" ? "~" : name
}
export default function Display() {
const user = cyan("user")
const dir = green(working_dir())
return <p>{user}@{browser_name} {dir}{"> "}</p>
}
export { userAgent }

View File

@ -1,42 +1,91 @@
// import { red } from "../shell/color"
// import { display_prompt, keyboard_events } from "../shell/events"
import { history_list } from "./shell/history"
import prompt from "./elements/prompt"
// import run from "./shell/command/run"
import run from "./shell/command/run"
const terminal_window = document.querySelector("main")
let history_index = 0
const term_win_unsafe = document.querySelector("main")
const enum Key {
Enter = "Enter",
ArrowUp = "ArrowUp",
ArrowDown = "ArrowDown",
Tab = "Tab"
}
function spawnps1(terminal_window_safe: HTMLElement) {
const ps1prompt = prompt()
terminal_window_safe.appendChild(ps1prompt.body)
input_processor(ps1prompt.input)
Enter = "Enter",
ArrowRight = "ArrowRight",
ArrowUp = "ArrowUp",
ArrowDown = "ArrowDown",
Tab = "Tab"
}
type InputClosure = (key_event: KeyboardEvent) => void
function key_enter(ps1input: HTMLInputElement, key_event: KeyboardEvent, input_closure: InputClosure) {
key_event.preventDefault()
// run(ps1input.value)
ps1input.removeEventListener("keydown", input_closure)
interface EnterArgs {
readonly term_win_safe: HTMLElement,
readonly ps1input: HTMLInputElement,
readonly closure: InputClosure
}
function key_enter(input: EnterArgs) {
const unknown_command_msg = run(input.term_win_safe, input.ps1input.value)
if (unknown_command_msg) {
input.term_win_safe.appendChild(unknown_command_msg)
}
input.ps1input.removeEventListener("keydown", input.closure)
spawnps1(input.term_win_safe)
}
function input_processor(ps1input: HTMLInputElement) {
const input_closure = (key_event: KeyboardEvent) => {
if (key_event.key === Key.Enter) {
key_enter(ps1input, key_event, input_closure)
function key_up_arrow(ps1input: HTMLInputElement) {
const history_item = history_list[history_index]
if (history_item) {
ps1input.value = history_item
history_index+=1
}
}
function key_down_arrow(ps1input: HTMLInputElement) {
const history_item = history_list[history_index]
if (history_item) {
history_index-=1
if (history_index === -1) {
history_index = 0
} else {
ps1input.value = history_item
}
}
ps1input.addEventListener("keydown", input_closure)
}
if (terminal_window) {
spawnps1(terminal_window)
function spawnps1(term_win_safe: HTMLElement) {
const ps1prompt = prompt()
term_win_safe.appendChild(ps1prompt.body)
bind_processor(term_win_safe, ps1prompt.input)
history_index = 0
ps1prompt.input.focus()
}
function bind_processor(term_win_safe: HTMLElement, ps1prompt_input: HTMLInputElement) {
const input_closure = (key_event: KeyboardEvent) => {
if (key_event.key === Key.Enter) {
key_event.preventDefault()
key_enter({
term_win_safe: term_win_safe,
ps1input: ps1prompt_input,
closure: input_closure
})
} else if (key_event.key === Key.Tab) {
key_event.preventDefault()
} else if (key_event.key === Key.ArrowRight) {
key_event.preventDefault()
} else if (key_event.key === Key.ArrowUp) {
key_event.preventDefault()
key_up_arrow(ps1prompt_input)
} else if (key_event.key === Key.ArrowDown) {
key_event.preventDefault()
key_down_arrow(ps1prompt_input)
}
}
ps1prompt_input.addEventListener("keydown", input_closure)
}
if (term_win_unsafe) {
spawnps1(term_win_unsafe)
} else {
}