forked from tools/josh
Fix #66
This commit is contained in:
parent
cd0d2cb16d
commit
d158b4f970
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fwdekker.com",
|
||||
"version": "1.8.9",
|
||||
"version": "1.9.0",
|
||||
"description": "The source code of [my personal website](https://fwdekker.com/).",
|
||||
"author": "Felix W. Dekker",
|
||||
"repository": {
|
||||
|
|
|
@ -2,7 +2,7 @@ import "./Extensions"
|
|||
import {Environment} from "./Environment";
|
||||
import {Directory, File, FileSystem, Path} from "./FileSystem"
|
||||
import {Persistence} from "./Persistence";
|
||||
import {IllegalArgumentError, IllegalStateError} from "./Shared";
|
||||
import {escapeHtml, IllegalArgumentError, IllegalStateError} from "./Shared";
|
||||
import {InputArgs} from "./Shell";
|
||||
import {EscapeCharacters} from "./Terminal";
|
||||
import {UserList} from "./UserList";
|
||||
|
@ -46,8 +46,12 @@ export class Commands {
|
|||
"cat": new Command(
|
||||
this.cat,
|
||||
`concatenate and print files`,
|
||||
`cat <u>file</u> <u>...</u>`,
|
||||
`Reads files sequentially, writing them to the standard output.`,
|
||||
`cat [<b>-e</b> | <b>--escape-html</b>] <u>file</u> <u>...</u>`,
|
||||
`Reads files sequentially, writing them to the standard output.
|
||||
|
||||
If the file contains valid HTML, it will be displayed as such by default. If the <b>--html</b> \\\
|
||||
option is given, special HTML characters are escaped and the raw text contents can be inspected.\\\
|
||||
`.trimLines(),
|
||||
new InputValidator({minArgs: 1})
|
||||
),
|
||||
"clear": new Command(
|
||||
|
@ -122,7 +126,7 @@ export class Commands {
|
|||
`display manual documentation pages`,
|
||||
`man <u>page</u> <u>...</u>`,
|
||||
`Displays the manual pages with names <u>page</u>. Equivalent to using <b>help</b> if at least one \\\
|
||||
<u>page</u> is given.`.trimLines(),
|
||||
<u>page</u> is given.`.trimMultiLines(),
|
||||
new InputValidator()
|
||||
),
|
||||
"mkdir": new Command(
|
||||
|
@ -175,7 +179,7 @@ export class Commands {
|
|||
this.rm,
|
||||
`remove file`,
|
||||
`rm [<b>-f</b> | <b>--force</b>] [<b>-r</b> | <b>-R</b> | <b>--recursive</b>] \\\
|
||||
[<b>--no-preserve-root</b>] <u>file</u> <u>...</u>`.trimLines(),
|
||||
[<b>--no-preserve-root</b>] <u>file</u> <u>...</u>`.trimMultiLines(),
|
||||
`Removes each given <u>file</u>. If more than one <u>file</u> is given, they are removed in the \\\
|
||||
order they are given in.
|
||||
|
||||
|
@ -285,10 +289,11 @@ export class Commands {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (node.contents.endsWith("\n"))
|
||||
streams.out.write(node.contents);
|
||||
const contents = input.hasAnyOption("e", "--escape-html") ? escapeHtml(node.contents) : node.contents;
|
||||
if (contents.endsWith("\n"))
|
||||
streams.out.write(contents);
|
||||
else
|
||||
streams.out.writeLine(node.contents);
|
||||
streams.out.writeLine(contents);
|
||||
return 0;
|
||||
})
|
||||
.reduce((acc, exitCode) => exitCode === 0 ? acc : exitCode);
|
||||
|
@ -637,7 +642,7 @@ export class Commands {
|
|||
this.fileSystem.add(path, new File(), false);
|
||||
return 0;
|
||||
} catch (error) {
|
||||
streams.err.writeLine(`touche: ${error.message}`);
|
||||
streams.err.writeLine(`touch: ${error.message}`);
|
||||
return -1;
|
||||
}
|
||||
})
|
||||
|
|
|
@ -162,7 +162,7 @@ export class FileSystem {
|
|||
|
||||
const targetNode = this.get(target);
|
||||
if (!(targetNode instanceof File))
|
||||
throw new IllegalArgumentError("Cannot open stream to directory.");
|
||||
throw new IllegalArgumentError(`Cannot open stream to directory '${target}'.`);
|
||||
|
||||
if (options === "write")
|
||||
targetNode.contents = "";
|
||||
|
|
|
@ -18,8 +18,7 @@ export const asciiHeaderHtml =
|
|||
/**
|
||||
* A function that does nothing.
|
||||
*/
|
||||
export const emptyFunction = () => {
|
||||
};
|
||||
export const emptyFunction = () => {};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -38,6 +37,19 @@ export function addOnLoad(fun: () => void): void {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all special HTML characters with escaped variants.
|
||||
*
|
||||
* @param string the string to escape special HTML characters in
|
||||
*/
|
||||
export function escapeHtml(string: string): string {
|
||||
return string
|
||||
.replaceAll(/</, "<")
|
||||
.replaceAll(/>/, ">")
|
||||
.replaceAll(/"/, """)
|
||||
.replaceAll(/'/, "'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extension of the given filename, or `""` if it doesn't have one.
|
||||
*
|
||||
|
@ -98,17 +110,6 @@ export function q(query: string): HTMLElement {
|
|||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this string with all HTML tags stripped.
|
||||
*
|
||||
* @param string the string to strip HTML tags from
|
||||
*/
|
||||
export function stripHtmlTags(string: string): string {
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = string;
|
||||
return div.textContent || div.innerText || "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that an argument is given to a function that should not have been given.
|
||||
|
|
|
@ -3,7 +3,7 @@ import {Environment} from "./Environment";
|
|||
import {Directory, FileSystem, Path} from "./FileSystem";
|
||||
import {InputParser} from "./InputParser";
|
||||
import {Persistence} from "./Persistence";
|
||||
import {asciiHeaderHtml, stripHtmlTags} from "./Shared";
|
||||
import {asciiHeaderHtml} from "./Shared";
|
||||
import {EscapeCharacters, InputHistory} from "./Terminal";
|
||||
import {UserList} from "./UserList";
|
||||
import {StreamSet} from "./Stream";
|
||||
|
@ -144,11 +144,11 @@ export class Shell {
|
|||
return 0;
|
||||
}
|
||||
|
||||
this.inputHistory.addEntry(inputString.trimStart());
|
||||
this.inputHistory.addEntry(inputString);
|
||||
|
||||
let input;
|
||||
try {
|
||||
input = InputParser.create(this.environment, this.fileSystem).parse(stripHtmlTags(inputString));
|
||||
input = InputParser.create(this.environment, this.fileSystem).parse(inputString);
|
||||
} catch (error) {
|
||||
streams.err.writeLine(`Could not parse input: ${error.message}`);
|
||||
this.environment.set("status", "-1");
|
||||
|
@ -157,7 +157,13 @@ export class Shell {
|
|||
|
||||
if (input.redirectTarget[0] !== "default") {
|
||||
const target = Path.interpret(this.environment.get("cwd"), input.redirectTarget[1]);
|
||||
streams.out = this.fileSystem.open(target, input.redirectTarget[0]);
|
||||
try {
|
||||
streams.out = this.fileSystem.open(target, input.redirectTarget[0]);
|
||||
} catch(error) {
|
||||
streams.err.writeLine(`open: ${error.message}`);
|
||||
this.environment.set("status", "-1");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const output = this.commands.execute(input, streams);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {moveCaretToEndOf, parseCssPixels} from "./Shared";
|
||||
import {escapeHtml, moveCaretToEndOf, parseCssPixels} from "./Shared";
|
||||
import {Shell} from "./Shell";
|
||||
import {Buffer, StreamSet} from "./Stream";
|
||||
|
||||
|
@ -96,7 +96,7 @@ export class Terminal {
|
|||
* Returns the input the user has entered in the HTML element.
|
||||
*/
|
||||
private get inputText(): string {
|
||||
return this.input.innerHTML.replaceAll(/<br>/, "");
|
||||
return this.input.innerText.replaceAll(/<br>/, "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,7 +105,7 @@ export class Terminal {
|
|||
* @param inputText the text to set as the text of the input HTML element
|
||||
*/
|
||||
private set inputText(inputText: string) {
|
||||
this.input.innerHTML = inputText;
|
||||
this.input.innerText = inputText;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,7 +207,7 @@ export class Terminal {
|
|||
*/
|
||||
processInput(input: string): void {
|
||||
this.inputText = "";
|
||||
this.outputText += `${this.prefixText}${this.isInputHidden ? "" : input.trim()}\n`;
|
||||
this.outputText += `${this.prefixText}${this.isInputHidden ? "" : escapeHtml(input)}\n`;
|
||||
|
||||
this.standardInput.writeLine(input);
|
||||
this.shell.execute(new StreamSet(this.standardInput, this.standardOutput, this.standardOutput));
|
||||
|
|
Loading…
Reference in New Issue