@mak-98/dirvi-cli 0.4.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/application/effect-to-action.d.ts +5 -7
- package/dist/application/effect-to-action.d.ts.map +1 -1
- package/dist/application/effect-to-action.js +81 -86
- package/dist/application/reducer-action.d.ts +23 -23
- package/dist/application/reducer-action.d.ts.map +1 -1
- package/dist/application/reducer.d.ts +4 -3
- package/dist/application/reducer.d.ts.map +1 -1
- package/dist/application/reducer.js +67 -42
- package/dist/domain/app-api.d.ts +47 -0
- package/dist/domain/app-api.d.ts.map +1 -0
- package/dist/domain/app-api.js +21 -0
- package/dist/domain/event-message.d.ts +12 -15
- package/dist/domain/event-message.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +40 -42
- package/dist/infrastructure/get-dir-entries.d.ts +3 -0
- package/dist/infrastructure/get-dir-entries.d.ts.map +1 -0
- package/dist/infrastructure/get-dir-entries.js +33 -0
- package/dist/infrastructure/get-dir-lazy-entries.d.ts +3 -0
- package/dist/infrastructure/get-dir-lazy-entries.d.ts.map +1 -0
- package/dist/infrastructure/get-dir-lazy-entries.js +33 -0
- package/dist/infrastructure/get-unix-abs-path.d.ts +3 -0
- package/dist/infrastructure/get-unix-abs-path.d.ts.map +1 -0
- package/dist/infrastructure/get-unix-abs-path.js +14 -0
- package/dist/infrastructure/ink-input-to-user-input.d.ts +2 -5
- package/dist/infrastructure/ink-input-to-user-input.js +42 -42
- package/dist/infrastructure/load-posix-app-api.d.ts +4 -0
- package/dist/infrastructure/load-posix-app-api.d.ts.map +1 -0
- package/dist/infrastructure/load-posix-app-api.js +82 -0
- package/dist/ui/App.d.ts +16 -15
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +127 -128
- package/dist/ui/AppShell.d.ts +6 -16
- package/dist/ui/AppShell.d.ts.map +1 -1
- package/dist/ui/AppShell.js +22 -13
- package/dist/ui/LoadingApp.d.ts +11 -0
- package/dist/ui/LoadingApp.d.ts.map +1 -0
- package/dist/ui/LoadingApp.js +67 -0
- package/dist/ui/components/StatusBar.d.ts +3 -5
- package/dist/ui/components/StatusBar.d.ts.map +1 -1
- package/dist/ui/components/StatusBar.js +3 -28
- package/dist/ui/components/ViewRowComponent.d.ts +4 -6
- package/dist/ui/components/ViewRowComponent.js +10 -30
- package/dist/ui/hooks/useView.d.ts +4 -7
- package/dist/ui/hooks/useView.d.ts.map +1 -1
- package/dist/ui/hooks/useView.js +20 -29
- package/dist/ui/view.d.ts +13 -17
- package/dist/ui/view.d.ts.map +1 -1
- package/dist/ui/view.js +84 -64
- package/package.json +2 -2
- package/dist/application/action.d.ts +0 -26
- package/dist/application/action.d.ts.map +0 -1
- package/dist/application/action.js +0 -1
- package/dist/application/dir-buffer-helpers.d.ts +0 -6
- package/dist/application/dir-buffer-helpers.d.ts.map +0 -1
- package/dist/application/dir-buffer-helpers.js +0 -21
- package/dist/application/display-rows.d.ts +0 -11
- package/dist/application/display-rows.d.ts.map +0 -1
- package/dist/application/display-rows.js +0 -63
- package/dist/application/fold-helpers.d.ts +0 -24
- package/dist/application/fold-helpers.d.ts.map +0 -1
- package/dist/application/fold-helpers.js +0 -47
- package/dist/application/intent-to-effect.d.ts +0 -59
- package/dist/application/intent-to-effect.d.ts.map +0 -1
- package/dist/application/intent-to-effect.js +0 -131
- package/dist/application/user-input-to-intent.d.ts +0 -39
- package/dist/application/user-input-to-intent.d.ts.map +0 -1
- package/dist/application/user-input-to-intent.js +0 -110
- package/dist/domain/print-message.d.ts +0 -11
- package/dist/domain/print-message.d.ts.map +0 -1
- package/dist/domain/print-message.js +0 -1
- package/dist/infrastructure/input.d.ts +0 -12
- package/dist/infrastructure/input.d.ts.map +0 -1
- package/dist/infrastructure/input.js +0 -81
- package/dist/infrastructure/load-initial-props.d.ts +0 -3
- package/dist/infrastructure/load-initial-props.d.ts.map +0 -1
- package/dist/infrastructure/load-initial-props.js +0 -36
- package/dist/infrastructure/user-input.d.ts +0 -32
- package/dist/infrastructure/user-input.d.ts.map +0 -1
- package/dist/infrastructure/user-input.js +0 -45
- package/dist/ui/App2.d.ts +0 -16
- package/dist/ui/App2.d.ts.map +0 -1
- package/dist/ui/App2.js +0 -107
- package/dist/ui/components/DirEntries.d.ts +0 -11
- package/dist/ui/components/DirEntries.d.ts.map +0 -1
- package/dist/ui/components/DirEntries.js +0 -64
- package/dist/ui/components/UnixEntry.d.ts +0 -9
- package/dist/ui/components/UnixEntry.d.ts.map +0 -1
- package/dist/ui/components/UnixEntry.js +0 -19
- package/dist/ui/components/UnixEntryComponent.d.ts +0 -9
- package/dist/ui/components/UnixEntryComponent.d.ts.map +0 -1
- package/dist/ui/components/UnixEntryComponent.js +0 -19
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { NavigationNode, State, EffectAction } from 'dirvi-lib';
|
|
2
1
|
import type { ReducerAction } from './reducer-action.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
//# sourceMappingURL=effect-to-action.d.ts.map
|
|
2
|
+
import { SerializableKey, TreeNode, TreeNodeApi } from 'dirvi-lib/dist/tree-surfer/tree-node/tree-node.types.js';
|
|
3
|
+
import { CursorApi, EffectAction, NavNode, NavNodeApi, State } from 'dirvi-lib';
|
|
4
|
+
export type EffectToAction<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = (effectAction: EffectAction<Id, BufferNode>, navigation: NavNode<Id, BufferNode>, state: State<Id, BufferNode>) => ReducerAction<Id, BufferNode> | undefined;
|
|
5
|
+
export declare function createEffectToAction<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(treeNodeApi: TreeNodeApi<Id, BufferNode>, cursorApi: CursorApi<Id>, navNodeApi: NavNodeApi<Id, BufferNode>): EffectToAction<Id, BufferNode>;
|
|
6
|
+
//# sourceMappingURL=effect-to-action.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect-to-action.d.ts","sourceRoot":"","sources":["../../src/application/effect-to-action.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"effect-to-action.d.ts","sourceRoot":"","sources":["../../src/application/effect-to-action.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,yDAAyD,CAAC;AACjH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAEhF,MAAM,MAAM,cAAc,CACxB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,IACzC,CACF,YAAY,EAAE,YAAY,CAAC,EAAE,EAAE,UAAU,CAAC,EAC1C,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,EACnC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,KACzB,aAAa,CAAC,EAAE,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC;AAE/C,wBAAgB,oBAAoB,CAClC,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,EAE3C,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,EACxC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,EACxB,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,GACrC,cAAc,CAAC,EAAE,EAAE,UAAU,CAAC,CAgHhC"}
|
|
@@ -1,88 +1,83 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
export function createEffectToAction(treeNodeApi, cursorApi, navNodeApi) {
|
|
2
|
+
function effectToAction(effectAction, navigation, state) {
|
|
3
|
+
switch (effectAction.effectActionType) {
|
|
4
|
+
case 'nextEntry': {
|
|
5
|
+
const cursor = navNodeApi.nextCursor(navigation, state.cursor);
|
|
6
|
+
return cursor === undefined
|
|
7
|
+
? undefined
|
|
8
|
+
: {
|
|
9
|
+
kind: 'changeCursor',
|
|
10
|
+
cursor,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
case 'prevEntry': {
|
|
14
|
+
const cursor = navNodeApi.previousCursor(navigation, state.cursor);
|
|
15
|
+
return cursor === undefined
|
|
16
|
+
? undefined
|
|
17
|
+
: {
|
|
18
|
+
kind: 'changeCursor',
|
|
19
|
+
cursor,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
case 'setBranchEntries':
|
|
23
|
+
return {
|
|
24
|
+
kind: 'updateBranch',
|
|
25
|
+
path: effectAction.path,
|
|
26
|
+
entries: effectAction.entries,
|
|
27
|
+
};
|
|
28
|
+
case 'navigateToParent': {
|
|
29
|
+
const cursor = navNodeApi.parentCursor(navigation, state.cursor);
|
|
30
|
+
return cursor === undefined
|
|
31
|
+
? undefined
|
|
32
|
+
: {
|
|
33
|
+
kind: 'changeCursor',
|
|
34
|
+
cursor,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
case 'fold': {
|
|
38
|
+
if (state.cursor.kind === 'fold') {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const path = [...state.cursor.parentPath, state.cursor.entryId];
|
|
42
|
+
const entry = treeNodeApi.getAtPath(state.buffer, path, (node) => node);
|
|
43
|
+
if (entry === undefined) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const cursor = navNodeApi.cursorAfterFold(navigation, state.cursor);
|
|
47
|
+
if (cursor === undefined) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
kind: 'fold',
|
|
52
|
+
parentPath: [...state.cursor.parentPath],
|
|
53
|
+
entry,
|
|
54
|
+
cursor,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
case 'unfold': {
|
|
58
|
+
if (state.cursor.kind !== 'fold') {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const node = navNodeApi.getNodeAtPath(navigation, [...state.cursor.parentPath]);
|
|
62
|
+
if (node === undefined || node.foldedEntries.length === 0) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const firstFoldedEntry = node.foldedEntries[0];
|
|
66
|
+
return {
|
|
67
|
+
kind: 'unfold',
|
|
68
|
+
parentPath: [...state.cursor.parentPath],
|
|
69
|
+
cursor: {
|
|
70
|
+
kind: 'entry',
|
|
71
|
+
parentPath: state.cursor.parentPath,
|
|
72
|
+
entryId: firstFoldedEntry.id,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
case 'toggleFold':
|
|
77
|
+
return effectToAction(state.cursor.kind === 'fold'
|
|
78
|
+
? { effectActionType: 'unfold' }
|
|
79
|
+
: { effectActionType: 'fold' }, navigation, state);
|
|
80
|
+
}
|
|
12
81
|
}
|
|
13
|
-
|
|
14
|
-
const cursor = NavigationNode.previousCursor(navigation, state.cursor);
|
|
15
|
-
return cursor === undefined
|
|
16
|
-
? undefined
|
|
17
|
-
: {
|
|
18
|
-
kind: 'changeCursor',
|
|
19
|
-
cursor,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
case 'updateDir':
|
|
23
|
-
return {
|
|
24
|
-
kind: 'updateDir',
|
|
25
|
-
path: effectAction.path,
|
|
26
|
-
entries: effectAction.entries,
|
|
27
|
-
};
|
|
28
|
-
case 'outDir': {
|
|
29
|
-
const cursor = NavigationNode.parentCursor(navigation, state.cursor);
|
|
30
|
-
return cursor === undefined
|
|
31
|
-
? undefined
|
|
32
|
-
: {
|
|
33
|
-
kind: 'changeCursor',
|
|
34
|
-
cursor,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
case 'fold': {
|
|
38
|
-
if (state.cursor.kind === 'fold') {
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
const path = [...state.cursor.parentPath, state.cursor.entryName];
|
|
42
|
-
const entry = NavigationNode.getEntryAtPath(navigation, path);
|
|
43
|
-
if (entry === undefined) {
|
|
44
|
-
return undefined;
|
|
45
|
-
}
|
|
46
|
-
const cursor = NavigationNode.cursorAfterFold(navigation, state.cursor);
|
|
47
|
-
if (cursor === undefined) {
|
|
48
|
-
return undefined;
|
|
49
|
-
}
|
|
50
|
-
return {
|
|
51
|
-
kind: 'fold',
|
|
52
|
-
parentPath: state.cursor.parentPath,
|
|
53
|
-
entry,
|
|
54
|
-
cursor,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
case 'unfold': {
|
|
58
|
-
if (state.cursor.kind !== 'fold') {
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
const node = NavigationNode.getNodeAtPath(
|
|
62
|
-
navigation,
|
|
63
|
-
state.cursor.parentPath,
|
|
64
|
-
);
|
|
65
|
-
if (node === undefined || node.foldedEntries.length === 0) {
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
const firstFoldedEntry = node.foldedEntries[0];
|
|
69
|
-
return {
|
|
70
|
-
kind: 'unfold',
|
|
71
|
-
parentPath: state.cursor.parentPath,
|
|
72
|
-
cursor: {
|
|
73
|
-
kind: 'entry',
|
|
74
|
-
parentPath: state.cursor.parentPath,
|
|
75
|
-
entryName: firstFoldedEntry.name,
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
case 'toggleFold':
|
|
80
|
-
return effectToAction(
|
|
81
|
-
state.cursor.kind === 'fold'
|
|
82
|
-
? { effectActionType: 'unfold' }
|
|
83
|
-
: { effectActionType: 'fold' },
|
|
84
|
-
navigation,
|
|
85
|
-
state,
|
|
86
|
-
);
|
|
87
|
-
}
|
|
82
|
+
return effectToAction;
|
|
88
83
|
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { Cursor,
|
|
2
|
-
export type ReducerAction =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//# sourceMappingURL=reducer-action.d.ts.map
|
|
1
|
+
import type { Cursor, SerializableKey, State, TreeNode } from 'dirvi-lib';
|
|
2
|
+
export type ReducerAction<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = {
|
|
3
|
+
kind: 'changeCursor';
|
|
4
|
+
cursor: Cursor<Id>;
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'updateBranch';
|
|
7
|
+
path: Id[];
|
|
8
|
+
entries: BufferNode[] | null;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'setState';
|
|
11
|
+
oldState: State<Id, BufferNode>;
|
|
12
|
+
newState: State<Id, BufferNode>;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'fold';
|
|
15
|
+
parentPath: Id[];
|
|
16
|
+
entry: BufferNode;
|
|
17
|
+
cursor: Cursor<Id>;
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'unfold';
|
|
20
|
+
parentPath: Id[];
|
|
21
|
+
cursor: Cursor<Id>;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=reducer-action.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reducer-action.d.ts","sourceRoot":"","sources":["../../src/application/reducer-action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"reducer-action.d.ts","sourceRoot":"","sources":["../../src/application/reducer-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1E,MAAM,MAAM,aAAa,CACvB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,IAEzC;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;CACpB,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;CAC9B,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAChC,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;CACjC,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,EAAE,EAAE,CAAC;IACjB,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;CACpB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,EAAE,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;CACpB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { State } from 'dirvi-lib';
|
|
1
|
+
import { FoldNodeService, SerializableKey, State, TreeNode, TreeNodeApi } from 'dirvi-lib';
|
|
2
2
|
import { ReducerAction } from './reducer-action.js';
|
|
3
|
-
export
|
|
4
|
-
|
|
3
|
+
export type Reducer<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = (state: State<Id, BufferNode>, action: ReducerAction<Id, BufferNode>) => State<Id, BufferNode>;
|
|
4
|
+
export declare function createReducer<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(treeNodeApi: TreeNodeApi<Id, BufferNode>, foldNodeService: FoldNodeService<Id>): Reducer<Id, BufferNode>;
|
|
5
|
+
//# sourceMappingURL=reducer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../src/application/reducer.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../src/application/reducer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,eAAe,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,MAAM,OAAO,CACjB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,IACzC,CACF,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,EAC5B,MAAM,EAAE,aAAa,CAAC,EAAE,EAAE,UAAU,CAAC,KAClC,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;AAE3B,wBAAgB,aAAa,CAC3B,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,EAE3C,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,EACxC,eAAe,EAAE,eAAe,CAAC,EAAE,CAAC,GACnC,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,CA0FzB"}
|
|
@@ -1,43 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
export function createReducer(treeNodeApi, foldNodeService) {
|
|
2
|
+
return (state, action) => {
|
|
3
|
+
switch (action.kind) {
|
|
4
|
+
case 'changeCursor':
|
|
5
|
+
return {
|
|
6
|
+
...state,
|
|
7
|
+
cursor: action.cursor,
|
|
8
|
+
};
|
|
9
|
+
case 'updateBranch':
|
|
10
|
+
const buffer = treeNodeApi.modifyAtPath(state.buffer, action.path, (node) => {
|
|
11
|
+
// A branch update cannot turn a leaf into a branch.
|
|
12
|
+
if (!treeNodeApi.isBranch(node)) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
...node,
|
|
17
|
+
children: action.entries,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
if (buffer === undefined) {
|
|
21
|
+
return state;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
...state,
|
|
25
|
+
buffer,
|
|
26
|
+
};
|
|
27
|
+
case 'setState': {
|
|
28
|
+
// A newer update has already been applied.
|
|
29
|
+
if (state !== action.oldState) {
|
|
30
|
+
return state;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
...action.newState,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
case 'fold': {
|
|
37
|
+
const foldNode = foldNodeService.addFoldedEntryAtPath(state.foldNode, action.parentPath, action.entry.id);
|
|
38
|
+
/*
|
|
39
|
+
* addFoldedEntryAtPath creates missing fold paths, so this should
|
|
40
|
+
* normally never be undefined. Preserve the existing state if it is.
|
|
41
|
+
*/
|
|
42
|
+
if (foldNode === undefined) {
|
|
43
|
+
return state;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
...state,
|
|
47
|
+
foldNode,
|
|
48
|
+
cursor: action.cursor,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
case 'unfold': {
|
|
52
|
+
const foldNode = foldNodeService.clearFoldedEntriesAtPath(state.foldNode, action.parentPath);
|
|
53
|
+
/*
|
|
54
|
+
* Unlike adding a fold, clearing only operates on an existing path.
|
|
55
|
+
* An undefined result means that the fold path no longer exists.
|
|
56
|
+
*/
|
|
57
|
+
if (foldNode === undefined) {
|
|
58
|
+
return state;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
...state,
|
|
62
|
+
foldNode,
|
|
63
|
+
cursor: action.cursor,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
43
68
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { CursorApi, FoldNodeApi, FoldNodeService, NavNodeApi, SerializableKey, StateApi, TreeNode, TreeNodeApi } from 'dirvi-lib';
|
|
2
|
+
export type AppApi<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = {
|
|
3
|
+
/**
|
|
4
|
+
* Name displayed to distinguish apps.
|
|
5
|
+
*/
|
|
6
|
+
name: string;
|
|
7
|
+
/**
|
|
8
|
+
* Message displayed when the entries are empty and there is nothing
|
|
9
|
+
* to display.
|
|
10
|
+
*/
|
|
11
|
+
emptyForestMessage: string;
|
|
12
|
+
/**
|
|
13
|
+
* Loads the children of the branch at `path`.
|
|
14
|
+
*
|
|
15
|
+
* The empty path represents the root branch.
|
|
16
|
+
*/
|
|
17
|
+
loadBranches: (path: Id[]) => Promise<BufferNode[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Subscribes to external data changes that require the tree state
|
|
20
|
+
* to be loaded again.
|
|
21
|
+
*
|
|
22
|
+
* Returns an unsubscribe function.
|
|
23
|
+
*/
|
|
24
|
+
subscribeToResync: (listener: () => void) => () => void;
|
|
25
|
+
treeNodeApi: TreeNodeApi<Id, BufferNode>;
|
|
26
|
+
/**
|
|
27
|
+
* Structural fold-tree traversal and immutable path updates.
|
|
28
|
+
*/
|
|
29
|
+
foldNodeApi: FoldNodeApi<Id>;
|
|
30
|
+
/**
|
|
31
|
+
* Semantic fold operations, including creating an empty fold root and
|
|
32
|
+
* adding, removing, or clearing folded entry names.
|
|
33
|
+
*/
|
|
34
|
+
foldNodeService: FoldNodeService<Id>;
|
|
35
|
+
cursorApi: CursorApi<Id>;
|
|
36
|
+
stateApi: StateApi<Id, BufferNode>;
|
|
37
|
+
navNodeApi: NavNodeApi<Id, BufferNode>;
|
|
38
|
+
};
|
|
39
|
+
export declare function createAppApis<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(): {
|
|
40
|
+
treeNodeApi: TreeNodeApi<Id, BufferNode>;
|
|
41
|
+
foldNodeApi: FoldNodeApi<Id>;
|
|
42
|
+
foldNodeService: FoldNodeService<Id>;
|
|
43
|
+
cursorApi: CursorApi<Id>;
|
|
44
|
+
stateApi: StateApi<Id, BufferNode>;
|
|
45
|
+
navNodeApi: NavNodeApi<Id, BufferNode>;
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=app-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-api.d.ts","sourceRoot":"","sources":["../../src/domain/app-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,SAAS,EACT,WAAW,EACX,eAAe,EACf,UAAU,EAAE,eAAe,EAC3B,QAAQ,EACR,QAAQ,EACR,WAAW,EACZ,MAAM,WAAW,CAAC;AAEnB,MAAM,MAAM,MAAM,CAChB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,IACzC;IACF;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAE3B;;;;OAIG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAEpD;;;;;OAKG;IACH,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAExD,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAEzC;;OAEG;IACH,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IAE7B;;;OAGG;IACH,eAAe,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC;IAErC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IAEzB,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAEnC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;CACxC,CAAC;AAEF,wBAAgB,aAAa,CAC3B,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,KACxC;IACH,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IACzC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,eAAe,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC;IACrC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IACnC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;CACxC,CAkCA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createCursorApi, createFoldNodeApi, createFoldNodeService, createNavNodeApi, createStateApi, createTreeNodeApi, } from 'dirvi-lib';
|
|
2
|
+
export function createAppApis() {
|
|
3
|
+
const treeNodeApi = createTreeNodeApi();
|
|
4
|
+
const foldNodeApi = createFoldNodeApi();
|
|
5
|
+
const foldNodeService = createFoldNodeService(foldNodeApi, (id) => ({
|
|
6
|
+
id,
|
|
7
|
+
children: [],
|
|
8
|
+
folds: new Set(),
|
|
9
|
+
}));
|
|
10
|
+
const cursorApi = createCursorApi();
|
|
11
|
+
const navNodeApi = createNavNodeApi(treeNodeApi, foldNodeApi, cursorApi);
|
|
12
|
+
const stateApi = createStateApi(treeNodeApi, foldNodeApi, cursorApi, navNodeApi);
|
|
13
|
+
return {
|
|
14
|
+
treeNodeApi,
|
|
15
|
+
foldNodeApi,
|
|
16
|
+
foldNodeService,
|
|
17
|
+
cursorApi,
|
|
18
|
+
stateApi,
|
|
19
|
+
navNodeApi,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export type EventMessage =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
path: UnixEntryPath;
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=event-message.d.ts.map
|
|
1
|
+
import { SerializableKey, State, TreeNode } from 'dirvi-lib';
|
|
2
|
+
export type EventMessage<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>> = {
|
|
3
|
+
type: 'view';
|
|
4
|
+
view: State<Id, BufferNode>;
|
|
5
|
+
} | {
|
|
6
|
+
type: 'displayed-leaves-paths';
|
|
7
|
+
paths: Id[][];
|
|
8
|
+
} | {
|
|
9
|
+
type: 'file';
|
|
10
|
+
path: Id[];
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=event-message.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-message.d.ts","sourceRoot":"","sources":["../../src/domain/event-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"event-message.d.ts","sourceRoot":"","sources":["../../src/domain/event-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE7D,MAAM,MAAM,YAAY,CACtB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,IAEzC;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;CAC7B,GACD;IACE,IAAI,EAAE,wBAAwB,CAAC;IAC/B,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC;CACf,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,EAAE,EAAE,CAAC;CACZ,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,76 +1,74 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { jsx as _jsx } from
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { render } from 'ink';
|
|
5
5
|
import { AppShell } from './ui/AppShell.js';
|
|
6
|
-
import { loadInitialProps } from './infrastructure/load-initial-props.js';
|
|
7
6
|
const program = new Command();
|
|
8
7
|
// ---*--- TERMINAL ALTERNATE SCREEN ---*---
|
|
9
|
-
// Restore the terminal
|
|
10
|
-
// last-resort fallback
|
|
8
|
+
// Restore the terminal away from alternate screen
|
|
9
|
+
// during normal cleanup and as a last-resort fallback
|
|
10
|
+
// when Node is exiting.
|
|
11
11
|
// Write UI to stderr
|
|
12
12
|
const uiOutput = process.stderr;
|
|
13
|
-
//
|
|
14
|
-
// separate JSON Lines message.
|
|
13
|
+
// The newline makes each message a separate JSON Lines message.
|
|
15
14
|
// Note: if you pipe output you'll need to use FORCE_COLOR=3
|
|
16
15
|
// to keep interactive screen colored.
|
|
17
|
-
const
|
|
18
|
-
|
|
16
|
+
const emitStdoutMsg = (message) => {
|
|
17
|
+
process.stdout.write(message);
|
|
19
18
|
};
|
|
20
19
|
const enterAlternateScreen = '\u001b[?1049h\u001b[2J\u001b[H\u001b[?25l';
|
|
21
20
|
const leaveAlternateScreen = '\u001b[?25h\u001b[?1049l';
|
|
22
21
|
// Idempotent terminal restoration
|
|
23
22
|
let alternateScreenActive = false;
|
|
24
23
|
const restoreTerminal = () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
if (!alternateScreenActive) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
uiOutput.write(leaveAlternateScreen);
|
|
28
|
+
alternateScreenActive = false;
|
|
30
29
|
};
|
|
31
30
|
// Node exit last resort
|
|
32
31
|
process.on('exit', restoreTerminal);
|
|
33
32
|
// ---*--- COMPOSITION ---*---
|
|
34
33
|
program
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
.name('direx')
|
|
35
|
+
.description('View and manage directories.')
|
|
36
|
+
.version('0.4.0')
|
|
37
|
+
.helpOption('--help')
|
|
38
|
+
.option('-d, --directory <path>', 'Directory to browse')
|
|
39
|
+
.action(async () => {
|
|
40
|
+
const options = program.opts();
|
|
41
41
|
let appError;
|
|
42
42
|
const useAlternateScreen = uiOutput.isTTY === true;
|
|
43
|
+
const stdoutIsInteractive = process.stdout.isTTY === true;
|
|
43
44
|
if (useAlternateScreen) {
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
uiOutput.write(enterAlternateScreen);
|
|
46
|
+
alternateScreenActive = true;
|
|
46
47
|
}
|
|
47
48
|
try {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// Errors thrown while leaving this await still execute the finally block.
|
|
59
|
-
await app.waitUntilExit();
|
|
60
|
-
} finally {
|
|
61
|
-
restoreTerminal(); // Always restore terminal regardless of error
|
|
49
|
+
const app = render(_jsx(AppShell, { ...(options.directory === undefined
|
|
50
|
+
? {}
|
|
51
|
+
: { directory: options.directory }), ...(stdoutIsInteractive ? {} : { print: emitStdoutMsg }), onError: (error) => {
|
|
52
|
+
appError = error;
|
|
53
|
+
} }), { stdout: uiOutput });
|
|
54
|
+
// Errors thrown while leaving this await still execute the finally block.
|
|
55
|
+
await app.waitUntilExit();
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
restoreTerminal(); // Always restore terminal regardless of error
|
|
62
59
|
}
|
|
63
60
|
// Re-throw an error reported by AppShell after the terminal
|
|
64
61
|
// has been restored, so the outer catch can format it.
|
|
65
62
|
if (appError !== undefined) {
|
|
66
|
-
|
|
63
|
+
throw appError;
|
|
67
64
|
}
|
|
68
|
-
|
|
65
|
+
});
|
|
69
66
|
// ---*--- RUN AND HANDLE ERROR ---*---
|
|
70
67
|
try {
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
await program.parseAsync(process.argv);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
process.stderr.write(`direx: ${message}\n`);
|
|
73
|
+
process.exitCode = 1;
|
|
76
74
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-dir-entries.d.ts","sourceRoot":"","sources":["../../src/infrastructure/get-dir-entries.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG7D,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyCtB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readdir, readlink } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { UnixPathSchema, PosixNameSchema } from 'dirvi-lib';
|
|
4
|
+
export async function getDirEntries(address) {
|
|
5
|
+
const directoryEntries = await readdir(address, {
|
|
6
|
+
withFileTypes: true,
|
|
7
|
+
});
|
|
8
|
+
return Promise.all(directoryEntries.map(async (directoryEntry) => {
|
|
9
|
+
const id = PosixNameSchema.parse(directoryEntry.name);
|
|
10
|
+
if (directoryEntry.isSymbolicLink()) {
|
|
11
|
+
const target = UnixPathSchema.parse(await readlink(join(address, directoryEntry.name)));
|
|
12
|
+
return {
|
|
13
|
+
kind: 'symlink',
|
|
14
|
+
id,
|
|
15
|
+
target,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (directoryEntry.isDirectory()) {
|
|
19
|
+
return {
|
|
20
|
+
kind: 'directory',
|
|
21
|
+
id: id,
|
|
22
|
+
children: null, // Directory not expanded.
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (directoryEntry.isFile()) {
|
|
26
|
+
return {
|
|
27
|
+
kind: 'file',
|
|
28
|
+
id: id,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
throw new Error(`Unsupported filesystem entry "${join(address, directoryEntry.name)}"`);
|
|
32
|
+
}));
|
|
33
|
+
}
|