Merge pull request #1986 from billyvg/feat/add-vim-command

feat: add `vim` terminal command
This commit is contained in:
hydroflame 2021-12-21 11:00:33 -05:00 committed by GitHub
commit 81e3f2afd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 107 additions and 48 deletions

@ -44,7 +44,7 @@ interface IProps {
hostname: string;
player: IPlayer;
router: IRouter;
vim?: boolean;
vim: boolean;
}
// TODO: try to removve global symbols

@ -40,6 +40,7 @@ export const TerminalHelpText: string[] = [
"tail [script] [args...] Displays dynamic logs for the specified script",
"top Displays all running scripts and their RAM usage",
"unalias [alias name] Deletes the specified alias",
"vim [file] Text editor - Open up and edit a script or text file in vim mode",
"weaken [server] Reduce the security of a server",
"wget [url] [target file] Retrieves code/text from a web server",
];
@ -402,6 +403,13 @@ export const HelpTexts: IMap<string[]> = {
" ",
"It is not necessary to differentiate between global and non-global aliases when using 'unalias'",
],
vim: [
"vim [file name]",
" ",
"Opens up the specified file in the Text Editor in vim mode. Only scripts (.script) or text files (.txt) can be ",
"edited using the Text Editor. If the file does not already exist, then a new, empty one ",
"will be created",
],
weaken: [
"weaken",
"",

@ -67,6 +67,7 @@ import { sudov } from "./commands/sudov";
import { tail } from "./commands/tail";
import { top } from "./commands/top";
import { unalias } from "./commands/unalias";
import { vim } from "./commands/vim";
import { weaken } from "./commands/weaken";
import { wget } from "./commands/wget";
import { hash } from "../hash/hash";
@ -789,6 +790,7 @@ export class Terminal implements ITerminal {
tail: tail,
top: top,
unalias: unalias,
vim: vim,
weaken: weaken,
wget: wget,
};

@ -0,0 +1,65 @@
import { ITerminal } from "../../ITerminal";
import { IRouter, ScriptEditorRouteOptions} from "../../../ui/Router";
import { IPlayer } from "../../../PersonObjects/IPlayer";
import { BaseServer } from "../../../Server/BaseServer";
import { isScriptFilename } from "../../../Script/isScriptFilename";
import { CursorPositions } from "../../../ScriptEditor/CursorPositions";
interface EditorParameters {
terminal: ITerminal;
router: IRouter;
player: IPlayer;
server: BaseServer;
args: (string | number | boolean)[];
}
export function commonEditor(command: string, {
terminal,
router,
player,
server,
args,
}: EditorParameters, scriptEditorRouteOptions?: ScriptEditorRouteOptions): void {
if (args.length !== 1) {
terminal.error(`Incorrect usage of ${command} command. Usage: ${command} [scriptname]`);
return;
}
try {
const filename = args[0] + "";
if (isScriptFilename(filename)) {
const filepath = terminal.getFilepath(filename);
const script = terminal.getScript(player, filename);
if (script == null) {
let code = "";
if (filename.endsWith(".ns") || filename.endsWith(".js")) {
code = `/** @param {NS} ns **/
export async function main(ns) {
}`;
}
CursorPositions.saveCursor(filename, {
row: 3,
column: 5,
});
router.toScriptEditor(filepath, code, scriptEditorRouteOptions);
} else {
router.toScriptEditor(filepath, script.code, scriptEditorRouteOptions);
}
} else if (filename.endsWith(".txt")) {
const filepath = terminal.getFilepath(filename);
const txt = terminal.getTextFile(player, filename);
if (txt == null) {
router.toScriptEditor(filepath, "", scriptEditorRouteOptions);
} else {
router.toScriptEditor(filepath, txt.text, scriptEditorRouteOptions);
}
} else {
terminal.error("Invalid file. Only scripts (.script, .ns, .js), or text files (.txt) can be edited with vim");
return;
}
} catch (e) {
terminal.error(e + "");
}
}

@ -2,8 +2,8 @@ import { ITerminal } from "../ITerminal";
import { IRouter } from "../../ui/Router";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import { isScriptFilename } from "../../Script/isScriptFilename";
import { CursorPositions } from "../../ScriptEditor/CursorPositions";
import {commonEditor} from './common/editor';
export function nano(
terminal: ITerminal,
@ -12,45 +12,5 @@ export function nano(
server: BaseServer,
args: (string | number | boolean)[],
): void {
if (args.length !== 1) {
terminal.error("Incorrect usage of nano command. Usage: nano [scriptname]");
return;
}
try {
const filename = args[0] + "";
if (isScriptFilename(filename)) {
const filepath = terminal.getFilepath(filename);
const script = terminal.getScript(player, filename);
if (script == null) {
let code = "";
if (filename.endsWith(".ns") || filename.endsWith(".js")) {
code = `/** @param {NS} ns **/
export async function main(ns) {
}`;
}
CursorPositions.saveCursor(filename, {
row: 3,
column: 5,
});
router.toScriptEditor(filepath, code);
} else {
router.toScriptEditor(filepath, script.code);
}
} else if (filename.endsWith(".txt")) {
const filepath = terminal.getFilepath(filename);
const txt = terminal.getTextFile(player, filename);
if (txt == null) {
router.toScriptEditor(filepath);
} else {
router.toScriptEditor(filepath, txt.text);
}
} else {
terminal.error("Invalid file. Only scripts (.script, .ns, .js), or text files (.txt) can be edited with nano");
return;
}
} catch (e) {
terminal.error(e + "");
}
return commonEditor('nano', {terminal, router, player, server, args});
}

@ -0,0 +1,16 @@
import { ITerminal } from "../ITerminal";
import { IRouter } from "../../ui/Router";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { BaseServer } from "../../Server/BaseServer";
import {commonEditor} from './common/editor';
export function vim(
terminal: ITerminal,
router: IRouter,
player: IPlayer,
server: BaseServer,
args: (string | number | boolean)[],
): void {
return commonEditor('vim', {terminal, router, player, server, args}, {vim: true});
}

@ -49,6 +49,7 @@ const commands = [
"tail",
"theme",
"top",
"vim",
"weaken",
];
@ -265,7 +266,7 @@ export async function determineAllPossibilitiesForTabCompletion(
return allPos;
}
if (isCommand("nano")) {
if (isCommand("nano") || isCommand("vim")) {
addAllScripts();
addAllTextFiles();
addAllDirectories();

@ -33,7 +33,7 @@ import createStyles from "@mui/styles/createStyles";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import { Page, IRouter } from "./Router";
import { Page, IRouter, ScriptEditorRouteOptions } from "./Router";
import { Overview } from "./React/Overview";
import { SidebarRoot } from "../Sidebar/ui/SidebarRoot";
import { AugmentationsRoot } from "../Augmentation/ui/AugmentationsRoot";
@ -97,6 +97,7 @@ const useStyles = makeStyles((theme: Theme) =>
let filename = "";
let code = "";
let vim = false;
export let Router: IRouter = {
page: () => {
@ -246,9 +247,10 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
toHacknetNodes: () => setPage(Page.Hacknet),
toMilestones: () => setPage(Page.Milestones),
toResleeves: () => setPage(Page.Resleeves),
toScriptEditor: (fn: string, c: string) => {
toScriptEditor: (fn: string, c: string, options?: ScriptEditorRouteOptions) => {
filename = fn;
code = c;
vim = !!options?.vim;
setPage(Page.ScriptEditor);
},
toSleeves: () => setPage(Page.Sleeves),
@ -335,6 +337,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
hostname={player.getCurrentServer().hostname}
player={player}
router={Router}
vim={vim}
/>
) : page === Page.ActiveScripts ? (
<ActiveScriptsRoot workerScripts={workerScripts} />

@ -38,6 +38,10 @@ export enum Page {
Recovery,
}
export interface ScriptEditorRouteOptions {
vim: boolean;
}
/**
* This class keeps track of player navigation/routing within the game.
*/
@ -66,7 +70,7 @@ export interface IRouter {
toJob(): void;
toMilestones(): void;
toResleeves(): void;
toScriptEditor(filename?: string, code?: string): void;
toScriptEditor(filename?: string, code?: string, options?: ScriptEditorRouteOptions): void;
toSleeves(): void;
toStockMarket(): void;
toTerminal(): void;