Updated terminal app
This commit is contained in:
parent
d20c1f6b80
commit
ed80c17dfa
26 changed files with 209 additions and 139 deletions
|
|
@ -6,7 +6,6 @@ import { faCaretLeft, faCaretRight, faHome, faRotateRight } from "@fortawesome/f
|
|||
import { HOME_URL, SEARCH_URL } from "../../../constants/applications/browser.js";
|
||||
import { isValidUrl } from "../../../features/utils/browser.js";
|
||||
import { useHistory } from "../../../hooks/utils/history.js";
|
||||
import { TITLE_SEPARATOR } from "../../../constants/windows.js";
|
||||
|
||||
/** @type {import("../../windows/WindowView.jsx").windowProps} */
|
||||
export function Browser({ startUrl, focus }) {
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export function Terminal({ setTitle, close: exit }) {
|
|||
});
|
||||
|
||||
if (output)
|
||||
promptOutput(output);
|
||||
promptOutput(`${output}\n`);
|
||||
};
|
||||
|
||||
const updateHistoryIndex = (delta) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import Command from "./command.js";
|
||||
import { blow } from "./commands/blow.js";
|
||||
import { cat } from "./commands/cat.js";
|
||||
import { cd } from "./commands/cd.js";
|
||||
import { clear } from "./commands/clear.js";
|
||||
|
|
@ -9,21 +8,21 @@ import { dir } from "./commands/dir.js";
|
|||
import { echo } from "./commands/echo.js";
|
||||
import { exit } from "./commands/exit.js";
|
||||
import { fortune } from "./commands/fortune.js";
|
||||
import { help } from "./commands/help.js";
|
||||
import { hostname } from "./commands/hostname.js";
|
||||
import { ls } from "./commands/ls.js";
|
||||
import { make } from "./commands/make.js";
|
||||
import { man } from "./commands/man.js";
|
||||
import { mkdir } from "./commands/mkdir.js";
|
||||
import { neofetch } from "./commands/neofetch.js";
|
||||
import { nice } from "./commands/nice.js";
|
||||
import { pwd } from "./commands/pwd.js";
|
||||
import { reboot } from "./commands/reboot.js";
|
||||
import { rm } from "./commands/rm.js";
|
||||
import { rmdir } from "./commands/rmdir.js";
|
||||
import { touch } from "./commands/touch.js";
|
||||
import { uptime } from "./commands/uptime.js";
|
||||
import { whatis } from "./commands/whatis.js";
|
||||
import { whoami } from "./commands/whoami.js";
|
||||
import { world } from "./commands/world.js";
|
||||
|
||||
export default class CommandsManager {
|
||||
/**
|
||||
|
|
@ -67,9 +66,6 @@ export default class CommandsManager {
|
|||
neofetch,
|
||||
fortune,
|
||||
cowsay,
|
||||
world,
|
||||
nice,
|
||||
blow,
|
||||
make,
|
||||
cat,
|
||||
man,
|
||||
|
|
@ -78,5 +74,7 @@ export default class CommandsManager {
|
|||
whoami,
|
||||
whatis,
|
||||
exit,
|
||||
help,
|
||||
uptime,
|
||||
];
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const blow = new Command("%blow")
|
||||
.setExecute(function() {
|
||||
return `fg: ${this.name}: No such job`;
|
||||
});
|
||||
|
|
@ -3,7 +3,7 @@ import Command from "../command.js";
|
|||
export const cat = new Command("cat")
|
||||
.setRequireArgs(true)
|
||||
.setManual({
|
||||
purpose: "Concetenate files and print on the standard output",
|
||||
purpose: "Concetenate files and display on the terminal screen",
|
||||
usage: "cat [OPTION]... [FILE]...",
|
||||
description: "Concetenate FILE(s) to standard output."
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import Command from "../command.js";
|
|||
export const cd = new Command("cd")
|
||||
.setRequireArgs(true)
|
||||
.setManual({
|
||||
purpose: "Change directory",
|
||||
purpose: "Change the current directory",
|
||||
usage: "cd path",
|
||||
description: "Change working directory to given path (the home directory by default)."
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const dir = new Command("dir", (args, { currentDirectory }) => {
|
||||
const folderNames = currentDirectory.subFolders.map((folder) => folder.id);
|
||||
|
||||
if (folderNames.length === 0)
|
||||
return { blank: true };
|
||||
|
||||
return folderNames.sort((nameA, nameB) => nameA.localeCompare(nameB)).join(" ");
|
||||
});
|
||||
export const dir = new Command("dir")
|
||||
.setManual({
|
||||
purpose: "List all directories in the current directory"
|
||||
})
|
||||
.setExecute((args, { currentDirectory }) => {
|
||||
const folderNames = currentDirectory.subFolders.map((folder) => folder.id);
|
||||
|
||||
if (folderNames.length === 0)
|
||||
return { blank: true };
|
||||
|
||||
return folderNames.sort((nameA, nameB) => nameA.localeCompare(nameB)).join(" ");
|
||||
});
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const echo = new Command("echo", (args, { rawInputValue }) => {
|
||||
return rawInputValue;
|
||||
});
|
||||
export const echo = new Command("echo")
|
||||
.setManual({
|
||||
purpose: "Display text on the terminal screen"
|
||||
})
|
||||
.setExecute((args, { rawInputValue }) => {
|
||||
return rawInputValue;
|
||||
});
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const exit = new Command("exit", (args, { exit }) => {
|
||||
exit();
|
||||
return { blank: true };
|
||||
});
|
||||
export const exit = new Command("exit")
|
||||
.setManual({
|
||||
purpose: "Quit terminal interface"
|
||||
})
|
||||
.setExecute((args, { exit }) => {
|
||||
exit();
|
||||
return { blank: true };
|
||||
});
|
||||
|
|
@ -94,6 +94,10 @@ const FORTUNES = [
|
|||
"Your true value depends entirely on what you are compared with.",
|
||||
];
|
||||
|
||||
export const fortune = new Command("fortune", () => {
|
||||
return randomFromArray(FORTUNES);
|
||||
});
|
||||
export const fortune = new Command("fortune")
|
||||
.setManual({
|
||||
purpose: "Tell fortune"
|
||||
})
|
||||
.setExecute(() => {
|
||||
return randomFromArray(FORTUNES);
|
||||
});
|
||||
26
src/features/applications/terminal/commands/help.js
Normal file
26
src/features/applications/terminal/commands/help.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import Command from "../command.js";
|
||||
import CommandsManager from "../commands.js";
|
||||
|
||||
export const help = new Command("help")
|
||||
.setExecute((args) => {
|
||||
if (args.length === 0) {
|
||||
return CommandsManager.COMMANDS.map((command) => {
|
||||
if (command.manual?.purpose) {
|
||||
return `${command.name} - ${command.manual.purpose}`;
|
||||
} else {
|
||||
return command.name;
|
||||
}
|
||||
}).sort().join("\n");
|
||||
}
|
||||
|
||||
const commandName = args[0].toLowerCase();
|
||||
const command = CommandsManager.find(commandName);
|
||||
|
||||
if (!command)
|
||||
return `${this.name}: ${commandName}: Command not found`;
|
||||
|
||||
if (!command.manual?.purpose)
|
||||
return `${this.name}: ${commandName}: No manual found`;
|
||||
|
||||
return command.manual.purpose;
|
||||
});
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const hostname = new Command("hostname", (args, { hostname }) => {
|
||||
return hostname;
|
||||
});
|
||||
export const hostname = new Command("hostname")
|
||||
.setManual({
|
||||
purpose: "Display the hostname"
|
||||
})
|
||||
.setExecute((args, { hostname }) => {
|
||||
return hostname;
|
||||
});
|
||||
|
|
@ -2,10 +2,9 @@ import Command from "../command.js";
|
|||
|
||||
export const ls = new Command("ls")
|
||||
.setManual({
|
||||
purpose: "list directory contents",
|
||||
purpose: "List directory contents",
|
||||
usage: "ls [OPTION]... [FILE]...",
|
||||
description: "List information about the FILEs (the current directory by default).\n"
|
||||
+ "Sort entries alphabetically if none of -cftuvSUX nor --sort is specified."
|
||||
description: "List information about the FILEs (the current directory by default)."
|
||||
})
|
||||
.setExecute(function(args, { currentDirectory }) {
|
||||
let directory = currentDirectory;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const make = new Command("make")
|
||||
.setRequireArgs(true)
|
||||
.setExecute(function(args) {
|
||||
if (args[0] === "love")
|
||||
return `${this.name}: *** No rule to make target 'love'. Stop.`;
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ export const man = new Command("man")
|
|||
.setExecute(function(args, { options }) {
|
||||
// Search function
|
||||
if (options.includes("k")) {
|
||||
const commands = CommandsManager.search(args[0]);
|
||||
const commands = CommandsManager.search(args[0].toLowerCase());
|
||||
return commands.map((command) => {
|
||||
if (command.manual?.purpose) {
|
||||
return `${command.name} - ${command.manual.purpose}`;
|
||||
} else {
|
||||
return command.name;
|
||||
}
|
||||
}).join("\n");
|
||||
}).sort().join("\n");
|
||||
}
|
||||
|
||||
const commandName = args[0].toLowerCase();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const mkdir = new Command("mkdir", (args, { currentDirectory }) => {
|
||||
const name = args[0];
|
||||
|
||||
if (currentDirectory.findSubFolder(name))
|
||||
export const mkdir = new Command("mkdir")
|
||||
.setManual({
|
||||
purpose: "Create directory"
|
||||
})
|
||||
.setRequireArgs(true)
|
||||
.setExecute((args, { currentDirectory }) => {
|
||||
const name = args[0];
|
||||
|
||||
if (currentDirectory.findSubFolder(name))
|
||||
return { blank: true };
|
||||
|
||||
currentDirectory.createFolder(name);
|
||||
return { blank: true };
|
||||
|
||||
currentDirectory.createFolder(name);
|
||||
return { blank: true };
|
||||
}).setRequireArgs(true);
|
||||
});
|
||||
|
|
@ -5,53 +5,57 @@ import { formatRelativeTime } from "../../../utils/date.js";
|
|||
import AppsManager from "../../applications.js";
|
||||
import Command from "../command.js";
|
||||
|
||||
export const neofetch = new Command("neofetch", (args, { username, hostname }) => {
|
||||
const leftColumn = ASCII_LOGO.split("\n");
|
||||
const rightColumnWidth = username.length + hostname.length + 1;
|
||||
export const neofetch = new Command("neofetch")
|
||||
.setManual({
|
||||
purpose: "Fetch system information"
|
||||
})
|
||||
.setExecute((args, { username, hostname }) => {
|
||||
const leftColumn = ASCII_LOGO.split("\n");
|
||||
const rightColumnWidth = username.length + hostname.length + 1;
|
||||
|
||||
const userAgent = navigator.userAgent;
|
||||
const userAgent = navigator.userAgent;
|
||||
|
||||
// Check for the browser name using regular expressions
|
||||
let browserName;
|
||||
if (userAgent.match(/Firefox\//)) {
|
||||
browserName = "Mozilla Firefox";
|
||||
} else if (userAgent.match(/Edg\//)) {
|
||||
browserName = "Microsoft Edge";
|
||||
} else if (userAgent.match(/Chrome\//)) {
|
||||
browserName = "Google Chrome";
|
||||
} else if (userAgent.match(/Safari\//)) {
|
||||
browserName = "Apple Safari";
|
||||
} else {
|
||||
browserName = "Unknown";
|
||||
}
|
||||
|
||||
const rightColumn = [
|
||||
`${username}@${hostname}`,
|
||||
"-".repeat(rightColumnWidth),
|
||||
`OS: ${NAME}`,
|
||||
`UPTIME: ${formatRelativeTime(START_DATE, 2, false)}`,
|
||||
`RESOLUTION: ${window.innerWidth}x${window.innerHeight}`,
|
||||
"THEME: default",
|
||||
"ICONS: Font Awesome",
|
||||
`TERMINAL: ${AppsManager.getApp(APPS.TERMINAL)?.name ?? "Unknown"}`,
|
||||
`BROWSER: ${browserName}`,
|
||||
`PLATFORM: ${navigator.platform}`,
|
||||
`LANGUAGE: ${navigator.language}`,
|
||||
];
|
||||
|
||||
const combined = [];
|
||||
for (let i = 1; i < leftColumn.length; i++) {
|
||||
let line = `${leftColumn[i]} `;
|
||||
|
||||
if (i <= rightColumn.length) {
|
||||
line += rightColumn[i - 1];
|
||||
// Check for the browser name using regular expressions
|
||||
let browserName;
|
||||
if (userAgent.match(/Firefox\//)) {
|
||||
browserName = "Mozilla Firefox";
|
||||
} else if (userAgent.match(/Edg\//)) {
|
||||
browserName = "Microsoft Edge";
|
||||
} else if (userAgent.match(/Chrome\//)) {
|
||||
browserName = "Google Chrome";
|
||||
} else if (userAgent.match(/Safari\//)) {
|
||||
browserName = "Apple Safari";
|
||||
} else {
|
||||
// This fixes a weird display bug on Safari mobile
|
||||
line += " ".repeat(rightColumnWidth);
|
||||
browserName = "Unknown";
|
||||
}
|
||||
|
||||
combined.push(line);
|
||||
}
|
||||
const rightColumn = [
|
||||
`${username}@${hostname}`,
|
||||
"-".repeat(rightColumnWidth),
|
||||
`OS: ${NAME}`,
|
||||
`UPTIME: ${formatRelativeTime(START_DATE, 2, false)}`,
|
||||
`RESOLUTION: ${window.innerWidth}x${window.innerHeight}`,
|
||||
"THEME: default",
|
||||
"ICONS: Font Awesome",
|
||||
`TERMINAL: ${AppsManager.getApp(APPS.TERMINAL)?.name ?? "Unknown"}`,
|
||||
`BROWSER: ${browserName}`,
|
||||
`PLATFORM: ${navigator.platform}`,
|
||||
`LANGUAGE: ${navigator.language}`,
|
||||
];
|
||||
|
||||
return combined.join("\n");
|
||||
});
|
||||
const combined = [];
|
||||
for (let i = 1; i < leftColumn.length; i++) {
|
||||
let line = `${leftColumn[i]} `;
|
||||
|
||||
if (i <= rightColumn.length) {
|
||||
line += rightColumn[i - 1];
|
||||
} else {
|
||||
// This fixes a weird display bug on Safari mobile
|
||||
line += " ".repeat(rightColumnWidth);
|
||||
}
|
||||
|
||||
combined.push(line);
|
||||
}
|
||||
|
||||
return combined.join("\n");
|
||||
});
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const nice = new Command("nice")
|
||||
.setExecute(function(args) {
|
||||
if (args[0] === "man" && args[1] === "woman")
|
||||
return `${this.name}: No manual entry for woman`;
|
||||
});
|
||||
|
|
@ -1,9 +1,13 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const pwd = new Command("pwd", (args, { currentDirectory }) => {
|
||||
if (currentDirectory.root) {
|
||||
return "/";
|
||||
} else {
|
||||
return currentDirectory.absolutePath;
|
||||
}
|
||||
});
|
||||
export const pwd = new Command("pwd")
|
||||
.setManual({
|
||||
purpose: "Display path of the current directory"
|
||||
})
|
||||
.setExecute((args, { currentDirectory }) => {
|
||||
if (currentDirectory.root) {
|
||||
return "/";
|
||||
} else {
|
||||
return currentDirectory.absolutePath;
|
||||
}
|
||||
});
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
import { reloadViewport } from "../../../utils/browser.js";
|
||||
import Command from "../command.js";
|
||||
|
||||
export const reboot = new Command("reboot", () => {
|
||||
reloadViewport();
|
||||
return { blank: true };
|
||||
});
|
||||
export const reboot = new Command("reboot")
|
||||
.setManual({
|
||||
purpose: "Reboot the system"
|
||||
})
|
||||
.setExecute(() => {
|
||||
reloadViewport();
|
||||
return { blank: true };
|
||||
});
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const rm = new Command("rm", (args, { currentDirectory }) => {
|
||||
const [name, extension] = args[0].split(".");
|
||||
const file = currentDirectory.findFile(name, extension);
|
||||
|
||||
if (!file)
|
||||
return `${this.name}: ${args[0]}: No such file`;
|
||||
export const rm = new Command("rm")
|
||||
.setRequireArgs(true)
|
||||
.setManual({
|
||||
purpose: "Remove a file"
|
||||
})
|
||||
.setExecute((args, { currentDirectory }) => {
|
||||
const [name, extension] = args[0].split(".");
|
||||
const file = currentDirectory.findFile(name, extension);
|
||||
|
||||
file.delete();
|
||||
return { blank: true };
|
||||
}).setRequireArgs(true);
|
||||
if (!file)
|
||||
return `${this.name}: ${args[0]}: No such file`;
|
||||
|
||||
file.delete();
|
||||
return { blank: true };
|
||||
});
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const rmdir = new Command("rmdir", (args, { currentDirectory }) => {
|
||||
const name = args[0];
|
||||
const folder = currentDirectory.findSubFolder(name);
|
||||
|
||||
if (!folder)
|
||||
return `${this.name}: ${args[0]}: No such directory`;
|
||||
export const rmdir = new Command("rmdir")
|
||||
.setRequireArgs(true)
|
||||
.setManual({
|
||||
purpose: "Remove a directory"
|
||||
})
|
||||
.setExecute((args, { currentDirectory }) => {
|
||||
const name = args[0];
|
||||
const folder = currentDirectory.findSubFolder(name);
|
||||
|
||||
folder.delete();
|
||||
return { blank: true };
|
||||
}).setRequireArgs(true);
|
||||
if (!folder)
|
||||
return `${this.name}: ${args[0]}: No such directory`;
|
||||
|
||||
folder.delete();
|
||||
return { blank: true };
|
||||
});
|
||||
12
src/features/applications/terminal/commands/uptime.js
Normal file
12
src/features/applications/terminal/commands/uptime.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { START_DATE } from "../../../../index.js";
|
||||
import { formatRelativeTime } from "../../../utils/date.js";
|
||||
import Command from "../command.js";
|
||||
|
||||
|
||||
export const uptime = new Command("uptime")
|
||||
.setManual({
|
||||
purpose: "Displays the current uptime of the system"
|
||||
})
|
||||
.setExecute(() => {
|
||||
return `Uptime: ${formatRelativeTime(START_DATE, 2, false)}`;
|
||||
});
|
||||
|
|
@ -3,6 +3,9 @@ import CommandsManager from "../commands.js";
|
|||
|
||||
export const whatis = new Command("whatis")
|
||||
.setRequireArgs(true)
|
||||
.setManual({
|
||||
purpose: "Show information about a command"
|
||||
})
|
||||
.setExecute(function(args) {
|
||||
const commandName = args[0].toLowerCase();
|
||||
const command = CommandsManager.find(commandName);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const whoami = new Command("whoami", (args, { username }) => {
|
||||
return username;
|
||||
});
|
||||
export const whoami = new Command("whoami")
|
||||
.setManual({
|
||||
purpose: "Display the username"
|
||||
})
|
||||
.setExecute((args, { username }) => {
|
||||
return username;
|
||||
});
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
import Command from "../command.js";
|
||||
|
||||
export const world = new Command("world")
|
||||
.setExecute(function() {
|
||||
return `${this.name}: Not found`;
|
||||
});
|
||||
Loading…
Reference in a new issue