@ssebastien/tcmd 0.1.3 → 0.1.7
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/README.md +256 -62
- package/bin/tcmd +10 -2
- package/bin/tcmd.js +13 -2
- package/desktop/dist/index.html +13 -0
- package/desktop/dist/main.js +20298 -0
- package/desktop/dist/style.css +1515 -0
- package/desktop/frontend/index.html +13 -0
- package/package.json +19 -6
- package/public/fonts/OFL.txt +93 -0
- package/public/index.html +14 -0
- package/public/licenses/LUCIDE.txt +43 -0
- package/public/main.js +20679 -0
- package/public/style.css +1515 -0
- package/scripts/build-desktop.js +31 -0
- package/scripts/serve-web.js +61 -0
- package/src/js/tcmd/components/App.html +80 -14
- package/src/js/tcmd/components/App.js +339 -114
- package/src/js/tcmd/components/App.xml +76 -22
- package/src/js/tcmd/components/BookmarkList.html +5 -5
- package/src/js/tcmd/components/BookmarkList.js +15 -41
- package/src/js/tcmd/components/BookmarkList.xml +1 -2
- package/src/js/tcmd/components/BookmarkRow.html +2 -1
- package/src/js/tcmd/components/BookmarkRow.js +14 -9
- package/src/js/tcmd/components/BookmarkRow.xml +1 -1
- package/src/js/tcmd/components/Breadcrumbs.js +1 -1
- package/src/js/tcmd/components/CommandArgRow.html +28 -0
- package/src/js/tcmd/components/CommandArgRow.js +146 -30
- package/src/js/tcmd/components/CommandArgRow.xml +55 -4
- package/src/js/tcmd/components/CommandBar.html +2 -2
- package/src/js/tcmd/components/CommandBar.js +33 -27
- package/src/js/tcmd/components/CommandBar.xml +2 -2
- package/src/js/tcmd/components/CommandItem.html +1 -1
- package/src/js/tcmd/components/CommandItem.js +25 -25
- package/src/js/tcmd/components/CommandItem.xml +2 -2
- package/src/js/tcmd/components/CommandPanel.html +29 -0
- package/src/js/tcmd/components/CommandPanel.js +78 -52
- package/src/js/tcmd/components/CommandPanel.xml +49 -25
- package/src/js/tcmd/components/Confirm.html +2 -2
- package/src/js/tcmd/components/EntryDetail.html +7 -7
- package/src/js/tcmd/components/EntryDetail.js +22 -8
- package/src/js/tcmd/components/FileList.html +5 -1
- package/src/js/tcmd/components/FileList.js +2 -1
- package/src/js/tcmd/components/FilePicker.html +10 -0
- package/src/js/tcmd/components/FilePicker.js +43 -0
- package/src/js/tcmd/components/FilePicker.xml +13 -0
- package/src/js/tcmd/components/FilePickerRow.html +6 -0
- package/src/js/tcmd/components/FilePickerRow.js +27 -0
- package/src/js/tcmd/components/FilePickerRow.xml +10 -0
- package/src/js/tcmd/components/FilePreview.html +14 -4
- package/src/js/tcmd/components/FilePreview.js +111 -12
- package/src/js/tcmd/components/FilePreview.xml +28 -8
- package/src/js/tcmd/components/FileRow.html +2 -1
- package/src/js/tcmd/components/FileRow.js +70 -12
- package/src/js/tcmd/components/FilterBar.html +1 -1
- package/src/js/tcmd/components/FilterBar.js +14 -4
- package/src/js/tcmd/components/FilterBar.xml +1 -1
- package/src/js/tcmd/components/Frame.js +324 -0
- package/src/js/tcmd/components/Help.html +15 -0
- package/src/js/tcmd/components/Help.js +260 -0
- package/src/js/tcmd/components/Help.xml +13 -4
- package/src/js/tcmd/components/HelpRow.html +8 -0
- package/src/js/tcmd/components/HelpRow.xml +7 -0
- package/src/js/tcmd/components/OverlayList.html +8 -0
- package/src/js/tcmd/components/OverlayList.js +69 -0
- package/src/js/tcmd/components/{CommandPalette.xml → OverlayList.xml} +2 -5
- package/src/js/tcmd/components/OverlayRow.html +5 -0
- package/src/js/tcmd/components/OverlayRow.js +47 -0
- package/src/js/tcmd/components/OverlayRow.xml +9 -0
- package/src/js/tcmd/components/Summary.html +1 -1
- package/src/js/tcmd/components/Summary.js +1 -6
- package/src/js/tcmd/components/format.js +4 -23
- package/src/js/tcmd/components/icons.js +176 -5
- package/src/js/tcmd/components/index.js +9 -5
- package/src/js/tcmd/components/rows.js +176 -48
- package/src/js/tcmd/core/base64.js +64 -0
- package/src/js/tcmd/core/bookmarks.js +45 -8
- package/src/js/tcmd/core/commands.js +978 -260
- package/src/js/tcmd/core/concurrency.js +59 -0
- package/src/js/tcmd/core/decompress.js +117 -0
- package/src/js/tcmd/core/directory.js +219 -93
- package/src/js/tcmd/core/format.js +36 -0
- package/src/js/tcmd/core/fs.js +438 -54
- package/src/js/tcmd/core/history.js +58 -0
- package/src/js/tcmd/core/index.js +3 -9
- package/src/js/tcmd/core/journal.js +93 -0
- package/src/js/tcmd/core/keymap.js +42 -6
- package/src/js/tcmd/core/operations.js +813 -48
- package/src/js/tcmd/core/os.js +29 -3
- package/src/js/tcmd/core/pane.js +33 -8
- package/src/js/tcmd/core/panel.js +280 -104
- package/src/js/tcmd/core/path.js +30 -3
- package/src/js/tcmd/core/permissions.js +107 -0
- package/src/js/tcmd/core/picker.js +156 -0
- package/src/js/tcmd/core/preview.js +102 -0
- package/src/js/tcmd/core/script.js +7 -95
- package/src/js/tcmd/core/selection.js +9 -1
- package/src/js/tcmd/core/session.js +498 -200
- package/src/js/tcmd/core/watch.js +153 -0
- package/src/js/tcmd/desktop/backend/api.js +165 -0
- package/src/js/tcmd/desktop/backend/fs.js +626 -0
- package/src/js/tcmd/desktop/backend/main.ts +9 -0
- package/src/js/tcmd/desktop/bookmarks.js +23 -0
- package/src/js/tcmd/desktop/fs.js +91 -0
- package/src/js/tcmd/desktop/main.js +194 -0
- package/src/js/tcmd/desktop/os.js +33 -0
- package/src/js/tcmd/index.js +0 -1
- package/src/js/tcmd/tui/app.js +118 -60
- package/src/js/tcmd/tui/catalogue.js +238 -42
- package/src/js/tcmd/tui/index.js +18 -19
- package/src/js/tcmd/tui/opentui.js +33 -0
- package/src/js/tcmd/tui/syntax.js +91 -0
- package/src/js/tcmd/tui/theme.js +32 -2
- package/src/js/tcmd/vendor/bzip2.js +276 -0
- package/src/js/tcmd/web/app.js +225 -41
- package/src/js/tcmd/web/bookmarks.js +36 -0
- package/src/js/tcmd/web/catalogue.js +81 -38
- package/src/js/tcmd/web/effects.js +223 -0
- package/src/js/tcmd/web/header.html +1 -1
- package/src/js/tcmd/web/header.js +15 -11
- package/src/js/tcmd/web/http.js +13 -0
- package/src/js/tcmd/web/index.js +2 -2
- package/src/js/tcmd/web/main.js +6 -66
- package/src/js/tcmd/web/opfs.js +297 -30
- package/src/js/tcmd/web/seed.js +4 -4
- package/src/js/tcmd/web/server.js +124 -21
- package/src/js/tcmd/web/theme.js +4 -0
- package/tinyjs.json +16 -0
- package/src/js/tcmd/components/CommandPalette.html +0 -7
- package/src/js/tcmd/components/CommandPalette.js +0 -58
- package/src/js/tcmd/components/PaletteRow.html +0 -3
- package/src/js/tcmd/components/PaletteRow.js +0 -43
- package/src/js/tcmd/components/PaletteRow.xml +0 -4
- package/src/js/tcmd/tui/frame.js +0 -269
- package/src/js/tcmd/tui/help.js +0 -32
package/src/js/tcmd/core/os.js
CHANGED
|
@@ -14,6 +14,13 @@
|
|
|
14
14
|
// - `edit(path)`: Promise<void> - $EDITOR (or vi)
|
|
15
15
|
// - `run(command, options)`: Promise<void> - `$SHELL -c command` in
|
|
16
16
|
// `options.cwd`
|
|
17
|
+
// - `copy(text)`: boolean - best-effort clipboard write. The TUI sends OSC 52
|
|
18
|
+
// through the renderer; the browser and desktop webview use the Clipboard
|
|
19
|
+
// API. False when the host has no clipboard.
|
|
20
|
+
// - `canEdit`: boolean - whether `edit` can launch an editor at all. A host
|
|
21
|
+
// without one (the web's null adapter) sets it false, so Enter on a file
|
|
22
|
+
// falls back to the fullscreen inspector instead of erroring (see
|
|
23
|
+
// `core/commands#pane.enter`).
|
|
17
24
|
|
|
18
25
|
// `node:child_process` is imported lazily: only `createNodeOs` needs it, so
|
|
19
26
|
// bundles that use the null adapter (the web view, tests) never pull in a Node
|
|
@@ -29,9 +36,14 @@ function loadChildProcess() {
|
|
|
29
36
|
|
|
30
37
|
// Function: createNodeOs
|
|
31
38
|
// Node/Bun-backed host adapter. `suspend`/`resume` are optional hooks the TUI
|
|
32
|
-
// uses to release and restore the terminal around interactive commands
|
|
33
|
-
|
|
39
|
+
// uses to release and restore the terminal around interactive commands;
|
|
40
|
+
// `copy` is the TUI's OSC 52 hook (`renderer.copyToClipboardOSC52`).
|
|
41
|
+
function createNodeOs({ suspend, resume, copy } = {}) {
|
|
34
42
|
return {
|
|
43
|
+
canEdit: true,
|
|
44
|
+
copy(text) {
|
|
45
|
+
return Boolean(copy?.(`${text ?? ""}`))
|
|
46
|
+
},
|
|
35
47
|
async open(path) {
|
|
36
48
|
await openWith(path, openerCandidates())
|
|
37
49
|
},
|
|
@@ -48,14 +60,28 @@ function createNodeOs({ suspend, resume } = {}) {
|
|
|
48
60
|
}
|
|
49
61
|
}
|
|
50
62
|
|
|
63
|
+
// Function: copyToBrowserClipboard
|
|
64
|
+
// Best-effort clipboard write for a browser or desktop webview. The write is
|
|
65
|
+
// asynchronous but fire-and-forget; a refused write (no permission, no user
|
|
66
|
+
// gesture) leaves the clipboard untouched.
|
|
67
|
+
function copyToBrowserClipboard(text) {
|
|
68
|
+
const clipboard = globalThis.navigator?.clipboard
|
|
69
|
+
if (!clipboard?.writeText) return false
|
|
70
|
+
void clipboard.writeText(`${text ?? ""}`).catch(() => {})
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
|
|
51
74
|
// Function: createNullOs
|
|
52
75
|
// Host adapter for environments without a shell (web): every operation fails
|
|
53
76
|
// with a clear message, which the dispatch path reports in the command bar.
|
|
77
|
+
// Clipboard access is the exception: the browser has one.
|
|
54
78
|
function createNullOs() {
|
|
55
79
|
const unsupported = (name) => async () => {
|
|
56
80
|
throw new Error(`${name} is not available in this environment`)
|
|
57
81
|
}
|
|
58
82
|
return {
|
|
83
|
+
canEdit: false,
|
|
84
|
+
copy: (text) => copyToBrowserClipboard(text),
|
|
59
85
|
open: unsupported("open"),
|
|
60
86
|
edit: unsupported("edit"),
|
|
61
87
|
run: unsupported("run"),
|
|
@@ -123,6 +149,6 @@ async function runDetached(command, args) {
|
|
|
123
149
|
})
|
|
124
150
|
}
|
|
125
151
|
|
|
126
|
-
export { createNodeOs, createNullOs }
|
|
152
|
+
export { copyToBrowserClipboard, createNodeOs, createNullOs }
|
|
127
153
|
|
|
128
154
|
// EOF
|
package/src/js/tcmd/core/pane.js
CHANGED
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
// Module: tcmd/core/pane
|
|
7
7
|
// A Pane is one column with a single directory: it owns that directory and
|
|
8
8
|
// proxies its cells (path, entries, cursor, marks, disk, …) as pane-level
|
|
9
|
-
// cells, so views and commands address the pane directly. Navigation
|
|
10
|
-
// and
|
|
9
|
+
// cells, so views and commands address the pane directly. Navigation reads the
|
|
10
|
+
// target first and commits atomically (see `core/directory#read`), so the pane
|
|
11
|
+
// keeps showing its current listing until the replacement is ready. The pane
|
|
12
|
+
// also owns its navigation history (back/forward snapshots of the view), which
|
|
13
|
+
// the session drives to restore position, selection and focus.
|
|
11
14
|
|
|
12
15
|
import { cell } from "select/state/cells"
|
|
13
16
|
import { createDirectory } from "./directory.js"
|
|
@@ -22,6 +25,23 @@ const PANE_BUFFERS = { left: "A", right: "B" }
|
|
|
22
25
|
// destination (DST).
|
|
23
26
|
const PANE_LABELS = { left: "SRC", right: "DST" }
|
|
24
27
|
|
|
28
|
+
// Function: currentPaneId
|
|
29
|
+
// The id of the pane that owns the current directory: the focused pane while
|
|
30
|
+
// focus is on source/destination, the anchor pane otherwise.
|
|
31
|
+
function currentPaneId(session) {
|
|
32
|
+
return session.currentId?.value ?? session.active?.value ?? "left"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Function: currentPane
|
|
36
|
+
// The pane that owns the current directory: the focused pane while focus is
|
|
37
|
+
// on source/destination, the anchor pane while it is on an auxiliary column
|
|
38
|
+
// (see `core/session`). Path-changing commands — open, up, history,
|
|
39
|
+
// breadcrumbs, relative arguments — target it; only cursor movement follows
|
|
40
|
+
// the focused column. `core/commands` keeps `pane()` for the latter.
|
|
41
|
+
function currentPane(session) {
|
|
42
|
+
return session.panes[currentPaneId(session)] ?? session.panes.left
|
|
43
|
+
}
|
|
44
|
+
|
|
25
45
|
// Function: createPane
|
|
26
46
|
// Creates a pane bound to a filesystem adapter at `path`.
|
|
27
47
|
//
|
|
@@ -31,10 +51,10 @@ const PANE_LABELS = { left: "SRC", right: "DST" }
|
|
|
31
51
|
// await pane.refresh()
|
|
32
52
|
// pane.entries.value // sorted, filtered FileEntry[]
|
|
33
53
|
// ```
|
|
34
|
-
function createPane({ fs, path: initialPath } = {}) {
|
|
54
|
+
function createPane({ fs, path: initialPath, context, watch } = {}) {
|
|
35
55
|
const pane = {}
|
|
36
56
|
pane.fs = fs
|
|
37
|
-
pane.directory = createDirectory({ fs, path: initialPath })
|
|
57
|
+
pane.directory = createDirectory({ fs, path: initialPath, context, watch })
|
|
38
58
|
|
|
39
59
|
// Proxy cells mirror the directory, so views address the pane uniformly.
|
|
40
60
|
const dir = pane.directory
|
|
@@ -46,29 +66,34 @@ function createPane({ fs, path: initialPath } = {}) {
|
|
|
46
66
|
pane.sort = dir.sort
|
|
47
67
|
pane.entries = dir.entries
|
|
48
68
|
pane.cursor = dir.cursor
|
|
49
|
-
pane.cursorStat = dir.cursorStat
|
|
50
69
|
pane.marked = dir.marked
|
|
51
70
|
pane.disk = dir.disk
|
|
52
71
|
pane.segments = dir.segments
|
|
72
|
+
pane.history = dir.history
|
|
73
|
+
pane.autoRefresh = dir.autoRefresh
|
|
53
74
|
|
|
54
75
|
// Function: current
|
|
55
76
|
// The pane's directory.
|
|
56
77
|
pane.current = () => pane.directory
|
|
57
78
|
|
|
58
79
|
// Function: refresh / navigate / up / open / back / forward /
|
|
59
|
-
// currentEntry / toggleMark / clearFilter — delegate to the
|
|
80
|
+
// currentEntry / toggleMark / setFilter / clearFilter — delegate to the
|
|
81
|
+
// directory.
|
|
60
82
|
pane.refresh = () => pane.directory.refresh()
|
|
61
|
-
pane.
|
|
83
|
+
pane.setAutoRefresh = (enabled) => pane.directory.setAutoRefresh(enabled)
|
|
84
|
+
pane.navigate = (path, options) => pane.directory.navigate(path, options)
|
|
62
85
|
pane.up = () => pane.directory.up()
|
|
63
86
|
pane.open = () => pane.directory.open()
|
|
64
87
|
pane.back = () => pane.directory.back()
|
|
65
88
|
pane.forward = () => pane.directory.forward()
|
|
66
89
|
pane.currentEntry = () => pane.directory.currentEntry()
|
|
67
90
|
pane.toggleMark = () => pane.directory.toggleMark()
|
|
91
|
+
pane.setFilter = (query) => pane.directory.setFilter(query)
|
|
68
92
|
pane.clearFilter = () => pane.directory.clearFilter()
|
|
93
|
+
pane.setContext = (context) => pane.directory.setContext(context)
|
|
69
94
|
pane.dispose = () => pane.directory.dispose()
|
|
70
95
|
|
|
71
96
|
return pane
|
|
72
97
|
}
|
|
73
98
|
|
|
74
|
-
export { PANE_BUFFERS, PANE_LABELS, createPane }
|
|
99
|
+
export { PANE_BUFFERS, PANE_LABELS, createPane, currentPane, currentPaneId }
|