dirvi-lib 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/domain/cursor.d.ts +17 -0
- package/dist/domain/cursor.d.ts.map +1 -0
- package/dist/domain/cursor.js +44 -0
- package/dist/domain/display-row.d.ts +9 -7
- package/dist/domain/display-row.d.ts.map +1 -1
- package/dist/domain/display-row.js +26 -24
- package/dist/domain/fold-node.d.ts +17 -0
- package/dist/domain/fold-node.d.ts.map +1 -0
- package/dist/domain/fold-node.js +81 -0
- package/dist/domain/fold.d.ts +10 -0
- package/dist/domain/fold.d.ts.map +1 -0
- package/dist/domain/fold.js +24 -0
- package/dist/domain/navigation-entry.d.ts +23 -0
- package/dist/domain/navigation-entry.d.ts.map +1 -0
- package/dist/domain/navigation-entry.js +52 -0
- package/dist/domain/navigation-node.d.ts +43 -0
- package/dist/domain/navigation-node.d.ts.map +1 -0
- package/dist/domain/navigation-node.js +198 -0
- package/dist/domain/state.d.ts +12 -0
- package/dist/domain/state.d.ts.map +1 -0
- package/dist/domain/state.js +12 -0
- package/dist/domain/unix-entry.d.ts +10 -0
- package/dist/domain/unix-entry.d.ts.map +1 -1
- package/dist/domain/unix-entry.js +81 -0
- package/dist/domain/view.d.ts +6 -8
- package/dist/domain/view.d.ts.map +1 -1
- package/dist/domain/view.js +12 -6
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { UnixEntryName, UnixEntryPath } from './unix-entry.js';
|
|
2
|
+
import { DisplayRow } from './display-row.js';
|
|
3
|
+
export type Cursor = {
|
|
4
|
+
kind: 'entry';
|
|
5
|
+
parentPath: UnixEntryPath;
|
|
6
|
+
entryName: UnixEntryName;
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'fold';
|
|
9
|
+
parentPath: UnixEntryPath;
|
|
10
|
+
};
|
|
11
|
+
export declare const Cursor: {
|
|
12
|
+
equal(left: Cursor, right: Cursor): boolean;
|
|
13
|
+
matchesDisplayRow(cursor: Cursor, row: DisplayRow): boolean;
|
|
14
|
+
fromDisplayRow(row: DisplayRow): Cursor;
|
|
15
|
+
getPath(cursor: Cursor): UnixEntryPath | undefined;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/domain/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,MAAM,MAAM,GACd;IACE,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,aAAa,CAAC;IAC1B,SAAS,EAAE,aAAa,CAAC;CAC1B,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,aAAa,CAAC;CAC3B,CAAC;AAEN,eAAO,MAAM,MAAM;gBACL,MAAM,SAAS,MAAM,GAAG,OAAO;8BAgBjB,MAAM,OAAO,UAAU,GAAG,OAAO;wBAevC,UAAU,GAAG,MAAM;oBAevB,MAAM,GAAG,aAAa,GAAG,SAAS;CAOnD,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { UnixEntryPath } from './unix-entry.js';
|
|
2
|
+
export const Cursor = {
|
|
3
|
+
equal(left, right) {
|
|
4
|
+
if (left.kind !== right.kind) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
if (!UnixEntryPath.equal(left.parentPath, right.parentPath)) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
if (left.kind === 'entry' && right.kind === 'entry') {
|
|
11
|
+
return left.entryName === right.entryName;
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
},
|
|
15
|
+
matchesDisplayRow(cursor, row) {
|
|
16
|
+
if (cursor.kind === 'entry' && row.kind === 'entry') {
|
|
17
|
+
return (UnixEntryPath.equal(cursor.parentPath, row.parentPath) &&
|
|
18
|
+
cursor.entryName === row.entry.name);
|
|
19
|
+
}
|
|
20
|
+
if (cursor.kind === 'fold' && row.kind === 'fold') {
|
|
21
|
+
return UnixEntryPath.equal(cursor.parentPath, row.parentPath);
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
},
|
|
25
|
+
fromDisplayRow(row) {
|
|
26
|
+
if (row.kind === 'entry') {
|
|
27
|
+
return {
|
|
28
|
+
kind: 'entry',
|
|
29
|
+
parentPath: row.parentPath,
|
|
30
|
+
entryName: row.entry.name,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
kind: 'fold',
|
|
35
|
+
parentPath: row.parentPath,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
getPath(cursor) {
|
|
39
|
+
if (cursor.kind === 'fold') {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
return [...cursor.parentPath, cursor.entryName];
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { UnixEntry, UnixEntryName, UnixEntryPath } from './unix-entry.js';
|
|
2
2
|
import type { UnixPath } from './unix-path.js';
|
|
3
|
-
export type EntryPath = UnixEntryName[];
|
|
4
|
-
export declare function pathsEqual(left: EntryPath, right: EntryPath): boolean;
|
|
5
3
|
export type DisplayEntry = {
|
|
6
4
|
kind: 'file';
|
|
7
5
|
name: UnixEntryName;
|
|
@@ -13,15 +11,19 @@ export type DisplayEntry = {
|
|
|
13
11
|
kind: 'directory';
|
|
14
12
|
name: UnixEntryName;
|
|
15
13
|
};
|
|
16
|
-
export declare
|
|
14
|
+
export declare const DisplayEntry: {
|
|
15
|
+
fromUnixEntry(entry: UnixEntry): DisplayEntry;
|
|
16
|
+
};
|
|
17
17
|
export type DisplayRow = {
|
|
18
18
|
kind: 'entry';
|
|
19
|
-
parentPath:
|
|
19
|
+
parentPath: UnixEntryPath;
|
|
20
20
|
entry: DisplayEntry;
|
|
21
21
|
} | {
|
|
22
22
|
kind: 'fold';
|
|
23
|
-
parentPath:
|
|
23
|
+
parentPath: UnixEntryPath;
|
|
24
24
|
entryNames: UnixEntryName[];
|
|
25
25
|
};
|
|
26
|
-
export declare
|
|
26
|
+
export declare const DisplayRow: {
|
|
27
|
+
equal(firstRow: DisplayRow, secondRow: DisplayRow): boolean;
|
|
28
|
+
};
|
|
27
29
|
//# sourceMappingURL=display-row.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"display-row.d.ts","sourceRoot":"","sources":["../../src/domain/display-row.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"display-row.d.ts","sourceRoot":"","sources":["../../src/domain/display-row.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,MAAM,YAAY,GACpB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;CACrB,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,QAAQ,CAAC;CAClB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;CACrB,CAAC;AAEN,eAAO,MAAM,YAAY;yBACF,SAAS,GAAG,YAAY;CAU9C,CAAA;AAED,MAAM,MAAM,UAAU,GAClB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,aAAa,CAAC;IAC1B,KAAK,EAAE,YAAY,CAAC;CACrB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,aAAa,CAAC;IAC1B,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B,CAAC;AAEN,eAAO,MAAM,UAAU;oBACL,UAAU,aAAa,UAAU,GAAG,OAAO;CAqB5D,CAAC"}
|
|
@@ -1,27 +1,29 @@
|
|
|
1
|
+
import { UnixEntryPath } from './unix-entry.js';
|
|
1
2
|
import { entryNamesEqual } from './unix-entry.js';
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
export const DisplayEntry = {
|
|
4
|
+
fromUnixEntry(entry) {
|
|
5
|
+
if (entry.kind === 'directory') {
|
|
6
|
+
return {
|
|
7
|
+
kind: 'directory',
|
|
8
|
+
name: entry.name,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return entry;
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
};
|
|
14
|
+
export const DisplayRow = {
|
|
15
|
+
equal(firstRow, secondRow) {
|
|
16
|
+
if (firstRow.kind !== secondRow.kind) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (firstRow.kind === 'fold' && secondRow.kind === 'fold') {
|
|
20
|
+
return (UnixEntryPath.equal(firstRow.parentPath, secondRow.parentPath) &&
|
|
21
|
+
entryNamesEqual(firstRow.entryNames, secondRow.entryNames));
|
|
22
|
+
}
|
|
23
|
+
if (firstRow.kind === 'entry' && secondRow.kind === 'entry') {
|
|
24
|
+
return (UnixEntryPath.equal(firstRow.parentPath, secondRow.parentPath) &&
|
|
25
|
+
firstRow.entry.name === secondRow.entry.name);
|
|
26
|
+
}
|
|
16
27
|
return false;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return (pathsEqual(firstRow.parentPath, secondRow.parentPath) &&
|
|
20
|
-
entryNamesEqual(firstRow.entryNames, secondRow.entryNames));
|
|
21
|
-
}
|
|
22
|
-
if (firstRow.kind === 'entry' && secondRow.kind === 'entry') {
|
|
23
|
-
return (pathsEqual(firstRow.parentPath, secondRow.parentPath) &&
|
|
24
|
-
firstRow.entry.name === secondRow.entry.name);
|
|
25
|
-
}
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { UnixEntry, UnixEntryName, UnixEntryPath } from './unix-entry.js';
|
|
2
|
+
export type FoldNode = {
|
|
3
|
+
children: Record<UnixEntryName, FoldNode>;
|
|
4
|
+
folds: UnixEntryName[];
|
|
5
|
+
};
|
|
6
|
+
export declare const FoldNode: {
|
|
7
|
+
getAtPath(rootNode: FoldNode, path: UnixEntryPath): FoldNode | undefined;
|
|
8
|
+
getIfEntryFolded(node: FoldNode | undefined, entry: UnixEntry): boolean;
|
|
9
|
+
modifyAtPath(rootNode: FoldNode, path: UnixEntryName[], modifier: (targetNode: FoldNode) => FoldNode): FoldNode;
|
|
10
|
+
addFoldedEntry(node: FoldNode, entry: UnixEntry): FoldNode;
|
|
11
|
+
addFoldedEntryAtPath(rootNode: FoldNode, path: UnixEntryName[], entry: UnixEntry): FoldNode;
|
|
12
|
+
createEmpty(): FoldNode;
|
|
13
|
+
setFoldedEntries(node: FoldNode, entries: UnixEntry[]): FoldNode;
|
|
14
|
+
removeFoldedEntry(node: FoldNode, entry: UnixEntry): FoldNode;
|
|
15
|
+
clearFoldedEntries(node: FoldNode): FoldNode;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=fold-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold-node.d.ts","sourceRoot":"","sources":["../../src/domain/fold-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE1E,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAC1C,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,QAAQ;wBAEC,QAAQ,QAAQ,aAAa,GAAG,QAAQ,GAAG,SAAS;2BAgBjD,QAAQ,GAAG,SAAS,SAAS,SAAS,GAAG,OAAO;2BAM3D,QAAQ,QACZ,aAAa,EAAE,YACX,CAAC,UAAU,EAAE,QAAQ,KAAK,QAAQ,GAC3C,QAAQ;yBAwBU,QAAQ,SAAS,SAAS,GAAG,QAAQ;mCAU9C,QAAQ,QACZ,aAAa,EAAE,SACd,SAAS,GACf,QAAQ;mBAMI,QAAQ;2BAOA,QAAQ,WAAW,SAAS,EAAE,GAAG,QAAQ;4BAOxC,QAAQ,SAAS,SAAS,GAAG,QAAQ;6BAWpC,QAAQ,GAAG,QAAQ;CAO7C,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export const FoldNode = {
|
|
2
|
+
// Query-Like
|
|
3
|
+
getAtPath(rootNode, path) {
|
|
4
|
+
const [currentName, ...remainingPath] = path;
|
|
5
|
+
if (currentName === undefined) {
|
|
6
|
+
return rootNode;
|
|
7
|
+
}
|
|
8
|
+
const childNode = rootNode.children[currentName];
|
|
9
|
+
if (childNode === undefined) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
return FoldNode.getAtPath(childNode, remainingPath);
|
|
13
|
+
},
|
|
14
|
+
getIfEntryFolded(node, entry) {
|
|
15
|
+
return node !== undefined && hasFoldedEntryNamed(node, entry.name);
|
|
16
|
+
},
|
|
17
|
+
// Command/Modifer-Like
|
|
18
|
+
modifyAtPath(rootNode, path, modifier) {
|
|
19
|
+
const [currentName, ...remainingPath] = path;
|
|
20
|
+
// Base case
|
|
21
|
+
if (currentName === undefined) {
|
|
22
|
+
return modifier(rootNode);
|
|
23
|
+
}
|
|
24
|
+
// Create childNode to create path in tree to the needed node
|
|
25
|
+
const childNode = rootNode.children[currentName] ?? FoldNode.createEmpty();
|
|
26
|
+
return {
|
|
27
|
+
...rootNode,
|
|
28
|
+
children: {
|
|
29
|
+
...rootNode.children,
|
|
30
|
+
[currentName]: FoldNode.modifyAtPath(childNode, remainingPath, modifier),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
addFoldedEntry(node, entry) {
|
|
35
|
+
// Avoid duplicates
|
|
36
|
+
if (hasFoldedEntryNamed(node, entry.name)) {
|
|
37
|
+
return node;
|
|
38
|
+
}
|
|
39
|
+
return setFoldedEntriesNamed(node, [...node.folds, entry.name]);
|
|
40
|
+
},
|
|
41
|
+
addFoldedEntryAtPath(rootNode, path, entry) {
|
|
42
|
+
return FoldNode.modifyAtPath(rootNode, path, (node) => FoldNode.addFoldedEntry(node, entry));
|
|
43
|
+
},
|
|
44
|
+
createEmpty() {
|
|
45
|
+
return {
|
|
46
|
+
children: Object.create(null),
|
|
47
|
+
folds: [],
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
setFoldedEntries(node, entries) {
|
|
51
|
+
return setFoldedEntriesNamed(node, entries.map((entry) => entry.name));
|
|
52
|
+
},
|
|
53
|
+
removeFoldedEntry(node, entry) {
|
|
54
|
+
if (!hasFoldedEntryNamed(node, entry.name)) {
|
|
55
|
+
return node;
|
|
56
|
+
}
|
|
57
|
+
return setFoldedEntriesNamed(node, node.folds.filter((entryName) => entryName !== entry.name));
|
|
58
|
+
},
|
|
59
|
+
clearFoldedEntries(node) {
|
|
60
|
+
if (node.folds.length === 0) {
|
|
61
|
+
return node;
|
|
62
|
+
}
|
|
63
|
+
return setFoldedEntriesNamed(node, []);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
// PRIVATE HELPERS
|
|
67
|
+
// Queries
|
|
68
|
+
function hasFoldedEntryNamed(node, entryName) {
|
|
69
|
+
return node.folds.includes(entryName);
|
|
70
|
+
}
|
|
71
|
+
function uniqueEntryNames(entryNames) {
|
|
72
|
+
return [...new Set(entryNames)];
|
|
73
|
+
}
|
|
74
|
+
// Adding
|
|
75
|
+
function setFoldedEntriesNamed(node, entryNames) {
|
|
76
|
+
const uniqueNames = uniqueEntryNames(entryNames);
|
|
77
|
+
return {
|
|
78
|
+
...node,
|
|
79
|
+
folds: uniqueNames,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { UnixEntryName } from './unix-entry.js';
|
|
2
|
+
export type FoldNode = {
|
|
3
|
+
children: Record<UnixEntryName, FoldNode>;
|
|
4
|
+
folds: UnixEntryName[];
|
|
5
|
+
};
|
|
6
|
+
export declare const FoldNode: {
|
|
7
|
+
createEmpty(): FoldNode;
|
|
8
|
+
updateAtPath(rootNode: FoldNode, path: UnixEntryName[], update: (targetNode: FoldNode) => FoldNode): FoldNode;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=fold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../../src/domain/fold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAC1C,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,QAAQ;mBACJ,QAAQ;2BAQX,QAAQ,QACZ,aAAa,EAAE,UACb,CAAC,UAAU,EAAE,QAAQ,KAAK,QAAQ,GACzC,QAAQ;CAmBZ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const FoldNode = {
|
|
2
|
+
createEmpty() {
|
|
3
|
+
return {
|
|
4
|
+
children: Object.create(null),
|
|
5
|
+
folds: [],
|
|
6
|
+
};
|
|
7
|
+
},
|
|
8
|
+
updateAtPath(rootNode, path, update) {
|
|
9
|
+
const [currentName, ...remainingPath] = path;
|
|
10
|
+
// Base case
|
|
11
|
+
if (currentName === undefined) {
|
|
12
|
+
return update(rootNode);
|
|
13
|
+
}
|
|
14
|
+
// Create childNode to create path in tree to the needed node
|
|
15
|
+
const childNode = rootNode.children[currentName] ?? FoldNode.createEmpty();
|
|
16
|
+
return {
|
|
17
|
+
...rootNode,
|
|
18
|
+
children: {
|
|
19
|
+
...rootNode.children,
|
|
20
|
+
[currentName]: FoldNode.updateAtPath(childNode, remainingPath, update),
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { UnixEntryName } from './unix-entry.js';
|
|
2
|
+
import { UnixPath } from './unix-path.js';
|
|
3
|
+
import { State } from './state.js';
|
|
4
|
+
export type NavigationEntry = {
|
|
5
|
+
kind: 'file';
|
|
6
|
+
name: UnixEntryName;
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'symlink';
|
|
9
|
+
name: UnixEntryName;
|
|
10
|
+
target: UnixPath;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'directory';
|
|
13
|
+
name: UnixEntryName;
|
|
14
|
+
node?: NavigationNode;
|
|
15
|
+
};
|
|
16
|
+
export type NavigationNode = {
|
|
17
|
+
entries: NavigationEntry[];
|
|
18
|
+
foldedEntries: NavigationEntry[];
|
|
19
|
+
};
|
|
20
|
+
export declare const NavigationNode: {
|
|
21
|
+
derive(state: State): NavigationNode;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=navigation-entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-entry.d.ts","sourceRoot":"","sources":["../../src/domain/navigation-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,MAAM,MAAM,eAAe,GACvB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;CACrB,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,QAAQ,CAAC;CAClB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEN,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,aAAa,EAAE,eAAe,EAAE,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,cAAc;kBACX,KAAK,GAAG,cAAc;CAGrC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const NavigationNode = {
|
|
2
|
+
derive(state) {
|
|
3
|
+
return deriveNode(state.buffer.entries, state.folds);
|
|
4
|
+
},
|
|
5
|
+
};
|
|
6
|
+
function deriveNode(entries, foldNode) {
|
|
7
|
+
if (entries === undefined) {
|
|
8
|
+
return {
|
|
9
|
+
entries: [],
|
|
10
|
+
foldedEntries: [],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const foldedNames = new Set(foldNode?.folds ?? []);
|
|
14
|
+
const visibleEntries = [];
|
|
15
|
+
const foldedEntries = [];
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const navigationEntry = deriveEntry(entry, foldNode?.children[entry.name]);
|
|
18
|
+
if (foldedNames.has(entry.name)) {
|
|
19
|
+
foldedEntries.push(navigationEntry);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
visibleEntries.push(navigationEntry);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
entries: visibleEntries,
|
|
27
|
+
foldedEntries,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function deriveEntry(entry, foldNode) {
|
|
31
|
+
switch (entry.kind) {
|
|
32
|
+
case 'file':
|
|
33
|
+
return {
|
|
34
|
+
kind: 'file',
|
|
35
|
+
name: entry.name,
|
|
36
|
+
};
|
|
37
|
+
case 'symlink':
|
|
38
|
+
return {
|
|
39
|
+
kind: 'symlink',
|
|
40
|
+
name: entry.name,
|
|
41
|
+
target: entry.target,
|
|
42
|
+
};
|
|
43
|
+
case 'directory':
|
|
44
|
+
return {
|
|
45
|
+
kind: 'directory',
|
|
46
|
+
name: entry.name,
|
|
47
|
+
node: entry.entries === undefined
|
|
48
|
+
? undefined
|
|
49
|
+
: deriveNode(entry.entries, foldNode),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { UnixEntry, UnixEntryName, UnixEntryPath } from './unix-entry.js';
|
|
2
|
+
import { UnixPath } from './unix-path.js';
|
|
3
|
+
import { FoldNode } from './fold-node.js';
|
|
4
|
+
import { Cursor } from './cursor.js';
|
|
5
|
+
export type NavigationEntry = {
|
|
6
|
+
kind: 'file';
|
|
7
|
+
name: UnixEntryName;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'symlink';
|
|
10
|
+
name: UnixEntryName;
|
|
11
|
+
target: UnixPath;
|
|
12
|
+
} | {
|
|
13
|
+
/**
|
|
14
|
+
* Undefined node means the directory has not been loaded.
|
|
15
|
+
*/
|
|
16
|
+
kind: 'directory';
|
|
17
|
+
name: UnixEntryName;
|
|
18
|
+
node?: NavigationNode;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A directory as navigated: list of visible entries and folded entries.
|
|
22
|
+
*/
|
|
23
|
+
export type NavigationNode = {
|
|
24
|
+
/**
|
|
25
|
+
* Currently visible entries.
|
|
26
|
+
*/
|
|
27
|
+
entries: NavigationEntry[];
|
|
28
|
+
/**
|
|
29
|
+
* Currently loaded entries hidden by this directory's fold.
|
|
30
|
+
*/
|
|
31
|
+
foldedEntries: NavigationEntry[];
|
|
32
|
+
};
|
|
33
|
+
export declare const NavigationNode: {
|
|
34
|
+
from(entries: UnixEntry[] | undefined, foldNode: FoldNode | undefined): NavigationNode;
|
|
35
|
+
getNodeAtPath(navigation: NavigationNode, path: UnixEntryPath): NavigationNode | undefined;
|
|
36
|
+
getEntryAtPath(navigation: NavigationNode, path: UnixEntryPath): NavigationEntry | undefined;
|
|
37
|
+
nextCursor(rootNode: NavigationNode, cursor: Cursor): Cursor | undefined;
|
|
38
|
+
previousCursor(rootNode: NavigationNode, cursor: Cursor): Cursor | undefined;
|
|
39
|
+
cursorAfterFold(rootNode: NavigationNode, cursor: Cursor): Cursor | undefined;
|
|
40
|
+
parentCursor(navigation: NavigationNode, cursor: Cursor): Cursor | undefined;
|
|
41
|
+
visibleFilesPaths(navigation: NavigationNode, parentPath?: UnixEntryPath): UnixEntryPath[];
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=navigation-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-node.d.ts","sourceRoot":"","sources":["../../src/domain/navigation-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,MAAM,eAAe,GACvB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;CACrB,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,QAAQ,CAAC;CAClB,GACD;IACE;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAEN;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;OAEG;IACH,OAAO,EAAE,eAAe,EAAE,CAAC;IAE3B;;OAEG;IACH,aAAa,EAAE,eAAe,EAAE,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,cAAc;kBAEd,SAAS,EAAE,GAAG,SAAS,YACtB,QAAQ,GAAG,SAAS,GAC7B,cAAc;8BA4DH,cAAc,QACpB,aAAa,GAClB,cAAc,GAAG,SAAS;+BAyBf,cAAc,QACpB,aAAa,GAClB,eAAe,GAAG,SAAS;yBA0BT,cAAc,UAAU,MAAM,GAAG,MAAM,GAAG,SAAS;6BAc/C,cAAc,UAAU,MAAM,GAAG,MAAM,GAAG,SAAS;8BAehE,cAAc,UAChB,MAAM,GACb,MAAM,GAAG,SAAS;6BAsCI,cAAc,UAAU,MAAM,GAAG,MAAM,GAAG,SAAS;kCA6B9D,cAAc,eACd,aAAa,GACxB,aAAa,EAAE;CA2BnB,CAAC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { UnixEntryPath } from './unix-entry.js';
|
|
2
|
+
import { Cursor } from './cursor.js';
|
|
3
|
+
export const NavigationNode = {
|
|
4
|
+
from(entries, foldNode) {
|
|
5
|
+
if (entries === undefined) {
|
|
6
|
+
return {
|
|
7
|
+
entries: [],
|
|
8
|
+
foldedEntries: [],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const foldedNames = new Set(foldNode?.folds ?? []);
|
|
12
|
+
const visibleEntries = [];
|
|
13
|
+
const foldedEntries = [];
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
let navigationEntry;
|
|
16
|
+
switch (entry.kind) {
|
|
17
|
+
case 'file':
|
|
18
|
+
navigationEntry = {
|
|
19
|
+
kind: 'file',
|
|
20
|
+
name: entry.name,
|
|
21
|
+
};
|
|
22
|
+
break;
|
|
23
|
+
case 'symlink':
|
|
24
|
+
navigationEntry = {
|
|
25
|
+
kind: 'symlink',
|
|
26
|
+
name: entry.name,
|
|
27
|
+
target: entry.target,
|
|
28
|
+
};
|
|
29
|
+
break;
|
|
30
|
+
case 'directory': {
|
|
31
|
+
const childFoldNode = foldNode?.children[entry.name];
|
|
32
|
+
navigationEntry = {
|
|
33
|
+
kind: 'directory',
|
|
34
|
+
name: entry.name,
|
|
35
|
+
node: entry.entries === undefined
|
|
36
|
+
? undefined
|
|
37
|
+
: NavigationNode.from(entry.entries, childFoldNode),
|
|
38
|
+
};
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (foldedNames.has(entry.name)) {
|
|
43
|
+
foldedEntries.push(navigationEntry);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
visibleEntries.push(navigationEntry);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
entries: visibleEntries,
|
|
51
|
+
foldedEntries,
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
getNodeAtPath(navigation, path) {
|
|
55
|
+
const [currentName, ...remainingPath] = path;
|
|
56
|
+
// An empty path identifies the current node.
|
|
57
|
+
if (currentName === undefined) {
|
|
58
|
+
return navigation;
|
|
59
|
+
}
|
|
60
|
+
const entry = [...navigation.entries, ...navigation.foldedEntries].find((candidate) => candidate.name === currentName);
|
|
61
|
+
if (entry === undefined || entry.kind !== 'directory') {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
// The directory has not been loaded/opened.
|
|
65
|
+
if (entry.node === undefined) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
return NavigationNode.getNodeAtPath(entry.node, remainingPath);
|
|
69
|
+
},
|
|
70
|
+
getEntryAtPath(navigation, path) {
|
|
71
|
+
const [currentName, ...remainingPath] = path;
|
|
72
|
+
if (currentName === undefined) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
const entry = [...navigation.entries, ...navigation.foldedEntries].find((candidate) => candidate.name === currentName);
|
|
76
|
+
if (entry === undefined) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
if (remainingPath.length === 0) {
|
|
80
|
+
return entry;
|
|
81
|
+
}
|
|
82
|
+
if (entry.kind !== 'directory' || entry.node === undefined) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return NavigationNode.getEntryAtPath(entry.node, remainingPath);
|
|
86
|
+
},
|
|
87
|
+
nextCursor(rootNode, cursor) {
|
|
88
|
+
const cursors = cursorsInNode(rootNode, []);
|
|
89
|
+
const currentIndex = cursors.findIndex((candidate) => Cursor.equal(candidate, cursor));
|
|
90
|
+
if (currentIndex === -1 || currentIndex === cursors.length - 1) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
return cursors[currentIndex + 1];
|
|
94
|
+
},
|
|
95
|
+
previousCursor(rootNode, cursor) {
|
|
96
|
+
const cursors = cursorsInNode(rootNode, []);
|
|
97
|
+
const currentIndex = cursors.findIndex((candidate) => Cursor.equal(candidate, cursor));
|
|
98
|
+
if (currentIndex <= 0) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
return cursors[currentIndex - 1];
|
|
102
|
+
},
|
|
103
|
+
cursorAfterFold(rootNode, cursor) {
|
|
104
|
+
if (cursor.kind === 'fold') {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const cursors = cursorsInNode(rootNode, []);
|
|
108
|
+
const currentIndex = cursors.findIndex((candidate) => Cursor.equal(candidate, cursor));
|
|
109
|
+
if (currentIndex === -1) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
const foldedPath = [...cursor.parentPath, cursor.entryName];
|
|
113
|
+
for (let index = currentIndex + 1; index < cursors.length; index += 1) {
|
|
114
|
+
const candidate = cursors[index];
|
|
115
|
+
if (candidate === undefined) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (cursorBelongsToSubtree(candidate, foldedPath)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
return candidate;
|
|
122
|
+
}
|
|
123
|
+
// The fold row will be created at the end of this directory.
|
|
124
|
+
return {
|
|
125
|
+
kind: 'fold',
|
|
126
|
+
parentPath: cursor.parentPath,
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
parentCursor(navigation, cursor) {
|
|
130
|
+
const parentPath = cursor.parentPath;
|
|
131
|
+
// The cursor is already in the root directory.
|
|
132
|
+
if (parentPath.length === 0) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
const entryName = parentPath.at(-1);
|
|
136
|
+
if (entryName === undefined) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
const containingPath = parentPath.slice(0, -1);
|
|
140
|
+
const entry = NavigationNode.getEntryAtPath(navigation, parentPath);
|
|
141
|
+
if (entry === undefined || entry.kind !== 'directory') {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
kind: 'entry',
|
|
146
|
+
parentPath: containingPath,
|
|
147
|
+
entryName,
|
|
148
|
+
};
|
|
149
|
+
},
|
|
150
|
+
visibleFilesPaths(navigation, parentPath = []) {
|
|
151
|
+
const paths = [];
|
|
152
|
+
for (const entry of navigation.entries) {
|
|
153
|
+
const entryPath = [...parentPath, entry.name];
|
|
154
|
+
switch (entry.kind) {
|
|
155
|
+
case 'file':
|
|
156
|
+
paths.push(entryPath);
|
|
157
|
+
break;
|
|
158
|
+
case 'symlink':
|
|
159
|
+
// Do not recurse through symlinks.
|
|
160
|
+
break;
|
|
161
|
+
case 'directory':
|
|
162
|
+
if (entry.node !== undefined) {
|
|
163
|
+
paths.push(...NavigationNode.visibleFilesPaths(entry.node, entryPath));
|
|
164
|
+
}
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return paths;
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
function cursorsInNode(node, parentPath) {
|
|
172
|
+
const cursors = [];
|
|
173
|
+
for (const entry of node.entries) {
|
|
174
|
+
cursors.push({
|
|
175
|
+
kind: 'entry',
|
|
176
|
+
parentPath,
|
|
177
|
+
entryName: entry.name,
|
|
178
|
+
});
|
|
179
|
+
if (entry.kind !== 'directory' || entry.node === undefined) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
cursors.push(...cursorsInNode(entry.node, [...parentPath, entry.name]));
|
|
183
|
+
}
|
|
184
|
+
if (node.foldedEntries.length > 0) {
|
|
185
|
+
cursors.push({
|
|
186
|
+
kind: 'fold',
|
|
187
|
+
parentPath,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return cursors;
|
|
191
|
+
}
|
|
192
|
+
function cursorBelongsToSubtree(cursor, entryPath) {
|
|
193
|
+
if (cursor.kind === 'fold') {
|
|
194
|
+
return UnixEntryPath.isStrictPathPrefix(entryPath, cursor.parentPath);
|
|
195
|
+
}
|
|
196
|
+
const cursorPath = [...cursor.parentPath, cursor.entryName];
|
|
197
|
+
return UnixEntryPath.isStrictPathPrefix(entryPath, cursorPath);
|
|
198
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { UnixEntry } from './unix-entry.js';
|
|
2
|
+
import type { FoldNode } from './fold-node.js';
|
|
3
|
+
import { Cursor } from './cursor.js';
|
|
4
|
+
export type State = {
|
|
5
|
+
buffer: UnixEntry[];
|
|
6
|
+
folds: FoldNode;
|
|
7
|
+
cursor: Cursor;
|
|
8
|
+
};
|
|
9
|
+
export declare const View: {
|
|
10
|
+
getEntryAtCursor(view: State): UnixEntry | undefined;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/domain/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,MAAM,KAAK,GAAG;IAClB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,IAAI;2BACQ,KAAK,GAAG,SAAS,GAAG,SAAS;CAUrD,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { UnixEntry } from './unix-entry.js';
|
|
2
|
+
import { Cursor } from './cursor.js';
|
|
3
|
+
export const View = {
|
|
4
|
+
getEntryAtCursor(view) {
|
|
5
|
+
const path = Cursor.getPath(view.cursor);
|
|
6
|
+
// Nothing on folds
|
|
7
|
+
if (path === undefined) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
return UnixEntry.getEntryAtPath(view.buffer, path);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -15,4 +15,14 @@ export type UnixEntry = {
|
|
|
15
15
|
name: UnixEntryName;
|
|
16
16
|
entries?: UnixEntry[];
|
|
17
17
|
};
|
|
18
|
+
export declare const UnixEntry: {
|
|
19
|
+
getEntryAtPath(entries: UnixEntry[], path: UnixEntryPath): UnixEntry | undefined;
|
|
20
|
+
getEntriesAtPath(entries: UnixEntry[], path: UnixEntryPath): UnixEntry[] | undefined;
|
|
21
|
+
setEntriesAtPath(entries: UnixEntry[], path: UnixEntryPath, newEntries: UnixEntry[] | undefined): UnixEntry[];
|
|
22
|
+
};
|
|
23
|
+
export type UnixEntryPath = UnixEntryName[];
|
|
24
|
+
export declare const UnixEntryPath: {
|
|
25
|
+
equal(left: UnixEntryPath, right: UnixEntryPath): boolean;
|
|
26
|
+
isStrictPathPrefix(prefix: UnixEntryPath, path: UnixEntryPath): boolean;
|
|
27
|
+
};
|
|
18
28
|
//# sourceMappingURL=unix-entry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unix-entry.d.ts","sourceRoot":"","sources":["../../src/domain/unix-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"unix-entry.d.ts","sourceRoot":"","sources":["../../src/domain/unix-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI1C,eAAO,MAAM,mBAAmB,aAQ5B,CAAC;AAEL,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEjE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,EAAE,EACrB,KAAK,EAAE,aAAa,EAAE,GACrB,OAAO,CAKT;AAED,MAAM,MAAM,SAAS,GACjB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;CACrB,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,QAAQ,CAAC;CAClB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;IAEpB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;CACvB,CAAC;AAEN,eAAO,MAAM,SAAS;4BAGT,SAAS,EAAE,QACd,aAAa,GAClB,SAAS,GAAG,SAAS;8BA6Bb,SAAS,EAAE,QACd,aAAa,GAClB,SAAS,EAAE,GAAG,SAAS;8BAgBf,SAAS,EAAE,QACd,aAAa,cACP,SAAS,EAAE,GAAG,SAAS,GAClC,SAAS,EAAE;CAyDf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,aAAa,EAAE,CAAC;AAE5C,eAAO,MAAM,aAAa;gBACZ,aAAa,SAAS,aAAa,GAAG,OAAO;+BAK/C,aAAa,QACf,aAAa,GAClB,OAAO;CAOX,CAAA"}
|
|
@@ -13,3 +13,84 @@ export function entryNamesEqual(left, right) {
|
|
|
13
13
|
return (left.length === right.length &&
|
|
14
14
|
left.every((name, index) => name === right[index]));
|
|
15
15
|
}
|
|
16
|
+
export const UnixEntry = {
|
|
17
|
+
// Query-Like
|
|
18
|
+
getEntryAtPath(entries, path) {
|
|
19
|
+
if (path.length === 0) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
let entry;
|
|
23
|
+
for (const [index, name] of path.entries()) {
|
|
24
|
+
entry = entries.find((candidate) => candidate.name === name);
|
|
25
|
+
if (entry === undefined) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
if (index === path.length - 1) {
|
|
29
|
+
return entry;
|
|
30
|
+
}
|
|
31
|
+
if (entry.kind !== 'directory' || entry.entries === undefined) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
entries = entry.entries;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
},
|
|
38
|
+
getEntriesAtPath(entries, path) {
|
|
39
|
+
if (path.length === 0) {
|
|
40
|
+
return entries;
|
|
41
|
+
}
|
|
42
|
+
const entry = UnixEntry.getEntryAtPath(entries, path);
|
|
43
|
+
if (entry?.kind !== 'directory') {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
return entry.entries;
|
|
47
|
+
},
|
|
48
|
+
// Command/Modifer-Like
|
|
49
|
+
setEntriesAtPath(entries, path, newEntries) {
|
|
50
|
+
const [currentName, ...remainingPath] = path;
|
|
51
|
+
if (currentName === undefined) {
|
|
52
|
+
throw new Error('Cannot update directory entries with an empty path');
|
|
53
|
+
}
|
|
54
|
+
let found = false;
|
|
55
|
+
const updatedEntries = entries.map((entry) => {
|
|
56
|
+
if (entry.name !== currentName) {
|
|
57
|
+
return entry;
|
|
58
|
+
}
|
|
59
|
+
found = true;
|
|
60
|
+
if (remainingPath.length === 0) {
|
|
61
|
+
if (entry.kind !== 'directory') {
|
|
62
|
+
throw new Error(`Cannot update entries for non-directory entry "${entry.name}"`);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
...entry,
|
|
66
|
+
entries: newEntries,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (entry.kind !== 'directory') {
|
|
70
|
+
throw new Error(`Cannot descend through non-directory entry "${entry.name}"`);
|
|
71
|
+
}
|
|
72
|
+
if (entry.entries === undefined) {
|
|
73
|
+
throw new Error(`Cannot descend into unexpanded directory "${entry.name}"`);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
...entry,
|
|
77
|
+
entries: UnixEntry.setEntriesAtPath(entry.entries, remainingPath, newEntries),
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
if (!found) {
|
|
81
|
+
throw new Error(`Directory path does not contain entry "${currentName}"`);
|
|
82
|
+
}
|
|
83
|
+
return updatedEntries;
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
export const UnixEntryPath = {
|
|
87
|
+
equal(left, right) {
|
|
88
|
+
return entryNamesEqual(left, right);
|
|
89
|
+
},
|
|
90
|
+
isStrictPathPrefix(prefix, path) {
|
|
91
|
+
if (path.length <= prefix.length) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return prefix.every((name, index) => path[index] === name);
|
|
95
|
+
}
|
|
96
|
+
};
|
package/dist/domain/view.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { UnixEntry
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
children: Record<UnixEntryName, FoldNode>;
|
|
5
|
-
folds: UnixEntryName[];
|
|
6
|
-
};
|
|
7
|
-
export declare function createEmptyFoldNode(): FoldNode;
|
|
8
|
-
export type Cursor = DisplayRow;
|
|
1
|
+
import { UnixEntry } from './unix-entry.js';
|
|
2
|
+
import type { FoldNode } from './fold-node.js';
|
|
3
|
+
import { Cursor } from './cursor.js';
|
|
9
4
|
export type DirectoryBuffer = {
|
|
10
5
|
entries: UnixEntry[];
|
|
11
6
|
};
|
|
@@ -14,4 +9,7 @@ export type View = {
|
|
|
14
9
|
folds: FoldNode;
|
|
15
10
|
cursor: Cursor;
|
|
16
11
|
};
|
|
12
|
+
export declare const View: {
|
|
13
|
+
getEntryAtCursor(view: View): UnixEntry | undefined;
|
|
14
|
+
};
|
|
17
15
|
//# sourceMappingURL=view.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/domain/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/domain/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,IAAI;2BACQ,IAAI,GAAG,SAAS,GAAG,SAAS;CAUpD,CAAA"}
|
package/dist/domain/view.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { UnixEntry } from './unix-entry.js';
|
|
2
|
+
import { Cursor } from './cursor.js';
|
|
3
|
+
export const View = {
|
|
4
|
+
getEntryAtCursor(view) {
|
|
5
|
+
const path = Cursor.getPath(view.cursor);
|
|
6
|
+
// Nothing on folds
|
|
7
|
+
if (path === undefined) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
return UnixEntry.getEntryAtPath(view.buffer.entries, path);
|
|
11
|
+
}
|
|
12
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
export * from './domain/cursor.js';
|
|
1
2
|
export * from './domain/display-row.js';
|
|
3
|
+
export * from './domain/fold-node.js';
|
|
4
|
+
export * from './domain/navigation-node.js';
|
|
5
|
+
export * from './domain/state.js';
|
|
2
6
|
export * from './domain/unix-entry.js';
|
|
3
7
|
export * from './domain/unix-path.js';
|
|
4
|
-
export * from './domain/view.js';
|
|
5
8
|
export * from './infrastructure/get-cwd.js';
|
|
6
9
|
export * from './infrastructure/get-dir-lazy-entries.js';
|
|
7
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AAEtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0CAA0C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
export * from './domain/cursor.js';
|
|
1
2
|
export * from './domain/display-row.js';
|
|
3
|
+
export * from './domain/fold-node.js';
|
|
4
|
+
export * from './domain/navigation-node.js';
|
|
5
|
+
export * from './domain/state.js';
|
|
2
6
|
export * from './domain/unix-entry.js';
|
|
3
7
|
export * from './domain/unix-path.js';
|
|
4
|
-
export * from './domain/view.js';
|
|
5
8
|
export * from './infrastructure/get-cwd.js';
|
|
6
9
|
export * from './infrastructure/get-dir-lazy-entries.js';
|