improved terminal with history

This commit is contained in:
Djeeberjr 2023-06-26 20:04:26 +02:00
parent dbd8038851
commit 3a2613d916

View File

@ -1,6 +1,5 @@
package bin; package bin;
import kernel.log.Log;
import kernel.binstore.BinStore; import kernel.binstore.BinStore;
import kernel.ps.ProcessHandle; import kernel.ps.ProcessHandle;
import kernel.ps.Process; import kernel.ps.Process;
@ -11,11 +10,18 @@ import kernel.ui.WindowContext;
using tink.CoreApi; using tink.CoreApi;
class Terminal implements Process { 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 input:String = "";
private var backlog:Array<String> = []; private var backlog:Array<String> = [];
private var handle:ProcessHandle; private var history:Array<String> = [];
private var requestRender: () -> Void; private var historyIndex:Int = 0;
private var runningPID:PID = -1; private var runningPID:PID = -1;
public function new() {} public function new() {}
@ -25,18 +31,20 @@ class Terminal implements Process {
var statelessContext = handle.createStatelessWindowContext(); var statelessContext = handle.createStatelessWindowContext();
this.context = statelessContext.ctx; this.ctx = statelessContext.ctx;
this.requestRender = statelessContext.requestRender; this.requestRender = statelessContext.requestRender;
statelessContext.setRenderFunc(this.render); 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; if (this.runningPID > 0) return;
this.input += char; this.input += char;
this.requestRender(); this.requestRender();
})); }));
handle.addCallbackLink(this.context.onKey.handle(e -> { // Add key event handlers
handle.addCallbackLink(this.ctx.onKey.handle(e -> {
switch (e.keyCode) { switch (e.keyCode) {
case 259: // Backspace case 259: // Backspace
if (this.runningPID > 0) return; if (this.runningPID > 0) return;
@ -48,9 +56,16 @@ class Terminal implements Process {
var command = this.input; var command = this.input;
this.input = ""; this.input = "";
this.requestRender(); this.requestRender();
this.historyIndex = 0;
this.invokeCommand(command); this.invokeCommand(command);
case 269: // END case 269: // END
this.stopCurrentPS(); 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() { private function render() {
redrawBacklog(); var size = this.ctx.getSize();
redrawInput();
}
private function redrawBacklog() {
var size = this.context.getSize();
var linesAvailable = size.y - 1; var linesAvailable = size.y - 1;
var start:Int = this.backlog.length - linesAvailable; var start:Int = this.backlog.length - linesAvailable;
@ -79,29 +89,28 @@ class Terminal implements Process {
for (i in 0...linesAvailable) { for (i in 0...linesAvailable) {
var line = this.backlog[start + i]; var line = this.backlog[start + i];
this.context.setCursorPos(0, i); this.ctx.setCursorPos(0, i);
this.context.clearLine(); this.ctx.clearLine();
if (line != null) { if (line != null) {
this.context.write(line); this.ctx.write(line);
} }
} }
this.moveCursorToInput();
this.ctx.setCursorPos(0, size.y - 1);
this.ctx.clearLine();
this.ctx.setTextColor(Color.Blue);
this.ctx.write("> ");
this.ctx.setTextColor(Color.White);
this.ctx.write(this.input);
if (this.runningPID < 0) {
this.ctx.setCursorBlink(true);
} else {
this.ctx.setCursorBlink(false);
} }
private function redrawInput() {
var size = this.context.getSize();
this.context.setCursorPos(0, size.y - 1);
this.context.clearLine();
this.context.setTextColor(Color.Blue);
this.context.write("> ");
this.context.setTextColor(Color.White);
this.context.write(this.input);
this.context.setCursorBlink(true);
} }
private function invokeCommand(command:String):Void { private function invokeCommand(command:String):Void {
@ -110,6 +119,13 @@ class Terminal implements Process {
if (args.length == 0) { if (args.length == 0) {
return; return;
} }
this.history.push(command);
if (this.history.length > MAX_BACKLOG) {
this.history.shift();
}
var commandName = args[0]; var commandName = args[0];
// Handle built-in commands // Handle built-in commands
@ -125,8 +141,7 @@ class Terminal implements Process {
var ps = getProgByName(commandName); var ps = getProgByName(commandName);
if (ps == null) { if (ps == null) {
this.backlog.push("Unknown command: " + commandName); this.backlog.push("Unknown command: " + commandName);
this.redrawBacklog(); this.requestRender();
this.redrawInput();
return; return;
} }
@ -149,6 +164,11 @@ class Terminal implements Process {
} else { } else {
this.backlog[this.backlog.length - 1] += s; 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(); 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<String> { private function parseArgs(command:String):Array<String> {
// TODO: tim and quote handling // TODO: tim and quote handling
return command.split(" "); return command.split(" ");
@ -173,7 +196,7 @@ class Terminal implements Process {
private function clear() { private function clear() {
this.backlog = []; this.backlog = [];
this.redrawBacklog(); this.requestRender();
} }
private function getProgByName(name:String):Process { private function getProgByName(name:String):Process {
@ -186,7 +209,7 @@ class Terminal implements Process {
} }
private function moveCursorToInput() { private function moveCursorToInput() {
var size = this.context.getSize(); var size = this.ctx.getSize();
this.context.setCursorPos(this.input.length + 2, size.y - 1); this.ctx.setCursorPos(this.input.length + 2, size.y - 1);
} }
} }