mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +01:00
MISC: Various small fixes (#574)
* ns.ls filter can include leading slash in filename * scp from terminal accepts multiple filenames * terminal displays root / instead of ~ as base * cd with no args returns to root
This commit is contained in:
parent
ed93fea141
commit
40b89baca1
@ -902,7 +902,7 @@ export const ns: InternalAPI<NSFull> = {
|
||||
];
|
||||
|
||||
if (!substring) return allFilenames.sort();
|
||||
return allFilenames.filter((filename) => filename.includes(substring)).sort();
|
||||
return allFilenames.filter((filename) => ("/" + filename).includes(substring)).sort();
|
||||
},
|
||||
getRecentScripts: () => (): RecentScript[] => {
|
||||
return recentScripts.map((rs) => ({
|
||||
|
@ -4,8 +4,8 @@ import { directoryExistsOnServer, resolveDirectory } from "../../Paths/Directory
|
||||
|
||||
export function cd(args: (string | number | boolean)[], server: BaseServer): void {
|
||||
if (args.length > 1) return Terminal.error("Incorrect number of arguments. Usage: cd [dir]");
|
||||
// If no arg was provided, just use "".
|
||||
const userInput = String(args[0] ?? "");
|
||||
// If no arg was provided, just use "/".
|
||||
const userInput = String(args[0] ?? "/");
|
||||
const targetDir = resolveDirectory(userInput, Terminal.currDir);
|
||||
// Explicitly checking null due to root being ""
|
||||
if (targetDir === null) return Terminal.error(`Could not resolve directory ${userInput}`);
|
||||
|
@ -5,36 +5,62 @@ import { hasScriptExtension } from "../../Paths/ScriptFilePath";
|
||||
import { hasTextExtension } from "../../Paths/TextFilePath";
|
||||
import { checkEnum } from "../../utils/helpers/enum";
|
||||
import { LiteratureName } from "../../Literature/data/LiteratureNames";
|
||||
import { ContentFile } from "../../Paths/ContentFile";
|
||||
|
||||
export function scp(args: (string | number | boolean)[], server: BaseServer): void {
|
||||
if (args.length !== 2) {
|
||||
if (args.length < 2) {
|
||||
return Terminal.error("Incorrect usage of scp command. Usage: scp [source filename] [destination hostname]");
|
||||
}
|
||||
const [scriptname, destHostname] = args.map((arg) => arg + "");
|
||||
|
||||
const path = Terminal.getFilepath(scriptname);
|
||||
if (!path) return Terminal.error(`Invalid file path: ${scriptname}`);
|
||||
|
||||
// Validate destination server
|
||||
const destHostname = String(args.pop());
|
||||
const destServer = GetServer(destHostname);
|
||||
if (!destServer) return Terminal.error(`Invalid destination server: ${args[1]}`);
|
||||
if (!destServer) return Terminal.error(`Invalid destination server: ${destHostname}`);
|
||||
|
||||
// Lit files
|
||||
if (path.endsWith(".lit")) {
|
||||
if (!checkEnum(LiteratureName, path) || !server.messages.includes(path)) {
|
||||
return Terminal.error(`No file at path ${path}`);
|
||||
// Validate filepaths
|
||||
const filenames = args.map(String);
|
||||
const files: (LiteratureName | ContentFile)[] = [];
|
||||
|
||||
// File validation loop, handle all errors before copying any files
|
||||
for (const filename of filenames) {
|
||||
const path = Terminal.getFilepath(filename);
|
||||
if (!path) return Terminal.error(`Invalid file path: ${filename}`);
|
||||
// Validate .lit files
|
||||
if (path.endsWith(".lit")) {
|
||||
if (!checkEnum(LiteratureName, path) || !server.messages.includes(path)) {
|
||||
return Terminal.error(`scp failed: ${path} does not exist on server ${server.hostname}`);
|
||||
}
|
||||
files.push(path);
|
||||
continue;
|
||||
}
|
||||
if (destServer.messages.includes(path)) return Terminal.print(`${path} was already on ${destHostname}`);
|
||||
destServer.messages.push(path);
|
||||
return Terminal.print(`Copied ${path} to ${destHostname}`);
|
||||
// Error for invalid filetype
|
||||
if (!hasScriptExtension(path) && !hasTextExtension(path)) {
|
||||
return Terminal.error(
|
||||
`scp failed: ${path} has invalid extension. scp only works for scripts (.js or .script), text files (.txt), and literature files (.lit)`,
|
||||
);
|
||||
}
|
||||
const sourceContentFile = server.getContentFile(path);
|
||||
if (!sourceContentFile) return Terminal.error(`scp failed: ${path} does not exist on server ${server.hostname}`);
|
||||
files.push(sourceContentFile);
|
||||
}
|
||||
|
||||
if (!hasScriptExtension(path) && !hasTextExtension(path)) {
|
||||
return Terminal.error("scp only works for scripts, text files (.txt), and literature files (.lit)");
|
||||
// Actually copy the files (no more errors possible)
|
||||
for (const file of files) {
|
||||
// Lit files, entire "file" is just the name
|
||||
if (checkEnum(LiteratureName, file)) {
|
||||
if (destServer.messages.includes(file)) {
|
||||
Terminal.print(`${file} was already on ${destHostname}, file skipped`);
|
||||
continue;
|
||||
}
|
||||
destServer.messages.push(file);
|
||||
Terminal.print(`${file} copied to ${destHostname}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Content files (script and txt)
|
||||
const { filename, content } = file;
|
||||
const { overwritten } = destServer.writeToContentFile(filename, content);
|
||||
if (overwritten) Terminal.warn(`${filename} already existed on ${destHostname} and was overwritten`);
|
||||
else Terminal.print(`${filename} copied to ${destHostname}`);
|
||||
}
|
||||
// Text or script
|
||||
const source = server.getContentFile(path);
|
||||
if (!source) return Terminal.error(`No file at path ${path}`);
|
||||
const { overwritten } = destServer.writeToContentFile(path, source.content);
|
||||
if (overwritten) Terminal.warn(`${path} already exists on ${destHostname} and will be overwritten`);
|
||||
Terminal.print(`${path} copied to ${destHostname}`);
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ export async function getTabCompletionPossibilities(terminalText: string, baseDi
|
||||
// Just some booleans so the mismatch between command length and arg number are not as confusing.
|
||||
const onCommand = commandLength === 1;
|
||||
const onFirstCommandArg = commandLength === 2;
|
||||
const onSecondCommandArg = commandLength === 3;
|
||||
// const onSecondCommandArg = commandLength === 3; // unused
|
||||
|
||||
// These are always added.
|
||||
addGlobalAliases();
|
||||
@ -239,11 +239,12 @@ export async function getTabCompletionPossibilities(terminalText: string, baseDi
|
||||
return possibilities;
|
||||
|
||||
case "scp":
|
||||
if (onFirstCommandArg) {
|
||||
addScripts();
|
||||
addTextFiles();
|
||||
addLiterature();
|
||||
} else if (onSecondCommandArg) addServerNames();
|
||||
if (!onFirstCommandArg) {
|
||||
addServerNames();
|
||||
}
|
||||
addScripts();
|
||||
addTextFiles();
|
||||
addLiterature();
|
||||
return possibilities;
|
||||
|
||||
case "rm":
|
||||
|
@ -197,7 +197,7 @@ export function TerminalInput(): React.ReactElement {
|
||||
// Run command.
|
||||
if (event.key === KEY.ENTER && value !== "") {
|
||||
event.preventDefault();
|
||||
Terminal.print(`[${Player.getCurrentServer().hostname} ~${Terminal.cwd()}]> ${value}`);
|
||||
Terminal.print(`[${Player.getCurrentServer().hostname} /${Terminal.cwd()}]> ${value}`);
|
||||
Terminal.executeCommands(value);
|
||||
saveValue("");
|
||||
return;
|
||||
@ -282,7 +282,7 @@ export function TerminalInput(): React.ReactElement {
|
||||
if (Settings.EnableBashHotkeys) {
|
||||
if (event.code === KEYCODE.C && event.ctrlKey && ref && ref.selectionStart === ref.selectionEnd) {
|
||||
event.preventDefault();
|
||||
Terminal.print(`[${Player.getCurrentServer().hostname} ~${Terminal.cwd()}]> ${value}`);
|
||||
Terminal.print(`[${Player.getCurrentServer().hostname} /${Terminal.cwd()}]> ${value}`);
|
||||
modifyInput("clearall");
|
||||
}
|
||||
|
||||
@ -361,7 +361,7 @@ export function TerminalInput(): React.ReactElement {
|
||||
className: classes.input,
|
||||
startAdornment: (
|
||||
<Typography color={Terminal.action === null ? "primary" : "secondary"} flexShrink={0}>
|
||||
[{Player.getCurrentServer().hostname} ~{Terminal.cwd()}]>
|
||||
[{Player.getCurrentServer().hostname} /{Terminal.cwd()}]>
|
||||
</Typography>
|
||||
),
|
||||
spellCheck: false,
|
||||
|
@ -13,6 +13,7 @@ import { hasScriptExtension } from "../../../src/Paths/ScriptFilePath";
|
||||
import { LiteratureName } from "../../../src/Literature/data/LiteratureNames";
|
||||
import { MessageFilename } from "../../../src/Message/MessageHelpers";
|
||||
import { Terminal } from "../../../src/Terminal";
|
||||
import { IPAddress } from "../../../src/Types/strings";
|
||||
|
||||
describe("getTabCompletionPossibilities", function () {
|
||||
let closeServer: Server;
|
||||
@ -23,7 +24,7 @@ describe("getTabCompletionPossibilities", function () {
|
||||
Player.init();
|
||||
|
||||
closeServer = new Server({
|
||||
ip: "8.8.8.8",
|
||||
ip: "8.8.8.8" as IPAddress,
|
||||
hostname: "near",
|
||||
hackDifficulty: 1,
|
||||
moneyAvailable: 70000,
|
||||
@ -33,7 +34,7 @@ describe("getTabCompletionPossibilities", function () {
|
||||
serverGrowth: 3000,
|
||||
});
|
||||
farServer = new Server({
|
||||
ip: "4.4.4.4",
|
||||
ip: "4.4.4.4" as IPAddress,
|
||||
hostname: "far",
|
||||
hackDifficulty: 1,
|
||||
moneyAvailable: 70000,
|
||||
@ -87,23 +88,22 @@ describe("getTabCompletionPossibilities", function () {
|
||||
it("completes the scp command", async () => {
|
||||
writeFiles();
|
||||
let options = await getTabCompletionPossibilities("scp ", root);
|
||||
expect(options.sort()).toEqual(
|
||||
[
|
||||
"note.txt",
|
||||
"folder1/text.txt",
|
||||
"folder1/text2.txt",
|
||||
"hack.js",
|
||||
"weaken.js",
|
||||
"grow.js",
|
||||
"old.script",
|
||||
"folder1/test.js",
|
||||
"anotherFolder/win.js",
|
||||
LiteratureName.AGreenTomorrow,
|
||||
].sort(),
|
||||
);
|
||||
const filesToMatch = [
|
||||
"note.txt",
|
||||
"folder1/text.txt",
|
||||
"folder1/text2.txt",
|
||||
"hack.js",
|
||||
"weaken.js",
|
||||
"grow.js",
|
||||
"old.script",
|
||||
"folder1/test.js",
|
||||
"anotherFolder/win.js",
|
||||
LiteratureName.AGreenTomorrow,
|
||||
];
|
||||
expect(options.sort()).toEqual(filesToMatch.sort());
|
||||
// Test the second command argument (server name)
|
||||
options = await getTabCompletionPossibilities("scp note.txt ", root);
|
||||
expect(options).toEqual(["home", "near", "far"]);
|
||||
expect(options.sort()).toEqual(["home", "near", "far", ...filesToMatch].sort());
|
||||
});
|
||||
|
||||
it("completes the kill, tail, mem, and check commands", async () => {
|
||||
|
Loading…
Reference in New Issue
Block a user