From 9718530c9f2df4c763c04bfac9e9de96153daa9e Mon Sep 17 00:00:00 2001 From: Prozilla Date: Mon, 11 Dec 2023 16:51:40 +0100 Subject: [PATCH] Updated terminal app --- .../applications/terminal/Terminal.jsx | 37 ++++- src/features/applications/terminal/command.js | 52 ++++--- .../applications/terminal/commands.js | 20 ++- .../applications/terminal/commands/blow.js | 7 +- .../applications/terminal/commands/cat.js | 15 +- .../applications/terminal/commands/cd.js | 29 ++-- .../applications/terminal/commands/clear.js | 21 ++- .../applications/terminal/commands/compgen.js | 10 ++ .../applications/terminal/commands/cowsay.js | 143 +++++++++--------- .../applications/terminal/commands/exit.js | 6 + .../applications/terminal/commands/ls.js | 4 +- .../applications/terminal/commands/make.js | 9 +- .../applications/terminal/commands/man.js | 37 ++++- .../applications/terminal/commands/nice.js | 9 +- .../applications/terminal/commands/rm.js | 2 +- .../applications/terminal/commands/rmdir.js | 2 +- .../applications/terminal/commands/touch.js | 6 +- .../applications/terminal/commands/whatis.js | 17 +++ .../applications/terminal/commands/whoami.js | 5 + .../applications/terminal/commands/world.js | 7 +- 20 files changed, 294 insertions(+), 144 deletions(-) create mode 100644 src/features/applications/terminal/commands/compgen.js create mode 100644 src/features/applications/terminal/commands/exit.js create mode 100644 src/features/applications/terminal/commands/whatis.js create mode 100644 src/features/applications/terminal/commands/whoami.js diff --git a/src/components/applications/terminal/Terminal.jsx b/src/components/applications/terminal/Terminal.jsx index a585459..96936e4 100644 --- a/src/components/applications/terminal/Terminal.jsx +++ b/src/components/applications/terminal/Terminal.jsx @@ -6,8 +6,9 @@ import { OutputLine } from "./OutputLine.jsx"; import { InputLine } from "./InputLine.jsx"; import { HOSTNAME, USERNAME } from "../../../constants/applications/terminal.js"; import CommandsManager from "../../../features/applications/terminal/commands.js"; +import { removeFromArray } from "../../../features/utils/array.js"; -export function Terminal({ setTitle }) { +export function Terminal({ setTitle, close: exit }) { const [inputKey, setInputKey] = useState(0); const [inputValue, setInputValue] = useState(""); const [history, setHistory] = useState([]); @@ -43,22 +44,46 @@ export function Terminal({ setTitle }) { if (value === "") return; - const args = value.split(/ +/); + // Get arguments + const args = value.match(/(?:[^\s"]+|"[^"]*")+/g); if (args[0].toLowerCase() === "sudo" && args.length > 1) { args.shift(); } + // Get command const commandName = args.shift().toLowerCase(); - const command = CommandsManager.find(commandName); if (!command) return `${commandName}: Command not found`; + // Get options + const options = []; + args.filter((arg) => arg.startsWith("-")).forEach((option) => { + if (option.startsWith("--")) { + const longOption = option.substring(2).toLowerCase(); + if (!options.includes(longOption)) + options.push(longOption); + } else { + const shortOptions = option.substring(1).split(""); + shortOptions.forEach((shortOption) => { + if (!options.includes(shortOption)) + options.push(shortOption); + }); + } + + removeFromArray(option, args); + }); + + // Check usage if (command.requireArgs && args.length === 0) - return `${commandName}: Incorrect syntax: ${commandName} requires at least 1 argument`; + return `${commandName}: Incorrect usage: ${commandName} requires at least 1 argument`; + + if (command.requireOptions && options.length === 0) + return `${commandName}: Incorrect usage: ${commandName} requires at least 1 option`; + // Execute command let response = null; try { @@ -70,7 +95,9 @@ export function Terminal({ setTitle }) { setCurrentDirectory, username: USERNAME, hostname: HOSTNAME, - rawInputValue + rawInputValue, + options, + exit }); if (response == null) diff --git a/src/features/applications/terminal/command.js b/src/features/applications/terminal/command.js index 31fa674..b740718 100644 --- a/src/features/applications/terminal/command.js +++ b/src/features/applications/terminal/command.js @@ -1,28 +1,33 @@ import { VirtualFolder } from "../../virtual-drive/virtualFolder.js"; import { VirtualRoot } from "../../virtual-drive/virtualRoot.js"; +/** + * @callback executeType + * @param {string[]} args + * @param {object} options + * @param {Function} options.promptOutput + * @param {Function} options.pushHistory + * @param {VirtualRoot} options.virtualRoot + * @param {VirtualFolder} options.currentDirectory + * @param {Function} options.setCurrentDirectory + * @param {string} options.username + * @param {string} options.hostname + * @param {string} options.rawInputValue + * @param {string[]} options.options + * @param {Function} options.exit + * @returns {string|{ blank: boolean }} + */ + export default class Command { /** @type {string} */ name; - /** - * @param {string[]} args - * @param {object} options - * @param {Function} options.promptOutput - * @param {Function} options.pushHistory - * @param {VirtualRoot} options.virtualRoot - * @param {VirtualFolder} options.currentDirectory - * @param {Function} options.setCurrentDirectory - * @param {string} options.username - * @param {string} options.hostname - * @param {string} options.rawInputValue - * @returns {string|{ blank: boolean }} - */ - execute = (args, options) => {}; + /** @type {executeType} */ + execute = () => {}; /** * @param {string} name - * @param {Function} execute + * @param {executeType} execute */ constructor(name, execute) { this.name = name; @@ -39,7 +44,7 @@ export default class Command { } /** - * @param {Function} execute + * @param {executeType} execute * @returns {Command} */ setExecute(execute) { @@ -57,11 +62,20 @@ export default class Command { } /** - * @param {{ purpose: string, usage: string, description: string}} name + * @param {boolean} value * @returns {Command} */ - setManual({ purpose, usage, description }) { - this.manual = { purpose, usage, description }; + setRequireOptions(value) { + this.requireOptions = value; + return this; + } + + /** + * @param {{ purpose: string, usage: string, description: string, options: object }} manual + * @returns {Command} + */ + setManual({ purpose, usage, description, options }) { + this.manual = { purpose, usage, description, options }; return this; } } \ No newline at end of file diff --git a/src/features/applications/terminal/commands.js b/src/features/applications/terminal/commands.js index 012b769..af80c53 100644 --- a/src/features/applications/terminal/commands.js +++ b/src/features/applications/terminal/commands.js @@ -1,10 +1,13 @@ +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"; +import { compgen } from "./commands/compgen.js"; import { cowsay } from "./commands/cowsay.js"; 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 { hostname } from "./commands/hostname.js"; import { ls } from "./commands/ls.js"; @@ -18,12 +21,14 @@ 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 { whatis } from "./commands/whatis.js"; +import { whoami } from "./commands/whoami.js"; import { world } from "./commands/world.js"; export default class CommandsManager { /** * @param {string} name - * @returns {CommandsManager} + * @returns {Command} */ static find(name) { let matchCommand = null; @@ -38,6 +43,15 @@ export default class CommandsManager { return matchCommand; } + /** + * @param {string} pattern + * @returns {Command[]} + */ + static search(pattern) { + const matches = this.COMMANDS.filter((command) => command.name.match(pattern)); + return matches; + } + static COMMANDS = [ echo, clear, @@ -60,5 +74,9 @@ export default class CommandsManager { cat, man, reboot, + compgen, + whoami, + whatis, + exit, ]; } \ No newline at end of file diff --git a/src/features/applications/terminal/commands/blow.js b/src/features/applications/terminal/commands/blow.js index 76aeb3c..aaa631d 100644 --- a/src/features/applications/terminal/commands/blow.js +++ b/src/features/applications/terminal/commands/blow.js @@ -1,5 +1,6 @@ import Command from "../command.js"; -export const blow = new Command("%blow", () => { - return "fg: %blow: No such job"; -}); \ No newline at end of file +export const blow = new Command("%blow") + .setExecute(function() { + return `fg: ${this.name}: No such job`; + }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/cat.js b/src/features/applications/terminal/commands/cat.js index 59f6c88..4b0f736 100644 --- a/src/features/applications/terminal/commands/cat.js +++ b/src/features/applications/terminal/commands/cat.js @@ -7,15 +7,20 @@ export const cat = new Command("cat") usage: "cat [OPTION]... [FILE]...", description: "Concetenate FILE(s) to standard output." }) - .setExecute((args, { currentDirectory }) => { + .setExecute(function(args, { currentDirectory, options }) { const [name, extension] = args[0].split("."); const file = currentDirectory.findFile(name, extension); - + if (!file) - return `rm: ${args[0]}: No such file`; - + return `${this.name}: ${args[0]}: No such file`; + if (file.content) { - return file.content; + if (!options.includes("e")) { + return file.content; + } else { + // Append "$" at the end of every line + return file.content.split("\n").join("$\n") + "$"; + } } else if (file.source) { return `Src: ${file.source}`; } else { diff --git a/src/features/applications/terminal/commands/cd.js b/src/features/applications/terminal/commands/cd.js index 8064670..86b2387 100644 --- a/src/features/applications/terminal/commands/cd.js +++ b/src/features/applications/terminal/commands/cd.js @@ -1,13 +1,20 @@ import Command from "../command.js"; -export const cd = new Command("cd", (args, { currentDirectory, setCurrentDirectory }) => { - const path = args[0] ?? "~"; - const destination = currentDirectory.navigate(path); - - if (!destination) - return `cd: ${args[0]}: No such file or directory`; - - console.log(destination); - setCurrentDirectory(destination); - return { blank: true }; -}).setRequireArgs(true); \ No newline at end of file +export const cd = new Command("cd") + .setRequireArgs(true) + .setManual({ + purpose: "Change directory", + usage: "cd path", + description: "Change working directory to given path (the home directory by default)." + }) + .setExecute(function(args, { currentDirectory, setCurrentDirectory }) { + const path = args[0] ?? "~"; + const destination = currentDirectory.navigate(path); + + if (!destination) + return `${this.name}: ${args[0]}: No such file or directory`; + + console.log(destination); + setCurrentDirectory(destination); + return { blank: true }; + }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/clear.js b/src/features/applications/terminal/commands/clear.js index e6c1de8..88afbad 100644 --- a/src/features/applications/terminal/commands/clear.js +++ b/src/features/applications/terminal/commands/clear.js @@ -1,10 +1,15 @@ import Command from "../command.js"; -export const clear = new Command("clear", (args, { pushHistory }) => { - pushHistory({ - clear: true, - isInput: false - }); - - return { blank: true }; -}); \ No newline at end of file +export const clear = new Command("clear") + .setManual({ + purpose: "Clear terminal screen", + usage: "clear", + }) + .setExecute(function(args, { pushHistory }) { + pushHistory({ + clear: true, + isInput: false + }); + + return { blank: true }; + }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/compgen.js b/src/features/applications/terminal/commands/compgen.js new file mode 100644 index 0000000..4cd5094 --- /dev/null +++ b/src/features/applications/terminal/commands/compgen.js @@ -0,0 +1,10 @@ +import Command from "../command.js"; +import CommandsManager from "../commands.js"; + +export const compgen = new Command("compgen") + .setRequireOptions(true) + .setExecute(function(args, { options }) { + if (options.includes("c")) { + return CommandsManager.COMMANDS.map((command) => command.name).sort().join("\n"); + } + }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/cowsay.js b/src/features/applications/terminal/commands/cowsay.js index 1f00ba9..3f71327 100644 --- a/src/features/applications/terminal/commands/cowsay.js +++ b/src/features/applications/terminal/commands/cowsay.js @@ -8,92 +8,99 @@ const COW = ` ||----w | || ||`; -export const cowsay = new Command("cowsay", (args, { rawInputValue }) => { - // Separate input value into lines - const segments = rawInputValue.split(" "); - const lines = []; - let currentLine = ""; - let maxLineWidth = 0; +export const cowsay = new Command("cowsay") + .setRequireArgs(true) + .setManual({ + purpose: "Show a cow saying something", + usage: "cowsay text", + description: "Show ASCII art of a cow saying something." + }) + .setExecute(function(args, { rawInputValue }) { + // Separate input value into lines + const segments = rawInputValue.split(" "); + const lines = []; + let currentLine = ""; + let maxLineWidth = 0; - const addLine = (line) => { - line = line.trimEnd(); - lines.push(line); - if (line.length > maxLineWidth) - maxLineWidth = line.length; - }; + const addLine = (line) => { + line = line.trimEnd(); + lines.push(line); + if (line.length > maxLineWidth) + maxLineWidth = line.length; + }; - const nextLine = (word) => { - addLine(currentLine); + const nextLine = (word) => { + addLine(currentLine); - if (word) { - currentLine = word + " "; - } else { - currentLine = ""; - } - }; + if (word) { + currentLine = word + " "; + } else { + currentLine = ""; + } + }; - segments.forEach((segment) => { - // Add empty spaces preceding lines - if (segment === "") { - currentLine += " "; - return; - } + segments.forEach((segment) => { + // Add empty spaces preceding lines + if (segment === "") { + currentLine += " "; + return; + } - const words = segment.split("\n"); - for (let i = 0; i < words.length; i++) { - const word = words[i]; - - // Handle next lines - if (i > 0) - nextLine(); + const words = segment.split("\n"); + for (let i = 0; i < words.length; i++) { + const word = words[i]; + + // Handle next lines + if (i > 0) + nextLine(); - // Fit word on current line - if ((currentLine + word).length <= MAX_WIDTH) { - currentLine += word + " "; - } else if (word.length > MAX_WIDTH) { - const remainingSpaces = MAX_WIDTH - currentLine.length; + // Fit word on current line + if ((currentLine + word).length <= MAX_WIDTH) { + currentLine += word + " "; + } else if (word.length > MAX_WIDTH) { + const remainingSpaces = MAX_WIDTH - currentLine.length; - if (remainingSpaces >= 2) { - addLine(currentLine + word.substring(0, remainingSpaces - 1) + "-"); - currentLine = word.substring(remainingSpaces - 1) + " "; + if (remainingSpaces >= 2) { + addLine(currentLine + word.substring(0, remainingSpaces - 1) + "-"); + currentLine = word.substring(remainingSpaces - 1) + " "; + } else { + nextLine(word); + } } else { nextLine(word); } - } else { - nextLine(word); } - } - }); + }); - if (currentLine.length > 0) - addLine(currentLine); + if (currentLine.length > 0) + addLine(currentLine); - // Turn lines into speech bubble - const speechBubble = [` ${"_".repeat(maxLineWidth + 2)} `]; + // Turn lines into speech bubble + const speechBubble = [` ${"_".repeat(maxLineWidth + 2)} `]; - for (let i = 0; i < lines.length; i++) { - let line = lines[i]; - const missingSpaces = maxLineWidth - line.length; + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + const missingSpaces = maxLineWidth - line.length; - if (missingSpaces > 0) - line += " ".repeat(missingSpaces); + if (missingSpaces > 0) + line += " ".repeat(missingSpaces); - if (lines.length > 1) { - if (i === 0) { - line = `/ ${line} \\`; - } else if (i === lines.length - 1) { - line = `\\ ${line} /`; + if (lines.length > 1) { + if (i === 0) { + line = `/ ${line} \\`; + } else if (i === lines.length - 1) { + line = `\\ ${line} /`; + } else { + line = `| ${line} |`; + } } else { - line = `| ${line} |`; + line = `< ${line} >`; } - } else { - line = `< ${line} >`; + + speechBubble.push(line); } - speechBubble.push(line); - } + speechBubble.push(` ${"-".repeat(maxLineWidth + 2)} `); - speechBubble.push(` ${"-".repeat(maxLineWidth + 2)} `); - - return speechBubble.join("\n") + COW; -}).setRequireArgs(true); \ No newline at end of file + return speechBubble.join("\n") + COW; + }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/exit.js b/src/features/applications/terminal/commands/exit.js new file mode 100644 index 0000000..4317c03 --- /dev/null +++ b/src/features/applications/terminal/commands/exit.js @@ -0,0 +1,6 @@ +import Command from "../command.js"; + +export const exit = new Command("exit", (args, { exit }) => { + exit(); + return { blank: true }; +}); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/ls.js b/src/features/applications/terminal/commands/ls.js index cf03910..adb65fa 100644 --- a/src/features/applications/terminal/commands/ls.js +++ b/src/features/applications/terminal/commands/ls.js @@ -7,7 +7,7 @@ export const ls = new Command("ls") description: "List information about the FILEs (the current directory by default).\n" + "Sort entries alphabetically if none of -cftuvSUX nor --sort is specified." }) - .setExecute((args, { currentDirectory }) => { + .setExecute(function(args, { currentDirectory }) { let directory = currentDirectory; if (args.length > 0) { @@ -15,7 +15,7 @@ export const ls = new Command("ls") } if (!directory) - return `ls: Cannot access '${args[0]}': No such file or directory`; + return `${this.name}: Cannot access '${args[0]}': No such file or directory`; const folderNames = directory.subFolders.map((folder) => folder.id); const fileNames = directory.files.map((file) => file.id); diff --git a/src/features/applications/terminal/commands/make.js b/src/features/applications/terminal/commands/make.js index 8b79b80..d9c3afd 100644 --- a/src/features/applications/terminal/commands/make.js +++ b/src/features/applications/terminal/commands/make.js @@ -1,6 +1,7 @@ import Command from "../command.js"; -export const make = new Command("make", (args) => { - if (args[0] === "love") - return "make: *** No rule to make target `love'. Stop."; -}); \ No newline at end of file +export const make = new Command("make") + .setExecute(function(args) { + if (args[0] === "love") + return `${this.name}: *** No rule to make target 'love'. Stop.`; + }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/man.js b/src/features/applications/terminal/commands/man.js index ff525be..e0ed37c 100644 --- a/src/features/applications/terminal/commands/man.js +++ b/src/features/applications/terminal/commands/man.js @@ -6,22 +6,38 @@ const MARGIN = 5; export const man = new Command("man") .setRequireArgs(true) .setManual({ - purpose: "show system reference manuals", - usage: "man [OPTION]... page", + purpose: "Show system reference manuals", + usage: "man [OPTION]... page\n" + + "man -k [OPTION]... regexp", 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: { + "-k": "Search for manual page using regexp" + } }) - .setExecute((args) => { + .setExecute(function(args, { options }) { + // Search function + if (options.includes("k")) { + const commands = CommandsManager.search(args[0]); + return commands.map((command) => { + if (command.manual?.purpose) { + return `${command.name} - ${command.manual.purpose}`; + } else { + return command.name; + } + }).join("\n"); + } + const commandName = args[0].toLowerCase(); const command = CommandsManager.find(commandName); if (!command) - return `man: ${commandName}: Command not found`; + return `${this.name}: ${commandName}: Command not found`; const manual = command.manual; if (!manual) - return `man: ${commandName}: No manual found`; + return `${this.name}: ${commandName}: No manual found`; const formatText = (text) => { const lines = text.split("\n").map((line) => " ".repeat(MARGIN) + line); @@ -50,5 +66,14 @@ export const man = new Command("man") ]); } + if (manual.options) { + sections.push([ + "OPTIONS", + formatText(Object.entries(manual.options).map(([key, value]) => { + return `${key} ${value}`; + }).join("\n")) + ]); + } + return sections.map((section) => section.join("\n")).join("\n\n"); }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/nice.js b/src/features/applications/terminal/commands/nice.js index 2f82ebc..325608d 100644 --- a/src/features/applications/terminal/commands/nice.js +++ b/src/features/applications/terminal/commands/nice.js @@ -1,6 +1,7 @@ import Command from "../command.js"; -export const nice = new Command("nice", (args) => { - if (args[0] === "man" && args[1] === "woman") - return "nice: No manual entry for woman"; -}); \ No newline at end of file +export const nice = new Command("nice") + .setExecute(function(args) { + if (args[0] === "man" && args[1] === "woman") + return `${this.name}: No manual entry for woman`; + }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/rm.js b/src/features/applications/terminal/commands/rm.js index ea3a5d9..36b13c7 100644 --- a/src/features/applications/terminal/commands/rm.js +++ b/src/features/applications/terminal/commands/rm.js @@ -5,7 +5,7 @@ export const rm = new Command("rm", (args, { currentDirectory }) => { const file = currentDirectory.findFile(name, extension); if (!file) - return `rm: ${args[0]}: No such file`; + return `${this.name}: ${args[0]}: No such file`; file.delete(); return { blank: true }; diff --git a/src/features/applications/terminal/commands/rmdir.js b/src/features/applications/terminal/commands/rmdir.js index 2cedd17..00517a3 100644 --- a/src/features/applications/terminal/commands/rmdir.js +++ b/src/features/applications/terminal/commands/rmdir.js @@ -5,7 +5,7 @@ export const rmdir = new Command("rmdir", (args, { currentDirectory }) => { const folder = currentDirectory.findSubFolder(name); if (!folder) - return `rmdir: ${args[0]}: No such directory`; + return `${this.name}: ${args[0]}: No such directory`; folder.delete(); return { blank: true }; diff --git a/src/features/applications/terminal/commands/touch.js b/src/features/applications/terminal/commands/touch.js index 9b405c3..17b9c00 100644 --- a/src/features/applications/terminal/commands/touch.js +++ b/src/features/applications/terminal/commands/touch.js @@ -3,14 +3,14 @@ import Command from "../command.js"; export const touch = new Command("touch") .setRequireArgs(true) .setManual({ - purpose: "change file timestamps", + purpose: "Change file timestamps", usage: "touch [OPTION]... FILE...", 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." }) - .setExecute((args, { currentDirectory }) => { + .setExecute(function(args, { currentDirectory }) { if (args[0] === "girls\\" && args[1] === "boo**") - return "touch: Cannot touch 'girls boo**': Permission denied"; + return `${this.name}: Cannot touch 'girls boo**': Permission denied`; const [name, extension] = args[0].split("."); diff --git a/src/features/applications/terminal/commands/whatis.js b/src/features/applications/terminal/commands/whatis.js new file mode 100644 index 0000000..ff36cb9 --- /dev/null +++ b/src/features/applications/terminal/commands/whatis.js @@ -0,0 +1,17 @@ +import Command from "../command.js"; +import CommandsManager from "../commands.js"; + +export const whatis = new Command("whatis") + .setRequireArgs(true) + .setExecute(function(args) { + 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 information found`; + + return `${commandName} - ${command.manual.purpose}`; + }); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/whoami.js b/src/features/applications/terminal/commands/whoami.js new file mode 100644 index 0000000..c8a93c5 --- /dev/null +++ b/src/features/applications/terminal/commands/whoami.js @@ -0,0 +1,5 @@ +import Command from "../command.js"; + +export const whoami = new Command("whoami", (args, { username }) => { + return username; +}); \ No newline at end of file diff --git a/src/features/applications/terminal/commands/world.js b/src/features/applications/terminal/commands/world.js index 6a46490..0adaa9f 100644 --- a/src/features/applications/terminal/commands/world.js +++ b/src/features/applications/terminal/commands/world.js @@ -1,5 +1,6 @@ import Command from "../command.js"; -export const world = new Command("world", () => { - return "world: Not found"; -}); \ No newline at end of file +export const world = new Command("world") + .setExecute(function() { + return `${this.name}: Not found`; + }); \ No newline at end of file