Compare commits

...

2 Commits

6 changed files with 168 additions and 110 deletions

View File

@@ -18,7 +18,7 @@ const LsEntryUtils = {
return Object.entries(entry) return Object.entries(entry)
.filter(([_, value]) => value !== '') .filter(([_, value]) => value !== '')
.map(([_, value]) => value) .map(([_, value]) => value)
.join(' '); .join(' ').trimStart();
} }
}; };
@@ -72,6 +72,7 @@ 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); const flagInfo = checkFlags(args.flags);
const nodes: TreeNode[] = data; const nodes: TreeNode[] = data;
@@ -96,65 +97,62 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
const f_g: boolean = flagInfo.has('g'); const f_g: boolean = flagInfo.has('g');
const f_o: boolean = flagInfo.has('o'); const f_o: boolean = flagInfo.has('o');
let shouldShift: boolean = false
const valuedArgs = args.flags.filter((flag: string) => const valuedArgs = args.flags.filter((flag: string) =>
flag.includes('=') && ls.flags.includes(flag.split('=')[0])); flag.includes('=') && ls.flags.includes(flag.split('=')[0]));
const w: HTMLElement = document.createElement('div');
for (const node of nodes) {
const elem: HTMLElement = document.createElement('div');
const children: TreeNode[] = node.children.map((child) => this.getFs().getNodeByINode(child));
const rows: string[] = [];
const timeArg = valuedArgs.find((flag) => flag.startsWith('time'));
const shouldNamesShift: boolean = children.some((child) => child.name.match(/\s/) !== null);
let timestamp: SortNodeBy.ATIME | SortNodeBy.CTIME | SortNodeBy.MTIME = SortNodeBy.MTIME;
if(timeArg) {
let value: string = timeArg.split('=')[1];
if (value && isValidNodeTimestamp(value)) timestamp = value;
}
if (!f_U && !f_f) {
const sortArg = valuedArgs.find((flag) => flag.startsWith('sort'));
let sortBy: SortNodeBy = SortNodeBy.NAME;
if(f_t) sortBy = timestamp;
if(f_S) sortBy = SortNodeBy.SIZE;
if(f_X) sortBy = SortNodeBy.EXTENSION;
if(sortArg) {
let value = sortArg.split('=')[1];
if(value && isValidNodeSortMethod(value)) sortBy = value;
}
Sort.nodeArraySort.call(this, children, f_r, sortBy);
}
if (f_l || f_g || f_o) { if (f_l || f_g || f_o) {
const w: HTMLElement = document.createElement('div');
for (const node of nodes) { for (const node of nodes) {
const elem: HTMLElement = document.createElement('div'); const maxSizeWidth = Math.max(
const children: TreeNode[] = node.children.map((child) => this.getFs().getNodeByINode(child)); ...children.map((child) => child.size.toString().length));
const rows: string[] = [];
const timeArg = valuedArgs.find((flag) => flag.startsWith('time'));
let timestamp: SortNodeBy.ATIME | SortNodeBy.CTIME | SortNodeBy.MTIME = SortNodeBy.MTIME;
if(timeArg) {
let value: string = timeArg.split('=')[1];
if (value && isValidNodeTimestamp(value)) {
timestamp = value;
console.log(timestamp);
}
}
if (!f_U && !f_f) {
const sortArg = valuedArgs.find((flag) => flag.startsWith('sort'));
let sortBy: SortNodeBy = SortNodeBy.NAME;
if(f_t) sortBy = timestamp;
if(f_S) sortBy = SortNodeBy.SIZE;
if(f_X) sortBy = SortNodeBy.EXTENSION;
if(sortArg) {
let value = sortArg.split('=')[1];
if(value && isValidNodeSortMethod(value)) {
sortBy = value;
console.log(sortBy, 'sortBy');
}
}
Sort.nodeArraySort.call(this, children, f_r, sortBy);
}
const sizes = children.map((child) => child.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 || f_A)) continue; if (child.name.startsWith('.') && !(f_a || f_A)) continue;
const cols: LsEntry = { const entry: LsEntry = {
inode: null, 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, f_si), size: formatSize.call(this, f_h, child, maxSizeWidth, f_si),
modt: formatModtime(child, timestamp), modt: formatModtime(child, timestamp),
name: formatName(child, flagInfo, shouldShift) name: formatName(child, flagInfo, shouldNamesShift)
}; };
if (f_i) cols.inode = child.inode; if (f_i) entry.inode = child.inode;
rows.push(LsEntryUtils.toString(cols)); rows.push(LsEntryUtils.toString(entry));
} }
if (f_a && !f_A) { if (f_a && !f_A) {
@@ -165,11 +163,11 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
owners: formatOwners.call(this, node, flagInfo), owners: formatOwners.call(this, node, flagInfo),
size: formatSize.call(this, f_h, node, maxSizeWidth, f_si), size: formatSize.call(this, f_h, node, maxSizeWidth, f_si),
modt: formatModtime(node, timestamp), modt: formatModtime(node, timestamp),
name: '.' name: shouldNamesShift ? ' .' : '.'
}; };
let parent: LsEntry = { let parent: LsEntry = {
...current, ...current,
name: '..' name: shouldNamesShift ? ' ..' : '..'
}; };
if (node.parent) { if (node.parent) {
const parentNode: TreeNode = this.getFs().getNodeByINode(node.parent); const parentNode: TreeNode = this.getFs().getNodeByINode(node.parent);
@@ -180,7 +178,7 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
owners: formatOwners.call(this, parentNode, flagInfo), owners: formatOwners.call(this, parentNode, flagInfo),
size: formatSize.call(this, f_h, parentNode, maxSizeWidth, f_si), size: formatSize.call(this, f_h, parentNode, maxSizeWidth, f_si),
modt: formatModtime(parentNode, timestamp), modt: formatModtime(parentNode, timestamp),
name: '..' name: shouldNamesShift ? ' ..' : '..'
}; };
} }
@@ -206,12 +204,7 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
rows.push('\n'); rows.push('\n');
} }
for(const row of rows) {
const name: string = row[row.length - 1];
if(!name.startsWith('"') || !name.startsWith("'"))
name.padStart(1, ' ');
else continue;
}
for (let i = 0; i < rows.length; i++) { for (let i = 0; i < rows.length; i++) {
const p: HTMLElement = document.createElement('p'); const p: HTMLElement = document.createElement('p');
@@ -226,23 +219,49 @@ function result_ls(this: Bash, data: any, args: CommandArgs): HTMLElement {
} }
return w; return w;
} }
const maxWidth: number = (this.getTerminalWidth() / this.getTerminalFontSize()) * 0.8;
const nameLengths: number[] = nodes.map(node => node.name.length);
let columns: string[][] = [];
let lowBound: number = 1;
let highBound: number = Math.floor(maxWidth / 3);
let c: number = (lowBound + highBound) / 2;
nodeBinarySearch(nodes.length, nameLengths, lowBound, highBound, maxWidth);
return dummysonoerror; //TEMP SO NO ERROR CUZ RETURNS HTMLElement EVERY TIME, DELETE LATER for(let i = 0; i < c -1; i++) {
const colSize: number = i < (nodes.length % c) ? nodes.length : nodes.length -1;
for(let j = 0; j < colSize -1; j++){
if(j >= nodes.length -1) break;
columns[i].push(nodes[j].name);
}
}
//w.appendChild();
}
return w;
} }
function checkMaxColumns(this: Bash, files: TreeNode[]) { function nodeBinarySearch(
const paddingWidth: number = 2; n: number,
const maxWidth: number = (this.getTerminalWidth() / this.getTerminalFontSize()) * 0.8; nameLengths: number[],
low: number,
high: number,
max: number) {
let c: number = (low + high) / 2;
//Upper bound set to max width / min column width - 1 character + padding if(low + 1 < high) {
let lowBound: number = 1; const calcWidth: number =
let highBound: number = Math.floor(maxWidth / (1 + paddingWidth)); nameLengths.reduce((result, value) => result + value) + (c-1) * 2
if (calcWidth <= max) {
low = c;
} else high = c;
nodeBinarySearch(n, nameLengths, low, high, max);
}
} }
function isValidNodeSortMethod(value: string): value is SortNodeBy { function isValidNodeSortMethod(value: string): value is SortNodeBy {
@@ -341,9 +360,9 @@ function formatName(node: TreeNode, flag: any, shouldShift: boolean) {
if (/\s/.test(node.name)) { if (/\s/.test(node.name)) {
name = `${char}${node.name}${char}` name = `${char}${node.name}${char}`
shouldShift = true;
} else { } else {
name = `${node.name}`; //Shift non quoted names 1 char right to align if any names in group have a quote
name = `${shouldShift ? ' ' : ''}${node.name}`;
} }
return flag.has('p') && node.type === Type.Directory ? `${name}/` : name; return flag.has('p') && node.type === Type.Directory ? `${name}/` : name;

View File

@@ -0,0 +1,78 @@
export class Posix {
private static readonly CharTable = {
// Space and punctuation (32-47)
' ': 32,
'!': 33,
'"': 34,
'#': 35,
'$': 36,
'%': 37,
'&': 38,
"'": 39,
'(': 40,
')': 41,
'*': 42,
'+': 43,
',': 44,
'-': 45,
'.': 46,
'/': 47,
// Numbers 0-9 (48-57)
'0': 48, '1': 49, '2': 50, '3': 51, '4': 52,
'5': 53, '6': 54, '7': 55, '8': 56, '9': 57,
// More punctuation (58-64)
':': 58,
';': 59,
'<': 60,
'=': 61,
'>': 62,
'?': 63,
'@': 64,
// LETTERS - INTERLEAVED AaBbCc... (65-116)
'A': 65, 'a': 66,
'B': 67, 'b': 68,
'C': 69, 'c': 70,
'D': 71, 'd': 72,
'E': 73, 'e': 74,
'F': 75, 'f': 76,
'G': 77, 'g': 78,
'H': 79, 'h': 80,
'I': 81, 'i': 82,
'J': 83, 'j': 84,
'K': 85, 'k': 86,
'L': 87, 'l': 88,
'M': 89, 'm': 90,
'N': 91, 'n': 92,
'O': 93, 'o': 94,
'P': 95, 'p': 96,
'Q': 97, 'q': 98,
'R': 99, 'r': 100,
'S': 101, 's': 102,
'T': 103, 't': 104,
'U': 105, 'u': 106,
'V': 107, 'v': 108,
'W': 109, 'w': 110,
'X': 111, 'x': 112,
'Y': 113, 'y': 114,
'Z': 115, 'z': 116,
// Specials after letters (now 117-126)
'[': 117,
'\\': 118,
']': 119,
'^': 120,
'_': 121,
'`': 122,
'{': 123,
'|': 124,
'}': 125,
'~': 126
} as const;
public static GetCharWeight(char: string): number {
return this.CharTable[char as keyof typeof this.CharTable];
}
}

View File

@@ -3,46 +3,5 @@ import type { TreeNode } from "./fs";
export class Search { export class Search {
public static nodeBinarySearch(
this: Bash,
nodes: TreeNode[],
max: number
): number {
let low: number = 1;
let high: number = nodes.length;
let c: number = (low + high) / 2;
const nameLengths: number[] = nodes.map(node => node.name.length);
}
private static binarySearchDNC(
n: number,
nameLengths: number[],
low: number,
high: number,
max: number): number {
let c: number = (low + high) / 2;
if(low + 1 < high) {
for(let i = 0; i < c; i++) {
const colSize: number =
i < (n % c) ? n : n -1;
}
const calculatedWidth: number =
nameLengths.reduce((result, value) => result + value) + (c-1) * 2
if (calculatedWidth <= max) {
low = c;
return c;
}
else {
high = c;
}
this.binarySearchDNC(n, nameLengths, low, high, max);
}
}
} }

View File

@@ -1,5 +1,6 @@
import type { TreeNode } from './fs'; import type { TreeNode } from './fs';
import type { Bash } from './bash'; import type { Bash } from './bash';
import { Posix } from './posix';
export enum SortNodeBy { export enum SortNodeBy {
NAME = 'name', NAME = 'name',
@@ -85,17 +86,19 @@ export class Sort {
): number { ): number {
switch (sortBy) { switch (sortBy) {
case SortNodeBy.NAME: { case SortNodeBy.NAME: {
const minLength = Math.min(a.name.length, b.name.length); const nameA: string = a.name.startsWith('.') ? a.name.slice(1) : a.name;
const nameB: string = b.name.startsWith('.') ? b.name.slice(1) : b.name;
const minLength = Math.min(nameA.length, nameB.length);
for (let i = 0; i < minLength; i++) { for (let i = 0; i < minLength; i++) {
const charCodeA = a.name.charCodeAt(i); const charCodeA = Posix.GetCharWeight(nameA[i]);
const charCodeB = b.name.charCodeAt(i); const charCodeB = Posix.GetCharWeight(nameB[i]);
if (charCodeA !== charCodeB) { if (charCodeA !== charCodeB) {
return reverse ? charCodeB - charCodeA : charCodeA - charCodeB; return reverse ? charCodeB - charCodeA : charCodeA - charCodeB;
} }
} }
return reverse ? b.name.length - a.name.length : a.name.length - b.name.length; return reverse ? nameB.length - nameA.length : nameA.length - nameB.length;
} }
case SortNodeBy.MTIME: case SortNodeBy.MTIME:
case SortNodeBy.ATIME: case SortNodeBy.ATIME:

View File

@@ -8,7 +8,7 @@
<span class=" pointer self-start pr-2">$</span> <span class=" pointer self-start pr-2">$</span>
<p>{cmd}</p> <p>{cmd}</p>
</div> </div>
<div style="white-space: nowrap;" class=" relative"> <div style="white-space: pre;" class=" relative">
{#if typeof output === 'string'} {#if typeof output === 'string'}
{output} {output}
{:else if output instanceof Element} {:else if output instanceof Element}

View File

@@ -1,4 +1,4 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
@@ -11,7 +11,6 @@ const config = {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter. // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters. // See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter()
} }
}; };