@linxiraos/pi-tui 1.1.27 → 1.2.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/CHANGELOG.md +47 -463
- package/README.md +7 -5
- package/dist/types/app-keybindings.d.ts +1 -1
- package/dist/types/apps/cleanse-board.d.ts +1 -1
- package/dist/types/apps/debug/log-viewer.d.ts +4 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +2 -0
- package/dist/types/apps/git/git-tui.d.ts +2 -2
- package/dist/types/apps/git/help.d.ts +3 -1
- package/dist/types/apps/if-bench-board.d.ts +2 -2
- package/dist/types/apps/setup-model-picker.d.ts +1 -1
- package/dist/types/autocomplete.d.ts +5 -2
- package/dist/types/charts/chart-plan.d.ts +674 -0
- package/dist/types/charts/chart-svg.d.ts +59 -0
- package/dist/types/charts/table-data.d.ts +175 -0
- package/dist/types/chat/assistant-message.d.ts +5 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +2 -0
- package/dist/types/chat/compaction-summary-message.d.ts +1 -0
- package/dist/types/chat/execution-shared.d.ts +6 -5
- package/dist/types/chat/fence-figure.d.ts +42 -0
- package/dist/types/chat/figure-markdown.d.ts +42 -0
- package/dist/types/chat/messages.d.ts +1 -1
- package/dist/types/chat/svg-figure.d.ts +33 -0
- package/dist/types/chat/svg-source.d.ts +49 -0
- package/dist/types/chat/table-chart.d.ts +89 -0
- package/dist/types/chat/tool-execution.d.ts +2 -0
- package/dist/types/chat/user-message.d.ts +15 -2
- package/dist/types/chrome/shared.d.ts +9 -0
- package/dist/types/chrome/transcript-container.d.ts +6 -0
- package/dist/types/components/box.d.ts +1 -0
- package/dist/types/components/disclosure.d.ts +1 -0
- package/dist/types/components/editor.d.ts +15 -4
- package/dist/types/components/form.d.ts +1 -0
- package/dist/types/components/image.d.ts +12 -44
- package/dist/types/components/key-value-list.d.ts +1 -0
- package/dist/types/components/layout/row.d.ts +1 -0
- package/dist/types/components/layout/stack.d.ts +1 -0
- package/dist/types/components/markdown.d.ts +36 -3
- package/dist/types/components/scroll-view.d.ts +1 -0
- package/dist/types/components/section.d.ts +1 -0
- package/dist/types/components/table.d.ts +1 -0
- package/dist/types/components/text.d.ts +1 -0
- package/dist/types/components/tree-view.d.ts +7 -0
- package/dist/types/components/truncated-text.d.ts +1 -0
- package/dist/types/fuzzy.d.ts +29 -1
- package/dist/types/key-hint-format.d.ts +1 -1
- package/dist/types/keybinding-matchers.d.ts +3 -0
- package/dist/types/keybindings.d.ts +1 -1
- package/dist/types/kitty-graphics.d.ts +2 -2
- package/dist/types/loop-watchdog.d.ts +8 -7
- package/dist/types/multiplexers/cmux.d.ts +16 -0
- package/dist/types/multiplexers/herdr.d.ts +26 -0
- package/dist/types/multiplexers/notify.d.ts +13 -0
- package/dist/types/multiplexers/orca.d.ts +12 -0
- package/dist/types/multiplexers/screen.d.ts +9 -0
- package/dist/types/multiplexers/tmux.d.ts +29 -0
- package/dist/types/multiplexers/types.d.ts +100 -0
- package/dist/types/multiplexers/wmux.d.ts +12 -0
- package/dist/types/multiplexers/zellij.d.ts +12 -0
- package/dist/types/native/backend.d.ts +3 -2
- package/dist/types/native/blobs.d.ts +7 -3
- package/dist/types/native/encode.d.ts +3 -4
- package/dist/types/native/overlay.d.ts +5 -0
- package/dist/types/overlays/agent-hub-projection.d.ts +6 -5
- package/dist/types/overlays/agent-hub-types.d.ts +9 -0
- package/dist/types/overlays/agent-hub.d.ts +2 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +11 -2
- package/dist/types/overlays/agents-hub.d.ts +9 -0
- package/dist/types/overlays/annotation-overlay.d.ts +19 -2
- package/dist/types/overlays/annotation-types.d.ts +2 -0
- package/dist/types/overlays/ask-dialog.d.ts +5 -2
- package/dist/types/overlays/history-search.d.ts +10 -0
- package/dist/types/overlays/hook-selector.d.ts +9 -4
- package/dist/types/overlays/jobs-panel.d.ts +1 -7
- package/dist/types/overlays/model-browser.d.ts +54 -7
- package/dist/types/overlays/model-hub.d.ts +23 -0
- package/dist/types/overlays/oauth-selector.d.ts +0 -1
- package/dist/types/overlays/plan-review-overlay.d.ts +3 -2
- package/dist/types/overlays/session-observer-registry.d.ts +2 -0
- package/dist/types/overlays/session-selector.d.ts +6 -2
- package/dist/types/overlays/settings-defs.d.ts +1 -0
- package/dist/types/overlays/usage-dashboard.d.ts +8 -4
- package/dist/types/overlays/usage-display.d.ts +3 -1
- package/dist/types/prompt/composer.d.ts +1 -1
- package/dist/types/prompt/custom-editor.d.ts +11 -8
- package/dist/types/prompt/image-source.d.ts +2 -1
- package/dist/types/prompt/interactive-context-helpers.d.ts +4 -1
- package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
- package/dist/types/prompt/welcome.d.ts +6 -1
- package/dist/types/render/composite.d.ts +2 -0
- package/dist/types/render/output-pane.d.ts +1 -0
- package/dist/types/render/render-utils.d.ts +1 -0
- package/dist/types/render/tool-card.d.ts +6 -0
- package/dist/types/render/width-aware-text.d.ts +2 -0
- package/dist/types/setup/scenes/types.d.ts +1 -0
- package/dist/types/status-line/component.d.ts +3 -0
- package/dist/types/status-line/host.d.ts +4 -1
- package/dist/types/status-line/segments.d.ts +2 -0
- package/dist/types/status-line/types.d.ts +14 -3
- package/dist/types/terminal-capabilities.d.ts +27 -35
- package/dist/types/terminal-multiplexer.d.ts +127 -14
- package/dist/types/terminal.d.ts +22 -6
- package/dist/types/theme/active-symbols.d.ts +1 -1
- package/dist/types/theme/schema.d.ts +11 -2
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/theme/theme-class.d.ts +7 -0
- package/dist/types/theme/theme.d.ts +1 -1
- package/dist/types/theme/tui-adapters.d.ts +3 -0
- package/dist/types/tmux.d.ts +11 -4
- package/dist/types/tools/daemon.d.ts +1 -1
- package/dist/types/tools/eval.d.ts +22 -3
- package/dist/types/tools/glob.d.ts +4 -0
- package/dist/types/tools/native-view.d.ts +47 -0
- package/dist/types/tools/output-meta.d.ts +11 -1
- package/dist/types/tools/renderer.d.ts +37 -2
- package/dist/types/tools/streaming-output.d.ts +20 -1
- package/dist/types/tools/task.d.ts +0 -4
- package/dist/types/tools/write.d.ts +9 -2
- package/dist/types/tools/yield.d.ts +22 -0
- package/dist/types/tui.d.ts +31 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/vim.d.ts +19 -5
- package/package.json +13 -9
- package/src/app-keybindings.d.ts +1 -1
- package/src/app-keybindings.ts +1 -1
- package/src/apps/autoresearch-dashboard.ts +7 -3
- package/src/apps/cleanse-board.ts +2 -2
- package/src/apps/cleanse-picker.ts +1 -1
- package/src/apps/debug/log-viewer.ts +188 -72
- package/src/apps/debug/raw-sse-buffer.ts +8 -0
- package/src/apps/debug/raw-sse.ts +39 -5
- package/src/apps/git/diff-pane.ts +26 -5
- package/src/apps/git/git-tui.ts +2 -2
- package/src/apps/git/help.ts +29 -20
- package/src/apps/if-bench-board.ts +2 -2
- package/src/apps/ps-top.ts +2 -2
- package/src/apps/setup-model-picker.ts +1 -1
- package/src/autocomplete.d.ts +5 -2
- package/src/autocomplete.ts +67 -43
- package/src/charts/chart-plan.d.ts +674 -0
- package/src/charts/chart-plan.ts +5081 -0
- package/src/charts/chart-svg.d.ts +59 -0
- package/src/charts/chart-svg.ts +4657 -0
- package/src/charts/table-data.d.ts +175 -0
- package/src/charts/table-data.ts +1478 -0
- package/src/chat/advisor-message.ts +11 -0
- package/src/chat/assistant-message.d.ts +5 -0
- package/src/chat/assistant-message.ts +219 -50
- package/src/chat/chat-transcript-builder.d.ts +2 -0
- package/src/chat/chat-transcript-builder.ts +5 -3
- package/src/chat/compaction-summary-message.d.ts +1 -0
- package/src/chat/compaction-summary-message.ts +8 -0
- package/src/chat/execution-shared.d.ts +6 -5
- package/src/chat/execution-shared.ts +42 -25
- package/src/chat/fence-figure.d.ts +42 -0
- package/src/chat/fence-figure.ts +80 -0
- package/src/chat/figure-markdown.d.ts +42 -0
- package/src/chat/figure-markdown.ts +174 -0
- package/src/chat/messages.d.ts +1 -1
- package/src/chat/messages.ts +1 -1
- package/src/chat/read-tool-group.ts +6 -4
- package/src/chat/skill-message.ts +6 -0
- package/src/chat/svg-figure.d.ts +33 -0
- package/src/chat/svg-figure.ts +399 -0
- package/src/chat/svg-source.d.ts +49 -0
- package/src/chat/svg-source.ts +188 -0
- package/src/chat/table-chart.d.ts +89 -0
- package/src/chat/table-chart.ts +294 -0
- package/src/chat/tool-execution.d.ts +2 -0
- package/src/chat/tool-execution.ts +80 -6
- package/src/chat/user-message.d.ts +15 -2
- package/src/chat/user-message.ts +55 -3
- package/src/chrome/shared.ts +53 -0
- package/src/chrome/transcript-container.d.ts +6 -0
- package/src/chrome/transcript-container.ts +93 -13
- package/src/components/box.d.ts +1 -0
- package/src/components/box.ts +5 -0
- package/src/components/disclosure.d.ts +1 -0
- package/src/components/disclosure.ts +8 -0
- package/src/components/editor.d.ts +15 -4
- package/src/components/editor.ts +294 -46
- package/src/components/form.d.ts +1 -0
- package/src/components/form.ts +8 -0
- package/src/components/image.d.ts +12 -44
- package/src/components/image.ts +47 -151
- package/src/components/key-value-list.d.ts +1 -0
- package/src/components/key-value-list.ts +4 -0
- package/src/components/layout/row.d.ts +1 -0
- package/src/components/layout/row.ts +7 -0
- package/src/components/layout/stack.d.ts +1 -0
- package/src/components/layout/stack.ts +7 -0
- package/src/components/markdown.d.ts +36 -3
- package/src/components/markdown.ts +433 -318
- package/src/components/scroll-view.d.ts +1 -0
- package/src/components/scroll-view.ts +5 -0
- package/src/components/section.d.ts +1 -0
- package/src/components/section.ts +5 -0
- package/src/components/settings-list.ts +2 -0
- package/src/components/table.d.ts +1 -0
- package/src/components/table.ts +4 -0
- package/src/components/text.d.ts +1 -0
- package/src/components/text.ts +7 -0
- package/src/components/tree-view.d.ts +7 -0
- package/src/components/tree-view.ts +38 -8
- package/src/components/truncated-text.d.ts +1 -0
- package/src/components/truncated-text.ts +5 -0
- package/src/desktop-notify.ts +1 -1
- package/src/fuzzy.d.ts +29 -1
- package/src/fuzzy.ts +115 -30
- package/src/key-hint-format.d.ts +1 -1
- package/src/key-hint-format.ts +1 -1
- package/src/keybinding-matchers.d.ts +3 -0
- package/src/keybinding-matchers.ts +6 -2
- package/src/keybindings.d.ts +1 -1
- package/src/keybindings.ts +1 -1
- package/src/kitty-graphics.d.ts +2 -2
- package/src/kitty-graphics.ts +4 -4
- package/src/loop-watchdog.d.ts +8 -7
- package/src/loop-watchdog.ts +18 -13
- package/src/multiplexers/cmux.d.ts +16 -0
- package/src/multiplexers/cmux.ts +29 -0
- package/src/multiplexers/herdr.d.ts +26 -0
- package/src/multiplexers/herdr.ts +64 -0
- package/src/multiplexers/notify.d.ts +13 -0
- package/src/multiplexers/notify.ts +24 -0
- package/src/multiplexers/orca.d.ts +12 -0
- package/src/multiplexers/orca.ts +16 -0
- package/src/multiplexers/screen.d.ts +9 -0
- package/src/multiplexers/screen.ts +15 -0
- package/src/multiplexers/tmux.d.ts +29 -0
- package/src/multiplexers/tmux.ts +40 -0
- package/src/multiplexers/types.d.ts +100 -0
- package/src/multiplexers/types.ts +110 -0
- package/src/multiplexers/wmux.d.ts +12 -0
- package/src/multiplexers/wmux.ts +16 -0
- package/src/multiplexers/zellij.d.ts +12 -0
- package/src/multiplexers/zellij.ts +24 -0
- package/src/native/backend.d.ts +3 -2
- package/src/native/backend.ts +174 -18
- package/src/native/blobs.d.ts +7 -3
- package/src/native/blobs.ts +47 -12
- package/src/native/encode.d.ts +3 -4
- package/src/native/encode.ts +58 -31
- package/src/native/overlay.d.ts +5 -0
- package/src/native/overlay.ts +13 -0
- package/src/native/reconcile.ts +4 -0
- package/src/overlays/agent-hub-projection.d.ts +6 -5
- package/src/overlays/agent-hub-projection.ts +124 -13
- package/src/overlays/agent-hub-types.d.ts +9 -0
- package/src/overlays/agent-hub-types.ts +6 -0
- package/src/overlays/agent-hub.ts +44 -29
- package/src/overlays/agent-transcript-viewer.ts +91 -23
- package/src/overlays/agents-hub.ts +28 -8
- package/src/overlays/annotation-overlay.ts +293 -90
- package/src/overlays/annotation-types.ts +2 -0
- package/src/overlays/ask-dialog.ts +7 -10
- package/src/overlays/btw-history-panel.ts +12 -1
- package/src/overlays/copy-selector.ts +30 -8
- package/src/overlays/extensions/state-manager.ts +52 -12
- package/src/overlays/history-search.ts +100 -7
- package/src/overlays/hook-selector.ts +12 -5
- package/src/overlays/jobs-panel.ts +28 -46
- package/src/overlays/model-browser.ts +341 -110
- package/src/overlays/model-hub.ts +300 -49
- package/src/overlays/move-overlay.ts +28 -14
- package/src/overlays/oauth-selector.ts +54 -70
- package/src/overlays/plan-review-overlay.ts +194 -70
- package/src/overlays/plugin-settings.ts +3 -3
- package/src/overlays/report-panel.ts +2 -2
- package/src/overlays/rewind-selector.ts +86 -17
- package/src/overlays/session-observer-registry.d.ts +2 -0
- package/src/overlays/session-observer-registry.ts +10 -2
- package/src/overlays/session-selector.ts +64 -26
- package/src/overlays/settings-defs.ts +4 -3
- package/src/overlays/settings-selector.ts +33 -8
- package/src/overlays/snapcompact-shape-preview.ts +2 -3
- package/src/overlays/stats-notice.ts +1 -1
- package/src/overlays/tree-selector.ts +41 -20
- package/src/overlays/usage-dashboard.ts +100 -50
- package/src/overlays/usage-display.ts +10 -4
- package/src/prompt/attachment-chips.ts +15 -11
- package/src/prompt/composer-attachments.ts +6 -4
- package/src/prompt/composer.ts +4 -15
- package/src/prompt/custom-editor.ts +54 -26
- package/src/prompt/image-source.ts +2 -1
- package/src/prompt/interactive-context-helpers.ts +30 -18
- package/src/prompt/macos-spelling.ts +7 -0
- package/src/prompt/magic-keywords.ts +11 -2
- package/src/prompt/model-mention-autocomplete.ts +14 -14
- package/src/prompt/tips.txt +6 -5
- package/src/prompt/welcome.ts +55 -12
- package/src/prompt/word-completion.ts +38 -5
- package/src/render/composite.d.ts +2 -0
- package/src/render/composite.ts +64 -0
- package/src/render/output-pane.d.ts +1 -0
- package/src/render/output-pane.ts +6 -0
- package/src/render/render-utils.d.ts +1 -0
- package/src/render/render-utils.ts +11 -0
- package/src/render/tool-card.d.ts +6 -0
- package/src/render/tool-card.ts +15 -0
- package/src/render/width-aware-text.d.ts +2 -0
- package/src/render/width-aware-text.ts +5 -0
- package/src/setup/scenes/model.ts +2 -1
- package/src/setup/scenes/types.ts +1 -0
- package/src/status-line/component.ts +292 -78
- package/src/status-line/host.ts +4 -1
- package/src/status-line/segments.ts +40 -22
- package/src/status-line/types.ts +15 -3
- package/src/terminal-capabilities.d.ts +27 -35
- package/src/terminal-capabilities.ts +75 -189
- package/src/terminal-multiplexer.d.ts +127 -14
- package/src/terminal-multiplexer.ts +112 -33
- package/src/terminal.d.ts +22 -6
- package/src/terminal.ts +139 -37
- package/src/theme/active-symbols.d.ts +1 -1
- package/src/theme/active-symbols.ts +1 -1
- package/src/theme/schema-validation.ts +1 -0
- package/src/theme/schema.d.ts +11 -2
- package/src/theme/schema.ts +14 -1
- package/src/theme/session-color.ts +1 -7
- package/src/theme/symbols.d.ts +1 -1
- package/src/theme/symbols.ts +6 -1
- package/src/theme/theme-class.d.ts +7 -0
- package/src/theme/theme-class.ts +26 -1
- package/src/theme/theme-schema.json +5 -1
- package/src/theme/theme.d.ts +1 -1
- package/src/theme/theme.ts +8 -4
- package/src/theme/tui-adapters.d.ts +3 -0
- package/src/theme/tui-adapters.ts +68 -0
- package/src/tmux.d.ts +11 -4
- package/src/tmux.ts +47 -11
- package/src/tools/ast-edit.ts +59 -35
- package/src/tools/ast-grep.ts +35 -16
- package/src/tools/bash.ts +92 -42
- package/src/tools/daemon.d.ts +1 -1
- package/src/tools/daemon.ts +1 -1
- package/src/tools/default-renderer.ts +35 -19
- package/src/tools/edit.ts +142 -120
- package/src/tools/eval-format/index.ts +28 -2
- package/src/tools/eval-format/javascript.ts +7 -5
- package/src/tools/eval.d.ts +22 -3
- package/src/tools/eval.ts +364 -208
- package/src/tools/fetch.ts +5 -6
- package/src/tools/glob.d.ts +4 -0
- package/src/tools/glob.ts +33 -65
- package/src/tools/grep.ts +81 -48
- package/src/tools/index.ts +2 -0
- package/src/tools/lsp.ts +81 -59
- package/src/tools/mcp.ts +111 -68
- package/src/tools/native-view.d.ts +47 -0
- package/src/tools/native-view.ts +102 -1
- package/src/tools/output-meta.d.ts +11 -1
- package/src/tools/output-meta.ts +23 -3
- package/src/tools/read.ts +7 -5
- package/src/tools/renderer.d.ts +37 -2
- package/src/tools/renderer.ts +42 -2
- package/src/tools/streaming-output.d.ts +20 -1
- package/src/tools/streaming-output.ts +149 -50
- package/src/tools/task.d.ts +0 -4
- package/src/tools/task.ts +112 -59
- package/src/tools/todo.ts +119 -30
- package/src/tools/wait.ts +34 -24
- package/src/tools/web-search.ts +1 -1
- package/src/tools/write.d.ts +9 -2
- package/src/tools/write.ts +147 -95
- package/src/tools/yield.d.ts +22 -0
- package/src/tools/yield.ts +225 -0
- package/src/tui.d.ts +31 -0
- package/src/tui.ts +309 -160
- package/src/utils.d.ts +6 -0
- package/src/utils.ts +19 -0
- package/src/vim.d.ts +19 -5
- package/src/vim.ts +333 -18
- package/src/windows-input-mode.ts +8 -0
|
@@ -92,6 +92,7 @@ export declare class ScrollView implements Component {
|
|
|
92
92
|
/** Apply Arrow, Shift+Arrow, Page, Home, and End navigation keys. */
|
|
93
93
|
handleScrollKey(data: string): boolean;
|
|
94
94
|
invalidate(): void;
|
|
95
|
+
releaseRenderCaches(): void;
|
|
95
96
|
/** Permanently release a wrapped child's timers, subscriptions, and other resources. */
|
|
96
97
|
dispose(): void;
|
|
97
98
|
/**
|
|
@@ -408,6 +408,11 @@ export class ScrollView implements Component {
|
|
|
408
408
|
this.#child?.invalidate?.();
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
+
releaseRenderCaches(): void {
|
|
412
|
+
this.#cache = undefined;
|
|
413
|
+
this.#child?.releaseRenderCaches?.();
|
|
414
|
+
}
|
|
415
|
+
|
|
411
416
|
/** Permanently release a wrapped child's timers, subscriptions, and other resources. */
|
|
412
417
|
dispose(): void {
|
|
413
418
|
if (this.#disposed) return;
|
|
@@ -15,6 +15,7 @@ export declare class Section implements Component {
|
|
|
15
15
|
#private;
|
|
16
16
|
constructor(options: SectionOptions);
|
|
17
17
|
invalidate(): void;
|
|
18
|
+
releaseRenderCaches(): void;
|
|
18
19
|
dispose(): void;
|
|
19
20
|
/** A `section` headed by the styled title; the rule is the terminal's. */
|
|
20
21
|
describe(_cx: DescribeContext): NativeNode;
|
|
@@ -51,6 +51,11 @@ export class Section implements Component {
|
|
|
51
51
|
this.#cache = undefined;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
releaseRenderCaches(): void {
|
|
55
|
+
this.#cache = undefined;
|
|
56
|
+
if (isComponent(this.#options.body)) this.#options.body.releaseRenderCaches?.();
|
|
57
|
+
}
|
|
58
|
+
|
|
54
59
|
dispose(): void {
|
|
55
60
|
if (this.#disposed) return;
|
|
56
61
|
this.#disposed = true;
|
|
@@ -346,6 +346,8 @@ export class SettingsList implements Component {
|
|
|
346
346
|
return { row: id, option: component.selectList.getSelectedItem()?.value };
|
|
347
347
|
}
|
|
348
348
|
if (component instanceof TextFormField) {
|
|
349
|
+
// Native inline text editing has no error slot; show the form until corrected.
|
|
350
|
+
if (component.hasError) return null;
|
|
349
351
|
const draft = component.getValue();
|
|
350
352
|
return {
|
|
351
353
|
row: id,
|
|
@@ -29,6 +29,7 @@ export declare class Table implements Component {
|
|
|
29
29
|
constructor(rows: readonly (readonly TableCell[])[], columns: readonly TableColumn[], options?: TableOptions);
|
|
30
30
|
setRows(rows: readonly (readonly TableCell[])[]): boolean;
|
|
31
31
|
invalidate(): void;
|
|
32
|
+
releaseRenderCaches(): void;
|
|
32
33
|
/**
|
|
33
34
|
* A native `table`. Column priorities carry over unchanged (lower gives
|
|
34
35
|
* way first); truncating columns truncate at the end, the rest keep
|
package/src/components/table.ts
CHANGED
|
@@ -117,6 +117,10 @@ export class Table implements Component {
|
|
|
117
117
|
this.#native = undefined;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
releaseRenderCaches(): void {
|
|
121
|
+
this.#cache = undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
120
124
|
/**
|
|
121
125
|
* A native `table`. Column priorities carry over unchanged (lower gives
|
|
122
126
|
* way first); truncating columns truncate at the end, the rest keep
|
package/src/components/text.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export declare class Text implements Component {
|
|
|
26
26
|
*/
|
|
27
27
|
setStyleFn(styleFn?: (text: string) => string): this;
|
|
28
28
|
invalidate(): void;
|
|
29
|
+
releaseRenderCaches(): void;
|
|
29
30
|
/**
|
|
30
31
|
* Wrapped text; styling re-derived from the styled source so a theme swap
|
|
31
32
|
* re-resolves tokens. A background fill becomes the node's tone.
|
package/src/components/text.ts
CHANGED
|
@@ -109,6 +109,13 @@ export class Text implements Component {
|
|
|
109
109
|
this.#cachedLines = undefined;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
releaseRenderCaches(): void {
|
|
113
|
+
this.#cachedText = undefined;
|
|
114
|
+
this.#cachedWidth = undefined;
|
|
115
|
+
this.#cachedWidthConfigEpoch = undefined;
|
|
116
|
+
this.#cachedLines = undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
112
119
|
/**
|
|
113
120
|
* Wrapped text; styling re-derived from the styled source so a theme swap
|
|
114
121
|
* re-resolves tokens. A background fill becomes the node's tone.
|
|
@@ -34,6 +34,13 @@ export interface FlattenTreeOptions<T, K extends TreeKey> {
|
|
|
34
34
|
rootDepth?: number;
|
|
35
35
|
/** Override the display depth inherited by direct children. */
|
|
36
36
|
getChildDepth?: (item: T, row: TreeRow<T, K>, children: readonly T[]) => number;
|
|
37
|
+
/**
|
|
38
|
+
* Reuse the parent ancestor list when a child keeps the same display depth
|
|
39
|
+
* and the current item has no siblings (`siblingCount === 1`). Otherwise
|
|
40
|
+
* retain the current item as an ancestor so connector gutters remain
|
|
41
|
+
* accurate, including when the item has multiple children.
|
|
42
|
+
*/
|
|
43
|
+
compactSameDepthAncestors?: boolean;
|
|
37
44
|
/** Stop projection after this many structural items. Omit for no traversal cap. */
|
|
38
45
|
maxItems?: number;
|
|
39
46
|
}
|
|
@@ -43,17 +43,41 @@ export interface FlattenTreeOptions<T, K extends TreeKey> {
|
|
|
43
43
|
rootDepth?: number;
|
|
44
44
|
/** Override the display depth inherited by direct children. */
|
|
45
45
|
getChildDepth?: (item: T, row: TreeRow<T, K>, children: readonly T[]) => number;
|
|
46
|
+
/**
|
|
47
|
+
* Reuse the parent ancestor list when a child keeps the same display depth
|
|
48
|
+
* and the current item has no siblings (`siblingCount === 1`). Otherwise
|
|
49
|
+
* retain the current item as an ancestor so connector gutters remain
|
|
50
|
+
* accurate, including when the item has multiple children.
|
|
51
|
+
*/
|
|
52
|
+
compactSameDepthAncestors?: boolean;
|
|
46
53
|
/** Stop projection after this many structural items. Omit for no traversal cap. */
|
|
47
54
|
maxItems?: number;
|
|
48
55
|
}
|
|
49
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Ancestors live in a shared parent chain instead of a per-row array: a linear
|
|
59
|
+
* conversation is an n-deep path, and copying the array at every level costs
|
|
60
|
+
* O(n²) memory — 80k-entry sessions exhausted RAM opening `/tree`. Rows build
|
|
61
|
+
* the array lazily, so only rendered rows pay O(depth).
|
|
62
|
+
*/
|
|
63
|
+
interface AncestorChain<K extends TreeKey> {
|
|
64
|
+
value: TreeAncestor<K>;
|
|
65
|
+
parent: AncestorChain<K> | undefined;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function ancestorArray<K extends TreeKey>(chain: AncestorChain<K> | undefined): readonly TreeAncestor<K>[] {
|
|
69
|
+
const out: TreeAncestor<K>[] = [];
|
|
70
|
+
for (let node = chain; node !== undefined; node = node.parent) out.push(node.value);
|
|
71
|
+
return out.reverse();
|
|
72
|
+
}
|
|
73
|
+
|
|
50
74
|
interface PendingTreeRow<T, K extends TreeKey> {
|
|
51
75
|
item: T;
|
|
52
76
|
parentKey: K | undefined;
|
|
53
77
|
depth: number;
|
|
54
78
|
siblingIndex: number;
|
|
55
79
|
siblingCount: number;
|
|
56
|
-
|
|
80
|
+
chain: AncestorChain<K> | undefined;
|
|
57
81
|
}
|
|
58
82
|
|
|
59
83
|
interface FlattenTreeResult<T, K extends TreeKey> {
|
|
@@ -77,13 +101,14 @@ function projectTree<T, K extends TreeKey>(options: FlattenTreeOptions<T, K>): F
|
|
|
77
101
|
depth: rootDepth,
|
|
78
102
|
siblingIndex: index,
|
|
79
103
|
siblingCount: roots.length,
|
|
80
|
-
|
|
104
|
+
chain: undefined,
|
|
81
105
|
});
|
|
82
106
|
}
|
|
83
107
|
|
|
84
108
|
while (stack.length > 0 && rows.length < maxItems) {
|
|
85
109
|
const pending = stack.pop()!;
|
|
86
110
|
const key = options.getKey(pending.item);
|
|
111
|
+
const chain = pending.chain;
|
|
87
112
|
const row: TreeRow<T, K> = {
|
|
88
113
|
item: pending.item,
|
|
89
114
|
key,
|
|
@@ -93,7 +118,9 @@ function projectTree<T, K extends TreeKey>(options: FlattenTreeOptions<T, K>): F
|
|
|
93
118
|
siblingIndex: pending.siblingIndex,
|
|
94
119
|
siblingCount: pending.siblingCount,
|
|
95
120
|
isLast: pending.siblingIndex === pending.siblingCount - 1,
|
|
96
|
-
ancestors
|
|
121
|
+
get ancestors() {
|
|
122
|
+
return ancestorArray(chain);
|
|
123
|
+
},
|
|
97
124
|
};
|
|
98
125
|
rows.push(row);
|
|
99
126
|
|
|
@@ -104,10 +131,13 @@ function projectTree<T, K extends TreeKey>(options: FlattenTreeOptions<T, K>): F
|
|
|
104
131
|
0,
|
|
105
132
|
Math.trunc(options.getChildDepth?.(pending.item, row, children) ?? pending.depth + 1),
|
|
106
133
|
);
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
134
|
+
const childChain: AncestorChain<K> | undefined =
|
|
135
|
+
options.compactSameDepthAncestors && childDepth === pending.depth && pending.siblingCount === 1
|
|
136
|
+
? chain
|
|
137
|
+
: {
|
|
138
|
+
value: { key, depth: pending.depth, isLast: row.isLast, siblingCount: pending.siblingCount },
|
|
139
|
+
parent: chain,
|
|
140
|
+
};
|
|
111
141
|
for (let index = children.length - 1; index >= 0; index--) {
|
|
112
142
|
stack.push({
|
|
113
143
|
item: children[index],
|
|
@@ -115,7 +145,7 @@ function projectTree<T, K extends TreeKey>(options: FlattenTreeOptions<T, K>): F
|
|
|
115
145
|
depth: childDepth,
|
|
116
146
|
siblingIndex: index,
|
|
117
147
|
siblingCount: children.length,
|
|
118
|
-
|
|
148
|
+
chain: childChain,
|
|
119
149
|
});
|
|
120
150
|
}
|
|
121
151
|
}
|
|
@@ -9,6 +9,7 @@ export declare class TruncatedText implements Component {
|
|
|
9
9
|
/** Return bounded source text and the last-known truncation state. */
|
|
10
10
|
debugState(): Record<string, unknown>;
|
|
11
11
|
invalidate(): void;
|
|
12
|
+
releaseRenderCaches(): void;
|
|
12
13
|
/** First line only, clamped to one visual line with an end ellipsis. */
|
|
13
14
|
describe(_cx: DescribeContext): NativeNode;
|
|
14
15
|
render(width: number): readonly string[];
|
|
@@ -41,6 +41,11 @@ export class TruncatedText implements Component {
|
|
|
41
41
|
this.#cachedLines = undefined;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
releaseRenderCaches(): void {
|
|
45
|
+
this.#cachedWidth = -1;
|
|
46
|
+
this.#cachedLines = undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
/** First line only, clamped to one visual line with an end ellipsis. */
|
|
45
50
|
describe(_cx: DescribeContext): NativeNode {
|
|
46
51
|
if (this.#native) return this.#native;
|
package/src/desktop-notify.ts
CHANGED
|
@@ -176,7 +176,7 @@ export function sendDesktopNotification(message: string | TerminalNotification):
|
|
|
176
176
|
try {
|
|
177
177
|
// `.unref()` lets the event loop exit while the notifier is still running.
|
|
178
178
|
// Without it, an unresponsive D-Bus activation (slow `notify-send`, hung
|
|
179
|
-
// `gdbus` waiting on a stalled session bus) would keep `
|
|
179
|
+
// `gdbus` waiting on a stalled session bus) would keep `zetacode` alive past
|
|
180
180
|
// the renderer's shutdown — a completion toast must never delay process
|
|
181
181
|
// exit. Ignored stdio alone does not detach the child from the parent's
|
|
182
182
|
// reference count.
|
package/src/fuzzy.d.ts
CHANGED
|
@@ -16,6 +16,20 @@ export interface FuzzyFilterResult<T> {
|
|
|
16
16
|
score: number;
|
|
17
17
|
}
|
|
18
18
|
export declare function fuzzyMatch(query: string, text: string): FuzzyMatch;
|
|
19
|
+
/**
|
|
20
|
+
* A query normalized and tokenized once for matching against many texts.
|
|
21
|
+
*
|
|
22
|
+
* `fuzzyMatch(query, text)` re-normalizes `query` (and rebuilds its
|
|
23
|
+
* alphanumeric-swap variants) on every call; filters that test one query
|
|
24
|
+
* against every row should build one `FuzzyQuery` per keystroke instead.
|
|
25
|
+
* `query.match(text)` returns exactly what `fuzzyMatch(query, text)` returns.
|
|
26
|
+
*/
|
|
27
|
+
export declare class FuzzyQuery {
|
|
28
|
+
#private;
|
|
29
|
+
constructor(query: string);
|
|
30
|
+
/** Same result as `fuzzyMatch(query, text)`; `text` may be a prepared {@link FuzzyText}. */
|
|
31
|
+
match(text: string | FuzzyText): FuzzyMatch;
|
|
32
|
+
}
|
|
19
33
|
/**
|
|
20
34
|
* A text prepared once for repeated fuzzy matching.
|
|
21
35
|
*
|
|
@@ -30,7 +44,21 @@ export declare class FuzzyText {
|
|
|
30
44
|
#private;
|
|
31
45
|
constructor(text: string);
|
|
32
46
|
/** Match `query` (space-separated tokens; all must match) against the prepared text. */
|
|
33
|
-
match(query: string): FuzzyMatch;
|
|
47
|
+
match(query: string | FuzzyQuery): FuzzyMatch;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Items prepared once for repeated {@link fuzzyRank}-equivalent ranking.
|
|
51
|
+
*
|
|
52
|
+
* `fuzzyRank` resolves each candidate's search index through the bounded module
|
|
53
|
+
* cache, which holds at most {@link INDEX_CACHE_MAX} entries; larger candidate
|
|
54
|
+
* lists (the full model catalog) rebuild the overflow on every query. Hold one
|
|
55
|
+
* corpus per stable candidate list and call {@link rank} per keystroke instead.
|
|
56
|
+
*/
|
|
57
|
+
export declare class FuzzyCorpus<T> {
|
|
58
|
+
#private;
|
|
59
|
+
constructor(items: readonly T[], getText: (item: T) => string);
|
|
60
|
+
/** Same results as `fuzzyRank(items, query, getText)` for the prepared items. */
|
|
61
|
+
rank(query: string): FuzzyFilterResult<T>[];
|
|
34
62
|
}
|
|
35
63
|
/**
|
|
36
64
|
* Filter and sort items by fuzzy match quality (best matches first).
|
package/src/fuzzy.ts
CHANGED
|
@@ -68,27 +68,41 @@ function normalizeForSearch(value: string): string {
|
|
|
68
68
|
// index across keystrokes eliminates the redundant normalize + word-split + Set
|
|
69
69
|
// build on every character. Consumers only read the result, so sharing is safe.
|
|
70
70
|
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
71
|
+
// Only short texts are cached (long inputs — pasted prompts, transcripts
|
|
72
|
+
// searched via the message selector — would bloat memory). The map is a
|
|
73
|
+
// bounded LRU: a hit re-inserts the entry (Map iteration order is insertion
|
|
74
|
+
// order) and a miss at capacity evicts the oldest entry, so a burst of one-off
|
|
75
|
+
// texts can't pin itself forever and starve later selectors of the cache.
|
|
76
|
+
// A single ranking pass only admits/promotes its first INDEX_CACHE_MAX
|
|
77
|
+
// candidates; the tail of a larger list is looked up without promotion and
|
|
78
|
+
// built uncached otherwise, so re-ranking an oversized list keeps its head
|
|
79
|
+
// cached instead of cyclically evicting every entry. Candidate lists larger
|
|
80
|
+
// than the cap should hold a {@link FuzzyCorpus}.
|
|
76
81
|
const INDEX_CACHE_MAX = 4096;
|
|
77
82
|
const MAX_CACHED_TEXT_LEN = 4096;
|
|
78
83
|
const indexCache = new Map<string, SearchIndex>();
|
|
79
84
|
|
|
80
|
-
function buildSearchIndex(text: string): SearchIndex {
|
|
85
|
+
function buildSearchIndex(text: string, admit = true): SearchIndex {
|
|
81
86
|
// Long inputs (pasted prompts, transcripts) are never cached; bypass the Map
|
|
82
87
|
// entirely so they don't pay a hash lookup on every search.
|
|
83
88
|
if (text.length > MAX_CACHED_TEXT_LEN) return buildUncachedSearchIndex(text);
|
|
84
89
|
|
|
85
90
|
const cached = indexCache.get(text);
|
|
86
|
-
if (cached !== undefined)
|
|
91
|
+
if (cached !== undefined) {
|
|
92
|
+
if (admit) {
|
|
93
|
+
indexCache.delete(text);
|
|
94
|
+
indexCache.set(text, cached);
|
|
95
|
+
}
|
|
96
|
+
return cached;
|
|
97
|
+
}
|
|
87
98
|
|
|
88
99
|
const result = buildUncachedSearchIndex(text);
|
|
89
|
-
if (
|
|
90
|
-
|
|
100
|
+
if (!admit) return result;
|
|
101
|
+
if (indexCache.size >= INDEX_CACHE_MAX) {
|
|
102
|
+
const oldest = indexCache.keys().next().value;
|
|
103
|
+
if (oldest !== undefined) indexCache.delete(oldest);
|
|
91
104
|
}
|
|
105
|
+
indexCache.set(text, result);
|
|
92
106
|
return result;
|
|
93
107
|
}
|
|
94
108
|
|
|
@@ -307,11 +321,11 @@ function scoreTokenDirect(token: string, index: SearchIndex): FuzzyMatch {
|
|
|
307
321
|
return best ?? { matches: false, score: 0 };
|
|
308
322
|
}
|
|
309
323
|
|
|
310
|
-
function scoreToken(token: string, index: SearchIndex): FuzzyMatch {
|
|
324
|
+
function scoreToken(token: string, swapVariants: readonly string[], index: SearchIndex): FuzzyMatch {
|
|
311
325
|
let best = scoreTokenDirect(token, index);
|
|
312
326
|
if (best.matches) return best;
|
|
313
327
|
|
|
314
|
-
for (const variant of
|
|
328
|
+
for (const variant of swapVariants) {
|
|
315
329
|
const match = scoreTokenDirect(variant, index);
|
|
316
330
|
if (!match.matches) continue;
|
|
317
331
|
const score = match.score + ALPHANUMERIC_SWAP_PENALTY;
|
|
@@ -323,18 +337,26 @@ function scoreToken(token: string, index: SearchIndex): FuzzyMatch {
|
|
|
323
337
|
return best;
|
|
324
338
|
}
|
|
325
339
|
|
|
326
|
-
/** A query normalized and split once, so
|
|
327
|
-
* same query for every candidate
|
|
340
|
+
/** A query normalized and split once, so ranking doesn't re-normalize the
|
|
341
|
+
* same query (or rebuild its alphanumeric-swap variants) for every candidate. */
|
|
328
342
|
interface PreparedQuery {
|
|
329
343
|
normalized: string;
|
|
330
344
|
tokens: string[];
|
|
345
|
+
/** `buildAlphanumericSwapQueries` of each token, index-aligned with `tokens`. */
|
|
346
|
+
tokenSwaps: string[][];
|
|
331
347
|
compact: string;
|
|
332
348
|
}
|
|
333
349
|
|
|
334
350
|
function prepareQuery(query: string): PreparedQuery | null {
|
|
335
351
|
const normalized = normalizeForSearch(query);
|
|
336
352
|
if (normalized.length === 0) return null;
|
|
337
|
-
|
|
353
|
+
const tokens = normalized.split(" ");
|
|
354
|
+
return {
|
|
355
|
+
normalized,
|
|
356
|
+
tokens,
|
|
357
|
+
tokenSwaps: tokens.map(buildAlphanumericSwapQueries),
|
|
358
|
+
compact: normalized.replaceAll(" ", ""),
|
|
359
|
+
};
|
|
338
360
|
}
|
|
339
361
|
|
|
340
362
|
function fuzzyMatchCore(pq: PreparedQuery | null, index: SearchIndex): FuzzyMatch {
|
|
@@ -359,8 +381,8 @@ function fuzzyMatchCore(pq: PreparedQuery | null, index: SearchIndex): FuzzyMatc
|
|
|
359
381
|
totalScore += compactPhraseIndex * 0.01;
|
|
360
382
|
}
|
|
361
383
|
|
|
362
|
-
for (
|
|
363
|
-
const match = scoreToken(
|
|
384
|
+
for (let i = 0; i < pq.tokens.length; i++) {
|
|
385
|
+
const match = scoreToken(pq.tokens[i]!, pq.tokenSwaps[i]!, index);
|
|
364
386
|
if (!match.matches) {
|
|
365
387
|
return { matches: false, score: 0 };
|
|
366
388
|
}
|
|
@@ -376,6 +398,33 @@ export function fuzzyMatch(query: string, text: string): FuzzyMatch {
|
|
|
376
398
|
return fuzzyMatchCore(pq, buildSearchIndex(text));
|
|
377
399
|
}
|
|
378
400
|
|
|
401
|
+
/**
|
|
402
|
+
* A query normalized and tokenized once for matching against many texts.
|
|
403
|
+
*
|
|
404
|
+
* `fuzzyMatch(query, text)` re-normalizes `query` (and rebuilds its
|
|
405
|
+
* alphanumeric-swap variants) on every call; filters that test one query
|
|
406
|
+
* against every row should build one `FuzzyQuery` per keystroke instead.
|
|
407
|
+
* `query.match(text)` returns exactly what `fuzzyMatch(query, text)` returns.
|
|
408
|
+
*/
|
|
409
|
+
export class FuzzyQuery {
|
|
410
|
+
readonly #prepared: PreparedQuery | null;
|
|
411
|
+
|
|
412
|
+
constructor(query: string) {
|
|
413
|
+
this.#prepared = prepareQuery(query);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/** Same result as `fuzzyMatch(query, text)`; `text` may be a prepared {@link FuzzyText}. */
|
|
417
|
+
match(text: string | FuzzyText): FuzzyMatch {
|
|
418
|
+
const pq = this.#prepared;
|
|
419
|
+
if (pq === null) return { matches: true, score: 0 };
|
|
420
|
+
return fuzzyMatchCore(pq, typeof text === "string" ? buildSearchIndex(text) : fuzzyTextIndex(text));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Module-private read access to `FuzzyText#index` for `FuzzyQuery.match`;
|
|
425
|
+
// assigned by FuzzyText's static initializer.
|
|
426
|
+
let fuzzyTextIndex: (text: FuzzyText) => SearchIndex;
|
|
427
|
+
|
|
379
428
|
/**
|
|
380
429
|
* A text prepared once for repeated fuzzy matching.
|
|
381
430
|
*
|
|
@@ -393,10 +442,57 @@ export class FuzzyText {
|
|
|
393
442
|
this.#index = buildUncachedSearchIndex(text);
|
|
394
443
|
}
|
|
395
444
|
|
|
445
|
+
static {
|
|
446
|
+
fuzzyTextIndex = text => text.#index;
|
|
447
|
+
}
|
|
448
|
+
|
|
396
449
|
/** Match `query` (space-separated tokens; all must match) against the prepared text. */
|
|
397
|
-
match(query: string): FuzzyMatch {
|
|
398
|
-
return fuzzyMatchCore(prepareQuery(query), this.#index);
|
|
450
|
+
match(query: string | FuzzyQuery): FuzzyMatch {
|
|
451
|
+
return typeof query === "string" ? fuzzyMatchCore(prepareQuery(query), this.#index) : query.match(this);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Items prepared once for repeated {@link fuzzyRank}-equivalent ranking.
|
|
457
|
+
*
|
|
458
|
+
* `fuzzyRank` resolves each candidate's search index through the bounded module
|
|
459
|
+
* cache, which holds at most {@link INDEX_CACHE_MAX} entries; larger candidate
|
|
460
|
+
* lists (the full model catalog) rebuild the overflow on every query. Hold one
|
|
461
|
+
* corpus per stable candidate list and call {@link rank} per keystroke instead.
|
|
462
|
+
*/
|
|
463
|
+
export class FuzzyCorpus<T> {
|
|
464
|
+
readonly #items: readonly T[];
|
|
465
|
+
readonly #indexes: SearchIndex[];
|
|
466
|
+
|
|
467
|
+
constructor(items: readonly T[], getText: (item: T) => string) {
|
|
468
|
+
this.#items = items;
|
|
469
|
+
this.#indexes = items.map(item => buildUncachedSearchIndex(getText(item)));
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** Same results as `fuzzyRank(items, query, getText)` for the prepared items. */
|
|
473
|
+
rank(query: string): FuzzyFilterResult<T>[] {
|
|
474
|
+
if (!query.trim()) return this.#items.map(item => ({ item, score: 0 }));
|
|
475
|
+
const indexes = this.#indexes;
|
|
476
|
+
return rankIndexed(this.#items, prepareQuery(query), i => indexes[i]!);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function rankIndexed<T>(
|
|
481
|
+
items: readonly T[],
|
|
482
|
+
pq: PreparedQuery | null,
|
|
483
|
+
indexAt: (i: number) => SearchIndex,
|
|
484
|
+
): FuzzyFilterResult<T>[] {
|
|
485
|
+
const results: FuzzyFilterResult<T>[] = [];
|
|
486
|
+
for (let i = 0; i < items.length; i++) {
|
|
487
|
+
const index = indexAt(i);
|
|
488
|
+
const match = pq === null ? { matches: true, score: 0 } : fuzzyMatchCore(pq, index);
|
|
489
|
+
if (match.matches) {
|
|
490
|
+
results.push({ item: items[i]!, score: match.score });
|
|
491
|
+
}
|
|
399
492
|
}
|
|
493
|
+
|
|
494
|
+
results.sort((a, b) => a.score - b.score);
|
|
495
|
+
return results;
|
|
400
496
|
}
|
|
401
497
|
|
|
402
498
|
/**
|
|
@@ -411,18 +507,7 @@ export function fuzzyRank<T>(items: readonly T[], query: string, getText: (item:
|
|
|
411
507
|
// A non-blank query that normalizes to empty (pure punctuation) matches
|
|
412
508
|
// everything with score 0, but still calls getText per item — consumers rely
|
|
413
509
|
// on its side effects (see fuzzy-cache.test.ts).
|
|
414
|
-
|
|
415
|
-
const results: FuzzyFilterResult<T>[] = [];
|
|
416
|
-
for (const item of items) {
|
|
417
|
-
const text = getText(item);
|
|
418
|
-
const match = pq === null ? { matches: true, score: 0 } : fuzzyMatchCore(pq, buildSearchIndex(text));
|
|
419
|
-
if (match.matches) {
|
|
420
|
-
results.push({ item, score: match.score });
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
results.sort((a, b) => a.score - b.score);
|
|
425
|
-
return results;
|
|
510
|
+
return rankIndexed(items, prepareQuery(query), i => buildSearchIndex(getText(items[i]!), i < INDEX_CACHE_MAX));
|
|
426
511
|
}
|
|
427
512
|
|
|
428
513
|
export function fuzzyFilter<T>(items: T[], query: string, getText: (item: T) => string): T[] {
|
package/src/key-hint-format.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Key-hint formatting, kept free of the native addon: it imports only types
|
|
3
|
-
* plus the theme symbol mirror, so addon-free CLI paths (`
|
|
3
|
+
* plus the theme symbol mirror, so addon-free CLI paths (`zetacode --version`,
|
|
4
4
|
* help text in cli/command-help.ts) can format keys without loading
|
|
5
5
|
* `@linxiraos/pi-natives` through the keybindings registry.
|
|
6
6
|
*/
|
package/src/key-hint-format.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Key-hint formatting, kept free of the native addon: it imports only types
|
|
3
|
-
* plus the theme symbol mirror, so addon-free CLI paths (`
|
|
3
|
+
* plus the theme symbol mirror, so addon-free CLI paths (`zetacode --version`,
|
|
4
4
|
* help text in cli/command-help.ts) can format keys without loading
|
|
5
5
|
* `@linxiraos/pi-natives` through the keybindings registry.
|
|
6
6
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { KeyId } from "./app-keybindings";
|
|
1
2
|
/**
|
|
2
3
|
* Match the coding-agent interrupt key.
|
|
3
4
|
*
|
|
@@ -18,6 +19,8 @@ export declare function matchesSelectDown(data: string): boolean;
|
|
|
18
19
|
export declare function matchesSelectPageUp(data: string): boolean;
|
|
19
20
|
/** Match the generic selector page-down keybinding. */
|
|
20
21
|
export declare function matchesSelectPageDown(data: string): boolean;
|
|
22
|
+
/** Effective external-editor key: the first bound key, or Ctrl+G when unbound. */
|
|
23
|
+
export declare function appExternalEditorKey(): KeyId;
|
|
21
24
|
/** Match the external-editor keybinding, falling back to Ctrl+G when unbound. */
|
|
22
25
|
export declare function matchesAppExternalEditor(data: string): boolean;
|
|
23
26
|
/**
|
|
@@ -53,11 +53,15 @@ export function matchesSelectPageDown(data: string): boolean {
|
|
|
53
53
|
return getKeybindings().matches(data, "tui.select.pageDown");
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/** Effective external-editor key: the first bound key, or Ctrl+G when unbound. */
|
|
57
|
+
export function appExternalEditorKey(): KeyId {
|
|
58
|
+
return getKeybindings().getKeys("app.editor.external")[0] ?? "ctrl+g";
|
|
59
|
+
}
|
|
60
|
+
|
|
56
61
|
/** Match the external-editor keybinding, falling back to Ctrl+G when unbound. */
|
|
57
62
|
export function matchesAppExternalEditor(data: string): boolean {
|
|
58
63
|
const keybindings = getKeybindings();
|
|
59
|
-
|
|
60
|
-
if (externalEditorKeys.length > 0) {
|
|
64
|
+
if (keybindings.getKeys("app.editor.external").length > 0) {
|
|
61
65
|
return keybindings.matches(data, "app.editor.external");
|
|
62
66
|
}
|
|
63
67
|
return matchesKey(data, "ctrl+g");
|
package/src/keybindings.d.ts
CHANGED
|
@@ -107,7 +107,7 @@ export declare const TUI_KEYBINDINGS: {
|
|
|
107
107
|
readonly description: "Delete word backward";
|
|
108
108
|
};
|
|
109
109
|
readonly "tui.editor.deleteWordForward": {
|
|
110
|
-
readonly defaultKeys: ["alt+delete", "alt+d", "super+alt+delete", "super+alt+d"];
|
|
110
|
+
readonly defaultKeys: ["alt+delete", "alt+d", "ctrl+delete", "super+alt+delete", "super+alt+d"];
|
|
111
111
|
readonly description: "Delete word forward";
|
|
112
112
|
};
|
|
113
113
|
readonly "tui.editor.deleteToLineStart": {
|
package/src/keybindings.ts
CHANGED
|
@@ -105,7 +105,7 @@ export const TUI_KEYBINDINGS = {
|
|
|
105
105
|
description: "Delete word backward",
|
|
106
106
|
},
|
|
107
107
|
"tui.editor.deleteWordForward": {
|
|
108
|
-
defaultKeys: ["alt+delete", "alt+d", "super+alt+delete", "super+alt+d"],
|
|
108
|
+
defaultKeys: ["alt+delete", "alt+d", "ctrl+delete", "super+alt+delete", "super+alt+d"],
|
|
109
109
|
description: "Delete word forward",
|
|
110
110
|
},
|
|
111
111
|
"tui.editor.deleteToLineStart": {
|
package/src/kitty-graphics.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ export interface KittyGraphicsFeatures {
|
|
|
30
30
|
* cannot use cursor-positioned placements because the outer terminal does not
|
|
31
31
|
* know pane scroll/reflow state. An explicit `PI_FORCE_IMAGE_PROTOCOL=kitty`
|
|
32
32
|
* opts into placeholders under any multiplexer — matching `timg -pk`.
|
|
33
|
-
* Automatic
|
|
34
|
-
* that
|
|
33
|
+
* Automatic fallback stays off inside multiplexers whose pane marker does not
|
|
34
|
+
* prove that a Kitty renderer is enabled (Herdr's is experimental).
|
|
35
35
|
*
|
|
36
36
|
* `PI_NO_KITTY_PLACEHOLDERS=1` and `PI_KITTY_PLACEHOLDERS=0` remain hard
|
|
37
37
|
* opt-outs; `PI_KITTY_PLACEHOLDERS=1` explicitly opts in anywhere else.
|
package/src/kitty-graphics.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* forms. Protocol gating (`imageProtocol === Kitty`) lives in the caller.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { isInsideTerminalMultiplexer, terminalMultiplexerSessions } from "./terminal-multiplexer";
|
|
19
19
|
import { wrapTmuxPassthroughIfNeeded } from "./tmux";
|
|
20
20
|
|
|
21
21
|
/** Kitty Unicode placeholder base character (U+10EEEE, Plane 16 PUA). */
|
|
@@ -67,8 +67,8 @@ export interface KittyGraphicsFeatures {
|
|
|
67
67
|
* cannot use cursor-positioned placements because the outer terminal does not
|
|
68
68
|
* know pane scroll/reflow state. An explicit `PI_FORCE_IMAGE_PROTOCOL=kitty`
|
|
69
69
|
* opts into placeholders under any multiplexer — matching `timg -pk`.
|
|
70
|
-
* Automatic
|
|
71
|
-
* that
|
|
70
|
+
* Automatic fallback stays off inside multiplexers whose pane marker does not
|
|
71
|
+
* prove that a Kitty renderer is enabled (Herdr's is experimental).
|
|
72
72
|
*
|
|
73
73
|
* `PI_NO_KITTY_PLACEHOLDERS=1` and `PI_KITTY_PLACEHOLDERS=0` remain hard
|
|
74
74
|
* opt-outs; `PI_KITTY_PLACEHOLDERS=1` explicitly opts in anywhere else.
|
|
@@ -81,7 +81,7 @@ export function detectKittyUnicodePlaceholdersSupport(terminalId: string, env: N
|
|
|
81
81
|
if (force === "0" || force === "false" || force === "off" || force === "no" || force === "n") return false;
|
|
82
82
|
const insideMultiplexer = isInsideTerminalMultiplexer(env);
|
|
83
83
|
if (insideMultiplexer && env.PI_FORCE_IMAGE_PROTOCOL?.trim().toLowerCase() === "kitty") return true;
|
|
84
|
-
if (
|
|
84
|
+
if (terminalMultiplexerSessions(env).some(multiplexer => multiplexer.imagesRequireOverride)) return false;
|
|
85
85
|
return (
|
|
86
86
|
terminalId === "kitty" ||
|
|
87
87
|
terminalId === "ghostty" ||
|
package/src/loop-watchdog.d.ts
CHANGED
|
@@ -21,13 +21,14 @@ interface LoopWatchdogTimer {
|
|
|
21
21
|
cancel?(): void;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Always-on event-loop lag probe. Each tick is scheduled `intervalMs` ahead
|
|
25
|
-
*
|
|
26
|
-
* the loop was blocked that long. The overshoot is
|
|
27
|
-
* edge (one block ⇒ one line, deduped via
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
24
|
+
* Always-on event-loop lag probe. Each tick is scheduled `intervalMs` ahead,
|
|
25
|
+
* with that target recorded as its deadline; a tick that fires `thresholdMs`
|
|
26
|
+
* past its deadline means the loop was blocked that long. The overshoot is
|
|
27
|
+
* logged once on the rising edge (one block ⇒ one line, deduped via
|
|
28
|
+
* `#wasBlocked`). Attribution via
|
|
29
|
+
* {@link takeLoopPhaseAttribution} totals each innermost phase only after the tick's
|
|
30
|
+
* deadline. A phase is named, with `phaseMs`, only when its total outweighs all
|
|
31
|
+
* unlabeled time in that late window; otherwise the block remains "unknown".
|
|
31
32
|
*
|
|
32
33
|
* The handle is `unref`'d so the probe never keeps the process alive, and stop()
|
|
33
34
|
* cancels the armed timer when the handle exposes `cancel` (the default
|