import {addOnLoad, asciiHeaderHtml, moveCaretToEndOf, q} from "./shared.js"; import {FileSystem} from "./fs.js"; import {Commands} from "./commands.js"; export class Terminal { private _terminal: any; private _input: any; private _output: any; private _prefixDiv: any; private _user: string; private _loggedIn: boolean; private _inputHistory: InputHistory; private _fs:FileSystem; private _commands: Commands; constructor(terminal, input, output, prefixDiv) { this._terminal = terminal; this._input = input; this._output = output; this._prefixDiv = prefixDiv; this._user = "felix"; this._loggedIn = true; this._inputHistory = new InputHistory(); this._fs = new FileSystem(); this._commands = new Commands(this, this._fs); this._terminal.addEventListener("click", this._onclick.bind(this)); this._terminal.addEventListener("keypress", this._onkeypress.bind(this)); this._terminal.addEventListener("keydown", this._onkeydown.bind(this)); this.reset(); this._input.focus(); } get inputText() { return this._input.innerHTML .replaceAll(/
/, ""); } set inputText(inputText) { this._input.innerHTML = inputText; } get outputText() { return this._output.innerHTML; } set outputText(outputText) { this._output.innerHTML = outputText; } get prefixText() { return this._prefixDiv.innerHTML; } set prefixText(prefixText) { this._prefixDiv.innerHTML = prefixText; } static generateHeader() { return "" + `${asciiHeaderHtml} Student MSc Computer Science @ TU Delft, the Netherlands ${(new Date()).toISOString()} Type "help" for help. `.trimLines(); } generatePrefix() { if (!this._loggedIn) { if (this._user === undefined) { return "login as: "; } else { return `Password for ${this._user}@fwdekker.com: `; } } return `${this._user}@fwdekker.com ${this._fs.pwd}> `; } clear() { this.outputText = ""; } reset() { this._fs.reset(); this.outputText = Terminal.generateHeader(); this.prefixText = this.generatePrefix(); } continueLogin(input) { if (this._user === undefined) { this.outputText += `${this.prefixText}${input}\n`; this._user = input.trim(); this._input.classList.add("terminalCurrentFocusInputHidden"); } else { this.outputText += `${this.prefixText}\n`; if ((this._user === "felix" && input === "hotel123") || (this._user === "root" && input === "password")) { this._loggedIn = true; this.outputText += Terminal.generateHeader(); } else { this._user = undefined; this.outputText += "Access denied\n"; } this._input.classList.remove("terminalCurrentFocusInputHidden"); } } logOut() { this._user = undefined; this._loggedIn = false; this._inputHistory.clear(); } ignoreInput() { this.outputText += `${this.prefixText}${this.inputText}\n`; this.prefixText = this.generatePrefix(); this.inputText = ""; } processInput(input) { this.inputText = ""; if (!this._loggedIn) { this.continueLogin(input); } else { this.outputText += `${this.prefixText}${input}\n`; this._inputHistory.addEntry(input); const output = this._commands.parse(input.trim()); if (output !== "") { this.outputText += output + `\n`; } } this.prefixText = this.generatePrefix(); } _onclick() { this._input.focus(); } _onkeypress(e) { switch (e.key.toLowerCase()) { case "enter": this.processInput(this.inputText.replaceAll(/ /, " ")); e.preventDefault(); break; } } _onkeydown(e) { switch (e.key.toLowerCase()) { case "arrowup": this.inputText = this._inputHistory.previousEntry(); window.setTimeout(() => moveCaretToEndOf(this._input), 0); break; case "arrowdown": this.inputText = this._inputHistory.nextEntry(); window.setTimeout(() => moveCaretToEndOf(this._input), 0); break; case "c": if (e.ctrlKey) { this.ignoreInput(); e.preventDefault(); } break; } } } class InputHistory { private _history: string[]; private _index: number; constructor() { this._history = []; this._index = -1; } addEntry(entry: string) { if (entry.trim() !== "") this._history.unshift(entry); this._index = -1; } clear() { this._history = []; this._index = -1; } getEntry(index) { if (index >= 0) return this._history[index]; else return ""; } nextEntry() { this._index--; if (this._index < -1) this._index = -1; return this.getEntry(this._index); } previousEntry() { this._index++; if (this._index >= this._history.length) this._index = this._history.length - 1; return this.getEntry(this._index); } } export let terminal; addOnLoad(() => { terminal = new Terminal( q("#terminal"), q("#terminalCurrentFocusInput"), q("#terminalOutput"), q("#terminalCurrentPrefix") ); terminal.processInput("ls"); }); export function run(command: string) { terminal.processInput(command); } export function relToAbs(filename) { return terminal._fs.pwd + filename; }