Fix stuff, help command

This commit is contained in:
Daniel Kluge 2021-12-17 18:55:00 +01:00
parent a535c5b69a
commit c25a0e34e2
8 changed files with 77 additions and 19 deletions

View File

@ -11,7 +11,7 @@ const REPLHistory: NextPage<REPLHistoryParams> = ({history, inputRef}) => {
const focusInput = () => {if (inputRef.current) inputRef.current.focus();};
return <div className={styles.container} onClick={focusInput}>
{ history.map((value, idx) => <div className={styles.line} key={idx}>{value === "" ? "\u00A0" : value}</div>) }
{ history.map((value, idx) => <pre className={styles.line} key={idx}>{value === "" ? "\u00A0" : value}</pre>) }
</div>;
};

View File

@ -15,19 +15,34 @@ const REPLInput: NextPage<REPLInputParams> = ({historyCallback, inputRef}) => {
const [justTabbed, setJustTabbed] = React.useState<number>(0);
const replinOnChange = (e: React.FormEvent<HTMLInputElement>) => {
const currentInput = (e.target as HTMLInputElement).value.toLowerCase();
(e.target as HTMLInputElement).value = currentInput;
const suggest = commandCompletion(currentInput);
setCurrentCmd(suggest);
if (suggest.length === 0) suggest.push("");
if (typed.current) typed.current.innerHTML = currentInput;
if (completion.current) completion.current.innerHTML = suggest[0].substring(currentInput.length);
const input = (e.target as HTMLInputElement);
const currentInput = input.value.toLowerCase();
// Force lowercase
input.value = currentInput;
if (currentInput.includes(" ")) {
// Command already typed
input.maxLength = 524288; // Default value
if (typed.current) typed.current.innerHTML = "";
if (completion.current) completion.current.innerHTML = "";
setCurrentCmd([]);
return;
} else {
input.maxLength = 20;
// Get completion hint
const suggest = commandCompletion(currentInput);
setCurrentCmd(suggest);
if (suggest.length === 0) suggest.push("");
if (typed.current) typed.current.innerHTML = currentInput;
if (completion.current) completion.current.innerHTML = suggest[0].substring(currentInput.length);
}
};
const tabComplete = (e: React.KeyboardEvent<HTMLInputElement>) => {
const input = (e.target as HTMLInputElement);
if (e.key === "Tab" && currentCmd.length !== 0) {
e.preventDefault();
(e.target as HTMLInputElement).value = currentCmd[justTabbed % currentCmd.length];
input.value = currentCmd[justTabbed % currentCmd.length];
if(typed.current) typed.current.innerHTML = currentCmd[justTabbed % currentCmd.length];
if(completion.current) completion.current.innerHTML = "";
setJustTabbed(justTabbed + 1);
@ -35,7 +50,7 @@ const REPLInput: NextPage<REPLInputParams> = ({historyCallback, inputRef}) => {
if (e.key === "Enter") {
const result = executeCommand((e.target as HTMLInputElement).value);
(e.target as HTMLInputElement).value = "";
input.value = "";
if(typed.current) typed.current.innerHTML = "";
if(completion.current) completion.current.innerHTML = "";
historyCallback(result);
@ -47,7 +62,7 @@ const REPLInput: NextPage<REPLInputParams> = ({historyCallback, inputRef}) => {
return <div className={styles.wrapperwrapper}>
<span className={styles.inputstart}>$&nbsp;</span>
<div className={styles.wrapper}>
<input ref={inputRef as MutableRefObject<HTMLInputElement>} className={styles.in} type={"text"} onChange={replinOnChange} onKeyDown={tabComplete} spellCheck={"false"} autoFocus />
<input ref={inputRef as MutableRefObject<HTMLInputElement>} className={styles.in} type={"text"} onChange={replinOnChange} onKeyDown={tabComplete} spellCheck={"false"} autoFocus maxLength={20} />
<span className={styles.completionWrapper}><span ref={typed} className={styles.typed}></span><span ref={completion} className={styles.completion}></span></span>
</div>
</div>;

View File

@ -1,4 +1,4 @@
import type { Command } from "./types";
import type { Command, Flag } from "./types";
function illegalUse(raw: string, cmd: Command): string[] {
return [
@ -31,6 +31,10 @@ function checkSubcmd(subcmds: string[], cmd: Command): boolean {
return true;
}
function checkFlagInclude(flagsProvided: string[], flag: Flag): boolean {
return flagsProvided.includes(`-${flag.short}`) || flagsProvided.includes(`--${flag.long}`);
}
export function printSyntax(cmd: Command): string[] {
let flagsOption = "";
let flagsDesc = [];
@ -82,4 +86,31 @@ const about: Command = {
}
};
export const commandList = [about];
const help: Command = {
name: "help",
desc: "Shows helptext.",
flags: [{ long: "more", short: "m", desc: "Show more information." }],
execute: (flags, _args, _raw) => {
checkFlags(flags, help);
if (help.flags && checkFlagInclude(flags, help.flags[0])) {
return [
"Hello user!",
"What you see here should resemble an CLI. If you ever used Linux this should be pretty easy for you.",
"Everyone else: Have no fear. It is pretty simple. You just type in commands and the output is shown here or it does something on the webite.",
"To find out, which commands are available, you can type just 'help'.",
"",
"Have fun!"
];
} else {
const available = ["Available commands:"];
commandList.forEach(cmd => available.push(`\t${cmd.name}\t${cmd.desc}`));
available.concat([
"",
"Need more help? Type 'help -m'!"
]);
return available;
}
}
};
export const commandList = [about, help];

View File

@ -1,4 +1,4 @@
interface Flag {
export interface Flag {
short: string;
long: string;
desc: string;
@ -15,5 +15,5 @@ export interface Command {
desc: string;
flags?: Flag[];
subcommands?: SubCommand[];
execute: (flags: string[], args: string[], raw: string) => string[];
execute: (flags: string[], args: string[], raw: string, extra?: any) => string[];
}

2
package-lock.json generated
View File

@ -6,7 +6,7 @@
"": {
"name": "my_website",
"dependencies": {
"next": "^12.0.7",
"next": "12.0.7",
"react": "17.0.2",
"react-dom": "17.0.2"
},

View File

@ -1,13 +1,17 @@
import type { NextPage } from "next";
import Head from "next/head";
import REPL from "../components/REPL";
import styles from "../styles/Home.module.css";
const Home: NextPage = () => {
return (
return (<>
<Head>
<title>c0ntroller.de</title>
</Head>
<div className={styles.container}>
<REPL />
</div>
);
</>);
};
export default Home;

View File

@ -9,4 +9,8 @@
.line {
padding: 3px 0;
white-space: pre-wrap;
font-family: inherit;
display: block;
margin: 0;
}

View File

@ -53,13 +53,17 @@
.completionWrapper span {
padding: 0;
margin: 0;
display: inline-block;
display: flex;
flex-direction: column;
}
.typed {
opacity: 0;
flex-shrink: 1;
overflow-x: hidden;
}
.completion {
color: var(--repl-color-hint);
flex-grow: 1;
}