From c25a0e34e2f1753750d02bb1bc343a310483c85e Mon Sep 17 00:00:00 2001 From: Daniel Kluge Date: Fri, 17 Dec 2021 18:55:00 +0100 Subject: [PATCH] Fix stuff, help command --- components/REPL/REPLHistory.tsx | 2 +- components/REPL/REPLInput.tsx | 35 +++++++++++++------ .../{definitions.tsx => definitions.ts} | 35 +++++++++++++++++-- lib/commands/types.tsx | 4 +-- package-lock.json | 2 +- pages/index.tsx | 8 +++-- styles/REPL/REPLHistory.module.css | 4 +++ styles/REPL/REPLInput.module.css | 6 +++- 8 files changed, 77 insertions(+), 19 deletions(-) rename lib/commands/{definitions.tsx => definitions.ts} (67%) diff --git a/components/REPL/REPLHistory.tsx b/components/REPL/REPLHistory.tsx index fbe289e..1daeb8a 100644 --- a/components/REPL/REPLHistory.tsx +++ b/components/REPL/REPLHistory.tsx @@ -11,7 +11,7 @@ const REPLHistory: NextPage = ({history, inputRef}) => { const focusInput = () => {if (inputRef.current) inputRef.current.focus();}; return
- { history.map((value, idx) =>
{value === "" ? "\u00A0" : value}
) } + { history.map((value, idx) =>
{value === "" ? "\u00A0" : value}
) }
; }; diff --git a/components/REPL/REPLInput.tsx b/components/REPL/REPLInput.tsx index 91a1f69..7366081 100644 --- a/components/REPL/REPLInput.tsx +++ b/components/REPL/REPLInput.tsx @@ -15,19 +15,34 @@ const REPLInput: NextPage = ({historyCallback, inputRef}) => { const [justTabbed, setJustTabbed] = React.useState(0); const replinOnChange = (e: React.FormEvent) => { - 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) => { + 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 = ({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 = ({historyCallback, inputRef}) => { return
- } className={styles.in} type={"text"} onChange={replinOnChange} onKeyDown={tabComplete} spellCheck={"false"} autoFocus /> + } className={styles.in} type={"text"} onChange={replinOnChange} onKeyDown={tabComplete} spellCheck={"false"} autoFocus maxLength={20} />
; diff --git a/lib/commands/definitions.tsx b/lib/commands/definitions.ts similarity index 67% rename from lib/commands/definitions.tsx rename to lib/commands/definitions.ts index 9956680..8be13eb 100644 --- a/lib/commands/definitions.tsx +++ b/lib/commands/definitions.ts @@ -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]; \ No newline at end of file +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]; \ No newline at end of file diff --git a/lib/commands/types.tsx b/lib/commands/types.tsx index c515cd7..8e7ac51 100644 --- a/lib/commands/types.tsx +++ b/lib/commands/types.tsx @@ -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[]; } diff --git a/package-lock.json b/package-lock.json index 2cd3975..0c6ac64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" }, diff --git a/pages/index.tsx b/pages/index.tsx index 5f446b1..0f13d6d 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -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 (<> + + c0ntroller.de +
- ); + ); }; export default Home; diff --git a/styles/REPL/REPLHistory.module.css b/styles/REPL/REPLHistory.module.css index a47ac6d..9471f24 100644 --- a/styles/REPL/REPLHistory.module.css +++ b/styles/REPL/REPLHistory.module.css @@ -9,4 +9,8 @@ .line { padding: 3px 0; + white-space: pre-wrap; + font-family: inherit; + display: block; + margin: 0; } \ No newline at end of file diff --git a/styles/REPL/REPLInput.module.css b/styles/REPL/REPLInput.module.css index 15e1008..ab09f38 100644 --- a/styles/REPL/REPLInput.module.css +++ b/styles/REPL/REPLInput.module.css @@ -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; }