From 3a2613d916703f96fa553a3d526dd532063a619a Mon Sep 17 00:00:00 2001 From: Djeeberjr Date: Mon, 26 Jun 2023 20:04:26 +0200 Subject: [PATCH] improved terminal with history --- src/bin/Terminal.hx | 91 ++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/src/bin/Terminal.hx b/src/bin/Terminal.hx index cb578ff..1691e3b 100644 --- a/src/bin/Terminal.hx +++ b/src/bin/Terminal.hx @@ -1,6 +1,5 @@ package bin; -import kernel.log.Log; import kernel.binstore.BinStore; import kernel.ps.ProcessHandle; import kernel.ps.Process; @@ -11,11 +10,18 @@ import kernel.ui.WindowContext; using tink.CoreApi; class Terminal implements Process { - private var context:WindowContext; + private static inline final MAX_BACKLOG:Int = 100; + + private var handle:ProcessHandle; + + private var ctx:WindowContext; + private var requestRender: () -> Void; + private var input:String = ""; private var backlog:Array = []; - private var handle:ProcessHandle; - private var requestRender: () -> Void; + private var history:Array = []; + private var historyIndex:Int = 0; + private var runningPID:PID = -1; public function new() {} @@ -25,18 +31,20 @@ class Terminal implements Process { var statelessContext = handle.createStatelessWindowContext(); - this.context = statelessContext.ctx; + this.ctx = statelessContext.ctx; this.requestRender = statelessContext.requestRender; statelessContext.setRenderFunc(this.render); - handle.addCallbackLink(this.context.onChar.handle(char -> { + // Add input event handlers + handle.addCallbackLink(this.ctx.onChar.handle(char -> { if (this.runningPID > 0) return; this.input += char; this.requestRender(); })); - handle.addCallbackLink(this.context.onKey.handle(e -> { + // Add key event handlers + handle.addCallbackLink(this.ctx.onKey.handle(e -> { switch (e.keyCode) { case 259: // Backspace if (this.runningPID > 0) return; @@ -48,9 +56,16 @@ class Terminal implements Process { var command = this.input; this.input = ""; this.requestRender(); + this.historyIndex = 0; this.invokeCommand(command); case 269: // END this.stopCurrentPS(); + case 265: // UP + if (this.historyIndex < this.history.length) { + this.historyIndex++; + this.input = this.history[this.history.length - this.historyIndex]; + this.requestRender(); + } } })); @@ -66,12 +81,7 @@ class Terminal implements Process { } private function render() { - redrawBacklog(); - redrawInput(); - } - - private function redrawBacklog() { - var size = this.context.getSize(); + var size = this.ctx.getSize(); var linesAvailable = size.y - 1; var start:Int = this.backlog.length - linesAvailable; @@ -79,29 +89,28 @@ class Terminal implements Process { for (i in 0...linesAvailable) { var line = this.backlog[start + i]; - this.context.setCursorPos(0, i); - this.context.clearLine(); + this.ctx.setCursorPos(0, i); + this.ctx.clearLine(); if (line != null) { - this.context.write(line); + this.ctx.write(line); } } - this.moveCursorToInput(); - } - private function redrawInput() { - var size = this.context.getSize(); + this.ctx.setCursorPos(0, size.y - 1); + this.ctx.clearLine(); - this.context.setCursorPos(0, size.y - 1); - this.context.clearLine(); + this.ctx.setTextColor(Color.Blue); + this.ctx.write("> "); - this.context.setTextColor(Color.Blue); - this.context.write("> "); + this.ctx.setTextColor(Color.White); + this.ctx.write(this.input); - this.context.setTextColor(Color.White); - this.context.write(this.input); - - this.context.setCursorBlink(true); + if (this.runningPID < 0) { + this.ctx.setCursorBlink(true); + } else { + this.ctx.setCursorBlink(false); + } } private function invokeCommand(command:String):Void { @@ -110,6 +119,13 @@ class Terminal implements Process { if (args.length == 0) { return; } + + this.history.push(command); + + if (this.history.length > MAX_BACKLOG) { + this.history.shift(); + } + var commandName = args[0]; // Handle built-in commands @@ -125,8 +141,7 @@ class Terminal implements Process { var ps = getProgByName(commandName); if (ps == null) { this.backlog.push("Unknown command: " + commandName); - this.redrawBacklog(); - this.redrawInput(); + this.requestRender(); return; } @@ -149,6 +164,11 @@ class Terminal implements Process { } else { this.backlog[this.backlog.length - 1] += s; } + + // Trim the backlog if it's too long + if (this.backlog.length > MAX_BACKLOG) { + this.backlog.shift(); + } } this.requestRender(); @@ -163,9 +183,12 @@ class Terminal implements Process { } }); - this.context.setCursorBlink(false); + this.ctx.setCursorBlink(false); } + /** + Convter a command string into an array of arguments where the first element is the command name + **/ private function parseArgs(command:String):Array { // TODO: tim and quote handling return command.split(" "); @@ -173,7 +196,7 @@ class Terminal implements Process { private function clear() { this.backlog = []; - this.redrawBacklog(); + this.requestRender(); } private function getProgByName(name:String):Process { @@ -186,7 +209,7 @@ class Terminal implements Process { } private function moveCursorToInput() { - var size = this.context.getSize(); - this.context.setCursorPos(this.input.length + 2, size.y - 1); + var size = this.ctx.getSize(); + this.ctx.setCursorPos(this.input.length + 2, size.y - 1); } }