Add simple glob support to nano/vim usage

This commit is contained in:
smolgumball 2022-01-09 20:26:26 -07:00
parent d8a5f5b03c
commit 74ba063772

@ -1,9 +1,12 @@
import { ITerminal } from "../../ITerminal";
import { removeLeadingSlash, removeTrailingSlash } from '../../DirectoryHelpers'
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";
import { Script } from "../../../Script/Script";
import { isEmpty } from "lodash";
interface EditorParameters {
terminal: ITerminal;
@ -22,6 +25,74 @@ export async function main(ns) {
}`;
interface ISimpleScriptGlob {
glob: string;
preGlob: string;
postGlob: string;
globError: string;
globMatches: string[];
globAgainst: Script[];
}
function containsSimpleGlob(filename: string): boolean {
return filename.includes("*");
}
function detectSimpleScriptGlob(
args: EditorParameters["args"],
player: IPlayer,
terminal: ITerminal,
): ISimpleScriptGlob | null {
if (args.length == 1 && containsSimpleGlob(`${args[0]}`)) {
const filename = `${args[0]}`;
const scripts = player.getCurrentServer().scripts;
const parsedGlob = parseSimpleScriptGlob(filename, scripts, terminal);
return parsedGlob;
}
return null;
}
function parseSimpleScriptGlob(globString: string, globDatabase: Script[], terminal: ITerminal): ISimpleScriptGlob {
const parsedGlob: ISimpleScriptGlob = {
glob: globString,
preGlob: "",
postGlob: "",
globError: "",
globMatches: [],
globAgainst: globDatabase,
};
// Ensure deep globs are minified to simple globs, which act as deep globs in this impl
globString = globString.replace("**", "*");
// Ensure only a single glob is present
if (globString.split("").filter((c) => c == "*").length !== 1) {
parsedGlob.globError = "Only a single glob is supported per command.\nexample: `nano my-dir/*.js`";
return parsedGlob;
}
// Split arg around glob, normalize preGlob path
[parsedGlob.preGlob, parsedGlob.postGlob] = globString.split("*");
parsedGlob.preGlob = removeLeadingSlash(parsedGlob.preGlob);
// Add CWD to preGlob path
const cwd = removeTrailingSlash(terminal.cwd())
parsedGlob.preGlob = `${cwd}/${parsedGlob.preGlob}`
// For every script on the current server, filter matched scripts per glob values & persist
globDatabase.forEach((script) => {
const filename = script.filename.startsWith('/') ? script.filename : `/${script.filename}`
if (filename.startsWith(parsedGlob.preGlob) && filename.endsWith(parsedGlob.postGlob)) {
parsedGlob.globMatches.push(filename);
}
});
// Rebuild glob for potential error reporting
parsedGlob.glob = `${parsedGlob.preGlob}*${parsedGlob.postGlob}`
return parsedGlob;
}
export function commonEditor(
command: string,
{ terminal, router, player, args }: EditorParameters,
@ -32,8 +103,15 @@ export function commonEditor(
return;
}
let filesToLoadOrCreate = args;
try {
const files = args.map((arg) => {
const globSearch = detectSimpleScriptGlob(args, player, terminal);
if (globSearch) {
if (isEmpty(globSearch.globError) === false) throw new Error(globSearch.globError);
filesToLoadOrCreate = globSearch.globMatches;
}
const files = filesToLoadOrCreate.map((arg) => {
const filename = `${arg}`;
if (isScriptFilename(filename)) {
@ -55,12 +133,18 @@ export function commonEditor(
if (filename.endsWith(".txt")) {
const filepath = terminal.getFilepath(filename);
const txt = terminal.getTextFile(player, filename);
return [filepath, txt == null ? "" : txt.text];
return [filepath, txt === null ? "" : txt.text];
}
throw new Error(`Invalid file. Only scripts (.script, .ns, .js), or text files (.txt) can be edited with ${command}`);
throw new Error(
`Invalid file. Only scripts (.script, .ns, .js), or text files (.txt) can be edited with ${command}`,
);
});
if (globSearch && files.length === 0) {
throw new Error(`Could not find any valid files to open with ${command} using glob: \`${globSearch.glob}\``)
}
router.toScriptEditor(Object.fromEntries(files), scriptEditorRouteOptions);
} catch (e) {
terminal.error(`${e}`);