path formatting fixed, long flag support, command execution path now gets passed with the command result to not make it dependant on dynamic bash variable unlike previously implemented with pwd (prev. working dir)

This commit is contained in:
2025-12-08 12:06:01 +01:00
committed by Kamil Olszewski
parent a109c7115e
commit d0ff245582
5 changed files with 82 additions and 43 deletions

View File

@@ -96,7 +96,7 @@ export class Bash {
} }
executeCommand(commandName: string, args: CommandArgs): void { executeCommand(commandName: string, args: CommandArgs): void {
let result: Result = { exitCode: ExitCode.ERROR }; let result: Result = { exitCode: ExitCode.ERROR, path: this.getCwd() };
const command = this._commands[commandName]; const command = this._commands[commandName];
if (!command) this.throwError(result); if (!command) this.throwError(result);
@@ -110,7 +110,7 @@ export class Bash {
let out: Result = command.method.call(this, args); let out: Result = command.method.call(this, args);
console.log(out); console.log(out);
this.appendNewResult(this.getCwd(), out.data?.data, this.user.history[0]); this.appendNewResult(out.path, out.data?.data, this.user.history[0]);
} }
throwError(result: Result): void { throwError(result: Result): void {
@@ -130,9 +130,9 @@ export class Bash {
} }
} }
private appendNewResult(workingDir: number, output: any, cmd: string) { private appendNewResult(inode: number, output: any, cmd: string) {
const data: PrintData = { const data: PrintData = {
path: this.vfs.formatPath(this.vfs.getPathByInode(workingDir)), path: this.vfs.formatPath(this.vfs.getPathByInode(inode)),
output: output, output: output,
cmd: cmd cmd: cmd
}; };
@@ -140,10 +140,10 @@ export class Bash {
this._terminal.PrintOutput(data); this._terminal.PrintOutput(data);
} }
formatBytes(bytes: number, dPoint?: number): string { formatBytes(bytes: number, dPoint?: number, pow: 1024 | 1000 = 1024): string {
if (!+bytes) return '0'; if (!+bytes) return '0';
const k: number = 1024; const k: number = pow;
const dp: number = dPoint ? (dPoint < 0 ? 0 : dPoint) : 1; const dp: number = dPoint ? (dPoint < 0 ? 0 : dPoint) : 1;
const units: string[] = ['', 'K', 'M', 'G', 'T', 'P']; const units: string[] = ['', 'K', 'M', 'G', 'T', 'P'];

View File

@@ -3,7 +3,7 @@ import { Type, type TreeNode } from '../fs';
import type { CommandArgs, ICommand, Result } from '../static'; import type { CommandArgs, ICommand, Result } from '../static';
export const cmd_cd = function (this: Bash, args: CommandArgs): Result { export const cmd_cd = function (this: Bash, args: CommandArgs): Result {
let result: Result = { exitCode: ExitCode.ERROR }; let result: Result = { exitCode: ExitCode.ERROR, path: this.getCwd() };
const path = args.args[0]; const path = args.args[0];
let targetNode: TreeNode | null; let targetNode: TreeNode | null;

View File

@@ -4,6 +4,7 @@ import { Sort } from '../sort';
import type { CommandArgs, ICommand, Result, resultData } from '../static'; import type { CommandArgs, ICommand, Result, resultData } from '../static';
type LsEntry = { type LsEntry = {
inode: number | null;
perms: string; perms: string;
children: string; children: string;
owners: string; owners: string;
@@ -38,7 +39,7 @@ const months: readonly string[] = [
export const cmd_ls = function (this: Bash, args: CommandArgs): Result { export const cmd_ls = function (this: Bash, args: CommandArgs): Result {
const resultData: resultData = { cmd: 'ls', data: null, args: args }; const resultData: resultData = { cmd: 'ls', data: null, args: args };
const result: Result = { exitCode: ExitCode.ERROR, data: resultData }; const result: Result = { exitCode: ExitCode.ERROR, path: this.getCwd(), data: resultData };
const nodes: TreeNode[] = []; const nodes: TreeNode[] = [];
//Check if args contain any nonexistent flags, if so add it to an array and check its length. if 0 no bad flags //Check if args contain any nonexistent flags, if so add it to an array and check its length. if 0 no bad flags
@@ -66,15 +67,28 @@ export const cmd_ls = function (this: Bash, args: CommandArgs): Result {
function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement { function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
const dummysonoerror: HTMLElement = document.createElement('div'); const dummysonoerror: HTMLElement = document.createElement('div');
const flagInfo = checkFlags(args.flags, ls.flags); const flagInfo = checkFlags(args.flags);
const nodes: TreeNode[] = data; const nodes: TreeNode[] = data;
const f_a: boolean = flagInfo.has('a') || flagInfo.has('f'); const f_a: boolean = flagInfo.has('a') || flagInfo.has('all');
const f_h: boolean = flagInfo.has('h'); const f_A: boolean = flagInfo.has('A') || flagInfo.has('almost-all');
const f_G: boolean = flagInfo.has('G') || flagInfo.has('no-group');
const f_h: boolean = flagInfo.has('h') || flagInfo.has('human-readable');
const f_r: boolean = flagInfo.has('r') || flagInfo.has('reverse');
const f_Q: boolean = flagInfo.has('Q') || flagInfo.has('quote-name');
const f_n: boolean = flagInfo.has('n') || flagInfo.has('numeric-uid-gid');
const f_N: boolean = flagInfo.has('N') || flagInfo.has('literal');
const f_L: boolean = flagInfo.has('L') || flagInfo.has('dereference');
const f_i: boolean = flagInfo.has('i') || flagInfo.has('inode');
const f_help: boolean = flagInfo.has('help');
const f_si: boolean = flagInfo.has('si');
const f_l: boolean = flagInfo.has('l');
const f_U: boolean = flagInfo.has('U'); const f_U: boolean = flagInfo.has('U');
const f_f: boolean = flagInfo.has('f'); const f_f: boolean = flagInfo.has('f');
const f_g: boolean = flagInfo.has('g');
const f_o: boolean = flagInfo.has('o');
if (flagInfo.has('l') || flagInfo.has('g') || flagInfo.has('o')) { if (f_l || f_g || f_o) {
const w: HTMLElement = document.createElement('div'); const w: HTMLElement = document.createElement('div');
for (const node of nodes) { for (const node of nodes) {
@@ -84,33 +98,37 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
if (!f_U && !f_f) { if (!f_U && !f_f) {
//TODO: Add sort by option later on //TODO: Add sort by option later on
Sort.nodeArraySort.call(this, children, flagInfo.has('r')); Sort.nodeArraySort.call(this, children, f_r);
} }
const sizes = children.map((child) => child.size); const sizes = children.map((child) => child.size);
const maxSizeWidth = Math.max(...sizes.map((size) => size)); const maxSizeWidth = Math.max(...sizes.map((size) => size));
for (const child of children) { for (const child of children) {
if (child.name.startsWith('.') && !(f_a || flagInfo.has('A'))) continue; if (child.name.startsWith('.') && !(f_a || f_A)) continue;
const cols: LsEntry = { const cols: LsEntry = {
inode: null,
perms: formatPermission(child), perms: formatPermission(child),
children: formatChildren(child), children: formatChildren(child),
owners: formatOwners.call(this, child, flagInfo), owners: formatOwners.call(this, child, flagInfo),
size: formatSize.call(this, f_h, child, maxSizeWidth), size: formatSize.call(this, f_h, child, maxSizeWidth, f_si),
modt: formatModtime(child), modt: formatModtime(child),
name: formatName(child, flagInfo) name: formatName(child, flagInfo)
}; };
if (f_i) cols.inode = child.inode;
rows.push(LsEntryUtils.toString(cols)); rows.push(LsEntryUtils.toString(cols));
} }
if (f_a && !flagInfo.has('A')) { if (f_a && !f_A) {
const current: LsEntry = { const current: LsEntry = {
inode: null,
perms: formatPermission(node), perms: formatPermission(node),
children: formatChildren(node), children: formatChildren(node),
owners: formatOwners.call(this, node, flagInfo), owners: formatOwners.call(this, node, flagInfo),
size: formatSize.call(this, f_h, node, maxSizeWidth), size: formatSize.call(this, f_h, node, maxSizeWidth, f_si),
modt: formatModtime(node), modt: formatModtime(node),
name: '.' name: '.'
}; };
@@ -121,16 +139,22 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
if (node.parent) { if (node.parent) {
const parentNode: TreeNode = this.getFs().getNodeByINode(node.parent); const parentNode: TreeNode = this.getFs().getNodeByINode(node.parent);
parent = { parent = {
inode: null,
perms: formatPermission(parentNode), perms: formatPermission(parentNode),
children: formatChildren(parentNode), children: formatChildren(parentNode),
owners: formatOwners.call(this, parentNode, flagInfo), owners: formatOwners.call(this, parentNode, flagInfo),
size: formatSize.call(this, f_h, parentNode, maxSizeWidth), size: formatSize.call(this, f_h, parentNode, maxSizeWidth, f_si),
modt: formatModtime(parentNode), modt: formatModtime(parentNode),
name: '..' name: '..'
}; };
} }
if (flagInfo.has('r')) { if (f_i) {
current.inode = node.inode;
parent.inode = node.parent ? node.parent : node.inode;
}
if (f_r) {
rows.push(LsEntryUtils.toString(parent), LsEntryUtils.toString(current)); rows.push(LsEntryUtils.toString(parent), LsEntryUtils.toString(current));
} else { } else {
rows.unshift(LsEntryUtils.toString(current), LsEntryUtils.toString(parent)); rows.unshift(LsEntryUtils.toString(current), LsEntryUtils.toString(parent));
@@ -203,12 +227,17 @@ function formatChildren(node: TreeNode): string {
return c.length > 1 ? c : ` ${c}`; return c.length > 1 ? c : ` ${c}`;
} }
function formatSize(this: Bash, humanReadable: boolean, node: TreeNode, max: number): string { function formatSize(
const byteSize: number = node.type === Type.Directory ? 4096 : 1; //TEMP, later calculate the size. this: Bash,
humanReadable: boolean,
node: TreeNode,
max: number,
f_si: boolean
): string {
let size: string; let size: string;
if (humanReadable) { if (humanReadable) {
size = this.formatBytes(byteSize); size = this.formatBytes(node.size, 1, f_si ? 1000 : 1024);
} else size = byteSize.toString(); } else size = node.size.toString();
return size.padStart(max, ' '); return size.padStart(max, ' ');
} }
@@ -243,7 +272,7 @@ function formatName(node: TreeNode, flag: any) {
return flag.has('p') && node.type === Type.Directory ? `${name}/` : name; return flag.has('p') && node.type === Type.Directory ? `${name}/` : name;
} }
const checkFlags = (pFlags: string[], dFlags: string[]) => { const checkFlags = (pFlags: string[]) => {
const flagSet = new Set(pFlags); const flagSet = new Set(pFlags);
return { has: (flag: string) => flagSet.has(flag) }; return { has: (flag: string) => flagSet.has(flag) };
@@ -273,7 +302,23 @@ export const ls: ICommand = {
'n', 'n',
'N', 'N',
'L', 'L',
'm' 'm',
'i',
'sort',
'time',
'help',
'all',
'almost-all',
'no-group',
'human-readable',
'reverse',
'quote-name',
'indicator-style',
'literal',
'numeric-uid-gid',
'inode',
'si',
'dereference'
] as string[], ] as string[],
help: 'PATH TO HELP.MD', help: 'PATH TO HELP.MD',
root: false root: false

View File

@@ -22,6 +22,7 @@ export type resultData = {
export type Result = { export type Result = {
exitCode: ExitCode; exitCode: ExitCode;
path: number; //the inode of the place that the command was executed in
data?: resultData; data?: resultData;
}; };
@@ -73,18 +74,7 @@ export const PASSWD: User[] = [
} }
]; ];
export const cmd_return = function (this: Bash, args: CommandArgs): Result {
let result: Result = { exitCode: ExitCode.ERROR };
return result;
};
export const COMMANDS = { export const COMMANDS = {
return: {
method: cmd_return,
flags: [] as string[],
help: 'PATH TO HELP.MD',
root: false
},
cd, cd,
ls ls
} as const satisfies Record<string, ICommand>; } as const satisfies Record<string, ICommand>;

View File

@@ -66,17 +66,21 @@ export class Terminal {
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
let curr = args[i]; let curr = args[i];
console.log(curr);
if (!curr.startsWith('-')) result.args.args.push(curr); if (curr.startsWith('--')) {
else { curr = curr.replaceAll('--', '');
if (curr.length === 0) continue;
result.args.flags.push(curr);
} else if (curr.startsWith('-')) {
curr = curr.replaceAll('-', ''); curr = curr.replaceAll('-', '');
if (curr.length === 0) continue;
if (curr.length > 0) {
for (let n = 0; n < curr.length; n++) { for (let n = 0; n < curr.length; n++) {
result.args.flags.push(curr[n]); result.args.flags.push(curr[n]);
} }
} } else result.args.args.push(curr);
}
} }
return result; return result;