dirvi-lib 0.3.0 → 0.5.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/posix-node.d.ts +29 -0
- package/dist/domain/posix-node.d.ts.map +1 -0
- package/dist/domain/posix-node.js +20 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/tree-surfer/cursor.d.ts +24 -0
- package/dist/tree-surfer/cursor.d.ts.map +1 -0
- package/dist/tree-surfer/cursor.js +65 -0
- package/dist/tree-surfer/fold-node/fold-node.impl.d.ts +5 -0
- package/dist/tree-surfer/fold-node/fold-node.impl.d.ts.map +1 -0
- package/dist/tree-surfer/fold-node/fold-node.impl.js +143 -0
- package/dist/tree-surfer/fold-node/fold-node.types.d.ts +70 -0
- package/dist/tree-surfer/fold-node/fold-node.types.d.ts.map +1 -0
- package/dist/tree-surfer/fold-node/fold-node.types.js +1 -0
- package/dist/tree-surfer/index.d.ts +9 -0
- package/dist/tree-surfer/index.d.ts.map +1 -0
- package/dist/tree-surfer/index.js +8 -0
- package/dist/tree-surfer/nav-node/nav-node.impl.d.ts +6 -0
- package/dist/tree-surfer/nav-node/nav-node.impl.d.ts.map +1 -0
- package/dist/tree-surfer/nav-node/nav-node.impl.js +191 -0
- package/dist/tree-surfer/nav-node/nav-node.types.d.ts +42 -0
- package/dist/tree-surfer/nav-node/nav-node.types.d.ts.map +1 -0
- package/dist/tree-surfer/nav-node/nav-node.types.js +3 -0
- package/dist/tree-surfer/state.d.ts +19 -0
- package/dist/tree-surfer/state.d.ts.map +1 -0
- package/dist/tree-surfer/state.js +109 -0
- package/dist/tree-surfer/tree-node/tree-node.arb.d.ts +31 -0
- package/dist/tree-surfer/tree-node/tree-node.arb.d.ts.map +1 -0
- package/dist/tree-surfer/tree-node/tree-node.arb.js +80 -0
- package/dist/tree-surfer/tree-node/tree-node.impl.d.ts +13 -0
- package/dist/tree-surfer/tree-node/tree-node.impl.d.ts.map +1 -0
- package/dist/tree-surfer/tree-node/tree-node.impl.js +87 -0
- package/dist/tree-surfer/tree-node/tree-node.test.d.ts +2 -0
- package/dist/tree-surfer/tree-node/tree-node.test.d.ts.map +1 -0
- package/dist/tree-surfer/tree-node/tree-node.test.js +117 -0
- package/dist/tree-surfer/tree-node/tree-node.types.d.ts +184 -0
- package/dist/tree-surfer/tree-node/tree-node.types.d.ts.map +1 -0
- package/dist/tree-surfer/tree-node/tree-node.types.js +12 -0
- package/dist/tree-surfer-ui/application/index.d.ts +3 -0
- package/dist/tree-surfer-ui/application/index.d.ts.map +1 -0
- package/dist/tree-surfer-ui/application/index.js +2 -0
- package/dist/tree-surfer-ui/application/intent-to-effect-no-state.test.d.ts +2 -0
- package/dist/tree-surfer-ui/application/intent-to-effect-no-state.test.d.ts.map +1 -0
- package/dist/tree-surfer-ui/application/intent-to-effect-no-state.test.js +192 -0
- package/dist/tree-surfer-ui/application/intent-to-effect.d.ts +6 -0
- package/dist/tree-surfer-ui/application/intent-to-effect.d.ts.map +1 -0
- package/dist/tree-surfer-ui/application/intent-to-effect.js +137 -0
- package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts +3 -0
- package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts.map +1 -0
- package/dist/tree-surfer-ui/application/user-input-to-intent.js +98 -0
- package/dist/tree-surfer-ui/application/user-input-to-intent.test.d.ts +2 -0
- package/dist/tree-surfer-ui/application/user-input-to-intent.test.d.ts.map +1 -0
- package/dist/tree-surfer-ui/application/user-input-to-intent.test.js +118 -0
- package/dist/tree-surfer-ui/domain/effect.d.ts +36 -0
- package/dist/tree-surfer-ui/domain/effect.d.ts.map +1 -0
- package/dist/tree-surfer-ui/domain/effect.js +1 -0
- package/dist/tree-surfer-ui/domain/index.d.ts +5 -0
- package/dist/tree-surfer-ui/domain/index.d.ts.map +1 -0
- package/dist/tree-surfer-ui/domain/index.js +4 -0
- package/dist/tree-surfer-ui/domain/input-state.d.ts +8 -0
- package/dist/tree-surfer-ui/domain/input-state.d.ts.map +1 -0
- package/dist/tree-surfer-ui/domain/input-state.js +1 -0
- package/dist/tree-surfer-ui/domain/intent.d.ts +25 -0
- package/dist/tree-surfer-ui/domain/intent.d.ts.map +1 -0
- package/dist/tree-surfer-ui/domain/intent.js +1 -0
- package/dist/tree-surfer-ui/domain/user-input.d.ts +19 -0
- package/dist/tree-surfer-ui/domain/user-input.d.ts.map +1 -0
- package/dist/tree-surfer-ui/domain/user-input.js +1 -0
- package/package.json +6 -3
- package/dist/domain/cursor.d.ts +0 -17
- package/dist/domain/cursor.d.ts.map +0 -1
- package/dist/domain/cursor.js +0 -44
- package/dist/domain/display-row.d.ts +0 -29
- package/dist/domain/display-row.d.ts.map +0 -1
- package/dist/domain/display-row.js +0 -29
- package/dist/domain/fold-node.d.ts +0 -17
- package/dist/domain/fold-node.d.ts.map +0 -1
- package/dist/domain/fold-node.js +0 -81
- package/dist/domain/fold.d.ts +0 -10
- package/dist/domain/fold.d.ts.map +0 -1
- package/dist/domain/fold.js +0 -24
- package/dist/domain/navigation-entry.d.ts +0 -23
- package/dist/domain/navigation-entry.d.ts.map +0 -1
- package/dist/domain/navigation-entry.js +0 -52
- package/dist/domain/navigation-node.d.ts +0 -43
- package/dist/domain/navigation-node.d.ts.map +0 -1
- package/dist/domain/navigation-node.js +0 -198
- package/dist/domain/state.d.ts +0 -12
- package/dist/domain/state.d.ts.map +0 -1
- package/dist/domain/state.js +0 -12
- package/dist/domain/unix-entry.d.ts +0 -28
- package/dist/domain/unix-entry.d.ts.map +0 -1
- package/dist/domain/unix-entry.js +0 -96
- package/dist/domain/view.d.ts +0 -15
- package/dist/domain/view.d.ts.map +0 -1
- package/dist/domain/view.js +0 -12
- package/dist/infrastructure/get-cwd.d.ts +0 -3
- package/dist/infrastructure/get-cwd.d.ts.map +0 -1
- package/dist/infrastructure/get-cwd.js +0 -13
- package/dist/infrastructure/get-dir-lazy-entries.d.ts +0 -4
- package/dist/infrastructure/get-dir-lazy-entries.d.ts.map +0 -1
- package/dist/infrastructure/get-dir-lazy-entries.js +0 -34
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UnixPath } from './unix-path.js';
|
|
3
|
+
import { Cursor, State } from '../tree-surfer/index.js';
|
|
4
|
+
import { FoldNode } from '../tree-surfer/fold-node/fold-node.types.js';
|
|
5
|
+
import { NavNode } from '../tree-surfer/nav-node/nav-node.types.js';
|
|
6
|
+
export declare const PosixNameSchema: z.ZodString;
|
|
7
|
+
export type PosixName = z.output<typeof PosixNameSchema>;
|
|
8
|
+
export type PosixNode = {
|
|
9
|
+
kind: 'file';
|
|
10
|
+
id: PosixName;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'symlink';
|
|
13
|
+
id: PosixName;
|
|
14
|
+
target: UnixPath;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'directory';
|
|
17
|
+
id: PosixName;
|
|
18
|
+
children: PosixNode[] | null;
|
|
19
|
+
};
|
|
20
|
+
export declare const PosixNodeApi: import("../tree-surfer/index.js").TreeNodeApi<string, PosixNode>;
|
|
21
|
+
export type PosixCursor = Cursor<PosixName>;
|
|
22
|
+
export declare const PosixCursorApi: import("../tree-surfer/cursor.js").CursorApi<string>;
|
|
23
|
+
export type PosixFoldNode = FoldNode<PosixName>;
|
|
24
|
+
export declare const PosixFoldNodeApi: import("../tree-surfer/index.js").FoldNodeApi<string>;
|
|
25
|
+
export type PosixNavNode = NavNode<PosixName, PosixNode>;
|
|
26
|
+
export declare const PosixNavApi: import("../tree-surfer/index.js").NavNodeApi<string, PosixNode>;
|
|
27
|
+
export type PosixState = State<PosixName, PosixNode>;
|
|
28
|
+
export declare const PosixStateApi: import("../tree-surfer/state.js").StateApi<string, PosixNode>;
|
|
29
|
+
//# sourceMappingURL=posix-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"posix-node.d.ts","sourceRoot":"","sources":["../../src/domain/posix-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAmC,MAAM,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,QAAQ,EAAE,MAAM,6CAA6C,CAAC;AAEvE,OAAO,EAAE,OAAO,EAAE,MAAM,2CAA2C,CAAC;AAIpE,eAAO,MAAM,eAAe,aAQxB,CAAC;AAEL,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAGzD,MAAM,MAAM,SAAS,GACjB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,SAAS,CAAC;CACf,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,SAAS,CAAC;IACd,MAAM,EAAE,QAAQ,CAAC;CAClB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,SAAS,CAAC;IACd,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEN,eAAO,MAAM,YAAY,kEAA4C,CAAC;AAStE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAE5C,eAAO,MAAM,cAAc,sDAA+B,CAAC;AAG3D,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEhD,eAAO,MAAM,gBAAgB,uDAAiC,CAAC;AAG/D,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAEzD,eAAO,MAAM,WAAW,iEAIvB,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAErD,eAAO,MAAM,aAAa,+DAKzB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createTreeNodeApi } from '../tree-surfer/tree-node/tree-node.impl.js';
|
|
3
|
+
import { createCursorApi, createStateApi } from '../tree-surfer/index.js';
|
|
4
|
+
import { createFoldNodeApi } from '../tree-surfer/fold-node/fold-node.impl.js';
|
|
5
|
+
import { createNavNodeApi } from '../tree-surfer/nav-node/nav-node.impl.js';
|
|
6
|
+
// Name
|
|
7
|
+
export const PosixNameSchema = z
|
|
8
|
+
.string()
|
|
9
|
+
.min(1)
|
|
10
|
+
.refine((value) => !value.includes('/'), {
|
|
11
|
+
message: "Entry name must not contain '/'",
|
|
12
|
+
})
|
|
13
|
+
.refine((value) => value !== '.' && value !== '..', {
|
|
14
|
+
message: "Entry name cannot be '.' or '..'",
|
|
15
|
+
});
|
|
16
|
+
export const PosixNodeApi = createTreeNodeApi();
|
|
17
|
+
export const PosixCursorApi = createCursorApi();
|
|
18
|
+
export const PosixFoldNodeApi = createFoldNodeApi();
|
|
19
|
+
export const PosixNavApi = createNavNodeApi(PosixNodeApi, PosixFoldNodeApi, PosixCursorApi);
|
|
20
|
+
export const PosixStateApi = createStateApi(PosixNodeApi, PosixFoldNodeApi, PosixCursorApi, PosixNavApi);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './domain/
|
|
4
|
-
export * from './domain/
|
|
5
|
-
export * from './domain/
|
|
6
|
-
export * from './domain/
|
|
1
|
+
export * from './tree-surfer-ui/application/user-input-to-intent.js';
|
|
2
|
+
export * from './tree-surfer-ui/application/intent-to-effect.js';
|
|
3
|
+
export * from './tree-surfer-ui/domain/effect.js';
|
|
4
|
+
export * from './tree-surfer-ui/domain/input-state.js';
|
|
5
|
+
export * from './tree-surfer-ui/domain/intent.js';
|
|
6
|
+
export * from './tree-surfer-ui/domain/user-input.js';
|
|
7
|
+
export * from './tree-surfer/index.js';
|
|
8
|
+
export * from './domain/posix-node.js';
|
|
7
9
|
export * from './domain/unix-path.js';
|
|
8
|
-
export * from './infrastructure/get-cwd.js';
|
|
9
|
-
export * from './infrastructure/get-dir-lazy-entries.js';
|
|
10
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,sDAAsD,CAAC;AACrE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,mCAAmC,CAAC;AAClD,cAAc,wCAAwC,CAAC;AACvD,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,wBAAwB,CAAC;AAEvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './domain/
|
|
4
|
-
export * from './domain/
|
|
5
|
-
export * from './domain/
|
|
6
|
-
export * from './domain/
|
|
1
|
+
export * from './tree-surfer-ui/application/user-input-to-intent.js';
|
|
2
|
+
export * from './tree-surfer-ui/application/intent-to-effect.js';
|
|
3
|
+
export * from './tree-surfer-ui/domain/effect.js';
|
|
4
|
+
export * from './tree-surfer-ui/domain/input-state.js';
|
|
5
|
+
export * from './tree-surfer-ui/domain/intent.js';
|
|
6
|
+
export * from './tree-surfer-ui/domain/user-input.js';
|
|
7
|
+
export * from './tree-surfer/index.js';
|
|
8
|
+
export * from './domain/posix-node.js';
|
|
7
9
|
export * from './domain/unix-path.js';
|
|
8
|
-
export * from './infrastructure/get-cwd.js';
|
|
9
|
-
export * from './infrastructure/get-dir-lazy-entries.js';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const CursorKind: {
|
|
2
|
+
readonly Entry: "entry";
|
|
3
|
+
readonly Fold: "fold";
|
|
4
|
+
};
|
|
5
|
+
export type CursorKind = (typeof CursorKind)[keyof typeof CursorKind];
|
|
6
|
+
export type CursorEntry<Id> = {
|
|
7
|
+
kind: typeof CursorKind.Entry;
|
|
8
|
+
parentPath: readonly Id[];
|
|
9
|
+
entryId: Id;
|
|
10
|
+
};
|
|
11
|
+
export type CursorFold<Id> = {
|
|
12
|
+
kind: typeof CursorKind.Fold;
|
|
13
|
+
parentPath: readonly Id[];
|
|
14
|
+
};
|
|
15
|
+
export type Cursor<Id> = CursorEntry<Id> | CursorFold<Id>;
|
|
16
|
+
export type CursorApi<Id> = {
|
|
17
|
+
isEntry(cursor: Cursor<Id>): cursor is CursorEntry<Id>;
|
|
18
|
+
isFold(cursor: Cursor<Id>): cursor is CursorFold<Id>;
|
|
19
|
+
equal(left: Cursor<Id>, right: Cursor<Id>): boolean;
|
|
20
|
+
getPath(cursor: Cursor<Id>): Id[] | undefined;
|
|
21
|
+
cursorBelongsToSubtree(cursor: Cursor<Id>, entryPath: readonly Id[]): boolean;
|
|
22
|
+
};
|
|
23
|
+
export declare function createCursorApi<Id>(): CursorApi<Id>;
|
|
24
|
+
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/tree-surfer/cursor.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;CAGb,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAEtE,MAAM,MAAM,WAAW,CAAC,EAAE,IAAI;IAC5B,IAAI,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAC9B,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC;IAC1B,OAAO,EAAE,EAAE,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,EAAE,IAAI;IAC3B,IAAI,EAAE,OAAO,UAAU,CAAC,IAAI,CAAC;IAC7B,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,MAAM,CAAC,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;AAE1D,MAAM,MAAM,SAAS,CAAC,EAAE,IAAI;IAC1B,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;IAEvD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAErD,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;IAEpD,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,SAAS,CAAC;IAE9C,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,GAAG,OAAO,CAAC;CAC/E,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE,CAAC,CA0CnD"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export const CursorKind = {
|
|
2
|
+
Entry: 'entry',
|
|
3
|
+
Fold: 'fold',
|
|
4
|
+
};
|
|
5
|
+
export function createCursorApi() {
|
|
6
|
+
const cursorApi = {
|
|
7
|
+
isEntry(cursor) {
|
|
8
|
+
return cursor.kind === CursorKind.Entry;
|
|
9
|
+
},
|
|
10
|
+
isFold(cursor) {
|
|
11
|
+
return cursor.kind === CursorKind.Fold;
|
|
12
|
+
},
|
|
13
|
+
equal(left, right) {
|
|
14
|
+
if (!idPathEqual(left.parentPath, right.parentPath)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (cursorApi.isFold(left)) {
|
|
18
|
+
return cursorApi.isFold(right);
|
|
19
|
+
}
|
|
20
|
+
return cursorApi.isEntry(right) && left.entryId === right.entryId;
|
|
21
|
+
},
|
|
22
|
+
getPath(cursor) {
|
|
23
|
+
if (cursorApi.isFold(cursor)) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return [...cursor.parentPath, cursor.entryId];
|
|
27
|
+
},
|
|
28
|
+
cursorBelongsToSubtree(cursor, entryPath) {
|
|
29
|
+
if (cursorApi.isFold(cursor)) {
|
|
30
|
+
return isStrictPathPrefix(entryPath, cursor.parentPath);
|
|
31
|
+
}
|
|
32
|
+
const cursorPath = [...cursor.parentPath, cursor.entryId];
|
|
33
|
+
return isStrictPathPrefix(entryPath, cursorPath);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
return cursorApi;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Returns true when both paths contain the same IDs in the same order.
|
|
40
|
+
*/
|
|
41
|
+
function idPathEqual(left, right) {
|
|
42
|
+
if (left.length !== right.length) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
46
|
+
if (left[index] !== right[index]) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns true when `prefix` is a strict prefix of `path`.
|
|
54
|
+
*/
|
|
55
|
+
function isStrictPathPrefix(prefix, path) {
|
|
56
|
+
if (prefix.length >= path.length) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
for (let index = 0; index < prefix.length; index += 1) {
|
|
60
|
+
if (prefix[index] !== path[index]) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { FoldNode, FoldNodeApi, FoldNodeService } from './fold-node.types.js';
|
|
2
|
+
import { SerializableKey } from '../tree-node/tree-node.types.js';
|
|
3
|
+
export declare function createFoldNodeApi<Id extends SerializableKey>(): FoldNodeApi<Id>;
|
|
4
|
+
export declare function createFoldNodeService<Id extends SerializableKey>(foldNodeApi: FoldNodeApi<Id>, createChild: (id: Id) => FoldNode<Id>): FoldNodeService<Id>;
|
|
5
|
+
//# sourceMappingURL=fold-node.impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold-node.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.impl.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,EACR,WAAW,EAEX,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,eAAe,KAAK,WAAW,CAAC,EAAE,CAAC,CAiC/E;AAED,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,eAAe,EAC9D,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,EAC5B,WAAW,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC,GACpC,eAAe,CAAC,EAAE,CAAC,CAiLrB"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createTreeNodeApi } from '../tree-node/tree-node.impl.js';
|
|
2
|
+
export function createFoldNodeApi() {
|
|
3
|
+
const treeNodeApi = createTreeNodeApi();
|
|
4
|
+
return {
|
|
5
|
+
getChildren(node) {
|
|
6
|
+
return node.children;
|
|
7
|
+
},
|
|
8
|
+
getChildById(node, id) {
|
|
9
|
+
return node.children.find((child) => child.id === id);
|
|
10
|
+
},
|
|
11
|
+
getAtPath(rootNode, path, selector) {
|
|
12
|
+
return treeNodeApi.getAtPath(rootNode.children, path, selector);
|
|
13
|
+
},
|
|
14
|
+
modifyAtPath(rootNode, path, modifier) {
|
|
15
|
+
const children = treeNodeApi.modifyAtPath(rootNode.children, path, modifier);
|
|
16
|
+
if (children === undefined) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
...rootNode,
|
|
21
|
+
children,
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function createFoldNodeService(foldNodeApi, createChild) {
|
|
27
|
+
return {
|
|
28
|
+
createEmptyRoot() {
|
|
29
|
+
return {
|
|
30
|
+
children: [],
|
|
31
|
+
folds: new Set(),
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
getIfEntryFoldedAtPath(rootNode, path, entryId) {
|
|
35
|
+
if (path.length === 0) {
|
|
36
|
+
return rootNode.folds.has(entryId);
|
|
37
|
+
}
|
|
38
|
+
const node = foldNodeApi.getAtPath(rootNode, path, (candidate) => candidate);
|
|
39
|
+
return node !== undefined && node.folds.has(entryId);
|
|
40
|
+
},
|
|
41
|
+
addFoldedEntryAtPath(rootNode, path, entryId) {
|
|
42
|
+
const ensuredRoot = ensurePath(rootNode, path);
|
|
43
|
+
if (path.length === 0) {
|
|
44
|
+
return addFoldedEntry(ensuredRoot, entryId);
|
|
45
|
+
}
|
|
46
|
+
return foldNodeApi.modifyAtPath(ensuredRoot, path, (node) => addFoldedEntry(node, entryId));
|
|
47
|
+
},
|
|
48
|
+
removeFoldedEntryAtPath(rootNode, path, entryId) {
|
|
49
|
+
if (path.length === 0) {
|
|
50
|
+
return removeFoldedEntry(rootNode, entryId);
|
|
51
|
+
}
|
|
52
|
+
return foldNodeApi.modifyAtPath(rootNode, path, (node) => removeFoldedEntry(node, entryId));
|
|
53
|
+
},
|
|
54
|
+
clearFoldedEntriesAtPath(rootNode, path) {
|
|
55
|
+
if (path.length === 0) {
|
|
56
|
+
return clearFoldedEntries(rootNode);
|
|
57
|
+
}
|
|
58
|
+
return foldNodeApi.modifyAtPath(rootNode, path, clearFoldedEntries);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
// Helpers:
|
|
62
|
+
// `Node extends FoldNodeRoot<Id> | FoldNode<Id>` is used to create two
|
|
63
|
+
// versions of functions: one for the root and one for the children.
|
|
64
|
+
// "Flat" functions
|
|
65
|
+
//
|
|
66
|
+
// Adds entry name to the given node.
|
|
67
|
+
function addFoldedEntry(node, entryId) {
|
|
68
|
+
if (node.folds.has(entryId)) {
|
|
69
|
+
return node;
|
|
70
|
+
}
|
|
71
|
+
const folds = new Set(node.folds);
|
|
72
|
+
folds.add(entryId);
|
|
73
|
+
return {
|
|
74
|
+
...node,
|
|
75
|
+
folds,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function removeFoldedEntry(node, entryId) {
|
|
79
|
+
if (!node.folds.has(entryId)) {
|
|
80
|
+
return node;
|
|
81
|
+
}
|
|
82
|
+
const folds = new Set(node.folds);
|
|
83
|
+
folds.delete(entryId);
|
|
84
|
+
return {
|
|
85
|
+
...node,
|
|
86
|
+
folds,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function clearFoldedEntries(node) {
|
|
90
|
+
if (node.folds.size === 0) {
|
|
91
|
+
return node;
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
...node,
|
|
95
|
+
folds: new Set(),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Ensures that the requested path exists in the fold-state tree.
|
|
100
|
+
*
|
|
101
|
+
* This creates fold nodes only; it does not modify the buffer tree.
|
|
102
|
+
*/
|
|
103
|
+
function ensurePath(rootNode, path) {
|
|
104
|
+
if (path.length === 0) {
|
|
105
|
+
return rootNode;
|
|
106
|
+
}
|
|
107
|
+
const children = ensureChildPath(rootNode.children, path, 0);
|
|
108
|
+
if (children === rootNode.children) {
|
|
109
|
+
return rootNode;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
...rootNode,
|
|
113
|
+
children,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function ensureChildPath(children, path, pathIndex) {
|
|
117
|
+
const id = path[pathIndex];
|
|
118
|
+
if (id === undefined) {
|
|
119
|
+
return children;
|
|
120
|
+
}
|
|
121
|
+
const childIndex = children.findIndex((child) => child.id === id);
|
|
122
|
+
const child = childIndex === -1 ? createChild(id) : children[childIndex];
|
|
123
|
+
let updatedChild = child;
|
|
124
|
+
if (pathIndex < path.length - 1) {
|
|
125
|
+
const updatedChildren = ensureChildPath(child.children, path, pathIndex + 1);
|
|
126
|
+
if (updatedChildren !== child.children) {
|
|
127
|
+
updatedChild = {
|
|
128
|
+
...child,
|
|
129
|
+
children: updatedChildren,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (childIndex === -1) {
|
|
134
|
+
return [...children, updatedChild];
|
|
135
|
+
}
|
|
136
|
+
if (updatedChild === child) {
|
|
137
|
+
return children;
|
|
138
|
+
}
|
|
139
|
+
const result = [...children];
|
|
140
|
+
result[childIndex] = updatedChild;
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { TreeNodeModifier, TreeNodeSelector } from '../tree-node/tree-node.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The whole fold state for a tree-node tree.
|
|
4
|
+
*
|
|
5
|
+
* The root has no ID because it represents the fold at the root.
|
|
6
|
+
* Its `children` contain the fold nodes for the forest's root entries.
|
|
7
|
+
*
|
|
8
|
+
* `folds` contains the IDs folded at this root. Fold order is not
|
|
9
|
+
* represented here; the buffer tree determines entry order.
|
|
10
|
+
*/
|
|
11
|
+
export type FoldNodeRoot<Id extends PropertyKey> = {
|
|
12
|
+
children: FoldNode<Id>[];
|
|
13
|
+
folds: ReadonlySet<Id>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Fold state associated with a node in the buffer tree.
|
|
17
|
+
*
|
|
18
|
+
* A fold node has the shape of an open tree node: its children are always
|
|
19
|
+
* represented by an array, and an empty `children` array means that no child
|
|
20
|
+
* fold nodes are currently represented.
|
|
21
|
+
*
|
|
22
|
+
* The `folds` set contains the IDs of entries folded at this node. Fold
|
|
23
|
+
* order is not represented here; the buffer tree determines entry order.
|
|
24
|
+
*
|
|
25
|
+
* The type is structurally compatible with `TreeNode`, allowing the shared
|
|
26
|
+
* `TreeNodeApi` to be used for path traversal and immutable updates.
|
|
27
|
+
*/
|
|
28
|
+
export type FoldNode<Id extends PropertyKey> = FoldNodeRoot<Id> & {
|
|
29
|
+
id: Id;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Operations for navigating and immutably updating fold-tree structure.
|
|
33
|
+
*
|
|
34
|
+
* This API is a projection of `TreeNodeApi` onto the fold-tree
|
|
35
|
+
* representation. Path operations are strict: they only operate on
|
|
36
|
+
* paths that already exist. Creation of missing fold paths belongs to
|
|
37
|
+
* `FoldNodeService`.
|
|
38
|
+
*/
|
|
39
|
+
export type FoldNodeApi<Id extends PropertyKey> = {
|
|
40
|
+
/**
|
|
41
|
+
* Returns the children of either the fold root or a fold node.
|
|
42
|
+
*/
|
|
43
|
+
getChildren(node: FoldNodeRoot<Id> | FoldNode<Id>): Iterable<FoldNode<Id>>;
|
|
44
|
+
/**
|
|
45
|
+
* Returns a direct child by ID.
|
|
46
|
+
*/
|
|
47
|
+
getChildById(node: FoldNodeRoot<Id> | FoldNode<Id>, id: Id): FoldNode<Id> | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Selects a fold node at a path below the root.
|
|
50
|
+
*/
|
|
51
|
+
getAtPath<Result>(rootNode: FoldNodeRoot<Id>, path: Id[], selector: TreeNodeSelector<FoldNode<Id>, Result>): Result | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Immutably modifies a fold node at a path below the root.
|
|
54
|
+
*/
|
|
55
|
+
modifyAtPath(rootNode: FoldNodeRoot<Id>, path: Id[], modifier: TreeNodeModifier<FoldNode<Id>>): FoldNodeRoot<Id> | undefined;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Semantic operations for managing folded buffer entries.
|
|
59
|
+
*
|
|
60
|
+
* Unlike `FoldNodeApi`, the service may create missing fold paths when
|
|
61
|
+
* adding a fold. This allows an empty root to be populated lazily.
|
|
62
|
+
*/
|
|
63
|
+
export type FoldNodeService<Id extends PropertyKey> = {
|
|
64
|
+
createEmptyRoot(): FoldNodeRoot<Id>;
|
|
65
|
+
getIfEntryFoldedAtPath(rootNode: FoldNodeRoot<Id>, path: Id[], entryId: Id): boolean;
|
|
66
|
+
addFoldedEntryAtPath(rootNode: FoldNodeRoot<Id>, path: Id[], entryId: Id): FoldNodeRoot<Id> | undefined;
|
|
67
|
+
removeFoldedEntryAtPath(rootNode: FoldNodeRoot<Id>, path: Id[], entryId: Id): FoldNodeRoot<Id> | undefined;
|
|
68
|
+
clearFoldedEntriesAtPath(rootNode: FoldNodeRoot<Id>, path: Id[]): FoldNodeRoot<Id> | undefined;
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=fold-node.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold-node.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAErF;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,WAAW,IAAI;IACjD,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IACzB,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,QAAQ,CAAC,EAAE,SAAS,WAAW,IAAI,YAAY,CAAC,EAAE,CAAC,GAAG;IAChE,EAAE,EAAE,EAAE,CAAC;CACR,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,CAAC,EAAE,SAAS,WAAW,IAAI;IAChD;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3E;;OAEG;IACH,YAAY,CACV,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,EACrC,EAAE,EAAE,EAAE,GACL,QAAQ,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IAE5B;;OAEG;IACH,SAAS,CAAC,MAAM,EACd,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,GAC/C,MAAM,GAAG,SAAS,CAAC;IAEtB;;OAEG;IACH,YAAY,CACV,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GACvC,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,eAAe,CACzB,EAAE,SAAS,WAAW,IACpB;IACF,eAAe,IAAI,YAAY,CAAC,EAAE,CAAC,CAAC;IAEpC,sBAAsB,CACpB,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,OAAO,EAAE,EAAE,GACV,OAAO,CAAC;IAEX,oBAAoB,CAClB,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,OAAO,EAAE,EAAE,GACV,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IAEhC,uBAAuB,CACrB,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,OAAO,EAAE,EAAE,GACV,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IAEhC,wBAAwB,CACtB,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,GACT,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;CACjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './fold-node/fold-node.impl.js';
|
|
2
|
+
export * from './fold-node/fold-node.types.js';
|
|
3
|
+
export * from './nav-node/nav-node.impl.js';
|
|
4
|
+
export * from './nav-node/nav-node.types.js';
|
|
5
|
+
export * from './tree-node/tree-node.impl.js';
|
|
6
|
+
export * from './tree-node/tree-node.types.js';
|
|
7
|
+
export * from './cursor.js';
|
|
8
|
+
export * from './state.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tree-surfer/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,aAAa,CAAC;AAE5B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './fold-node/fold-node.impl.js';
|
|
2
|
+
export * from './fold-node/fold-node.types.js';
|
|
3
|
+
export * from './nav-node/nav-node.impl.js';
|
|
4
|
+
export * from './nav-node/nav-node.types.js';
|
|
5
|
+
export * from './tree-node/tree-node.impl.js';
|
|
6
|
+
export * from './tree-node/tree-node.types.js';
|
|
7
|
+
export * from './cursor.js';
|
|
8
|
+
export * from './state.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SerializableKey, TreeNode, TreeNodeApi } from '../tree-node/tree-node.types.js';
|
|
2
|
+
import { FoldNodeApi } from '../fold-node/fold-node.types.js';
|
|
3
|
+
import { CursorApi } from '../cursor.js';
|
|
4
|
+
import { NavNodeApi } from './nav-node.types.js';
|
|
5
|
+
export declare function createNavNodeApi<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(treeNodeApi: TreeNodeApi<Id, BufferNode>, foldNodeApi: FoldNodeApi<Id>, cursorApi: CursorApi<Id>): NavNodeApi<Id, BufferNode>;
|
|
6
|
+
//# sourceMappingURL=nav-node.impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav-node.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/nav-node/nav-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACvG,OAAO,EAAE,WAAW,EAAgB,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAU,SAAS,EAAc,MAAM,cAAc,CAAC;AAC7D,OAAO,EAA6C,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE5F,wBAAgB,gBAAgB,CAC9B,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,EAE3C,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,EACxC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,EAC5B,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,GACvB,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAqP5B"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { CursorKind } from '../cursor.js';
|
|
2
|
+
import { isNavBranch } from './nav-node.types.js';
|
|
3
|
+
export function createNavNodeApi(treeNodeApi, foldNodeApi, cursorApi) {
|
|
4
|
+
const navNodeApi = {
|
|
5
|
+
// Return a nav node from the BufferNode tree and FoldNode tree.
|
|
6
|
+
from(entries, foldNode) {
|
|
7
|
+
const visibleEntriesSoFar = [];
|
|
8
|
+
const foldedEntriesSoFar = [];
|
|
9
|
+
for (const entry of entries) {
|
|
10
|
+
// Find the node
|
|
11
|
+
let navigationEntry;
|
|
12
|
+
if (treeNodeApi.isBranch(entry)) {
|
|
13
|
+
// If fold node does not have children (recursively no folds),
|
|
14
|
+
// then just use empty.
|
|
15
|
+
const childFoldNode = foldNodeApi.getChildById(foldNode, entry.id) ??
|
|
16
|
+
createEmptyFoldNode();
|
|
17
|
+
navigationEntry = {
|
|
18
|
+
...entry,
|
|
19
|
+
children: entry.children === null
|
|
20
|
+
? null
|
|
21
|
+
: navNodeApi.from(entry.children, childFoldNode),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
else if (treeNodeApi.isLeaf(entry)) {
|
|
25
|
+
navigationEntry = entry;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// This should be unreachable if BufferNode correctly extends TreeNode.
|
|
29
|
+
throw new Error('Unsupported tree node');
|
|
30
|
+
}
|
|
31
|
+
if (foldNode.folds.has(entry.id)) {
|
|
32
|
+
foldedEntriesSoFar.push(navigationEntry);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
visibleEntriesSoFar.push(navigationEntry);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
entries: visibleEntriesSoFar,
|
|
40
|
+
foldedEntries: foldedEntriesSoFar,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
getNodeAtPath(navigation, path) {
|
|
44
|
+
const [currentId, ...remainingPath] = path;
|
|
45
|
+
// An empty path identifies the current node.
|
|
46
|
+
if (currentId === undefined) {
|
|
47
|
+
return navigation;
|
|
48
|
+
}
|
|
49
|
+
const entry = [...navigation.entries, ...navigation.foldedEntries].find((candidate) => candidate.id === currentId);
|
|
50
|
+
if (entry === undefined) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
if (!isNavBranch(entry)) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
// The directory has not been loaded/opened.
|
|
57
|
+
if (entry.children === null) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return navNodeApi.getNodeAtPath(entry.children, remainingPath);
|
|
61
|
+
},
|
|
62
|
+
getEntryAtPath(navigation, path) {
|
|
63
|
+
const [currentId, ...remainingPath] = path;
|
|
64
|
+
if (currentId === undefined) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const entry = [...navigation.entries, ...navigation.foldedEntries].find((candidate) => candidate.id === currentId);
|
|
68
|
+
if (entry === undefined) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (remainingPath.length === 0) {
|
|
72
|
+
return entry;
|
|
73
|
+
}
|
|
74
|
+
if (!isNavBranch(entry) || entry.children === null) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return navNodeApi.getEntryAtPath(entry.children, remainingPath);
|
|
78
|
+
},
|
|
79
|
+
nextCursor(rootNode, cursor) {
|
|
80
|
+
const cursors = cursorsInNode(rootNode, []);
|
|
81
|
+
const currentIndex = cursors.findIndex((candidate) => cursorApi.equal(candidate, cursor));
|
|
82
|
+
if (currentIndex === -1 || currentIndex === cursors.length - 1) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return cursors[currentIndex + 1];
|
|
86
|
+
},
|
|
87
|
+
previousCursor(rootNode, cursor) {
|
|
88
|
+
const cursors = cursorsInNode(rootNode, []);
|
|
89
|
+
const currentIndex = cursors.findIndex((candidate) => cursorApi.equal(candidate, cursor));
|
|
90
|
+
if (currentIndex <= 0) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
return cursors[currentIndex - 1];
|
|
94
|
+
},
|
|
95
|
+
cursorAfterFold(rootNode, cursor) {
|
|
96
|
+
if (cursorApi.isFold(cursor)) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const cursors = cursorsInNode(rootNode, []);
|
|
100
|
+
const currentIndex = cursors.findIndex((candidate) => cursorApi.equal(candidate, cursor));
|
|
101
|
+
if (currentIndex === -1) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
const foldedPath = [...cursor.parentPath, cursor.entryId];
|
|
105
|
+
for (let index = currentIndex + 1; index < cursors.length; index += 1) {
|
|
106
|
+
const candidate = cursors[index];
|
|
107
|
+
if (candidate === undefined) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (cursorApi.cursorBelongsToSubtree(candidate, foldedPath)) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
return candidate;
|
|
114
|
+
}
|
|
115
|
+
// The fold row will be created at the end of this directory.
|
|
116
|
+
return {
|
|
117
|
+
kind: CursorKind.Fold,
|
|
118
|
+
parentPath: cursor.parentPath,
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
parentCursor(navigation, cursor) {
|
|
122
|
+
const parentPath = cursor.parentPath;
|
|
123
|
+
// The cursor is already in the root directory.
|
|
124
|
+
if (parentPath.length === 0) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
const entryId = parentPath.at(-1);
|
|
128
|
+
if (entryId === undefined) {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
const containingPath = parentPath.slice(0, -1);
|
|
132
|
+
const entry = navNodeApi.getEntryAtPath(navigation, [...parentPath]);
|
|
133
|
+
// The parent path must identify a navigable branch.
|
|
134
|
+
if (entry === undefined || !isNavBranch(entry)) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
kind: CursorKind.Entry,
|
|
139
|
+
parentPath: containingPath,
|
|
140
|
+
entryId: entryId,
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
cursors(navigation, parentPath = []) {
|
|
144
|
+
return cursorsInNode(navigation, parentPath);
|
|
145
|
+
},
|
|
146
|
+
visibleLeavesPaths(navigation, parentPath = []) {
|
|
147
|
+
const paths = [];
|
|
148
|
+
for (const entry of navigation.entries) {
|
|
149
|
+
const entryPath = [...parentPath, entry.id];
|
|
150
|
+
if (isNavBranch(entry)) {
|
|
151
|
+
// A null children value means that the directory has not been
|
|
152
|
+
// loaded/opened, so there are no visible descendant files.
|
|
153
|
+
if (entry.children !== null) {
|
|
154
|
+
paths.push(...navNodeApi.visibleLeavesPaths(entry.children, entryPath));
|
|
155
|
+
}
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
paths.push(entryPath);
|
|
159
|
+
}
|
|
160
|
+
return paths;
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
return navNodeApi;
|
|
164
|
+
}
|
|
165
|
+
function createEmptyFoldNode() {
|
|
166
|
+
return {
|
|
167
|
+
children: [],
|
|
168
|
+
folds: new Set(),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function cursorsInNode(node, parentPath) {
|
|
172
|
+
const cursors = [];
|
|
173
|
+
for (const entry of node.entries) {
|
|
174
|
+
cursors.push({
|
|
175
|
+
kind: CursorKind.Entry,
|
|
176
|
+
parentPath,
|
|
177
|
+
entryId: entry.id,
|
|
178
|
+
});
|
|
179
|
+
if (!isNavBranch(entry) || entry.children === null) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
cursors.push(...cursorsInNode(entry.children, [...parentPath, entry.id]));
|
|
183
|
+
}
|
|
184
|
+
if (node.foldedEntries.length > 0) {
|
|
185
|
+
cursors.push({
|
|
186
|
+
kind: CursorKind.Fold,
|
|
187
|
+
parentPath,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return cursors;
|
|
191
|
+
}
|