2022-12-15 13:21:26 +00:00
|
|
|
package bin;
|
|
|
|
|
2023-01-28 02:55:32 +00:00
|
|
|
import lib.ui.UIApp;
|
2022-12-19 20:06:23 +00:00
|
|
|
import lib.cli.TermHandle;
|
2023-01-28 02:55:32 +00:00
|
|
|
import lib.cli.CLIApp;
|
2022-12-19 20:06:23 +00:00
|
|
|
import lib.Color;
|
2022-12-15 13:21:26 +00:00
|
|
|
import kernel.ui.WindowContext;
|
|
|
|
import kernel.ui.WindowManager;
|
|
|
|
|
2023-01-28 02:55:32 +00:00
|
|
|
using tink.CoreApi;
|
|
|
|
|
|
|
|
class Terminal extends UIApp {
|
2022-12-15 13:21:26 +00:00
|
|
|
private var context:WindowContext;
|
|
|
|
private var input:String = "";
|
2022-12-19 16:35:52 +00:00
|
|
|
private var backlog:Array<String> = [];
|
2023-01-28 02:55:32 +00:00
|
|
|
private var exitTrigger: Bool -> Void;
|
2022-12-15 13:21:26 +00:00
|
|
|
|
|
|
|
public function new() {}
|
|
|
|
|
2023-01-28 02:55:32 +00:00
|
|
|
public function invoke(context: WindowContext): Future<Bool> {
|
|
|
|
this.context = context;
|
2022-12-15 13:21:26 +00:00
|
|
|
|
|
|
|
this.context.onChar.handle(char -> {
|
|
|
|
this.input += char;
|
|
|
|
this.redrawInput();
|
|
|
|
});
|
|
|
|
|
|
|
|
this.context.onKey.handle(e -> {
|
|
|
|
if (e.keyCode == 259) {
|
|
|
|
this.input = this.input.substr(0, this.input.length - 1);
|
|
|
|
this.redrawInput();
|
|
|
|
} else if (e.keyCode == 257) {
|
|
|
|
this.backlog.push("> " + this.input);
|
|
|
|
var command = this.input;
|
|
|
|
this.input = "";
|
|
|
|
this.redrawBacklog();
|
|
|
|
this.redrawInput();
|
|
|
|
this.invokeCommand(command);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
WindowManager.instance.focusContextToOutput(context, "main");
|
|
|
|
this.redrawInput();
|
2023-01-28 02:55:32 +00:00
|
|
|
|
|
|
|
return new Future<Bool>(cb -> {
|
|
|
|
this.exitTrigger = cb;
|
|
|
|
return null;
|
|
|
|
});
|
2022-12-15 13:21:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private function redrawBacklog() {
|
|
|
|
var size = this.context.getSize();
|
|
|
|
var linesAvailable = size.y - 1;
|
|
|
|
|
|
|
|
var start:Int = this.backlog.length - linesAvailable;
|
|
|
|
|
2022-12-19 16:35:52 +00:00
|
|
|
for (i in 0...linesAvailable) {
|
2022-12-15 13:21:26 +00:00
|
|
|
var line = this.backlog[start + i];
|
|
|
|
|
|
|
|
this.context.setCursorPos(0, i);
|
|
|
|
this.context.clearLine();
|
|
|
|
|
|
|
|
if (line != null) {
|
|
|
|
this.context.write(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.moveCursorToInput();
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-12-19 16:35:52 +00:00
|
|
|
private function invokeCommand(command:String):Void {
|
2022-12-15 13:21:26 +00:00
|
|
|
var args = this.parseArgs(command);
|
|
|
|
|
|
|
|
if (args.length == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var commandName = args[0];
|
|
|
|
|
|
|
|
// Handle built-in commands
|
|
|
|
switch (commandName) {
|
|
|
|
case "clear":
|
|
|
|
this.clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var commandArgs:Array<String> = args.slice(1);
|
|
|
|
var hadInput = false;
|
2022-12-19 16:35:52 +00:00
|
|
|
var handle = new TermHandle(commandArgs, {
|
2022-12-15 13:21:26 +00:00
|
|
|
onWrite: (s:String) -> {
|
|
|
|
if (!hadInput) {
|
|
|
|
this.backlog.push("");
|
|
|
|
hadInput = true;
|
|
|
|
}
|
|
|
|
this.backlog[this.backlog.length - 1] += s;
|
|
|
|
this.redrawBacklog();
|
|
|
|
},
|
|
|
|
onNewLine: () -> {
|
|
|
|
this.backlog.push("");
|
|
|
|
this.redrawBacklog();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-01-28 02:55:32 +00:00
|
|
|
var prog:CLIApp = getProgByName(commandName);
|
2022-12-15 13:21:26 +00:00
|
|
|
|
|
|
|
if (prog == null) {
|
|
|
|
this.backlog.push("Command not found: " + commandName);
|
|
|
|
this.redrawBacklog();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.context.setCursorBlink(false);
|
|
|
|
|
2022-12-19 16:35:52 +00:00
|
|
|
prog.invoke(handle).handle((exitCode) -> {
|
|
|
|
// Cleanup extra newline
|
|
|
|
if (this.backlog[this.backlog.length - 1] == "") {
|
|
|
|
this.backlog.pop();
|
|
|
|
}
|
2022-12-15 13:21:26 +00:00
|
|
|
|
2022-12-19 16:35:52 +00:00
|
|
|
this.redrawInput();
|
|
|
|
});
|
2022-12-15 13:21:26 +00:00
|
|
|
}
|
|
|
|
|
2022-12-19 16:35:52 +00:00
|
|
|
private function parseArgs(command:String):Array<String> {
|
2022-12-15 13:21:26 +00:00
|
|
|
// TODO: tim and quote handling
|
|
|
|
return command.split(" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
private function clear() {
|
|
|
|
this.backlog = [];
|
|
|
|
this.redrawBacklog();
|
|
|
|
}
|
|
|
|
|
2023-01-28 02:55:32 +00:00
|
|
|
private function getProgByName(name:String):CLIApp {
|
2022-12-15 13:21:26 +00:00
|
|
|
switch (name) {
|
|
|
|
case "hello":
|
|
|
|
return new HelloWorld();
|
2022-12-17 14:08:07 +00:00
|
|
|
case "net":
|
|
|
|
return new Net();
|
2022-12-19 22:28:46 +00:00
|
|
|
case "rs":
|
|
|
|
return new Redstone();
|
2023-01-27 13:34:25 +00:00
|
|
|
case "disk":
|
|
|
|
return new Disk();
|
2023-03-27 22:57:04 +00:00
|
|
|
case "gps":
|
|
|
|
return new GPS();
|
2022-12-15 13:21:26 +00:00
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private function moveCursorToInput() {
|
|
|
|
var size = this.context.getSize();
|
|
|
|
this.context.setCursorPos(this.input.length + 2, size.y - 1);
|
|
|
|
}
|
|
|
|
}
|