Updated terminal app
This commit is contained in:
parent
044d68ea37
commit
1e1bdf5089
31 changed files with 114 additions and 63 deletions
|
|
@ -37,6 +37,13 @@ export function Terminal({ startPath, input, setTitle, close: exit, active }) {
|
||||||
setStreamFocused(true);
|
setStreamFocused(true);
|
||||||
}, [streamFocused, streamOutput, streamRef]);
|
}, [streamFocused, streamOutput, streamRef]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!inputRef.current || !active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
inputRef.current.focus();
|
||||||
|
}, [inputRef, active]);
|
||||||
|
|
||||||
const prefix = `${ANSI.fg.cyan + USERNAME}@${HOSTNAME + ANSI.reset}:`
|
const prefix = `${ANSI.fg.cyan + USERNAME}@${HOSTNAME + ANSI.reset}:`
|
||||||
+ `${ANSI.fg.blue + (currentDirectory.root ? "/" : currentDirectory.path) + ANSI.reset}$ `;
|
+ `${ANSI.fg.blue + (currentDirectory.root ? "/" : currentDirectory.path) + ANSI.reset}$ `;
|
||||||
|
|
||||||
|
|
@ -102,7 +109,7 @@ export function Terminal({ startPath, input, setTitle, close: exit, active }) {
|
||||||
const command = CommandsManager.find(commandName);
|
const command = CommandsManager.find(commandName);
|
||||||
|
|
||||||
if (!command)
|
if (!command)
|
||||||
return `${commandName}: Command not found`;
|
return CommandsManager.formatError(commandName, "Command not found");
|
||||||
|
|
||||||
// Get options
|
// Get options
|
||||||
const options = [];
|
const options = [];
|
||||||
|
|
@ -138,10 +145,10 @@ export function Terminal({ startPath, input, setTitle, close: exit, active }) {
|
||||||
|
|
||||||
// Check usage
|
// Check usage
|
||||||
if (command.requireArgs && args.length === 0)
|
if (command.requireArgs && args.length === 0)
|
||||||
return `${commandName}: Incorrect usage: ${commandName} requires at least 1 argument`;
|
return CommandsManager.formatError(commandName, `Incorrect usage: ${commandName} requires at least 1 argument`);
|
||||||
|
|
||||||
if (command.requireOptions && options.length === 0)
|
if (command.requireOptions && options.length === 0)
|
||||||
return `${commandName}: Incorrect usage: ${commandName} requires at least 1 option`;
|
return CommandsManager.formatError(commandName, `Incorrect usage: ${commandName} requires at least 1 option`);
|
||||||
|
|
||||||
// Execute command
|
// Execute command
|
||||||
let response = null;
|
let response = null;
|
||||||
|
|
@ -162,13 +169,13 @@ export function Terminal({ startPath, input, setTitle, close: exit, active }) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response == null)
|
if (response == null)
|
||||||
return `${commandName}: Command failed`;
|
return CommandsManager.formatError(commandName, "Command failed");
|
||||||
|
|
||||||
if (!response.blank)
|
if (!response.blank)
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return `${commandName}: Command failed`;
|
return CommandsManager.formatError(commandName, "Command failed");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ansi-black-fg { color: var(--dark-grey-e); }
|
.ansi-black-fg { color: var(--dark-grey-e); }
|
||||||
.ansi-red-fg { color: var(--red-b); }
|
.ansi-red-fg { color: var(--red-b); }
|
||||||
.ansi-green-fg { color: var(--green-b); }
|
.ansi-green-fg { color: var(--green-b); }
|
||||||
.ansi-yellow-fg { color: var(--yellow-b); }
|
.ansi-yellow-fg { color: var(--yellow-b); }
|
||||||
|
|
@ -119,3 +119,5 @@
|
||||||
.ansi-magenta-bg { background-color: var(--purple-a); }
|
.ansi-magenta-bg { background-color: var(--purple-a); }
|
||||||
.ansi-cyan-bg { background-color: var(--cyan-a); }
|
.ansi-cyan-bg { background-color: var(--cyan-a); }
|
||||||
.ansi-white-bg { background-color: var(--white-a); }
|
.ansi-white-bg { background-color: var(--white-a); }
|
||||||
|
|
||||||
|
.ansi-dim { opacity: 0.65; }
|
||||||
|
|
@ -15,6 +15,9 @@ export const ANSI = {
|
||||||
},
|
},
|
||||||
bg: {
|
bg: {
|
||||||
|
|
||||||
|
},
|
||||||
|
decoration: {
|
||||||
|
dim: "\u001b[2m",
|
||||||
},
|
},
|
||||||
reset: "\u001b[0m",
|
reset: "\u001b[0m",
|
||||||
};
|
};
|
||||||
|
|
@ -42,6 +42,14 @@ export default class Command {
|
||||||
*/
|
*/
|
||||||
setName(name) {
|
setName(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
||||||
|
if (!this.manual?.usage) {
|
||||||
|
if (!this.manual)
|
||||||
|
this.manual = {};
|
||||||
|
|
||||||
|
this.manual.usage = name;
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ANSI } from "../../../config/apps/terminal.config.js";
|
||||||
import Command from "./command.js";
|
import Command from "./command.js";
|
||||||
|
|
||||||
let commands = [];
|
let commands = [];
|
||||||
|
|
@ -54,4 +55,13 @@ export default class CommandsManager {
|
||||||
loadCommands();
|
loadCommands();
|
||||||
CommandsManager.COMMANDS = commands;
|
CommandsManager.COMMANDS = commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} commandName
|
||||||
|
* @param {string} error
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
static formatError(commandName, error) {
|
||||||
|
return `${ANSI.fg.red}${commandName}: ${error}${ANSI.reset}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,20 @@
|
||||||
import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
|
import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const cat = new Command()
|
export const cat = new Command()
|
||||||
.setRequireArgs(true)
|
.setRequireArgs(true)
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Concetenate files and display on the terminal screen",
|
purpose: "Concetenate files and display on the terminal screen",
|
||||||
usage: "cat [OPTION]... [FILE]...",
|
usage: "cat [options] [files]",
|
||||||
description: "Concetenate FILE(s) to standard output."
|
description: "Concetenate files to standard output."
|
||||||
})
|
})
|
||||||
.setExecute(function(args, { currentDirectory, options }) {
|
.setExecute(function(args, { currentDirectory, options }) {
|
||||||
const { name, extension } = VirtualFile.convertId(args[0]);
|
const { name, extension } = VirtualFile.convertId(args[0]);
|
||||||
const file = currentDirectory.findFile(name, extension);
|
const file = currentDirectory.findFile(name, extension);
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
return `${this.name}: ${args[0]}: No such file`;
|
return CommandsManager.formatError(this.name, `${args[0]}: No such file`);
|
||||||
|
|
||||||
if (file.content) {
|
if (file.content) {
|
||||||
if (!options.includes("e")) {
|
if (!options.includes("e")) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const cd = new Command()
|
export const cd = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Change the current directory",
|
purpose: "Change the current directory",
|
||||||
usage: "cd path",
|
usage: "cd [PATH]",
|
||||||
description: "Change working directory to given path (the home directory by default)."
|
description: "Change working directory to given path (the home directory by default)."
|
||||||
})
|
})
|
||||||
.setExecute(function(args, { currentDirectory, setCurrentDirectory }) {
|
.setExecute(function(args, { currentDirectory, setCurrentDirectory }) {
|
||||||
|
|
@ -11,9 +12,8 @@ export const cd = new Command()
|
||||||
const destination = currentDirectory.navigate(path);
|
const destination = currentDirectory.navigate(path);
|
||||||
|
|
||||||
if (!destination)
|
if (!destination)
|
||||||
return `${this.name}: ${args[0]}: No such file or directory`;
|
return CommandsManager.formatError(this.name, `${args[0]}: No such file or directory`);
|
||||||
|
|
||||||
console.log(destination);
|
|
||||||
setCurrentDirectory(destination);
|
setCurrentDirectory(destination);
|
||||||
return { blank: true };
|
return { blank: true };
|
||||||
});
|
});
|
||||||
|
|
@ -3,7 +3,6 @@ import Command from "../command.js";
|
||||||
export const clear = new Command()
|
export const clear = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Clear terminal screen",
|
purpose: "Clear terminal screen",
|
||||||
usage: "clear",
|
|
||||||
})
|
})
|
||||||
.setExecute(function(args, { pushHistory }) {
|
.setExecute(function(args, { pushHistory }) {
|
||||||
pushHistory({
|
pushHistory({
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ import Command from "../command.js";
|
||||||
import CommandsManager from "../commands.js";
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const compgen = new Command()
|
export const compgen = new Command()
|
||||||
|
.setManual({
|
||||||
|
purpose: "Display a list of all commands"
|
||||||
|
})
|
||||||
.setRequireOptions(true)
|
.setRequireOptions(true)
|
||||||
.setExecute(function(args, { options }) {
|
.setExecute(function(args, { options }) {
|
||||||
if (options.includes("c")) {
|
if (options.includes("c")) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export const dir = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "List all directories in the current directory"
|
purpose: "List all directories in the current directory"
|
||||||
})
|
})
|
||||||
.setExecute((args, { currentDirectory }) => {
|
.setExecute(function(args, { currentDirectory }) {
|
||||||
const folderNames = currentDirectory.subFolders.map((folder) => folder.id);
|
const folderNames = currentDirectory.subFolders.map((folder) => folder.id);
|
||||||
|
|
||||||
if (folderNames.length === 0)
|
if (folderNames.length === 0)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,6 @@ export const echo = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Display text on the terminal screen"
|
purpose: "Display text on the terminal screen"
|
||||||
})
|
})
|
||||||
.setExecute((args, { rawInputValue }) => {
|
.setExecute(function(args, { rawInputValue }) {
|
||||||
return rawInputValue;
|
return rawInputValue;
|
||||||
});
|
});
|
||||||
|
|
@ -4,7 +4,7 @@ export const exit = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Quit terminal interface"
|
purpose: "Quit terminal interface"
|
||||||
})
|
})
|
||||||
.setExecute((args, { exit }) => {
|
.setExecute(function(args, { exit }) {
|
||||||
exit();
|
exit();
|
||||||
return { blank: true };
|
return { blank: true };
|
||||||
});
|
});
|
||||||
|
|
@ -58,6 +58,6 @@ export const fortune = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Tell fortune"
|
purpose: "Tell fortune"
|
||||||
})
|
})
|
||||||
.setExecute(() => {
|
.setExecute(function() {
|
||||||
return randomFromArray(FORTUNES);
|
return randomFromArray(FORTUNES);
|
||||||
});
|
});
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
|
import { ANSI } from "../../../../config/apps/terminal.config.js";
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
import CommandsManager from "../commands.js";
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const help = new Command()
|
export const help = new Command()
|
||||||
.setExecute((args) => {
|
.setExecute(function(args) {
|
||||||
if (args.length === 0) {
|
if (args.length === 0) {
|
||||||
return CommandsManager.COMMANDS.map((command) => {
|
return CommandsManager.COMMANDS.map((command) => {
|
||||||
if (command.manual?.purpose) {
|
if (command.manual?.purpose) {
|
||||||
return `${command.name} - ${command.manual.purpose}`;
|
return `${command.name} - ${ANSI.fg.green}${ANSI.decoration.dim}${command.manual.purpose}${ANSI.reset}`;
|
||||||
} else {
|
} else {
|
||||||
return command.name;
|
return command.name;
|
||||||
}
|
}
|
||||||
|
|
@ -17,10 +18,10 @@ export const help = new Command()
|
||||||
const command = CommandsManager.find(commandName);
|
const command = CommandsManager.find(commandName);
|
||||||
|
|
||||||
if (!command)
|
if (!command)
|
||||||
return `${this.name}: ${commandName}: Command not found`;
|
return CommandsManager.formatError(this.name, `${commandName}: Command not found`);
|
||||||
|
|
||||||
if (!command.manual?.purpose)
|
if (!command.manual?.purpose)
|
||||||
return `${this.name}: ${commandName}: No manual found`;
|
return CommandsManager.formatError(this.name, `${commandName}: No manual found`);
|
||||||
|
|
||||||
return command.manual.purpose;
|
return command.manual.purpose;
|
||||||
});
|
});
|
||||||
|
|
@ -4,6 +4,6 @@ export const hostname = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Display the hostname"
|
purpose: "Display the hostname"
|
||||||
})
|
})
|
||||||
.setExecute((args, { hostname }) => {
|
.setExecute(function(args, { hostname }) {
|
||||||
return hostname;
|
return hostname;
|
||||||
});
|
});
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { ANSI } from "../../../../config/apps/terminal.config.js";
|
import { ANSI } from "../../../../config/apps/terminal.config.js";
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const ls = new Command()
|
export const ls = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "List directory contents",
|
purpose: "List directory contents",
|
||||||
usage: "ls [OPTION]... [FILE]...",
|
usage: "ls [options] [files]",
|
||||||
description: "List information about the FILEs (the current directory by default)."
|
description: "List information about directories or files (the current directory by default)."
|
||||||
})
|
})
|
||||||
.setExecute(function(args, { currentDirectory }) {
|
.setExecute(function(args, { currentDirectory }) {
|
||||||
let directory = currentDirectory;
|
let directory = currentDirectory;
|
||||||
|
|
@ -15,7 +16,7 @@ export const ls = new Command()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!directory)
|
if (!directory)
|
||||||
return `${this.name}: Cannot access '${args[0]}': No such file or directory`;
|
return CommandsManager.formatError(this.name, `Cannot access '${args[0]}': No such file or directory`);
|
||||||
|
|
||||||
const folderNames = directory.subFolders.map((folder) => `${ANSI.fg.blue}${folder.id}${ANSI.reset}`);
|
const folderNames = directory.subFolders.map((folder) => `${ANSI.fg.blue}${folder.id}${ANSI.reset}`);
|
||||||
const fileNames = directory.files.map((file) => file.id);
|
const fileNames = directory.files.map((file) => file.id);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const make = new Command()
|
export const make = new Command()
|
||||||
.setRequireArgs(true)
|
.setRequireArgs(true)
|
||||||
.setExecute(function(args) {
|
.setExecute(function(args) {
|
||||||
if (args[0] === "love")
|
if (args[0] === "love")
|
||||||
return `${this.name}: *** No rule to make target 'love'. Stop.`;
|
return CommandsManager.formatError(this.name, "*** No rule to make target 'love'. Stop.");
|
||||||
});
|
});
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ANSI } from "../../../../config/apps/terminal.config.js";
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
import CommandsManager from "../commands.js";
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
|
|
@ -7,8 +8,8 @@ export const man = new Command()
|
||||||
.setRequireArgs(true)
|
.setRequireArgs(true)
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Show system reference manuals",
|
purpose: "Show system reference manuals",
|
||||||
usage: "man [OPTION]... page\n"
|
usage: "man [options] page\n"
|
||||||
+ "man -k [OPTION]... regexp",
|
+ "man -k [options] regexp",
|
||||||
description: "Each page arguments given to man is normally the name of a command.\n"
|
description: "Each page arguments given to man is normally the name of a command.\n"
|
||||||
+ "The manual page associated with this command is then found and displayed.",
|
+ "The manual page associated with this command is then found and displayed.",
|
||||||
options: {
|
options: {
|
||||||
|
|
@ -47,7 +48,7 @@ export const man = new Command()
|
||||||
const sections = [["NAME"]];
|
const sections = [["NAME"]];
|
||||||
|
|
||||||
if (manual.purpose) {
|
if (manual.purpose) {
|
||||||
sections[0].push(formatText(`${commandName} - ${command.manual.purpose}`));
|
sections[0].push(formatText(`${commandName} - ${ANSI.decoration.dim}${ANSI.fg.yellow}${command.manual.purpose}${ANSI.reset}`));
|
||||||
} else {
|
} else {
|
||||||
sections[0].push(formatText(commandName));
|
sections[0].push(formatText(commandName));
|
||||||
}
|
}
|
||||||
|
|
@ -70,10 +71,13 @@ export const man = new Command()
|
||||||
sections.push([
|
sections.push([
|
||||||
"OPTIONS",
|
"OPTIONS",
|
||||||
formatText(Object.entries(manual.options).map(([key, value]) => {
|
formatText(Object.entries(manual.options).map(([key, value]) => {
|
||||||
return `${key} ${value}`;
|
return `${key} ${ANSI.decoration.dim}${ANSI.fg.yellow}${value}${ANSI.reset}`;
|
||||||
}).join("\n"))
|
}).join("\n"))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sections.map((section) => section.join("\n")).join("\n\n");
|
return sections.map((section) => {
|
||||||
|
section[0] = ANSI.fg.yellow + section[0] + ANSI.reset;
|
||||||
|
return section.join("\n");
|
||||||
|
}).join("\n\n");
|
||||||
});
|
});
|
||||||
|
|
@ -2,10 +2,10 @@ import Command from "../command.js";
|
||||||
|
|
||||||
export const mkdir = new Command()
|
export const mkdir = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Create directory"
|
purpose: "Create a directory"
|
||||||
})
|
})
|
||||||
.setRequireArgs(true)
|
.setRequireArgs(true)
|
||||||
.setExecute((args, { currentDirectory }) => {
|
.setExecute(function(args, { currentDirectory }) {
|
||||||
const name = args[0];
|
const name = args[0];
|
||||||
|
|
||||||
if (currentDirectory.findSubFolder(name))
|
if (currentDirectory.findSubFolder(name))
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export const neofetch = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Fetch system information"
|
purpose: "Fetch system information"
|
||||||
})
|
})
|
||||||
.setExecute((args, { username, hostname }) => {
|
.setExecute(function(args, { username, hostname }) {
|
||||||
const leftColumn = ANSI_ASCII_LOGO.split("\n");
|
const leftColumn = ANSI_ASCII_LOGO.split("\n");
|
||||||
const rightColumnWidth = username.length + hostname.length + 1;
|
const rightColumnWidth = username.length + hostname.length + 1;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export const pwd = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Display path of the current directory"
|
purpose: "Display path of the current directory"
|
||||||
})
|
})
|
||||||
.setExecute((args, { currentDirectory }) => {
|
.setExecute(function(args, { currentDirectory }) {
|
||||||
if (currentDirectory.root) {
|
if (currentDirectory.root) {
|
||||||
return "/";
|
return "/";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export const reboot = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Reboot the system"
|
purpose: "Reboot the system"
|
||||||
})
|
})
|
||||||
.setExecute(() => {
|
.setExecute(function() {
|
||||||
reloadViewport();
|
reloadViewport();
|
||||||
return { blank: true };
|
return { blank: true };
|
||||||
});
|
});
|
||||||
|
|
@ -3,11 +3,9 @@ import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const reload = new Command()
|
export const reload = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Reload terminal commands",
|
purpose: "Reload the terminal",
|
||||||
usage: "reload",
|
|
||||||
})
|
})
|
||||||
.setExecute(() => {
|
.setExecute(function() {
|
||||||
CommandsManager.reload();
|
CommandsManager.reload();
|
||||||
|
|
||||||
return { blank: true };
|
return { blank: true };
|
||||||
});
|
});
|
||||||
|
|
@ -2,8 +2,8 @@ import Command from "../command.js";
|
||||||
|
|
||||||
export const rev = new Command()
|
export const rev = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Reverses text."
|
purpose: "Display the reverse of a text"
|
||||||
})
|
})
|
||||||
.setExecute((args, { rawInputValue }) => {
|
.setExecute(function(args, { rawInputValue }) {
|
||||||
return rawInputValue.split("").reverse().join("");
|
return rawInputValue.split("").reverse().join("");
|
||||||
});
|
});
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
|
import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const rm = new Command()
|
export const rm = new Command()
|
||||||
.setRequireArgs(true)
|
.setRequireArgs(true)
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Remove a file"
|
purpose: "Remove a file"
|
||||||
})
|
})
|
||||||
.setExecute((args, { currentDirectory }) => {
|
.setExecute(function(args, { currentDirectory }) {
|
||||||
const { name, extension } = VirtualFile.convertId(args[0]);
|
const { name, extension } = VirtualFile.convertId(args[0]);
|
||||||
const file = currentDirectory.findFile(name, extension);
|
const file = currentDirectory.findFile(name, extension);
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
return `${this.name}: ${args[0]}: No such file`;
|
return CommandsManager.formatError(this.name, `${args[0]}: No such file`);
|
||||||
|
|
||||||
file.delete();
|
file.delete();
|
||||||
return { blank: true };
|
return { blank: true };
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const rmdir = new Command()
|
export const rmdir = new Command()
|
||||||
.setRequireArgs(true)
|
.setRequireArgs(true)
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Remove a directory"
|
purpose: "Remove a directory"
|
||||||
})
|
})
|
||||||
.setExecute((args, { currentDirectory }) => {
|
.setExecute(function(args, { currentDirectory }) {
|
||||||
const name = args[0];
|
const name = args[0];
|
||||||
const folder = currentDirectory.findSubFolder(name);
|
const folder = currentDirectory.findSubFolder(name);
|
||||||
|
|
||||||
if (!folder)
|
if (!folder)
|
||||||
return `${this.name}: ${args[0]}: No such directory`;
|
return CommandsManager.formatError(this.name, `${args[0]}: No such directory`);
|
||||||
|
|
||||||
folder.delete();
|
folder.delete();
|
||||||
return { blank: true };
|
return { blank: true };
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
|
import CommandsManager from "../commands.js";
|
||||||
import Stream from "../stream.js";
|
import Stream from "../stream.js";
|
||||||
|
|
||||||
const ANIMATION_SPEED = 1.25;
|
const ANIMATION_SPEED = 1.25;
|
||||||
|
|
@ -173,11 +174,11 @@ function getLocomotive(frame, wagonCount = 1) {
|
||||||
|
|
||||||
export const sl = new Command()
|
export const sl = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Displays animations aimed to correct users who accidentally enter sl instead of ls. SL stands for Steam Locomotive.",
|
purpose: "Show animations aimed to correct users who accidentally enter sl instead of ls. SL stands for Steam Locomotive.",
|
||||||
usage: "sl\n"
|
usage: "sl\n"
|
||||||
+ "sl -w [NUMBER]",
|
+ "sl -w number",
|
||||||
options: {
|
options: {
|
||||||
"-w": "Set the amount of wagons (defaults to 1)"
|
"-w number": "Set the amount of wagons (defaults to 1)"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.addOption({
|
.addOption({
|
||||||
|
|
@ -185,14 +186,14 @@ export const sl = new Command()
|
||||||
long: "wagons",
|
long: "wagons",
|
||||||
isInput: true
|
isInput: true
|
||||||
})
|
})
|
||||||
.setExecute((args, { inputs }) => {
|
.setExecute(function(args, { inputs }) {
|
||||||
let wagonCount = 1;
|
let wagonCount = 1;
|
||||||
|
|
||||||
if (inputs?.w) {
|
if (inputs?.w) {
|
||||||
wagonCount = parseInt(inputs.w);
|
wagonCount = parseInt(inputs.w);
|
||||||
|
|
||||||
if (!wagonCount || wagonCount < 0) {
|
if (!wagonCount || wagonCount < 0) {
|
||||||
return `${this.name}: Please specify a valid amount of wagons`;
|
return CommandsManager.formatError(this.name, "Please specify a valid amount of wagons");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
|
import { VirtualFile } from "../../../virtual-drive/file/virtualFile.js";
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
export const touch = new Command()
|
export const touch = new Command()
|
||||||
.setRequireArgs(true)
|
.setRequireArgs(true)
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Change file timestamps",
|
purpose: "Changes file timestamps",
|
||||||
usage: "touch [OPTION]... FILE...",
|
usage: "touch [options] files",
|
||||||
description: "Update the access and modification times of each FILE to the current time.\n\n"
|
description: "Update the access and modification times of each FILE to the current time.\n\n"
|
||||||
+ "A FILE argument that does not exist is created empty."
|
+ "A file argument that does not exist is created empty."
|
||||||
})
|
})
|
||||||
.setExecute(function(args, { currentDirectory }) {
|
.setExecute(function(args, { currentDirectory }) {
|
||||||
if (args[0] === "girls\\" && args[1] === "boo**")
|
if (args[0] === "girls\\" && args[1] === "boo**")
|
||||||
return `${this.name}: Cannot touch 'girls boo**': Permission denied`;
|
return CommandsManager.formatError(this.name, "Cannot touch 'girls boo**': Permission denied");
|
||||||
|
|
||||||
const { name, extension } = VirtualFile.convertId(args[0]);
|
const { name, extension } = VirtualFile.convertId(args[0]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import Command from "../command.js";
|
||||||
|
|
||||||
export const uptime = new Command()
|
export const uptime = new Command()
|
||||||
.setManual({
|
.setManual({
|
||||||
purpose: "Displays the current uptime of the system"
|
purpose: "Display the current uptime of the system"
|
||||||
})
|
})
|
||||||
.setExecute(() => {
|
.setExecute(() => {
|
||||||
return `Uptime: ${formatRelativeTime(START_DATE, 2, false)}`;
|
return `Uptime: ${formatRelativeTime(START_DATE, 2, false)}`;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ANSI } from "../../../../config/apps/terminal.config.js";
|
||||||
import Command from "../command.js";
|
import Command from "../command.js";
|
||||||
import CommandsManager from "../commands.js";
|
import CommandsManager from "../commands.js";
|
||||||
|
|
||||||
|
|
@ -11,10 +12,10 @@ export const whatis = new Command()
|
||||||
const command = CommandsManager.find(commandName);
|
const command = CommandsManager.find(commandName);
|
||||||
|
|
||||||
if (!command)
|
if (!command)
|
||||||
return `${this.name}: ${commandName}: Command not found`;
|
return CommandsManager.formatError(this.name, `${commandName}: Command not found`);
|
||||||
|
|
||||||
if (!command.manual?.purpose)
|
if (!command.manual?.purpose)
|
||||||
return `${this.name}: ${commandName}: No information found`;
|
return CommandsManager.formatError(this.name, `${commandName}: No information found`);
|
||||||
|
|
||||||
return `${commandName} - ${command.manual.purpose}`;
|
return `${commandName} - ${ANSI.fg.green}${command.manual.purpose}`;
|
||||||
});
|
});
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { removeFromArray } from "../../features/_utils/array.utils.js";
|
import { removeFromArray } from "../../features/_utils/array.utils.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -31,16 +31,22 @@ export function useKeyboardListener({ onKeyDown, onKeyUp }) {
|
||||||
export function useShortcuts({ options, shortcuts, useCategories = true }) {
|
export function useShortcuts({ options, shortcuts, useCategories = true }) {
|
||||||
const [activeKeys, setActiveKeys] = useState([]);
|
const [activeKeys, setActiveKeys] = useState([]);
|
||||||
|
|
||||||
const checkShortcuts = (event, allowExecution = true) => {
|
const checkShortcuts = useCallback((event, allowExecution = true) => {
|
||||||
if (!shortcuts)
|
if (!shortcuts)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const keys = [...activeKeys];
|
||||||
|
|
||||||
|
// Prevent alt-tabbing from messing with alt key registration
|
||||||
|
if (keys.includes("Alt") && !event.altKey)
|
||||||
|
removeFromArray("Alt", keys);
|
||||||
|
|
||||||
const checkGroup = (group, category) => {
|
const checkGroup = (group, category) => {
|
||||||
for (const [name, shortcut] of Object.entries(group)) {
|
for (const [name, shortcut] of Object.entries(group)) {
|
||||||
let active = true;
|
let active = true;
|
||||||
|
|
||||||
shortcut.forEach((key) => {
|
shortcut.forEach((key) => {
|
||||||
if (!activeKeys.includes(key) && event.key !== key)
|
if (!keys.includes(key) && event.key !== key)
|
||||||
return active = false;
|
return active = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -68,7 +74,9 @@ export function useShortcuts({ options, shortcuts, useCategories = true }) {
|
||||||
} else {
|
} else {
|
||||||
checkGroup(shortcuts);
|
checkGroup(shortcuts);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
setActiveKeys(keys);
|
||||||
|
}, [activeKeys, options, shortcuts, useCategories]);
|
||||||
|
|
||||||
const onKeyDown = (event) => {
|
const onKeyDown = (event) => {
|
||||||
const isRepeated = activeKeys.includes(event.key);
|
const isRepeated = activeKeys.includes(event.key);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue