more features, flags now mostly work, added support for -R flag in ls with a custom bash method for recursive tree traversal
This commit is contained in:
@@ -33,7 +33,7 @@
|
||||
},
|
||||
"Interactible": false,
|
||||
"Func": null,
|
||||
"Parent": null
|
||||
"Parent": 1
|
||||
},
|
||||
"2": {
|
||||
"Inode": 2,
|
||||
|
||||
15
src/lib/stores/bash/commands/clear.ts
Normal file
15
src/lib/stores/bash/commands/clear.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ExitCode, type Bash } from "../bash";
|
||||
import type { CommandArgs, ICommand, Result } from "../static";
|
||||
|
||||
export const cmd_clear = function(this: Bash, args: CommandArgs): Result {
|
||||
let result: Result = { exitCode: ExitCode.ERROR, path: this.getCwd() };
|
||||
result.exitCode = ExitCode.SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
export const clear: ICommand = {
|
||||
method: cmd_clear,
|
||||
flags: [] as string[],
|
||||
help: 'PATH TO HELP.md',
|
||||
root: false
|
||||
};
|
||||
@@ -76,7 +76,8 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
|
||||
|
||||
|
||||
const flagInfo = checkFlags(args.flags);
|
||||
let nodes: TreeNode[] = data;
|
||||
const nodes: TreeNode[] = data;
|
||||
let nodeIndex: number = 0;
|
||||
|
||||
const f_a: boolean = flagInfo.has('a') || flagInfo.has('all');
|
||||
const f_A: boolean = flagInfo.has('A') || flagInfo.has('almost-all');
|
||||
@@ -105,6 +106,18 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
|
||||
|
||||
const w: HTMLElement = document.createElement('div');
|
||||
|
||||
if(f_R) {
|
||||
const treeWalkResult: TreeNode[] = [];
|
||||
const treeWalkCallback = (node: TreeNode) => { treeWalkResult.push(node); }
|
||||
|
||||
for(const node of nodes) {
|
||||
treeWalkResult.push(node);
|
||||
Fs.recursiveTraversalPre(node, treeWalkCallback);
|
||||
}
|
||||
nodes.length = 0;
|
||||
nodes.push(...treeWalkResult.filter((node) => node.type != Type.File));
|
||||
}
|
||||
|
||||
for (const node of nodes) {
|
||||
const elem: HTMLElement = document.createElement('div');
|
||||
const childrenMap: TreeNode[] = node.children.map((child) => Fs.getNodeByINode(child));
|
||||
@@ -121,11 +134,8 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
|
||||
const current: TreeNode = node;
|
||||
current.name = '.';
|
||||
|
||||
let parent: TreeNode = current;
|
||||
if(node.parent) {
|
||||
parent = Fs.getNodeByINode(node.parent);
|
||||
parent.name = '..';
|
||||
}
|
||||
const parent: TreeNode = Fs.getNodeByINode(node.parent);
|
||||
parent.name = '..';
|
||||
|
||||
children.unshift(current, parent);
|
||||
}
|
||||
@@ -153,48 +163,43 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
|
||||
|
||||
if (f_l || f_g || f_o) {
|
||||
const rows: string[] = [];
|
||||
const maxSizeWidth = Math.max(
|
||||
...children.map((child) => child.size.toString().length));
|
||||
|
||||
for (const node of nodes) {
|
||||
const maxSizeWidth = Math.max(
|
||||
...children.map((child) => child.size.toString().length));
|
||||
for (const child of children) {
|
||||
const entry: LsEntry = {
|
||||
inode: null,
|
||||
perms: formatPermission(child),
|
||||
children: formatChildren(child),
|
||||
owners: formatOwners.call(this, child, flagInfo),
|
||||
size: formatSize.call(this, f_h, child, maxSizeWidth, f_si),
|
||||
modt: formatModtime(child, timestamp),
|
||||
name: formatName(child, flagInfo, shouldNamesShift)
|
||||
};
|
||||
|
||||
for (const child of children) {
|
||||
const entry: LsEntry = {
|
||||
inode: null,
|
||||
perms: formatPermission(child),
|
||||
children: formatChildren(child),
|
||||
owners: formatOwners.call(this, child, flagInfo),
|
||||
size: formatSize.call(this, f_h, child, maxSizeWidth, f_si),
|
||||
modt: formatModtime(child, timestamp),
|
||||
name: formatName(child, flagInfo, shouldNamesShift)
|
||||
};
|
||||
if (f_i) entry.inode = child.inode;
|
||||
|
||||
if (f_i) entry.inode = child.inode;
|
||||
|
||||
rows.push(LsEntryUtils.toString(entry));
|
||||
}
|
||||
|
||||
//TODO: Calculate the total size of contents in the node
|
||||
rows.unshift('total ' + node.children.length.toString());
|
||||
|
||||
if (nodes.length > 1) {
|
||||
const nodePath: string =
|
||||
node.name === '/' ? '/:' : `${Fs.getPathByInode(node.inode).slice(1)}:`;
|
||||
rows.unshift(nodePath);
|
||||
rows.push('\n');
|
||||
}
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const p: HTMLElement = document.createElement('p');
|
||||
p.innerText = rows[i];
|
||||
elem.appendChild(p);
|
||||
}
|
||||
|
||||
w.appendChild(elem);
|
||||
rows.push(LsEntryUtils.toString(entry));
|
||||
}
|
||||
|
||||
return w;
|
||||
//TODO: Calculate the total size of contents in the node
|
||||
rows.unshift('total ' + node.children.length.toString());
|
||||
|
||||
if (nodes.length > 1) {
|
||||
const nodePath: HTMLElement = document.createElement('p');
|
||||
nodePath.innerText = `${Fs.getPathByInode(node.inode)}:`;
|
||||
w.appendChild(nodePath);
|
||||
if(nodeIndex +1 < nodes.length) elem.style.marginBottom = `${this.getTerminalFontSize() * 2}px`;
|
||||
}
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const p: HTMLElement = document.createElement('p');
|
||||
p.innerText = rows[i];
|
||||
elem.appendChild(p);
|
||||
}
|
||||
w.appendChild(elem);
|
||||
}
|
||||
else {
|
||||
const maxWidth: number = Math.ceil((this.getTerminalWidth() / this.getTerminalFontSize()) * 0.8);
|
||||
|
||||
let columns: string[][] = [];
|
||||
@@ -227,8 +232,10 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
|
||||
}
|
||||
|
||||
const wrapper: HTMLElement = document.createElement('div');
|
||||
|
||||
wrapper.style.display = 'flex';
|
||||
wrapper.style.columnGap = `${this.getTerminalFontSize() * 2}px`;
|
||||
wrapper.style.marginBottom = `${this.getTerminalFontSize() * 2}px`;
|
||||
|
||||
let fileIndex = 0;
|
||||
|
||||
@@ -250,11 +257,13 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
|
||||
|
||||
if (nodes.length > 1) {
|
||||
const nodePath: HTMLElement = document.createElement('p');
|
||||
nodePath.innerText = node.name === '/' ? '/:' : `${Fs.getPathByInode(node.inode).slice(1)}:`;
|
||||
nodePath.innerText = `${Fs.getPathByInode(node.inode)}`;
|
||||
w.appendChild(nodePath);
|
||||
}
|
||||
|
||||
w.appendChild(wrapper);
|
||||
}
|
||||
nodeIndex++;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
@@ -350,11 +359,11 @@ function formatModtime(node: TreeNode, sortBy: SortNodeBy.ATIME | SortNodeBy.CTI
|
||||
}
|
||||
|
||||
function formatName(node: TreeNode, flag: any, shouldShift: boolean) {
|
||||
let name: string;
|
||||
let name: string = node.name;
|
||||
const char: string = flag.has('Q') ? '"' : "'";
|
||||
|
||||
if (/\s/.test(node.name)) {
|
||||
name = `${char}${node.name}${char}`
|
||||
name = `${char}${name}${char}`
|
||||
} else {
|
||||
//Shift non quoted names 1 char right to align if any names in group have a quote
|
||||
name = `${shouldShift ? ' ' : ''}${node.name}`;
|
||||
|
||||
@@ -19,7 +19,7 @@ export type FsInitArgs = {
|
||||
|
||||
export type TreeNode = {
|
||||
inode: number;
|
||||
parent?: number;
|
||||
parent: number;
|
||||
name: string;
|
||||
type: Type;
|
||||
size: number; //Size in Bytes
|
||||
@@ -110,11 +110,11 @@ export class VirtualFS {
|
||||
return typeof path === 'string' && path.startsWith('/');
|
||||
};
|
||||
|
||||
getPathByInode(inode: number): string {
|
||||
public getPathByInode(inode: number): string {
|
||||
return this._iNodeToPathString(inode);
|
||||
}
|
||||
|
||||
formatPath(path: string): string {
|
||||
public formatPath(path: string): string {
|
||||
console.log(path, 'formatPath');
|
||||
const prefix = this._iNodeToPathString(this.home);
|
||||
|
||||
@@ -123,7 +123,7 @@ export class VirtualFS {
|
||||
} else return path;
|
||||
}
|
||||
|
||||
resolvePath(path: string): TreeNode {
|
||||
public resolvePath(path: string): TreeNode {
|
||||
if (path === '/') return this.getNodeByINode(this.rootINode);
|
||||
let parsedPath: string = path;
|
||||
|
||||
@@ -144,22 +144,32 @@ export class VirtualFS {
|
||||
return Node;
|
||||
}
|
||||
|
||||
getNodeByINode(inode: number): TreeNode {
|
||||
public getNodeByINode(inode: number): TreeNode {
|
||||
const node: TreeNode | undefined = this.FsTable.get(inode);
|
||||
if (!node) throw new Error('Could not get the node, no such i node exists');
|
||||
if (!node) throw new Error(`Could not get the node, no such inode exists - ${inode}`);
|
||||
return node;
|
||||
}
|
||||
|
||||
/* private _getPathToNode(node: TreeNode): string[] {
|
||||
const path: string[] = [];
|
||||
let current = node;
|
||||
path.push(node.name);
|
||||
public recursiveTraversalPre(node: TreeNode, callback: (param: TreeNode) => void, childIndex?: number[], depthIndex?: number): void {
|
||||
if(!depthIndex) depthIndex = 0;
|
||||
if(!childIndex) childIndex = [0];
|
||||
|
||||
while (current.parent) {
|
||||
current = current.parent;
|
||||
path.unshift(current.name);
|
||||
if(node.type != Type.File && node.children[childIndex[depthIndex]]) {
|
||||
node = this.getNodeByINode(node.children[childIndex[depthIndex]]);
|
||||
depthIndex++;
|
||||
if(!childIndex[depthIndex]) childIndex[depthIndex] = 0;
|
||||
|
||||
callback(node);
|
||||
}
|
||||
else {
|
||||
node = this.getNodeByINode(node.parent);
|
||||
childIndex[depthIndex] = 0;
|
||||
depthIndex--;
|
||||
childIndex[depthIndex]++;
|
||||
}
|
||||
|
||||
return path;
|
||||
} */
|
||||
if(depthIndex < 0) return;
|
||||
|
||||
this.recursiveTraversalPre(node, callback, childIndex, depthIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export class Sort {
|
||||
reverse: boolean = false,
|
||||
sortBy: SortNodeBy = SortNodeBy.NAME
|
||||
): TreeNode[] {
|
||||
if (nodes.length === 0) throw new Error('Tried to sort an empty node array!');
|
||||
if (nodes.length === 0) {console.warn('Tried to sort an empty node array!'); return [];}
|
||||
const parsedNodes: TreeNode[] = [];
|
||||
|
||||
if (typeof nodes[0] === 'number') {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Bash, ExitCode, type Group, type User } from './bash';
|
||||
import { ls } from './commands/ls';
|
||||
import { cd } from './commands/cd';
|
||||
import { clear } from './commands/clear';
|
||||
|
||||
export type ICommand = {
|
||||
method: (this: Bash, args: CommandArgs) => Result;
|
||||
@@ -76,7 +77,8 @@ export const PASSWD: User[] = [
|
||||
|
||||
export const COMMANDS = {
|
||||
cd,
|
||||
ls
|
||||
ls,
|
||||
clear
|
||||
} as const satisfies Record<string, ICommand>;
|
||||
|
||||
/* //export const commands {
|
||||
|
||||
@@ -8,7 +8,7 @@ export function isInitializing(): boolean {
|
||||
return initializing;
|
||||
}
|
||||
|
||||
function jsonToNodeTable(data: any, parent?: number): Map<number, TreeNode> {
|
||||
function jsonToNodeTable(data: any): Map<number, TreeNode> {
|
||||
const FsTable: Map<number, TreeNode> = new Map<number, TreeNode>();
|
||||
const entryList = Object.entries(data);
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ export function print(e: HTMLElement, data: PrintData): void {
|
||||
}
|
||||
|
||||
export function clear(): void {
|
||||
for (const n of outputInstances) {
|
||||
unmount(n);
|
||||
}
|
||||
console.log("outInstances", outputInstances);
|
||||
unmount(outputInstances);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ export type PrintData = {
|
||||
|
||||
export type PageCallbacks = {
|
||||
print: (data: PrintData) => void;
|
||||
clear: () => void;
|
||||
getWidth: () => number;
|
||||
getFontSize: () => number;
|
||||
};
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
if (!e) return;
|
||||
printOutput(e, data);
|
||||
},
|
||||
clear: clear,
|
||||
getWidth: getWidth,
|
||||
getFontSize: getFontSize
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user