Teascade.net/public/terminal/ts/jsxcommands.ts

449 lines
14 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

namespace JSXCommands {
/**
* Echoes the given arguments
*/
export class Echo implements JSTerminal.Program {
create(terminal: JSTerminal.Terminal, stdio: Std.IO, args?: string[]) {
if (args.filter((a) => { return a != ""; }).length == 0) {
stdio.println("Nothing echoes... nothing");
terminal.closeProgram(this);
return;
}
stdio.println(args.join(" "));
terminal.closeProgram(this);
}
enable() { }
disable() { }
onClose() { return true; }
getManual() {
return "Echoes the given arguments" +
"\n\nUsage: echo [anything to echo]";
}
}
/**
* Lists all files in the given directory or this directory, if path not specified.
*/
export class List implements JSTerminal.Program {
jsx: JavaScriptX.JSX;
constructor(jsx: JavaScriptX.JSX) {
this.jsx = jsx;
}
create(terminal: JSTerminal.Terminal, stdio: Std.IO, args?: string[]) {
let folder = this.jsx.currentFolder;
if (args.length > 0) {
let pathStr = args.slice(-1)[0];
let path = this.jsx.findPath(pathStr);
if (path instanceof JavaScriptX.Folder) {
args.splice(-1);
folder = path;
}
}
let argObj = parseArgsToObject(args);
let a = "a" in argObj;
if (a) {
stdio.println(".", "blue");
if (folder.parentFolder != null) {
stdio.println("..", "blue");
}
}
let files = folder.files.filter(f => (!f.hidden || a));
for (let i = 0; i < files.length; i++) {
let f = files[i];
stdio.println(JavaScriptX.formatToLength(f.name, 20),
((f.hidden) ? "blue" : (f instanceof JavaScriptX.Folder) ? "red" : "yellow")
);
stdio.print(" " +
((f instanceof JavaScriptX.Folder) ? "DIR" : ((f instanceof JavaScriptX.BinaryFile) ? "BIN" : "TXT")));
stdio.print(" " + new Date(f.created).toLocaleString());
}
terminal.closeProgram(this);
}
enable() { }
disable() { }
onClose() { return true; }
getManual() {
return "Lists all files in the given directory\nor this directory, if path not specified." +
"\n\nUsage: ls [options] [path]" +
"\n\nOptions:\n " + JavaScriptX.formatToLength("-a", 10) + "List all files (incl. hidden)";
}
}
/**
* Changes directory to the specified directory.
*/
export class ChangeDirectory implements JSTerminal.Program {
jsx: JavaScriptX.JSX;
constructor(jsx: JavaScriptX.JSX) {
this.jsx = jsx;
}
create(terminal: JSTerminal.Terminal, stdio: Std.IO, args?: string[]) {
if (args.length == 0) {
stdio.println("Insufficent parameters, usage:");
stdio.println("cd [path]");
terminal.closeProgram(this);
return;
}
let path = this.jsx.findPath(args[0]);
let folder = false;
if (path) {
if (path instanceof JavaScriptX.Folder) {
folder = true;
} else {
stdio.println(`'${args[0]}' is not a folder.`);
}
} else {
stdio.println(`'${args[0]}' not found.`);
}
if (folder && path instanceof JavaScriptX.Folder) { // second part only to satisfy TypeScript compiler
this.jsx.currentFolder = path;
}
terminal.closeProgram(this);
}
enable() { }
disable() { }
onClose() { return true; }
getManual() {
return "Changes directory to the specified directory." +
"\n\nUsage: cd [path]";
}
}
/**
* Creates a directory at specified location.
*/
export class MakeDirectory implements JSTerminal.Program, JavaScriptX.Manual {
jsx: JavaScriptX.JSX;
constructor(jsx: JavaScriptX.JSX) {
this.jsx = jsx;
}
create(terminal: JSTerminal.Terminal, stdio: Std.IO, args?: string[]) {
if (args.length == 0) {
stdio.println("Insufficent parameters, usage:");
stdio.println("mkdir [path]");
terminal.closeProgram(this);
return;
}
let pathArg = args.splice(-1)[0];
let argObj = parseArgsToObject(args);
let h = "h" in argObj;
let origPathpieces = pathArg.split("/");
let curr = [origPathpieces[0]];
let i = 0;
let createFolder = false;
do {
let path = this.jsx.findPath(curr.join("/"));
if (!path) {
if (origPathpieces.length == curr.length) {
createFolder = true;
} else {
stdio.println(`${curr.join("/")} not found!`);
}
break;
} else if (path && origPathpieces.length == curr.length) {
stdio.println(`${curr.join("/")} already exists!`);
} else if (!(path instanceof JavaScriptX.Folder)) {
stdio.println(`${curr.join("/")} is not a folder!`);
}
if (i < origPathpieces.length) {
i += 1;
curr.push(origPathpieces[i]);
}
} while (curr.length < origPathpieces.length + 1)
if (createFolder) {
let path = origPathpieces.slice(0, -1).join("/");
let name = origPathpieces.slice(-1)[0];
let relative = this.jsx.findPath(path);
if (relative instanceof JavaScriptX.Folder) {
relative.addFile(new JavaScriptX.Folder(name, h));
} else {
stdio.println("An error occoured creating the folder.");
}
}
terminal.closeProgram(this);
}
enable() { }
disable() { }
onClose() { return true; }
getManual() {
return "Creates a directory at specified location." +
"\n\nUsage: mkdir [options] [path]" +
"\n\nOptions:\n " + JavaScriptX.formatToLength("-h", 10) + "Makes the folder hidden.";
}
}
/**
* The Woman in the JSX equivalent to the UNIX Man.
* It's called Woman (not Man) because of the funny wording,
* where 'man' sounds like the gender 'man'
*/
export class Woman implements JSTerminal.Program, JavaScriptX.Manual {
jsx: JavaScriptX.JSX;
constructor(jsx: JavaScriptX.JSX) {
this.jsx = jsx;
}
create(terminal: JSTerminal.Terminal, stdio: Std.IO, args?: string[]) {
if (args.length == 0) {
this.readManual(stdio, this);
terminal.closeProgram(this);
return;
}
let filePath = args.slice(-1)[0];
for (let env in this.jsx.environmentVariables) {
if (filePath == env) {
filePath = env;
break;
}
let envFolder = this.jsx.findPath(this.jsx.environmentVariables[env]);
if (envFolder instanceof JavaScriptX.Folder) {
for (let i = 0; i < envFolder.files.length; i++) {
if (envFolder.files[i].name == filePath) {
filePath = envFolder.files[i].getPath();
break;
}
}
}
}
let f = this.jsx.findPath(filePath);
if (f && f instanceof JavaScriptX.BinaryFile && manualGuard(f.program)) {
this.readManual(stdio, f.program);
} else {
stdio.println("Nothing to womansplain.");
}
terminal.closeProgram(this);
}
enable() { }
disable() { }
onClose() { return true; }
getManual() {
return "The Woman in the JSX equivalent to the UNIX Man. " +
"It's called Woman (not Man) because of the funny wording, " +
"where 'man' sounds like the gender 'man'" +
"\n\nUsage: woman [path]";
}
readManual(stdio: Std.IO, manual: JavaScriptX.Manual) {
stdio.println(manual.getManual());
}
}
export class Caternate implements JSTerminal.Program, JavaScriptX.Manual {
jsx: JavaScriptX.JSX;
constructor(jsx: JavaScriptX.JSX) {
this.jsx = jsx;
}
create(terminal: JSTerminal.Terminal, stdio: Std.IO, args?: string[]) {
if (args.length == 0) {
stdio.println("Insufficent arguments.");
stdio.println("\nUsage: cat [path]");
terminal.closeProgram(this);
return;
}
let path = args.splice(-1)[0];
let file = this.jsx.findPath(path);
if (file instanceof JavaScriptX.BinaryFile) {
stdio.println("Unable to read binary files (yet).");
} else if (file instanceof JavaScriptX.Folder) {
stdio.println(file.name, "blue");
stdio.print(" is a DIRectory containing ")
stdio.print(file.files.length + "", "red");
stdio.print(" files.");
} else if (file instanceof JavaScriptX.TextFile) {
let contents = file.readContent();
stdio.println(contents);
}
terminal.closeProgram(this);
}
enable() { }
disable() { }
onClose() { return true; }
getManual() {
return "[cat]ernate reads data from given file and outputs it." +
"\n\nUsage: cat [path]";
}
readManual(stdio: Std.IO, manual: JavaScriptX.Manual) {
stdio.println(manual.getManual());
}
}
export class Touch implements JSTerminal.Program, JavaScriptX.Manual {
jsx: JavaScriptX.JSX;
constructor(jsx: JavaScriptX.JSX) {
this.jsx = jsx;
}
create(terminal: JSTerminal.Terminal, stdio: Std.IO, args?: string[]) {
if (args.length == 0) {
stdio.println("Insufficent arguments.");
stdio.println("\nUsage: touch [path]");
terminal.closeProgram(this);
return;
}
let path = args.splice(-1)[0];
let file = this.jsx.findPath(path);
if (file) {
file.created = new Date().getTime();
} else {
let origPathparts = path.split("/");
let curr = [origPathparts[0]];
for (let i = 1; i < origPathparts.length; i++) {
let currFile = this.jsx.findPath(curr.join("/"));
if (!currFile) {
stdio.println(`${curr.join("/")} not found.`);
terminal.closeProgram(this);
return;
}
curr.push(origPathparts[i]);
}
let filename = curr.splice(-1);
let folder = this.jsx.findPath(curr.join("/"));
if (folder instanceof JavaScriptX.Folder) {
folder.addFile(new JavaScriptX.TextFile(filename[0]));
} else {
stdio.println(`${curr.join("/")} is not a folder.`);
}
}
terminal.closeProgram(this);
}
enable() { }
disable() { }
onClose() { return true; }
getManual() {
return "Touch touches the file specified updating it's timestamp. If the file doesn't exist, it's created." +
"\n\nUsage: touch [path]";
}
readManual(stdio: Std.IO, manual: JavaScriptX.Manual) {
stdio.println(manual.getManual());
}
}
export class JEdi implements JSTerminal.Program, JavaScriptX.Manual {
jsx: JavaScriptX.JSX;
stdio: Std.IO;
terminal: JSTerminal.Terminal;
text: string[] = [""];
row = 0
constructor(jsx: JavaScriptX.JSX) {
this.jsx = jsx;
}
create(terminal: JSTerminal.Terminal, stdio: Std.IO, args?: string[]) {
this.stdio = stdio;
this.terminal = terminal;
this.doCommand();
}
enable() { }
disable() { }
onClose() { return true; }
getManual() {
return "(J)avascript (Edi)tor is a custom version of the UNIX editor 'ed'." +
"\nIt's quite simpler in the way that all of it's commands are whole words" +
"\n\nUsage: jedi [(optional) path]";
}
readManual(stdio: Std.IO, manual: JavaScriptX.Manual) {
stdio.println(manual.getManual());
}
doCommand() {
let readline = this.stdio.readline({
callback: c => this.exec(c),
prefix: "\n> ",
printAfterDone: true
})
}
exec(command: string) {
if (command == "exit" || command == "quit") {
this.terminal.closeProgram(this);
return;
} else if (command.split(" ")[0] == "append") {
let appended = command.split(" ").slice(1).join(" ");
debugger;
console.log(appended)
let rows = appended.split("\n");
console.log(rows)
for (let i = 0; i < rows.length; i++) {
if (this.text.length <= (this.row + i)) {
this.text.push("");
}
this.text[this.row + i] += rows[i];
}
this.row += rows.length - 1;
this.stdio.println(`${this.text[this.row]}`);
}
this.doCommand();
}
}
/**
* Parses all given args from '--arg val' into format {arg: val}
*/
function parseArgsToObject(args: string[], defaults: { [args: string]: string } = {}) {
let returned: { [arg: string]: string } = {};
for (let key in defaults) {
returned[key] = defaults[key];
}
let currArg: string = null;
args.forEach(arg => {
if (arg.startsWith("-")) {
if (arg.startsWith("--")) {
if (currArg) { returned[currArg] = null };
currArg = arg.substr(2);
return;
}
if (currArg) { returned[currArg] = null };
currArg = arg.substr(1);
} else {
if (currArg) {
returned[currArg] = arg;
currArg = null;
}
}
});
if (currArg) { returned[currArg] = null };
return returned;
}
function manualGuard(arg: any): arg is JavaScriptX.Manual {
return arg.getManual !== undefined
}
}