@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoadingApp.d.ts","sourceRoot":"","sources":["../../src/ui/LoadingApp.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAwB,eAAe,EAAS,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAI9C,KAAK,eAAe,CAClB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,IACzC;IACF,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,UAAU,CAAC,KAAK,IAAI,CAAC;IACxD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,CAAC;AA0BF,wBAAgB,UAAU,CACxB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,EAC3C,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,eAAe,CAAC,EAAE,EAAE,UAAU,CAAC,+BA+F5D"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from 'ink';
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { createIntentToEffect } from 'dirvi-lib';
|
|
5
|
+
import { App } from './App.js';
|
|
6
|
+
import { createReducer } from '../application/reducer.js';
|
|
7
|
+
import { createEffectToAction } from '../application/effect-to-action.js';
|
|
8
|
+
function createInitialState(rootBranches, createEmptyFoldRoot) {
|
|
9
|
+
if (rootBranches.length === 0) {
|
|
10
|
+
throw new Error('createInitialState cannot create a state for an empty forest');
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
buffer: rootBranches,
|
|
14
|
+
foldNode: createEmptyFoldRoot(),
|
|
15
|
+
cursor: {
|
|
16
|
+
kind: 'entry',
|
|
17
|
+
parentPath: [],
|
|
18
|
+
entryId: rootBranches[0].id,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function LoadingApp({ appApi, print, onError }) {
|
|
23
|
+
const [initialState, setInitialState] = useState();
|
|
24
|
+
const [empty, setEmpty] = useState(false);
|
|
25
|
+
const [error, setError] = useState();
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
let mounted = true;
|
|
28
|
+
appApi
|
|
29
|
+
.loadBranches([])
|
|
30
|
+
.then((rootBranches) => {
|
|
31
|
+
if (!mounted) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (rootBranches.length === 0) {
|
|
35
|
+
setEmpty(true);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
setInitialState(createInitialState(rootBranches, () => appApi.foldNodeService.createEmptyRoot()));
|
|
39
|
+
})
|
|
40
|
+
.catch((cause) => {
|
|
41
|
+
const nextError = cause instanceof Error ? cause : new Error(String(cause));
|
|
42
|
+
if (!mounted) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
setError(nextError);
|
|
46
|
+
onError?.(nextError);
|
|
47
|
+
});
|
|
48
|
+
return () => {
|
|
49
|
+
mounted = false;
|
|
50
|
+
};
|
|
51
|
+
}, [appApi, onError]);
|
|
52
|
+
// --- Pure function deps ---
|
|
53
|
+
const reducer = useMemo(() => createReducer(appApi.treeNodeApi, appApi.foldNodeService), [appApi.treeNodeApi, appApi.foldNodeService]);
|
|
54
|
+
const intentToEffect = useMemo(() => createIntentToEffect(appApi.stateApi, appApi.cursorApi, appApi.treeNodeApi), [appApi.stateApi, appApi.cursorApi, appApi.treeNodeApi]);
|
|
55
|
+
const effectToAction = useMemo(() => createEffectToAction(appApi.treeNodeApi, appApi.cursorApi, appApi.navNodeApi), [appApi.treeNodeApi, appApi.navNodeApi, appApi.cursorApi]);
|
|
56
|
+
// --- JSX ---
|
|
57
|
+
if (error !== undefined) {
|
|
58
|
+
return _jsx(Text, { color: "red", children: error.message });
|
|
59
|
+
}
|
|
60
|
+
if (empty) {
|
|
61
|
+
return _jsx(Text, { dimColor: true, children: appApi.emptyForestMessage });
|
|
62
|
+
}
|
|
63
|
+
if (initialState === undefined) {
|
|
64
|
+
return _jsx(Text, { dimColor: true, children: "Loading." });
|
|
65
|
+
}
|
|
66
|
+
return (_jsx(App, { appApi: appApi, initialState: initialState, reducer: reducer, intentToEffect: intentToEffect, effectToAction: effectToAction, ...(print === undefined ? {} : { print }), ...(onError === undefined ? {} : { onError }) }));
|
|
67
|
+
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { InputState } from 'dirvi-lib';
|
|
2
2
|
export declare const STATUS_BAR_HEIGHT = 1;
|
|
3
3
|
type StatusBarProps = {
|
|
4
|
-
|
|
4
|
+
inputState: InputState;
|
|
5
5
|
};
|
|
6
|
-
export declare function StatusBar({
|
|
7
|
-
inputState,
|
|
8
|
-
}: StatusBarProps): import('react').JSX.Element;
|
|
6
|
+
export declare function StatusBar({ inputState }: StatusBarProps): import("react").JSX.Element;
|
|
9
7
|
export {};
|
|
10
|
-
//# sourceMappingURL=StatusBar.d.ts.map
|
|
8
|
+
//# sourceMappingURL=StatusBar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBar.d.ts","sourceRoot":"","sources":["../../../src/ui/components/StatusBar.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,KAAK,cAAc,GAAG;IACpB,UAAU,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"StatusBar.d.ts","sourceRoot":"","sources":["../../../src/ui/components/StatusBar.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,KAAK,cAAc,GAAG;IACpB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,UAAU,EAAE,EAAE,cAAc,+BAyBvD"}
|
|
@@ -1,32 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
export const STATUS_BAR_HEIGHT = 1;
|
|
4
4
|
export function StatusBar({ inputState }) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
width: '100%',
|
|
8
|
-
height: STATUS_BAR_HEIGHT,
|
|
9
|
-
flexDirection: 'row',
|
|
10
|
-
justifyContent: 'space-between',
|
|
11
|
-
flexShrink: 0,
|
|
12
|
-
backgroundColor: 'gray',
|
|
13
|
-
children: [
|
|
14
|
-
_jsx(Box, {
|
|
15
|
-
flexShrink: 1,
|
|
16
|
-
children: _jsx(Text, {
|
|
17
|
-
color: 'black',
|
|
18
|
-
wrap: 'truncate-end',
|
|
19
|
-
children: inputMode === 'command' ? inputState.commandLine : '',
|
|
20
|
-
}),
|
|
21
|
-
}),
|
|
22
|
-
_jsx(Box, {
|
|
23
|
-
flexShrink: 1,
|
|
24
|
-
children: _jsx(Text, {
|
|
25
|
-
color: 'black',
|
|
26
|
-
wrap: 'truncate-start',
|
|
27
|
-
children: inputMode === 'normal' ? inputState.normalBuffer : '',
|
|
28
|
-
}),
|
|
29
|
-
}),
|
|
30
|
-
],
|
|
31
|
-
});
|
|
5
|
+
const inputMode = inputState.inputMode;
|
|
6
|
+
return (_jsxs(Box, { width: "100%", height: STATUS_BAR_HEIGHT, flexDirection: "row", justifyContent: "space-between", flexShrink: 0, backgroundColor: 'gray', children: [_jsx(Box, { flexShrink: 1, children: _jsx(Text, { color: "black", wrap: "truncate-end", children: inputMode === 'command' ? inputState.commandLine : '' }) }), _jsx(Box, { flexShrink: 1, children: _jsx(Text, { color: "black", wrap: "truncate-start", children: inputMode === 'normal' ? inputState.normalBuffer : '' }) })] }));
|
|
32
7
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { ViewRow } from '../view.js';
|
|
2
|
-
export declare function ViewRowComponent({
|
|
3
|
-
|
|
4
|
-
}:
|
|
5
|
-
|
|
6
|
-
}): import('react').JSX.Element;
|
|
7
|
-
//# sourceMappingURL=ViewRowComponent.d.ts.map
|
|
2
|
+
export declare function ViewRowComponent({ row }: {
|
|
3
|
+
row: ViewRow;
|
|
4
|
+
}): import("react").JSX.Element;
|
|
5
|
+
//# sourceMappingURL=ViewRowComponent.d.ts.map
|
|
@@ -1,33 +1,13 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx } from
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
export function ViewRowComponent({ row }) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
});
|
|
14
|
-
case 'directory':
|
|
15
|
-
return _jsx(Box, {
|
|
16
|
-
paddingLeft: row.indent * 2,
|
|
17
|
-
children: _jsxs(Text, {
|
|
18
|
-
inverse: row.selected,
|
|
19
|
-
color: 'blue',
|
|
20
|
-
children: [prefix, row.content],
|
|
21
|
-
}),
|
|
22
|
-
});
|
|
23
|
-
case 'fold':
|
|
24
|
-
return _jsx(Box, {
|
|
25
|
-
paddingLeft: row.indent * 2,
|
|
26
|
-
children: _jsxs(Text, {
|
|
27
|
-
inverse: row.selected,
|
|
28
|
-
dimColor: true,
|
|
29
|
-
children: [prefix, row.content],
|
|
30
|
-
}),
|
|
31
|
-
});
|
|
32
|
-
}
|
|
4
|
+
const prefix = '';
|
|
5
|
+
switch (row.type) {
|
|
6
|
+
case 'leaf':
|
|
7
|
+
return (_jsx(Box, { paddingLeft: row.indent * 2, children: _jsxs(Text, { inverse: row.selected, children: [prefix, row.content] }) }));
|
|
8
|
+
case 'branch':
|
|
9
|
+
return (_jsx(Box, { paddingLeft: row.indent * 2, children: _jsxs(Text, { inverse: row.selected, color: "blue", children: [prefix, row.content] }) }));
|
|
10
|
+
case 'fold':
|
|
11
|
+
return (_jsx(Box, { paddingLeft: row.indent * 2, children: _jsxs(Text, { inverse: row.selected, dimColor: true, children: [prefix, row.content] }) }));
|
|
12
|
+
}
|
|
33
13
|
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CursorApi, NavNode, SerializableKey, State, TreeNode } from 'dirvi-lib';
|
|
2
2
|
import { View } from '../view.js';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
terminalRows: number,
|
|
7
|
-
): View;
|
|
8
|
-
//# sourceMappingURL=useView.d.ts.map
|
|
3
|
+
export type UseView = <Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(navigation: NavNode<Id, BufferNode>, state: State<Id, BufferNode>, terminalRows: number) => View;
|
|
4
|
+
export declare function useView<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(navigation: NavNode<Id, BufferNode>, state: State<Id, BufferNode>, cursorApi: CursorApi<Id>, terminalRows: number): View;
|
|
5
|
+
//# sourceMappingURL=useView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useView.d.ts","sourceRoot":"","sources":["../../../src/ui/hooks/useView.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"useView.d.ts","sourceRoot":"","sources":["../../../src/ui/hooks/useView.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,OAAO,EACP,eAAe,EACf,KAAK,EACL,QAAQ,EACT,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,IAAI,EAAW,MAAM,YAAY,CAAC;AAI3C,MAAM,MAAM,OAAO,GAAG,CACpB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,EAE3C,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,EACnC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,EAC5B,YAAY,EAAE,MAAM,KACjB,IAAI,CAAC;AAIV,wBAAgB,OAAO,CACrB,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,EAE3C,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,EACnC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,EAC5B,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,EACxB,YAAY,EAAE,MAAM,GACnB,IAAI,CAoBN"}
|
package/dist/ui/hooks/useView.js
CHANGED
|
@@ -3,36 +3,27 @@ import { useRef } from 'react';
|
|
|
3
3
|
import { STATUS_BAR_HEIGHT } from '../components/StatusBar.js';
|
|
4
4
|
// Hooks that keeps Ref of the viewport's start, and returns View sliced to
|
|
5
5
|
// only the rows that should be visible.
|
|
6
|
-
export function useView(navigation, state, terminalRows) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
viewportHeight,
|
|
13
|
-
viewportStartRef.current,
|
|
14
|
-
);
|
|
15
|
-
return View.create(
|
|
16
|
-
navigation,
|
|
17
|
-
state.cursor,
|
|
18
|
-
viewportHeight,
|
|
19
|
-
viewportStartRef.current,
|
|
20
|
-
);
|
|
6
|
+
export function useView(navigation, state, cursorApi, terminalRows) {
|
|
7
|
+
const viewportStartRef = useRef(0);
|
|
8
|
+
const viewportHeight = Math.max(1, terminalRows - STATUS_BAR_HEIGHT);
|
|
9
|
+
const rows = View.createRows(navigation, state.cursor, cursorApi);
|
|
10
|
+
viewportStartRef.current = viewportStart(rows, viewportHeight, viewportStartRef.current);
|
|
11
|
+
return View.create(navigation, state.cursor, cursorApi, viewportHeight, viewportStartRef.current);
|
|
21
12
|
}
|
|
22
13
|
function viewportStart(rows, viewportHeight, currentViewportStart) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
14
|
+
const scrollMargin = 3;
|
|
15
|
+
const cursorIndex = rows.findIndex((row) => row.cursor);
|
|
16
|
+
const maximumViewportStart = Math.max(0, rows.length - viewportHeight);
|
|
17
|
+
let viewportStart = currentViewportStart;
|
|
18
|
+
if (cursorIndex >= 0) {
|
|
19
|
+
const firstVisibleCursorIndex = viewportStart + scrollMargin;
|
|
20
|
+
const lastVisibleCursorIndex = viewportStart + viewportHeight - 1 - scrollMargin;
|
|
21
|
+
if (cursorIndex < firstVisibleCursorIndex) {
|
|
22
|
+
viewportStart = cursorIndex - scrollMargin;
|
|
23
|
+
}
|
|
24
|
+
else if (cursorIndex > lastVisibleCursorIndex) {
|
|
25
|
+
viewportStart = cursorIndex - viewportHeight + 1 + scrollMargin;
|
|
26
|
+
}
|
|
35
27
|
}
|
|
36
|
-
|
|
37
|
-
return Math.max(0, Math.min(viewportStart, maximumViewportStart));
|
|
28
|
+
return Math.max(0, Math.min(viewportStart, maximumViewportStart));
|
|
38
29
|
}
|
package/dist/ui/view.d.ts
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { CursorApi, SerializableKey, TreeNode } from 'dirvi-lib';
|
|
2
|
+
import { Cursor, NavNode } from 'dirvi-lib';
|
|
3
|
+
export type ViewRowType = 'leaf' | 'branch' | 'fold';
|
|
3
4
|
export type ViewRow = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
id: string;
|
|
6
|
+
indent: number;
|
|
7
|
+
selected: boolean;
|
|
8
|
+
cursor: boolean;
|
|
9
|
+
content: string;
|
|
10
|
+
type: ViewRowType;
|
|
10
11
|
};
|
|
11
12
|
export type View = {
|
|
12
|
-
|
|
13
|
+
rows: ViewRow[];
|
|
13
14
|
};
|
|
14
15
|
export declare const View: {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
navigation: NavigationNode,
|
|
18
|
-
cursor: Cursor,
|
|
19
|
-
viewportHeight: number,
|
|
20
|
-
viewportStart: number,
|
|
21
|
-
): View;
|
|
16
|
+
createRows<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(navigation: NavNode<Id, BufferNode>, cursor: Cursor<Id>, cursorApi: CursorApi<Id>): ViewRow[];
|
|
17
|
+
create<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(navigation: NavNode<Id, BufferNode>, cursor: Cursor<Id>, cursorApi: CursorApi<Id>, viewportHeight: number, viewportStart: number): View;
|
|
22
18
|
};
|
|
23
|
-
//# sourceMappingURL=view.d.ts.map
|
|
19
|
+
//# sourceMappingURL=view.d.ts.map
|
package/dist/ui/view.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/ui/view.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/ui/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,MAAM,EAAyB,OAAO,EAAE,MAAM,WAAW,CAAC;AAEnE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAMrD,MAAM,MAAM,OAAO,GAAG;IAEpB,EAAE,EAAE,MAAM,CAAC;IAGX,MAAM,EAAE,MAAM,CAAC;IAGf,QAAQ,EAAE,OAAO,CAAC;IAGlB,MAAM,EAAE,OAAO,CAAC;IAGhB,OAAO,EAAE,MAAM,CAAC;IAGhB,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,IAAI;eAEb,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,cAE/B,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,UAC3B,MAAM,CAAC,EAAE,CAAC,aACP,SAAS,CAAC,EAAE,CAAC,GACvB,OAAO,EAAE;WAKV,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,cAE/B,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,UAC3B,MAAM,CAAC,EAAE,CAAC,aACP,SAAS,CAAC,EAAE,CAAC,kBACR,MAAM,iBACP,MAAM,GACpB,IAAI;CAOR,CAAC"}
|
package/dist/ui/view.js
CHANGED
|
@@ -1,78 +1,98 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNavBranch } from 'dirvi-lib';
|
|
2
2
|
export const View = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
createRows(navigation, cursor, cursorApi) {
|
|
4
|
+
return viewRowsAtNode(navigation, [], cursor, cursorApi);
|
|
5
|
+
},
|
|
6
|
+
create(navigation, cursor, cursorApi, viewportHeight, viewportStart) {
|
|
7
|
+
const rows = View.createRows(navigation, cursor, cursorApi);
|
|
8
|
+
return {
|
|
9
|
+
rows: rows.slice(viewportStart, viewportStart + viewportHeight),
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
12
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Converts one NavNode and its descendants into display ViewRows.
|
|
15
|
+
*
|
|
16
|
+
* `node` is the directory currently being visited.
|
|
17
|
+
*
|
|
18
|
+
* `parentPath` is the path of that directory. For example:
|
|
19
|
+
*
|
|
20
|
+
* [] root directory
|
|
21
|
+
* ['src'] root/src
|
|
22
|
+
* ['src', 'lib'] root/src/lib
|
|
23
|
+
*
|
|
24
|
+
* The function uses a depth-first, pre-order traversal:
|
|
25
|
+
*
|
|
26
|
+
* 1. Add an entry's row.
|
|
27
|
+
* 2. If the entry is an opened branch, recursively add its children.
|
|
28
|
+
* 3. After all visible entries, add the directory's fold row.
|
|
29
|
+
*
|
|
30
|
+
* This ordering is what makes the flat row list visually represent a tree.
|
|
31
|
+
*/
|
|
32
|
+
function viewRowsAtNode(node, parentPath, cursor, cursorApi) {
|
|
33
|
+
const rows = [];
|
|
34
|
+
/*
|
|
35
|
+
* `node.entries` contains only the entries currently visible in this
|
|
36
|
+
* directory. Folded entries are kept separately in `node.foldedEntries`
|
|
37
|
+
* and are represented by one fold row added below.
|
|
38
|
+
*/
|
|
39
|
+
for (const entry of node.entries) {
|
|
40
|
+
const entryCursor = {
|
|
41
|
+
kind: 'entry',
|
|
42
|
+
parentPath,
|
|
43
|
+
entryId: entry.id,
|
|
44
|
+
};
|
|
45
|
+
// If cursor at entry, needs to be rendered differently
|
|
46
|
+
const isCursor = cursorApi.equal(cursor, entryCursor);
|
|
47
|
+
// Add entry before visiting branches
|
|
48
|
+
rows.push(viewRowForEntry(entry, parentPath, isCursor));
|
|
49
|
+
// Case where there's no branches
|
|
50
|
+
if (!isNavBranch(entry) || entry.children === null) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
rows.push(...viewRowsAtNode(entry.children, [...parentPath, entry.id], cursor, cursorApi));
|
|
54
|
+
}
|
|
55
|
+
/*
|
|
56
|
+
* Folded entries are not rendered individually. They are represented
|
|
57
|
+
* by one synthetic row placed after all visible entries and descendants
|
|
58
|
+
* of this directory.
|
|
59
|
+
*/
|
|
60
|
+
if (node.foldedEntries.length > 0) {
|
|
61
|
+
const foldCursor = {
|
|
62
|
+
kind: 'fold',
|
|
63
|
+
parentPath,
|
|
64
|
+
};
|
|
65
|
+
const isCursor = cursorApi.equal(cursor, foldCursor);
|
|
66
|
+
rows.push({
|
|
67
|
+
id: foldId(parentPath),
|
|
68
|
+
indent: parentPath.length,
|
|
69
|
+
selected: isCursor,
|
|
70
|
+
cursor: isCursor,
|
|
71
|
+
content: `⋯ ${node.foldedEntries.length} folded`,
|
|
72
|
+
type: 'fold',
|
|
73
|
+
});
|
|
23
74
|
}
|
|
24
|
-
rows
|
|
25
|
-
...viewRowsAtNode(entry.node, [...parentPath, entry.name], cursor),
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
if (node.foldedEntries.length > 0) {
|
|
29
|
-
const isCursor =
|
|
30
|
-
cursor.kind === 'fold' &&
|
|
31
|
-
UnixEntryPath.equal(cursor.parentPath, parentPath);
|
|
32
|
-
rows.push({
|
|
33
|
-
id: foldId(parentPath),
|
|
34
|
-
indent: parentPath.length,
|
|
35
|
-
selected: isCursor,
|
|
36
|
-
cursor: isCursor,
|
|
37
|
-
content: `⋯ ${node.foldedEntries.length} folded`,
|
|
38
|
-
type: 'fold',
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
return rows;
|
|
75
|
+
return rows;
|
|
42
76
|
}
|
|
43
77
|
function viewRowForEntry(entry, parentPath, cursor) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
78
|
+
return {
|
|
79
|
+
id: entryId(parentPath, entry.id),
|
|
80
|
+
indent: parentPath.length,
|
|
81
|
+
selected: cursor,
|
|
82
|
+
cursor,
|
|
83
|
+
content: content(entry),
|
|
84
|
+
type: type(entry),
|
|
85
|
+
};
|
|
52
86
|
}
|
|
53
87
|
function entryId(parentPath, entryName) {
|
|
54
|
-
|
|
88
|
+
return `entry:${JSON.stringify([...parentPath, entryName])}`;
|
|
55
89
|
}
|
|
56
90
|
function foldId(parentPath) {
|
|
57
|
-
|
|
91
|
+
return `fold:${JSON.stringify(parentPath)}`;
|
|
58
92
|
}
|
|
59
93
|
function content(entry) {
|
|
60
|
-
|
|
61
|
-
case 'file':
|
|
62
|
-
return entry.name;
|
|
63
|
-
case 'directory':
|
|
64
|
-
return `${entry.name}/`;
|
|
65
|
-
case 'symlink':
|
|
66
|
-
return `${entry.name} -> ${entry.target}`;
|
|
67
|
-
}
|
|
94
|
+
return isNavBranch(entry) ? `${String(entry.id)}/` : String(entry.id);
|
|
68
95
|
}
|
|
69
96
|
function type(entry) {
|
|
70
|
-
|
|
71
|
-
case 'file':
|
|
72
|
-
return 'file';
|
|
73
|
-
case 'directory':
|
|
74
|
-
return 'directory';
|
|
75
|
-
case 'symlink':
|
|
76
|
-
return 'file';
|
|
77
|
-
}
|
|
97
|
+
return isNavBranch(entry) ? 'branch' : 'leaf';
|
|
78
98
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mak-98/dirvi-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A Vim-inspired TUI for browsing directories.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
],
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"commander": "^13.0.0",
|
|
16
|
-
"dirvi-lib": "0.
|
|
16
|
+
"dirvi-lib": "0.5.0",
|
|
17
17
|
"ink": "^7.1.1",
|
|
18
18
|
"react": "^19.0.0"
|
|
19
19
|
},
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { UnixEntry, UnixEntryPath } from 'dirvi-lib';
|
|
2
|
-
export type Action =
|
|
3
|
-
| {
|
|
4
|
-
kind: 'nextEntry';
|
|
5
|
-
}
|
|
6
|
-
| {
|
|
7
|
-
kind: 'prevEntry';
|
|
8
|
-
}
|
|
9
|
-
| {
|
|
10
|
-
kind: 'updateDir';
|
|
11
|
-
path: UnixEntryPath;
|
|
12
|
-
entries: UnixEntry[] | undefined;
|
|
13
|
-
}
|
|
14
|
-
| {
|
|
15
|
-
kind: 'outDir';
|
|
16
|
-
}
|
|
17
|
-
| {
|
|
18
|
-
kind: 'toggleFold';
|
|
19
|
-
}
|
|
20
|
-
| {
|
|
21
|
-
kind: 'fold';
|
|
22
|
-
}
|
|
23
|
-
| {
|
|
24
|
-
kind: 'unfold';
|
|
25
|
-
};
|
|
26
|
-
//# sourceMappingURL=action.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/application/action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,MAAM,MAAM,GACd;IACE,IAAI,EAAE,WAAW,CAAC;CACnB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;CACnB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;CAClC,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;CAChB,GACD;IACE,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dir-buffer-helpers.d.ts","sourceRoot":"","sources":["../../src/application/dir-buffer-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEvE,wBAAgB,WAAW,CACzB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,SAAS,GACd,SAAS,GAAG,SAAS,CA2BvB"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export function entryAtPath(buffer, path) {
|
|
2
|
-
if (path.length === 0) {
|
|
3
|
-
return undefined;
|
|
4
|
-
}
|
|
5
|
-
let entries = buffer.entries;
|
|
6
|
-
let entry;
|
|
7
|
-
for (const [index, name] of path.entries()) {
|
|
8
|
-
entry = entries.find((candidate) => candidate.name === name);
|
|
9
|
-
if (entry === undefined) {
|
|
10
|
-
return undefined;
|
|
11
|
-
}
|
|
12
|
-
if (index === path.length - 1) {
|
|
13
|
-
return entry;
|
|
14
|
-
}
|
|
15
|
-
if (entry.kind !== 'directory' || entry.entries === undefined) {
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
entries = entry.entries;
|
|
19
|
-
}
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { DisplayRow, UnixEntryPath, FoldNode, UnixEntry } from 'dirvi-lib';
|
|
2
|
-
export declare function createDisplayRows(
|
|
3
|
-
buffer: UnixEntry[],
|
|
4
|
-
folds: FoldNode,
|
|
5
|
-
): DisplayRow[];
|
|
6
|
-
export declare function displayRowAtPath(
|
|
7
|
-
buffer: UnixEntry[],
|
|
8
|
-
folds: FoldNode,
|
|
9
|
-
path: UnixEntryPath,
|
|
10
|
-
): DisplayRow | undefined;
|
|
11
|
-
//# sourceMappingURL=display-rows.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"display-rows.d.ts","sourceRoot":"","sources":["../../src/application/display-rows.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,aAAa,EACb,QAAQ,EACR,SAAS,EAEV,MAAM,WAAW,CAAC;AAuDnB,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EAAE,EACnB,KAAK,EAAE,QAAQ,GACd,UAAU,EAAE,CAEd;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EAAE,EACnB,KAAK,EAAE,QAAQ,EACf,IAAI,EAAE,aAAa,GAClB,UAAU,GAAG,SAAS,CAsBxB"}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { UnixEntryPath, FoldNode } from 'dirvi-lib';
|
|
2
|
-
function displayRowsAtPath(entries, path, foldNode) {
|
|
3
|
-
const rows = [];
|
|
4
|
-
let index = 0;
|
|
5
|
-
while (index < entries.length) {
|
|
6
|
-
const entry = entries[index];
|
|
7
|
-
if (foldNode !== undefined && FoldNode.getIfEntryFolded(foldNode, entry)) {
|
|
8
|
-
const entryNames = [];
|
|
9
|
-
while (
|
|
10
|
-
index < entries.length &&
|
|
11
|
-
FoldNode.getIfEntryFolded(foldNode, entries[index])
|
|
12
|
-
) {
|
|
13
|
-
entryNames.push(entries[index].name);
|
|
14
|
-
index += 1;
|
|
15
|
-
}
|
|
16
|
-
rows.push({
|
|
17
|
-
kind: 'fold',
|
|
18
|
-
parentPath: path,
|
|
19
|
-
entryNames,
|
|
20
|
-
});
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
rows.push({
|
|
24
|
-
kind: 'entry',
|
|
25
|
-
parentPath: path,
|
|
26
|
-
entry,
|
|
27
|
-
});
|
|
28
|
-
if (entry.kind === 'directory' && entry.entries !== undefined) {
|
|
29
|
-
rows.push(
|
|
30
|
-
...displayRowsAtPath(
|
|
31
|
-
entry.entries,
|
|
32
|
-
[...path, entry.name],
|
|
33
|
-
foldNode?.children[entry.name],
|
|
34
|
-
),
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
index += 1;
|
|
38
|
-
}
|
|
39
|
-
return rows;
|
|
40
|
-
}
|
|
41
|
-
export function createDisplayRows(buffer, folds) {
|
|
42
|
-
return displayRowsAtPath(buffer, [], folds);
|
|
43
|
-
}
|
|
44
|
-
export function displayRowAtPath(buffer, folds, path) {
|
|
45
|
-
if (path.length === 0) {
|
|
46
|
-
return undefined;
|
|
47
|
-
}
|
|
48
|
-
const rows = createDisplayRows(buffer, folds);
|
|
49
|
-
const parentPath = path.slice(0, -1);
|
|
50
|
-
const entryName = path[path.length - 1];
|
|
51
|
-
return rows.find((row) => {
|
|
52
|
-
if (row.kind === 'entry') {
|
|
53
|
-
return (
|
|
54
|
-
row.entry.name === entryName &&
|
|
55
|
-
UnixEntryPath.equal(row.parentPath, parentPath)
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
return (
|
|
59
|
-
UnixEntryPath.equal(row.parentPath, parentPath) &&
|
|
60
|
-
row.entryNames.includes(entryName)
|
|
61
|
-
);
|
|
62
|
-
});
|
|
63
|
-
}
|