@mak-98/dirvi-cli 0.4.0 → 0.6.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.
Files changed (92) hide show
  1. package/dist/application/effect-to-action.d.ts +5 -7
  2. package/dist/application/effect-to-action.d.ts.map +1 -1
  3. package/dist/application/effect-to-action.js +83 -86
  4. package/dist/application/reducer-action.d.ts +23 -23
  5. package/dist/application/reducer-action.d.ts.map +1 -1
  6. package/dist/application/reducer.d.ts +4 -3
  7. package/dist/application/reducer.d.ts.map +1 -1
  8. package/dist/application/reducer.js +67 -42
  9. package/dist/domain/app-api.d.ts +47 -0
  10. package/dist/domain/app-api.d.ts.map +1 -0
  11. package/dist/domain/app-api.js +21 -0
  12. package/dist/domain/event-message.d.ts +12 -15
  13. package/dist/domain/event-message.d.ts.map +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +56 -45
  16. package/dist/infrastructure/get-dir-entries.d.ts +3 -0
  17. package/dist/infrastructure/get-dir-entries.d.ts.map +1 -0
  18. package/dist/infrastructure/get-dir-entries.js +33 -0
  19. package/dist/infrastructure/get-dir-lazy-entries.d.ts +3 -0
  20. package/dist/infrastructure/get-dir-lazy-entries.d.ts.map +1 -0
  21. package/dist/infrastructure/get-dir-lazy-entries.js +33 -0
  22. package/dist/infrastructure/get-unix-abs-path.d.ts +3 -0
  23. package/dist/infrastructure/get-unix-abs-path.d.ts.map +1 -0
  24. package/dist/infrastructure/get-unix-abs-path.js +14 -0
  25. package/dist/infrastructure/ink-input-to-user-input.d.ts +2 -5
  26. package/dist/infrastructure/ink-input-to-user-input.js +42 -42
  27. package/dist/infrastructure/load-posix-app-api.d.ts +4 -0
  28. package/dist/infrastructure/load-posix-app-api.d.ts.map +1 -0
  29. package/dist/infrastructure/load-posix-app-api.js +82 -0
  30. package/dist/ui/App.d.ts +16 -15
  31. package/dist/ui/App.d.ts.map +1 -1
  32. package/dist/ui/App.js +124 -129
  33. package/dist/ui/AppShell.d.ts +6 -16
  34. package/dist/ui/AppShell.d.ts.map +1 -1
  35. package/dist/ui/AppShell.js +10 -13
  36. package/dist/ui/LoadingApp.d.ts +11 -0
  37. package/dist/ui/LoadingApp.d.ts.map +1 -0
  38. package/dist/ui/LoadingApp.js +67 -0
  39. package/dist/ui/components/StatusBar.d.ts +3 -5
  40. package/dist/ui/components/StatusBar.d.ts.map +1 -1
  41. package/dist/ui/components/StatusBar.js +3 -28
  42. package/dist/ui/components/ViewRowComponent.d.ts +4 -6
  43. package/dist/ui/components/ViewRowComponent.js +10 -30
  44. package/dist/ui/hooks/useView.d.ts +4 -7
  45. package/dist/ui/hooks/useView.d.ts.map +1 -1
  46. package/dist/ui/hooks/useView.js +20 -29
  47. package/dist/ui/view.d.ts +13 -17
  48. package/dist/ui/view.d.ts.map +1 -1
  49. package/dist/ui/view.js +84 -64
  50. package/package.json +2 -2
  51. package/dist/application/action.d.ts +0 -26
  52. package/dist/application/action.d.ts.map +0 -1
  53. package/dist/application/action.js +0 -1
  54. package/dist/application/dir-buffer-helpers.d.ts +0 -6
  55. package/dist/application/dir-buffer-helpers.d.ts.map +0 -1
  56. package/dist/application/dir-buffer-helpers.js +0 -21
  57. package/dist/application/display-rows.d.ts +0 -11
  58. package/dist/application/display-rows.d.ts.map +0 -1
  59. package/dist/application/display-rows.js +0 -63
  60. package/dist/application/fold-helpers.d.ts +0 -24
  61. package/dist/application/fold-helpers.d.ts.map +0 -1
  62. package/dist/application/fold-helpers.js +0 -47
  63. package/dist/application/intent-to-effect.d.ts +0 -59
  64. package/dist/application/intent-to-effect.d.ts.map +0 -1
  65. package/dist/application/intent-to-effect.js +0 -131
  66. package/dist/application/user-input-to-intent.d.ts +0 -39
  67. package/dist/application/user-input-to-intent.d.ts.map +0 -1
  68. package/dist/application/user-input-to-intent.js +0 -110
  69. package/dist/domain/print-message.d.ts +0 -11
  70. package/dist/domain/print-message.d.ts.map +0 -1
  71. package/dist/domain/print-message.js +0 -1
  72. package/dist/infrastructure/input.d.ts +0 -12
  73. package/dist/infrastructure/input.d.ts.map +0 -1
  74. package/dist/infrastructure/input.js +0 -81
  75. package/dist/infrastructure/load-initial-props.d.ts +0 -3
  76. package/dist/infrastructure/load-initial-props.d.ts.map +0 -1
  77. package/dist/infrastructure/load-initial-props.js +0 -36
  78. package/dist/infrastructure/user-input.d.ts +0 -32
  79. package/dist/infrastructure/user-input.d.ts.map +0 -1
  80. package/dist/infrastructure/user-input.js +0 -45
  81. package/dist/ui/App2.d.ts +0 -16
  82. package/dist/ui/App2.d.ts.map +0 -1
  83. package/dist/ui/App2.js +0 -107
  84. package/dist/ui/components/DirEntries.d.ts +0 -11
  85. package/dist/ui/components/DirEntries.d.ts.map +0 -1
  86. package/dist/ui/components/DirEntries.js +0 -64
  87. package/dist/ui/components/UnixEntry.d.ts +0 -9
  88. package/dist/ui/components/UnixEntry.d.ts.map +0 -1
  89. package/dist/ui/components/UnixEntry.js +0 -19
  90. package/dist/ui/components/UnixEntryComponent.d.ts +0 -9
  91. package/dist/ui/components/UnixEntryComponent.d.ts.map +0 -1
  92. 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
- export declare function effectToAction(
4
- effectAction: EffectAction,
5
- navigation: NavigationNode,
6
- state: State,
7
- ): ReducerAction | undefined;
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":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,wBAAgB,cAAc,CAC5B,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,cAAc,EAC1B,KAAK,EAAE,KAAK,GACX,aAAa,GAAG,SAAS,CAwG3B"}
1
+ {"version":3,"file":"effect-to-action.d.ts","sourceRoot":"","sources":["../../src/application/effect-to-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,eAAe,EACf,QAAQ,EACR,WAAW,EACZ,MAAM,yDAAyD,CAAC;AACjE,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,CA+GhC"}
@@ -1,88 +1,85 @@
1
- import { NavigationNode } from 'dirvi-lib';
2
- export function effectToAction(effectAction, navigation, state) {
3
- switch (effectAction.effectActionType) {
4
- case 'nextEntry': {
5
- const cursor = NavigationNode.nextCursor(navigation, state.cursor);
6
- return cursor === undefined
7
- ? undefined
8
- : {
9
- kind: 'changeCursor',
10
- cursor,
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, [
62
+ ...state.cursor.parentPath,
63
+ ]);
64
+ if (node === undefined || node.foldedEntries.length === 0) {
65
+ return undefined;
66
+ }
67
+ const firstFoldedEntry = node.foldedEntries[0];
68
+ return {
69
+ kind: 'unfold',
70
+ parentPath: [...state.cursor.parentPath],
71
+ cursor: {
72
+ kind: 'entry',
73
+ parentPath: state.cursor.parentPath,
74
+ entryId: firstFoldedEntry.id,
75
+ },
76
+ };
77
+ }
78
+ case 'toggleFold':
79
+ return effectToAction(state.cursor.kind === 'fold'
80
+ ? { effectActionType: 'unfold' }
81
+ : { effectActionType: 'fold' }, navigation, state);
82
+ }
12
83
  }
13
- case 'prevEntry': {
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
- }
84
+ return effectToAction;
88
85
  }
@@ -1,23 +1,23 @@
1
- import { Cursor, UnixEntry, UnixEntryPath } from 'dirvi-lib';
2
- export type ReducerAction =
3
- | {
4
- kind: 'changeCursor';
5
- cursor: Cursor;
6
- }
7
- | {
8
- kind: 'updateDir';
9
- path: UnixEntryPath;
10
- entries: UnixEntry[] | undefined;
11
- }
12
- | {
13
- kind: 'fold';
14
- parentPath: UnixEntryPath;
15
- entry: UnixEntry;
16
- cursor: Cursor;
17
- }
18
- | {
19
- kind: 'unfold';
20
- parentPath: UnixEntryPath;
21
- cursor: Cursor;
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,SAAS,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE7D,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;CAClC,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,aAAa,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,aAAa,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC"}
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 declare function reducer(state: State, action: ReducerAction): State;
4
- //# sourceMappingURL=reducer.d.ts.map
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,EAAa,KAAK,EAAY,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,GAAG,KAAK,CA8ClE"}
1
+ {"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../src/application/reducer.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,eAAe,EACf,KAAK,EACL,QAAQ,EACR,WAAW,EACZ,MAAM,WAAW,CAAC;AACnB,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
- import { UnixEntry, FoldNode } from 'dirvi-lib';
2
- export function reducer(state, action) {
3
- switch (action.kind) {
4
- case 'changeCursor':
5
- return {
6
- ...state,
7
- cursor: action.cursor,
8
- };
9
- case 'updateDir':
10
- return {
11
- ...state,
12
- buffer: UnixEntry.setEntriesAtPath(
13
- state.buffer,
14
- action.path,
15
- action.entries,
16
- ),
17
- };
18
- case 'fold': {
19
- const folds = FoldNode.addFoldedEntryAtPath(
20
- state.folds,
21
- action.parentPath,
22
- action.entry,
23
- );
24
- return {
25
- ...state,
26
- folds,
27
- cursor: action.cursor,
28
- };
29
- }
30
- case 'unfold': {
31
- const folds = FoldNode.modifyAtPath(
32
- state.folds,
33
- action.parentPath,
34
- (node) => FoldNode.clearFoldedEntries(node),
35
- );
36
- return {
37
- ...state,
38
- folds,
39
- cursor: action.cursor,
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,EACV,eAAe,EACf,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 { UnixEntryPath, State } from 'dirvi-lib';
2
- export type EventMessage =
3
- | {
4
- type: 'view';
5
- view: State;
6
- }
7
- | {
8
- type: 'displayed-files-paths';
9
- paths: string[];
10
- }
11
- | {
12
- type: 'file';
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,aAAa,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,MAAM,YAAY,GACpB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,CAAC;CACb,GACD;IACE,IAAI,EAAE,uBAAuB,CAAC;IAC9B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;CACrB,CAAC"}
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
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
- //# sourceMappingURL=index.d.ts.map
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,76 +1,87 @@
1
1
  #!/usr/bin/env node
2
- import { jsx as _jsx } from 'react/jsx-runtime';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { spawn } from 'node:child_process';
3
4
  import { Command } from 'commander';
4
5
  import { render } from 'ink';
5
6
  import { AppShell } from './ui/AppShell.js';
6
- import { loadInitialProps } from './infrastructure/load-initial-props.js';
7
7
  const program = new Command();
8
8
  // ---*--- TERMINAL ALTERNATE SCREEN ---*---
9
- // Restore the terminal during normal cleanup and as a
10
- // last-resort fallback when Node is exiting.
9
+ // Restore the terminal away from alternate screen
10
+ // during normal cleanup and as a last-resort fallback
11
+ // when Node is exiting.
11
12
  // Write UI to stderr
12
13
  const uiOutput = process.stderr;
13
- // Write Views to stdout. The newline makes each update a
14
- // separate JSON Lines message.
15
- // Note: if you pipe output you'll need to use FORCE_COLOR=3
16
- // to keep interactive screen colored.
17
- const emitEventMsg = (message) => {
18
- process.stdout.write(`${JSON.stringify(message)}\n`);
19
- };
20
14
  const enterAlternateScreen = '\u001b[?1049h\u001b[2J\u001b[H\u001b[?25l';
21
15
  const leaveAlternateScreen = '\u001b[?25h\u001b[?1049l';
22
16
  // Idempotent terminal restoration
23
17
  let alternateScreenActive = false;
24
18
  const restoreTerminal = () => {
25
- if (!alternateScreenActive) {
26
- return;
27
- }
28
- uiOutput.write(leaveAlternateScreen);
29
- alternateScreenActive = false;
19
+ if (!alternateScreenActive) {
20
+ return;
21
+ }
22
+ uiOutput.write(leaveAlternateScreen);
23
+ alternateScreenActive = false;
30
24
  };
31
25
  // Node exit last resort
32
26
  process.on('exit', restoreTerminal);
33
27
  // ---*--- COMPOSITION ---*---
34
28
  program
35
- .name('direx')
36
- .description('View and manage directories.')
37
- .version('0.3.2')
38
- .helpOption('--help')
39
- .action(async () => {
40
- const initialProps = await loadInitialProps();
29
+ .name('direx')
30
+ .description('View and manage directories.')
31
+ .version('0.5.1')
32
+ .helpOption('--help')
33
+ .option('-d, --directory <path>', 'Directory to browse')
34
+ .action(async () => {
35
+ const options = program.opts();
41
36
  let appError;
42
37
  const useAlternateScreen = uiOutput.isTTY === true;
38
+ const stdoutIsInteractive = process.stdout.isTTY === true;
43
39
  if (useAlternateScreen) {
44
- uiOutput.write(enterAlternateScreen);
45
- alternateScreenActive = true;
40
+ uiOutput.write(enterAlternateScreen);
41
+ alternateScreenActive = true;
46
42
  }
43
+ const stdout = (message) => {
44
+ // The newline makes each message a separate JSON Lines message.
45
+ // Note: if you pipe output you'll need to use FORCE_COLOR=3
46
+ // to keep interactive screen colored.
47
+ process.stdout.write(`${message}\n`);
48
+ };
49
+ const clipboard = (value) => {
50
+ if (process.platform !== 'darwin') {
51
+ return;
52
+ }
53
+ const child = spawn('pbcopy');
54
+ child.once('error', (error) => {
55
+ process.stderr.write(`direx: unable to copy to clipboard: ${error.message}\n`);
56
+ });
57
+ child.stdin.end(value);
58
+ };
47
59
  try {
48
- const app = render(
49
- _jsx(AppShell, {
50
- ...initialProps,
51
- print: process.stdout.isTTY ? undefined : emitEventMsg,
52
- onError: (error) => {
53
- appError = error;
54
- },
55
- }),
56
- { stdout: uiOutput },
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
60
+ const app = render(_jsx(AppShell, { ...(options.directory === undefined
61
+ ? {}
62
+ : { directory: options.directory }), ...(stdoutIsInteractive
63
+ ? {}
64
+ : { stdout }), clipboard: clipboard, onError: (error) => {
65
+ appError = error;
66
+ } }), { stdout: uiOutput });
67
+ // Errors thrown while leaving this await still execute the finally block.
68
+ await app.waitUntilExit();
69
+ }
70
+ finally {
71
+ restoreTerminal(); // Always restore terminal regardless of error
62
72
  }
63
73
  // Re-throw an error reported by AppShell after the terminal
64
74
  // has been restored, so the outer catch can format it.
65
75
  if (appError !== undefined) {
66
- throw appError;
76
+ throw appError;
67
77
  }
68
- });
78
+ });
69
79
  // ---*--- RUN AND HANDLE ERROR ---*---
70
80
  try {
71
- await program.parseAsync(process.argv);
72
- } catch (error) {
73
- const message = error instanceof Error ? error.message : String(error);
74
- process.stderr.write(`direx: ${message}\n`);
75
- process.exitCode = 1;
81
+ await program.parseAsync(process.argv);
82
+ }
83
+ catch (error) {
84
+ const message = error instanceof Error ? error.message : String(error);
85
+ process.stderr.write(`direx: ${message}\n`);
86
+ process.exitCode = 1;
76
87
  }
@@ -0,0 +1,3 @@
1
+ import type { UnixAbsolutePath, PosixNode } from 'dirvi-lib';
2
+ export declare function getDirEntries(address: UnixAbsolutePath): Promise<PosixNode[]>;
3
+ //# sourceMappingURL=get-dir-entries.d.ts.map
@@ -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"}