@oh-my-pi/pi-tui 18.4.2 → 18.4.4
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 +56 -0
- package/dist/types/apps/cleanse-board.d.ts +17 -0
- package/dist/types/apps/git/help.d.ts +16 -0
- package/dist/types/apps/git/sidebar.d.ts +18 -0
- package/dist/types/apps/live-visualizer.d.ts +10 -0
- package/dist/types/apps/ps-top.d.ts +15 -0
- package/dist/types/apps/standalone-picker.d.ts +3 -0
- package/dist/types/autocomplete.d.ts +8 -0
- package/dist/types/chat/advisor-message.d.ts +12 -2
- package/dist/types/chat/assistant-message.d.ts +20 -0
- package/dist/types/chat/bash-execution.d.ts +9 -0
- package/dist/types/chat/chat-transcript-builder.d.ts +6 -1
- package/dist/types/chat/collab-prompt-message.d.ts +4 -0
- package/dist/types/chat/compaction-summary-message.d.ts +15 -0
- package/dist/types/chat/eval-execution.d.ts +8 -0
- package/dist/types/chat/execution-shared.d.ts +58 -0
- package/dist/types/chat/late-diagnostics-message.d.ts +15 -1
- package/dist/types/chat/read-tool-group.d.ts +15 -0
- package/dist/types/chat/skill-message.d.ts +9 -0
- package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +3 -0
- package/dist/types/chat/thinking-display.d.ts +2 -0
- package/dist/types/chat/todo-reminder.d.ts +4 -1
- package/dist/types/chat/tool-execution.d.ts +25 -1
- package/dist/types/chat/transcript-actions.d.ts +37 -0
- package/dist/types/chat/transcript-entry.d.ts +3 -1
- package/dist/types/chat/user-message.d.ts +25 -0
- package/dist/types/chrome/collab-qrcode.d.ts +7 -0
- package/dist/types/chrome/context-thresholds.d.ts +11 -0
- package/dist/types/chrome/countdown-timer.d.ts +9 -3
- package/dist/types/chrome/diff.d.ts +12 -0
- package/dist/types/chrome/dynamic-border.d.ts +3 -0
- package/dist/types/chrome/format.d.ts +6 -0
- package/dist/types/chrome/message-divider.d.ts +13 -0
- package/dist/types/chrome/message-frame.d.ts +10 -0
- package/dist/types/chrome/message-notice.d.ts +23 -0
- package/dist/types/chrome/overlay-box.d.ts +11 -2
- package/dist/types/chrome/qrcode.d.ts +7 -0
- package/dist/types/chrome/segment-track.d.ts +7 -0
- package/dist/types/chrome/selector-helpers.d.ts +0 -6
- package/dist/types/chrome/status-notice.d.ts +14 -0
- package/dist/types/chrome/streaming-panel.d.ts +3 -0
- package/dist/types/chrome/tool-activity.d.ts +3 -0
- package/dist/types/chrome/transcript-container.d.ts +13 -0
- package/dist/types/chrome/transcript-status.d.ts +15 -3
- package/dist/types/components/box.d.ts +7 -0
- package/dist/types/components/disclosure.d.ts +9 -0
- package/dist/types/components/editor.d.ts +42 -0
- package/dist/types/components/form.d.ts +14 -0
- package/dist/types/components/image.d.ts +7 -0
- package/dist/types/components/input.d.ts +20 -1
- package/dist/types/components/key-value-list.d.ts +3 -0
- package/dist/types/components/layout/geometry.d.ts +16 -0
- package/dist/types/components/layout/row.d.ts +7 -0
- package/dist/types/components/layout/split-pane.d.ts +8 -0
- package/dist/types/components/layout/stack.d.ts +6 -0
- package/dist/types/components/loader.d.ts +48 -0
- package/dist/types/components/markdown.d.ts +8 -0
- package/dist/types/components/metric.d.ts +7 -0
- package/dist/types/components/progress-bar.d.ts +3 -0
- package/dist/types/components/scroll-view.d.ts +6 -0
- package/dist/types/components/section.d.ts +3 -0
- package/dist/types/components/select-list.d.ts +33 -0
- package/dist/types/components/settings-list.d.ts +68 -0
- package/dist/types/components/spacer.d.ts +4 -0
- package/dist/types/components/tab-bar.d.ts +9 -0
- package/dist/types/components/table.d.ts +7 -0
- package/dist/types/components/text.d.ts +6 -0
- package/dist/types/components/tree-view.d.ts +9 -0
- package/dist/types/components/truncated-text.d.ts +3 -0
- package/dist/types/components/wizard-step.d.ts +6 -0
- package/dist/types/hotkeys-markdown.d.ts +24 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/latex-block.d.ts +7 -0
- package/dist/types/loop-watchdog.d.ts +9 -0
- package/dist/types/native/apply.d.ts +39 -0
- package/dist/types/native/backend.d.ts +94 -0
- package/dist/types/native/blobs.d.ts +29 -0
- package/dist/types/native/describe.d.ts +56 -0
- package/dist/types/native/encode.d.ts +50 -0
- package/dist/types/native/icons.d.ts +18 -0
- package/dist/types/native/memo.d.ts +27 -0
- package/dist/types/native/node.d.ts +107 -0
- package/dist/types/native/overlay.d.ts +64 -0
- package/dist/types/native/picker.d.ts +124 -0
- package/dist/types/native/reconcile.d.ts +41 -0
- package/dist/types/native/settle.d.ts +11 -0
- package/dist/types/native/spans.d.ts +21 -0
- package/dist/types/native/state.d.ts +6 -0
- package/dist/types/native/tone.d.ts +24 -0
- package/dist/types/overlays/advisor-config.d.ts +20 -0
- package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
- package/dist/types/overlays/agent-hub.d.ts +10 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
- package/dist/types/overlays/agents-hub.d.ts +8 -0
- package/dist/types/overlays/annotation-overlay.d.ts +3 -0
- package/dist/types/overlays/ask-dialog.d.ts +23 -0
- package/dist/types/overlays/bordered-loader.d.ts +3 -0
- package/dist/types/overlays/btw-history-panel.d.ts +9 -0
- package/dist/types/overlays/btw-panel.d.ts +3 -0
- package/dist/types/overlays/cleanse-panel.d.ts +5 -2
- package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
- package/dist/types/overlays/copy-selector.d.ts +38 -0
- package/dist/types/overlays/error-banner.d.ts +9 -0
- package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
- package/dist/types/overlays/history-search.d.ts +18 -0
- package/dist/types/overlays/hook-editor.d.ts +28 -1
- package/dist/types/overlays/hook-input.d.ts +3 -0
- package/dist/types/overlays/hook-selector.d.ts +10 -0
- package/dist/types/overlays/hub-frame.d.ts +18 -0
- package/dist/types/overlays/jobs-panel.d.ts +24 -0
- package/dist/types/overlays/login-dialog.d.ts +10 -0
- package/dist/types/overlays/logout-account-selector.d.ts +4 -0
- package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
- package/dist/types/overlays/model-browser.d.ts +69 -0
- package/dist/types/overlays/model-hub.d.ts +7 -0
- package/dist/types/overlays/model-picker.d.ts +9 -1
- package/dist/types/overlays/move-overlay.d.ts +3 -0
- package/dist/types/overlays/oauth-selector.d.ts +4 -0
- package/dist/types/overlays/omfg-panel.d.ts +3 -0
- package/dist/types/overlays/pause-screen.d.ts +12 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
- package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
- package/dist/types/overlays/plugin-selector.d.ts +4 -0
- package/dist/types/overlays/plugin-settings.d.ts +30 -0
- package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
- package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
- package/dist/types/overlays/rewind-selector.d.ts +5 -0
- package/dist/types/overlays/session-info-overlay.d.ts +19 -1
- package/dist/types/overlays/session-selector.d.ts +64 -1
- package/dist/types/overlays/settings-defs.d.ts +14 -0
- package/dist/types/overlays/settings-selector.d.ts +21 -0
- package/dist/types/overlays/show-images-selector.d.ts +4 -0
- package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
- package/dist/types/overlays/stats-notice.d.ts +8 -0
- package/dist/types/overlays/theme-selector.d.ts +11 -0
- package/dist/types/overlays/thinking-selector.d.ts +4 -0
- package/dist/types/overlays/tree-selector.d.ts +60 -2
- package/dist/types/overlays/usage-dashboard.d.ts +26 -3
- package/dist/types/overlays/usage-row.d.ts +36 -2
- package/dist/types/prompt/attachment-chips.d.ts +8 -0
- package/dist/types/prompt/composer-attachments.d.ts +15 -3
- package/dist/types/prompt/composer.d.ts +18 -1
- package/dist/types/prompt/custom-editor.d.ts +48 -2
- package/dist/types/prompt/editor-top-gap.d.ts +2 -0
- package/dist/types/prompt/macos-spelling.d.ts +6 -0
- package/dist/types/prompt/magic-keywords.d.ts +9 -0
- package/dist/types/prompt/queued-messages.d.ts +23 -0
- package/dist/types/prompt/skill-tokens.d.ts +4 -2
- package/dist/types/prompt/welcome.d.ts +16 -0
- package/dist/types/render/code-cell.d.ts +10 -0
- package/dist/types/render/file-list.d.ts +8 -0
- package/dist/types/render/hyperlink.d.ts +14 -0
- package/dist/types/render/output-block.d.ts +43 -0
- package/dist/types/render/output-pane.d.ts +17 -0
- package/dist/types/render/tool-card.d.ts +8 -0
- package/dist/types/render/tree-list.d.ts +8 -0
- package/dist/types/render/width-aware-text.d.ts +7 -0
- package/dist/types/setup/scenes/outro.d.ts +7 -0
- package/dist/types/setup/scenes/sign-in.d.ts +16 -9
- package/dist/types/setup/scenes/splash.d.ts +8 -0
- package/dist/types/setup/scenes/types.d.ts +6 -27
- package/dist/types/setup/wizard-overlay.d.ts +9 -0
- package/dist/types/status-line/component.d.ts +49 -5
- package/dist/types/status-line/context-usage.d.ts +20 -0
- package/dist/types/status-line/footer.d.ts +8 -0
- package/dist/types/status-line/metrics.d.ts +1 -2
- package/dist/types/status-line/segments.d.ts +10 -1
- package/dist/types/status-line/types.d.ts +40 -1
- package/dist/types/stdin-buffer.d.ts +10 -7
- package/dist/types/terminal-capabilities.d.ts +1 -1
- package/dist/types/terminal.d.ts +36 -0
- package/dist/types/theme/defaults/index.d.ts +100 -0
- package/dist/types/theme/schema.d.ts +2 -0
- package/dist/types/theme/shimmer.d.ts +8 -0
- package/dist/types/theme/theme-class.d.ts +2 -0
- package/dist/types/theme/theme.d.ts +33 -1
- package/dist/types/tools/ask.d.ts +3 -0
- package/dist/types/tools/ast-edit.d.ts +10 -1
- package/dist/types/tools/ast-grep.d.ts +10 -1
- package/dist/types/tools/autoresearch.d.ts +21 -4
- package/dist/types/tools/bash.d.ts +30 -1
- package/dist/types/tools/cfg-render.d.ts +5 -1
- package/dist/types/tools/debug.d.ts +3 -1
- package/dist/types/tools/default-renderer.d.ts +6 -1
- package/dist/types/tools/edit.d.ts +14 -1
- package/dist/types/tools/eval.d.ts +12 -1
- package/dist/types/tools/fetch.d.ts +16 -1
- package/dist/types/tools/find.d.ts +15 -1
- package/dist/types/tools/github.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +14 -1
- package/dist/types/tools/goal.d.ts +3 -1
- package/dist/types/tools/grep.d.ts +14 -1
- package/dist/types/tools/grouped-file-output.d.ts +58 -0
- package/dist/types/tools/json-tree.d.ts +20 -0
- package/dist/types/tools/lsp.d.ts +3 -10
- package/dist/types/tools/mcp.d.ts +16 -1
- package/dist/types/tools/memory.d.ts +26 -0
- package/dist/types/tools/native-view.d.ts +90 -0
- package/dist/types/tools/proc-render.d.ts +7 -1
- package/dist/types/tools/read.d.ts +23 -1
- package/dist/types/tools/renderer.d.ts +57 -0
- package/dist/types/tools/report-tool-issue.d.ts +3 -0
- package/dist/types/tools/resolve.d.ts +14 -1
- package/dist/types/tools/task.d.ts +3 -0
- package/dist/types/tools/think.d.ts +3 -0
- package/dist/types/tools/todo.d.ts +12 -0
- package/dist/types/tools/vibe.d.ts +3 -1
- package/dist/types/tools/wait.d.ts +3 -0
- package/dist/types/tools/web-search-types.d.ts +90 -0
- package/dist/types/tools/web-search.d.ts +9 -168
- package/dist/types/tools/write.d.ts +14 -1
- package/dist/types/tools/xdev.d.ts +13 -0
- package/dist/types/tui.d.ts +49 -0
- package/package.json +9 -9
- package/src/apps/autoresearch-dashboard.ts +362 -4
- package/src/apps/cleanse-board.ts +219 -1
- package/src/apps/cleanse-picker.ts +9 -1
- package/src/apps/debug/log-viewer.ts +15 -15
- package/src/apps/debug/protocol-probe.ts +2 -20
- package/src/apps/git/avatar.ts +2 -22
- package/src/apps/git/git-tui.ts +406 -59
- package/src/apps/git/help.ts +130 -0
- package/src/apps/git/sidebar.ts +491 -0
- package/src/apps/live-visualizer.ts +65 -0
- package/src/apps/ps-top.ts +448 -17
- package/src/apps/session-picker.ts +1 -0
- package/src/apps/setup-model-picker.ts +5 -1
- package/src/apps/standalone-picker.ts +55 -1
- package/src/autocomplete.ts +44 -1
- package/src/chat/advisor-message.ts +72 -3
- package/src/chat/assistant-message.ts +538 -51
- package/src/chat/background-tan-message.ts +4 -4
- package/src/chat/bash-execution.ts +81 -0
- package/src/chat/cache-invalidation-marker.ts +8 -0
- package/src/chat/chat-transcript-builder.ts +37 -6
- package/src/chat/collab-prompt-message.ts +15 -3
- package/src/chat/compaction-summary-message.ts +74 -1
- package/src/chat/custom-message.ts +3 -1
- package/src/chat/eval-execution.ts +57 -0
- package/src/chat/execution-shared.ts +153 -1
- package/src/chat/hook-message.ts +1 -0
- package/src/chat/late-diagnostics-message.ts +85 -2
- package/src/chat/read-tool-group.ts +341 -1
- package/src/chat/served-model-marker.ts +8 -0
- package/src/chat/skill-message.ts +63 -0
- package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
- package/src/chat/thinking-display.ts +73 -11
- package/src/chat/todo-reminder.ts +34 -4
- package/src/chat/tool-execution.ts +385 -10
- package/src/chat/transcript-actions.ts +38 -0
- package/src/chat/transcript-browser.ts +2 -9
- package/src/chat/transcript-entry.ts +10 -1
- package/src/chat/transcript-render-helpers.ts +16 -15
- package/src/chat/ttsr-notification.ts +38 -1
- package/src/chat/user-message.ts +167 -4
- package/src/chrome/collab-qrcode.ts +27 -2
- package/src/chrome/context-thresholds.ts +34 -0
- package/src/chrome/countdown-timer.ts +24 -1
- package/src/chrome/diff.ts +60 -1
- package/src/chrome/dynamic-border.ts +7 -0
- package/src/chrome/format.ts +12 -0
- package/src/chrome/message-divider.ts +33 -1
- package/src/chrome/message-frame.ts +53 -10
- package/src/chrome/message-notice.ts +71 -0
- package/src/chrome/overlay-box.ts +45 -2
- package/src/chrome/qrcode.ts +28 -0
- package/src/chrome/segment-track.ts +26 -0
- package/src/chrome/selector-helpers.ts +1 -17
- package/src/chrome/status-notice.ts +46 -0
- package/src/chrome/streaming-panel.ts +25 -1
- package/src/chrome/tool-activity.ts +20 -0
- package/src/chrome/transcript-container.ts +139 -17
- package/src/chrome/transcript-status.ts +40 -11
- package/src/components/box.ts +51 -0
- package/src/components/disclosure.ts +33 -0
- package/src/components/editor.ts +239 -36
- package/src/components/form.ts +93 -9
- package/src/components/image.ts +30 -0
- package/src/components/input.ts +77 -26
- package/src/components/key-value-list.ts +18 -0
- package/src/components/layout/geometry.ts +44 -0
- package/src/components/layout/row.ts +30 -0
- package/src/components/layout/split-pane.ts +65 -0
- package/src/components/layout/stack.ts +27 -0
- package/src/components/loader.ts +183 -1
- package/src/components/markdown.ts +131 -56
- package/src/components/metric.ts +39 -0
- package/src/components/progress-bar.ts +28 -0
- package/src/components/scroll-view.ts +23 -0
- package/src/components/section.ts +16 -0
- package/src/components/select-list.ts +174 -25
- package/src/components/settings-list.ts +264 -7
- package/src/components/spacer.ts +17 -0
- package/src/components/tab-bar.ts +42 -0
- package/src/components/table.ts +34 -0
- package/src/components/text.ts +23 -0
- package/src/components/tree-view.ts +65 -0
- package/src/components/truncated-text.ts +14 -0
- package/src/components/wizard-step.ts +18 -9
- package/src/debug-server.ts +14 -7
- package/src/hotkeys-markdown.ts +251 -69
- package/src/index.ts +6 -0
- package/src/latex-block.ts +11 -0
- package/src/loop-watchdog.ts +38 -10
- package/src/native/apply.ts +275 -0
- package/src/native/backend.ts +682 -0
- package/src/native/blobs.ts +70 -0
- package/src/native/describe.ts +124 -0
- package/src/native/encode.ts +233 -0
- package/src/native/icons.ts +184 -0
- package/src/native/memo.ts +64 -0
- package/src/native/node.ts +112 -0
- package/src/native/overlay.ts +131 -0
- package/src/native/picker.ts +333 -0
- package/src/native/reconcile.ts +1063 -0
- package/src/native/settle.ts +23 -0
- package/src/native/spans.ts +308 -0
- package/src/native/state.ts +28 -0
- package/src/native/tone.ts +79 -0
- package/src/overlays/advisor-config.ts +420 -0
- package/src/overlays/agent-hub-renderer.ts +155 -18
- package/src/overlays/agent-hub.ts +1037 -44
- package/src/overlays/agent-transcript-viewer.ts +129 -0
- package/src/overlays/agents-hub.ts +688 -53
- package/src/overlays/annotation-overlay.ts +391 -52
- package/src/overlays/ask-dialog.ts +435 -24
- package/src/overlays/bordered-loader.ts +17 -0
- package/src/overlays/btw-history-panel.ts +182 -0
- package/src/overlays/btw-panel.ts +68 -2
- package/src/overlays/cleanse-panel.ts +105 -15
- package/src/overlays/codex-reset-fireworks.ts +65 -5
- package/src/overlays/composer-shape-preview.ts +26 -1
- package/src/overlays/copy-selector.ts +545 -23
- package/src/overlays/error-banner.ts +44 -0
- package/src/overlays/extensions/extension-list.ts +23 -17
- package/src/overlays/history-search.ts +175 -33
- package/src/overlays/hook-editor.ts +113 -6
- package/src/overlays/hook-input.ts +22 -1
- package/src/overlays/hook-selector.ts +311 -22
- package/src/overlays/hub-frame.ts +80 -0
- package/src/overlays/jobs-panel.ts +112 -0
- package/src/overlays/login-dialog.ts +183 -1
- package/src/overlays/logout-account-selector.ts +102 -4
- package/src/overlays/mcp-add-wizard.ts +232 -53
- package/src/overlays/model-browser.ts +681 -22
- package/src/overlays/model-hub.ts +1402 -78
- package/src/overlays/model-picker.ts +184 -7
- package/src/overlays/move-overlay.ts +45 -0
- package/src/overlays/oauth-selector.ts +227 -23
- package/src/overlays/omfg-panel.ts +86 -2
- package/src/overlays/pause-screen.ts +55 -4
- package/src/overlays/plan-review-overlay.ts +352 -0
- package/src/overlays/plan-save-overlay.ts +45 -0
- package/src/overlays/plugin-selector.ts +21 -1
- package/src/overlays/plugin-settings.ts +195 -5
- package/src/overlays/queue-mode-selector.ts +19 -1
- package/src/overlays/reset-usage-selector.ts +110 -40
- package/src/overlays/rewind-selector.ts +458 -44
- package/src/overlays/session-account-selector.ts +1 -1
- package/src/overlays/session-info-overlay.ts +137 -1
- package/src/overlays/session-selector.ts +807 -46
- package/src/overlays/settings-defs.ts +41 -0
- package/src/overlays/settings-selector.ts +585 -33
- package/src/overlays/show-images-selector.ts +18 -1
- package/src/overlays/snapcompact-shape-preview.ts +48 -3
- package/src/overlays/stats-notice.ts +31 -0
- package/src/overlays/theme-selector.ts +31 -1
- package/src/overlays/thinking-selector.ts +22 -1
- package/src/overlays/tree-selector.ts +570 -110
- package/src/overlays/usage-dashboard.ts +587 -12
- package/src/overlays/usage-row.ts +161 -25
- package/src/prompt/attachment-chips.ts +60 -0
- package/src/prompt/composer-attachments.ts +31 -9
- package/src/prompt/composer.ts +55 -2
- package/src/prompt/custom-editor.ts +302 -4
- package/src/prompt/editor-top-gap.ts +8 -0
- package/src/prompt/macos-spelling.ts +24 -9
- package/src/prompt/magic-keywords.ts +22 -1
- package/src/prompt/model-mention-autocomplete.ts +1 -0
- package/src/prompt/queued-messages.ts +101 -0
- package/src/prompt/skill-tokens.ts +5 -3
- package/src/prompt/welcome.ts +213 -6
- package/src/render/code-cell.ts +103 -2
- package/src/render/file-list.ts +29 -0
- package/src/render/hyperlink.ts +32 -0
- package/src/render/output-block.ts +110 -0
- package/src/render/output-pane.ts +37 -0
- package/src/render/tool-card.ts +137 -0
- package/src/render/tree-list.ts +39 -0
- package/src/render/width-aware-text.ts +20 -0
- package/src/setup/scenes/composer.ts +29 -0
- package/src/setup/scenes/glyph.ts +15 -0
- package/src/setup/scenes/model.ts +36 -8
- package/src/setup/scenes/outro.ts +28 -1
- package/src/setup/scenes/sign-in.ts +138 -24
- package/src/setup/scenes/splash.ts +28 -1
- package/src/setup/scenes/theme.ts +88 -3
- package/src/setup/scenes/types.ts +7 -28
- package/src/setup/startup-splash.ts +46 -9
- package/src/setup/wizard-overlay.ts +140 -23
- package/src/setup/wizard.ts +1 -1
- package/src/status-line/component.ts +414 -18
- package/src/status-line/context-usage.ts +279 -50
- package/src/status-line/footer.ts +94 -1
- package/src/status-line/metrics.ts +3 -6
- package/src/status-line/segments.ts +463 -97
- package/src/status-line/separators.ts +3 -16
- package/src/status-line/types.ts +43 -1
- package/src/stdin-buffer.ts +27 -21
- package/src/terminal-capabilities.ts +7 -0
- package/src/terminal.ts +153 -11
- package/src/theme/defaults/dark-neon-noir.json +100 -0
- package/src/theme/defaults/index.ts +2 -0
- package/src/theme/defaults/light-prism.json +5 -5
- package/src/theme/defaults/onyx.json +62 -62
- package/src/theme/mermaid-cache.ts +10 -1
- package/src/theme/schema.ts +15 -0
- package/src/theme/shimmer.ts +33 -0
- package/src/theme/theme-class.ts +24 -19
- package/src/theme/theme.ts +111 -9
- package/src/theme/tui-adapters.ts +14 -1
- package/src/tools/ask.ts +157 -1
- package/src/tools/ast-edit.ts +174 -1
- package/src/tools/ast-grep.ts +82 -2
- package/src/tools/autoresearch.ts +149 -1
- package/src/tools/bash.ts +233 -62
- package/src/tools/cfg-render.ts +66 -1
- package/src/tools/debug.ts +78 -1
- package/src/tools/default-renderer.ts +35 -1
- package/src/tools/edit.ts +357 -31
- package/src/tools/eval.ts +257 -1
- package/src/tools/fetch.ts +102 -3
- package/src/tools/find.ts +127 -1
- package/src/tools/github.ts +119 -10
- package/src/tools/glob.ts +116 -1
- package/src/tools/goal.ts +56 -1
- package/src/tools/grep.ts +83 -2
- package/src/tools/grouped-file-output.ts +205 -0
- package/src/tools/json-tree.ts +116 -1
- package/src/tools/lsp.ts +318 -1
- package/src/tools/mcp.ts +80 -1
- package/src/tools/memory.ts +93 -11
- package/src/tools/native-view.ts +292 -0
- package/src/tools/proc-render.ts +221 -1
- package/src/tools/read.ts +199 -4
- package/src/tools/renderer.ts +61 -0
- package/src/tools/report-tool-issue.ts +7 -1
- package/src/tools/resolve.ts +63 -1
- package/src/tools/streaming-output.ts +79 -16
- package/src/tools/task.ts +406 -4
- package/src/tools/think.ts +19 -1
- package/src/tools/todo.ts +89 -0
- package/src/tools/vibe.ts +230 -2
- package/src/tools/wait.ts +181 -1
- package/src/tools/web-search-types.ts +99 -0
- package/src/tools/web-search.ts +111 -170
- package/src/tools/write.ts +144 -5
- package/src/tools/xdev.ts +64 -1
- package/src/tui.ts +295 -4
- package/dist/types/setup/scenes/providers.d.ts +0 -3
- package/dist/types/setup/scenes/web-search.d.ts +0 -22
- package/src/setup/scenes/providers.ts +0 -110
- package/src/setup/scenes/web-search.ts +0 -165
package/src/components/editor.ts
CHANGED
|
@@ -14,6 +14,11 @@ import { BracketedPasteHandler, decodeReencodedPasteControls } from "../brackete
|
|
|
14
14
|
import { canonicalKeyId, getKeybindings, type KeybindingsManager } from "../keybindings";
|
|
15
15
|
import { extractPrintableText, matchesKey, parseKey } from "../keys";
|
|
16
16
|
import { KillRing } from "../kill-ring";
|
|
17
|
+
import type { TspEditorDecoration, TspEditorProps, TspTone } from "@oh-my-pi/pi-wire";
|
|
18
|
+
import { col, node } from "../native/describe";
|
|
19
|
+
import { sameItems, sameProps } from "../native/memo";
|
|
20
|
+
import { plainText } from "../native/spans";
|
|
21
|
+
import type { DescribeContext, NativeChild, NativeNode } from "../native/node";
|
|
17
22
|
import type { SymbolTheme } from "../symbols";
|
|
18
23
|
import { type Component, CURSOR_MARKER, type Focusable } from "../tui";
|
|
19
24
|
import {
|
|
@@ -52,7 +57,36 @@ export type { EditorBorderStyle, EditorTopBorder };
|
|
|
52
57
|
|
|
53
58
|
import { type SelectItem, SelectList, type SelectListLayoutOptions, type SelectListTheme } from "./select-list";
|
|
54
59
|
|
|
60
|
+
/** The TSP root an {@link Editor.describeLayout} hook builds around the `editor` node. */
|
|
61
|
+
export interface NativeEditorLayout {
|
|
62
|
+
readonly role: string;
|
|
63
|
+
/** Tone of the root (`pending` while a turn runs). */
|
|
64
|
+
readonly tone?: TspTone;
|
|
65
|
+
readonly children: readonly NativeChild[];
|
|
66
|
+
/** Keypath of the `editor` node inside the root (the autocomplete's caret anchor). */
|
|
67
|
+
readonly caret: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Vim mode as the TSP `editor.mode` label. */
|
|
71
|
+
const VIM_MODE_LABELS: Record<VimMode, string> = {
|
|
72
|
+
insert: "INSERT",
|
|
73
|
+
normal: "NORMAL",
|
|
74
|
+
visual: "VISUAL",
|
|
75
|
+
"visual-line": "VISUAL",
|
|
76
|
+
};
|
|
77
|
+
|
|
55
78
|
const PASSTHROUGH_COLOR = (text: string): string => text;
|
|
79
|
+
|
|
80
|
+
/** Value equality of two decoration lists, so an unchanged set keeps its identity across text edits elsewhere. */
|
|
81
|
+
function sameDecorations(a: readonly TspEditorDecoration[], b: readonly TspEditorDecoration[]): boolean {
|
|
82
|
+
if (a.length !== b.length) return false;
|
|
83
|
+
for (let i = 0; i < a.length; i++) {
|
|
84
|
+
const x = a[i]!;
|
|
85
|
+
const y = b[i]!;
|
|
86
|
+
if (x.from !== y.from || x.to !== y.to || x.s !== y.s || x.fx !== y.fx) return false;
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
56
90
|
const MENTION_CONTEXT_RE = /(?:^|\s)\^[^\s]*$/;
|
|
57
91
|
const AT_TOKEN_RE = /(?:^|\s)(@[^\s]*)$/;
|
|
58
92
|
|
|
@@ -63,12 +97,12 @@ const AUTOCOMPLETE_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {
|
|
|
63
97
|
/**
|
|
64
98
|
* `@` file lists are narrowed in place (`setFilter(liveToken)`) while a fresh
|
|
65
99
|
* search runs, so a slow walk never leaves entries that contradict the typed
|
|
66
|
-
* token on screen. An emptied list means the refresh is still pending
|
|
100
|
+
* token on screen. An emptied list means the refresh is still pending; the
|
|
101
|
+
* popup stays open but renders nothing until results arrive.
|
|
67
102
|
*/
|
|
68
103
|
const AT_FILE_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {
|
|
69
104
|
...AUTOCOMPLETE_SELECT_LIST_LAYOUT,
|
|
70
105
|
filterItems: (items, token) => items.filter(item => atCompletionMatches(token, item.value)),
|
|
71
|
-
noMatchText: "Searching…",
|
|
72
106
|
};
|
|
73
107
|
|
|
74
108
|
const SLASH_COMMAND_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {
|
|
@@ -568,7 +602,30 @@ export class Editor implements Component, Focusable {
|
|
|
568
602
|
* Width-changing output is allowed on lines without the cursor; it is truncated
|
|
569
603
|
* to the content width rather than reflowed. Cursor glyphs and inline hints are excluded. */
|
|
570
604
|
decorateText: ((text: string, context: EditorTextDecorationContext) => string) | undefined;
|
|
605
|
+
/**
|
|
606
|
+
* TSP counterpart of {@link decorateText}: styled ranges over the buffer
|
|
607
|
+
* (UTF-16 offsets into the lines joined by `\n`). Called only when the text
|
|
608
|
+
* changed or the editor was invalidated since the last description.
|
|
609
|
+
*/
|
|
610
|
+
describeDecorations: ((lines: readonly string[]) => readonly TspEditorDecoration[]) | undefined;
|
|
611
|
+
/** TSP code language of the buffer (`python`, `bash`): the terminal highlights it in the mono face. */
|
|
612
|
+
describeLanguage: (() => string | undefined) | undefined;
|
|
613
|
+
/**
|
|
614
|
+
* TSP chrome around the `editor` node (the prompt composer's chips, mode
|
|
615
|
+
* chip, send/stop): the root role, the children with `input` placed where
|
|
616
|
+
* the layout wants it, and the input's keypath for the caret-anchored
|
|
617
|
+
* autocomplete. Unset: a plain `omp.editor` column over the input.
|
|
618
|
+
*/
|
|
619
|
+
describeLayout: ((input: NativeNode, cx: DescribeContext) => NativeEditorLayout) | undefined;
|
|
620
|
+
/** TSP placeholder for the empty buffer; natively it replaces the rotating ANSI {@link placeholder} hints. */
|
|
621
|
+
nativePlaceholder: string | undefined;
|
|
571
622
|
#promptGutter: string | undefined;
|
|
623
|
+
/** Bumped by {@link invalidate}: host-side decoration inputs (spelling results, settings) changed. */
|
|
624
|
+
#nativeGeneration = 0;
|
|
625
|
+
#nativeDecor?: { text: string; generation: number; decor: readonly TspEditorDecoration[] | undefined };
|
|
626
|
+
#nativeEditor?: { props: TspEditorProps; node: NativeNode };
|
|
627
|
+
#nativeOverlay?: { list: SelectList; caret: string; node: NativeNode };
|
|
628
|
+
#nativeRoot?: { role: string; tone: TspTone | undefined; children: readonly NativeChild[]; node: NativeNode };
|
|
572
629
|
|
|
573
630
|
// Store last layout width for cursor navigation
|
|
574
631
|
#lastLayoutWidth: number = 80;
|
|
@@ -1032,7 +1089,7 @@ export class Editor implements Component, Focusable {
|
|
|
1032
1089
|
}
|
|
1033
1090
|
|
|
1034
1091
|
invalidate(): void {
|
|
1035
|
-
|
|
1092
|
+
this.#nativeGeneration++;
|
|
1036
1093
|
}
|
|
1037
1094
|
|
|
1038
1095
|
/** Active chrome style; a hidden border collapses every shape to borderless. */
|
|
@@ -1539,20 +1596,139 @@ export class Editor implements Component, Focusable {
|
|
|
1539
1596
|
if (bottomRow !== undefined) result.push(bottomRow);
|
|
1540
1597
|
|
|
1541
1598
|
// Add autocomplete list if active
|
|
1542
|
-
|
|
1599
|
+
const autocompleteList = this.#visibleAutocompleteList();
|
|
1600
|
+
if (autocompleteList) {
|
|
1543
1601
|
// Clamp the dropdown to the terminal viewport: the editor rows already
|
|
1544
1602
|
// rendered above plus a small reserve must stay visible.
|
|
1545
1603
|
const viewportRows = this.viewportRowsProvider?.() || process.stdout.rows || Number(Bun.env.LINES) || 24;
|
|
1546
|
-
|
|
1604
|
+
autocompleteList.setMaxVisible(
|
|
1547
1605
|
Math.max(3, Math.min(this.#autocompleteMaxVisible, viewportRows - result.length - 2)),
|
|
1548
1606
|
);
|
|
1549
|
-
|
|
1550
|
-
result.push(...autocompleteResult);
|
|
1607
|
+
result.push(...autocompleteList.render(width));
|
|
1551
1608
|
}
|
|
1552
1609
|
|
|
1553
1610
|
return result;
|
|
1554
1611
|
}
|
|
1555
1612
|
|
|
1613
|
+
/**
|
|
1614
|
+
* An `editor` node (key `input`) carrying the buffer, caret, Vim selection
|
|
1615
|
+
* anchor and mode, decorations, ghost completion, placeholder, prompt and
|
|
1616
|
+
* height cap; the frame, wrapping, scrolling and caret are the terminal's,
|
|
1617
|
+
* so composer shapes play no part. An open autocomplete popup follows as an
|
|
1618
|
+
* `overlay` anchored to the caret around the completion list. Typing and
|
|
1619
|
+
* caret moves change only `text` and `cursor` on the same node.
|
|
1620
|
+
*/
|
|
1621
|
+
describe(cx: DescribeContext): NativeNode {
|
|
1622
|
+
// Vertical caret motion walks visual rows; the terminal owns the real
|
|
1623
|
+
// wrap, so the surface width is the closest available layout width.
|
|
1624
|
+
this.#lastLayoutWidth = Math.max(1, cx.cols);
|
|
1625
|
+
const { lines, cursorLine, cursorCol } = this.#state;
|
|
1626
|
+
const text = lines.join("\n");
|
|
1627
|
+
let offset = 0;
|
|
1628
|
+
for (let i = 0; i < cursorLine; i++) offset += (lines[i]?.length ?? 0) + 1;
|
|
1629
|
+
const cursor = offset + cursorCol;
|
|
1630
|
+
|
|
1631
|
+
let decor = this.#nativeDecor;
|
|
1632
|
+
if (decor?.text !== text || decor.generation !== this.#nativeGeneration) {
|
|
1633
|
+
const next = this.describeDecorations?.(lines);
|
|
1634
|
+
decor = {
|
|
1635
|
+
text,
|
|
1636
|
+
generation: this.#nativeGeneration,
|
|
1637
|
+
decor:
|
|
1638
|
+
next && next.length > 0
|
|
1639
|
+
? decor?.decor && sameDecorations(decor.decor, next)
|
|
1640
|
+
? decor.decor
|
|
1641
|
+
: next
|
|
1642
|
+
: undefined,
|
|
1643
|
+
};
|
|
1644
|
+
this.#nativeDecor = decor;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
const placeholder = this.#getPlaceholder();
|
|
1648
|
+
const nativePlaceholder =
|
|
1649
|
+
this.nativePlaceholder !== undefined && !this.#autocompleteState && this.#isEditorEmpty()
|
|
1650
|
+
? this.nativePlaceholder
|
|
1651
|
+
: placeholder && plainText(placeholder).trim();
|
|
1652
|
+
const atLineEnd = cursorCol >= (lines[cursorLine]?.length ?? 0);
|
|
1653
|
+
const ghost = nativePlaceholder || !atLineEnd ? null : this.#getInlineHint();
|
|
1654
|
+
const vim = this.#vim;
|
|
1655
|
+
let anchor: number | null = null;
|
|
1656
|
+
if (vim?.visual && vim.anchor !== null) {
|
|
1657
|
+
let anchorOffset = 0;
|
|
1658
|
+
for (let i = 0; i < vim.anchor.line; i++) anchorOffset += (lines[i]?.length ?? 0) + 1;
|
|
1659
|
+
if (vim.mode === "visual-line") {
|
|
1660
|
+
// Linewise: stretch the anchor to the far edge of its line.
|
|
1661
|
+
const before =
|
|
1662
|
+
vim.anchor.line < cursorLine || (vim.anchor.line === cursorLine && vim.anchor.col <= cursorCol);
|
|
1663
|
+
anchor = before ? anchorOffset : anchorOffset + (lines[vim.anchor.line]?.length ?? 0);
|
|
1664
|
+
} else {
|
|
1665
|
+
anchor = anchorOffset + vim.anchor.col;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
const prompt = this.#promptGutter === undefined ? "" : plainText(this.#promptGutter);
|
|
1669
|
+
const props: TspEditorProps = {
|
|
1670
|
+
text,
|
|
1671
|
+
cursor,
|
|
1672
|
+
anchor: anchor ?? undefined,
|
|
1673
|
+
decor: decor.decor,
|
|
1674
|
+
ghost: ghost ? plainText(ghost) : undefined,
|
|
1675
|
+
placeholder: nativePlaceholder || undefined,
|
|
1676
|
+
prompt: prompt || undefined,
|
|
1677
|
+
mode: vim ? VIM_MODE_LABELS[vim.mode] : undefined,
|
|
1678
|
+
lang: this.describeLanguage?.(),
|
|
1679
|
+
maxLines: this.#maxHeight,
|
|
1680
|
+
};
|
|
1681
|
+
let editor = this.#nativeEditor;
|
|
1682
|
+
if (!editor || !sameProps(editor.props, props)) {
|
|
1683
|
+
editor = { props, node: node("editor", props, undefined, "input") };
|
|
1684
|
+
this.#nativeEditor = editor;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
const layout = this.describeLayout?.(editor.node, cx) ?? {
|
|
1688
|
+
role: "omp.editor",
|
|
1689
|
+
children: [editor.node],
|
|
1690
|
+
caret: "input",
|
|
1691
|
+
};
|
|
1692
|
+
const children: NativeChild[] = [...layout.children];
|
|
1693
|
+
const list = this.#visibleAutocompleteList();
|
|
1694
|
+
if (list) {
|
|
1695
|
+
list.setNativeMark(this.#autocompleteMark());
|
|
1696
|
+
const overlay = this.#nativeOverlay;
|
|
1697
|
+
if (overlay?.list !== list || overlay.caret !== layout.caret) {
|
|
1698
|
+
this.#nativeOverlay = {
|
|
1699
|
+
list,
|
|
1700
|
+
caret: layout.caret,
|
|
1701
|
+
node: node("overlay", { anchor: { caret: layout.caret }, role: "omp.autocomplete" }, [list], "complete"),
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
children.push(this.#nativeOverlay!.node);
|
|
1705
|
+
} else {
|
|
1706
|
+
this.#nativeOverlay = undefined;
|
|
1707
|
+
}
|
|
1708
|
+
const root = this.#nativeRoot;
|
|
1709
|
+
if (root && root.role === layout.role && root.tone === layout.tone && sameItems(root.children, children)) {
|
|
1710
|
+
return root.node;
|
|
1711
|
+
}
|
|
1712
|
+
const described = col(children, layout.tone ? { role: layout.role, tone: layout.tone } : { role: layout.role });
|
|
1713
|
+
this.#nativeRoot = { role: layout.role, tone: layout.tone, children, node: described };
|
|
1714
|
+
return described;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
/**
|
|
1718
|
+
* The typed text the open popup matches item labels against, for the TSP
|
|
1719
|
+
* `mark`: the completion prefix (the live `@` token while a file list
|
|
1720
|
+
* narrows in place) without its sigil, from its last path segment on.
|
|
1721
|
+
*/
|
|
1722
|
+
#autocompleteMark(): string {
|
|
1723
|
+
let typed = this.#autocompletePrefix;
|
|
1724
|
+
if (typed.startsWith("@")) {
|
|
1725
|
+
const line = this.#state.lines[this.#state.cursorLine] ?? "";
|
|
1726
|
+
typed = AT_TOKEN_RE.exec(line.slice(0, this.#state.cursorCol))?.[1] ?? typed;
|
|
1727
|
+
}
|
|
1728
|
+
typed = typed.replace(/^[/@:#$^]"?/, "");
|
|
1729
|
+
return typed.slice(typed.lastIndexOf("/") + 1);
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1556
1732
|
handleInput(data: string): void {
|
|
1557
1733
|
// Iterative, not recursive: the bytes trailing a completed bracketed
|
|
1558
1734
|
// paste (which may themselves contain further pastes) loop back here,
|
|
@@ -1651,10 +1827,13 @@ export class Editor implements Component, Focusable {
|
|
|
1651
1827
|
|
|
1652
1828
|
// Handle autocomplete special keys first (but don't block other input)
|
|
1653
1829
|
if (this.#autocompleteState && this.#autocompleteList) {
|
|
1654
|
-
// Escape - cancel autocomplete
|
|
1830
|
+
// Escape - cancel autocomplete. A hidden popup (empty narrowed `@` list) is
|
|
1831
|
+
// dropped too, so its pending refresh cannot pop up afterward, but the key
|
|
1832
|
+
// falls through: the user never saw anything to dismiss.
|
|
1655
1833
|
if (kb.matchesCanonical(canonical, "tui.select.cancel")) {
|
|
1834
|
+
const visible = this.isShowingAutocomplete();
|
|
1656
1835
|
this.#cancelAutocomplete(true);
|
|
1657
|
-
return;
|
|
1836
|
+
if (visible) return;
|
|
1658
1837
|
}
|
|
1659
1838
|
// Right arrow at end of line accepts the selection like Tab (fish-style).
|
|
1660
1839
|
// Mid-line, right arrow keeps its cursor-movement role and falls through.
|
|
@@ -1720,31 +1899,8 @@ export class Editor implements Component, Focusable {
|
|
|
1720
1899
|
// arrow at end of line moves the cursor.
|
|
1721
1900
|
this.#cancelAutocomplete();
|
|
1722
1901
|
this.onAutocompleteUpdate?.();
|
|
1723
|
-
} else
|
|
1724
|
-
|
|
1725
|
-
this.#isSlashCommandNameAutocompleteSelection() || isDirectoryCompletionValue(selected.value);
|
|
1726
|
-
const result = this.#autocompleteProvider.applyCompletion(
|
|
1727
|
-
this.#state.lines,
|
|
1728
|
-
this.#state.cursorLine,
|
|
1729
|
-
this.#state.cursorCol,
|
|
1730
|
-
selected,
|
|
1731
|
-
this.#autocompletePrefix,
|
|
1732
|
-
);
|
|
1733
|
-
|
|
1734
|
-
this.#state.lines = result.lines;
|
|
1735
|
-
this.#state.cursorLine = result.cursorLine;
|
|
1736
|
-
this.#setCursorCol(result.cursorCol);
|
|
1737
|
-
|
|
1738
|
-
this.#cancelAutocomplete();
|
|
1739
|
-
this.onAutocompleteUpdate?.();
|
|
1740
|
-
|
|
1741
|
-
this.#notifyChange();
|
|
1742
|
-
|
|
1743
|
-
result.onApplied?.();
|
|
1744
|
-
|
|
1745
|
-
if (shouldChainAutocomplete) {
|
|
1746
|
-
queueMicrotask(() => void this.#tryTriggerAutocomplete());
|
|
1747
|
-
}
|
|
1902
|
+
} else {
|
|
1903
|
+
this.#acceptAutocompleteSelection(selected);
|
|
1748
1904
|
}
|
|
1749
1905
|
// Only an accepted candidate consumes the key; an empty list falls through.
|
|
1750
1906
|
if (selected) return;
|
|
@@ -4108,6 +4264,35 @@ export class Editor implements Component, Focusable {
|
|
|
4108
4264
|
}
|
|
4109
4265
|
await this.#queueAutocompleteRequest({ kind: "regular", explicitTab });
|
|
4110
4266
|
}
|
|
4267
|
+
/** Apply `selected` the way Tab does: complete it in place and chain into directories/commands. */
|
|
4268
|
+
#acceptAutocompleteSelection(selected: SelectItem): void {
|
|
4269
|
+
if (!this.#autocompleteProvider) return;
|
|
4270
|
+
const shouldChainAutocomplete =
|
|
4271
|
+
this.#isSlashCommandNameAutocompleteSelection() || isDirectoryCompletionValue(selected.value);
|
|
4272
|
+
const result = this.#autocompleteProvider.applyCompletion(
|
|
4273
|
+
this.#state.lines,
|
|
4274
|
+
this.#state.cursorLine,
|
|
4275
|
+
this.#state.cursorCol,
|
|
4276
|
+
selected,
|
|
4277
|
+
this.#autocompletePrefix,
|
|
4278
|
+
);
|
|
4279
|
+
|
|
4280
|
+
this.#state.lines = result.lines;
|
|
4281
|
+
this.#state.cursorLine = result.cursorLine;
|
|
4282
|
+
this.#setCursorCol(result.cursorCol);
|
|
4283
|
+
|
|
4284
|
+
this.#cancelAutocomplete();
|
|
4285
|
+
this.onAutocompleteUpdate?.();
|
|
4286
|
+
|
|
4287
|
+
this.#notifyChange();
|
|
4288
|
+
|
|
4289
|
+
result.onApplied?.();
|
|
4290
|
+
|
|
4291
|
+
if (shouldChainAutocomplete) {
|
|
4292
|
+
queueMicrotask(() => void this.#tryTriggerAutocomplete());
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
|
|
4111
4296
|
#createAutocompleteList(
|
|
4112
4297
|
prefix: string,
|
|
4113
4298
|
items: Array<{ value: string; label: string; description?: string }>,
|
|
@@ -4117,7 +4302,14 @@ export class Editor implements Component, Focusable {
|
|
|
4117
4302
|
: prefix.startsWith("@")
|
|
4118
4303
|
? AT_FILE_SELECT_LIST_LAYOUT
|
|
4119
4304
|
: AUTOCOMPLETE_SELECT_LIST_LAYOUT;
|
|
4120
|
-
|
|
4305
|
+
const list = new SelectList(items, this.#autocompleteMaxVisible, this.#theme.selectList, layout);
|
|
4306
|
+
// A pointer pick on the popup (TSP `select`/`activate`) accepts it like Tab.
|
|
4307
|
+
list.onSelect = item => {
|
|
4308
|
+
if (this.#autocompleteList !== list) return;
|
|
4309
|
+
if (this.#autocompleteState === "assist") this.#applySpellingSuggestion();
|
|
4310
|
+
else this.#acceptAutocompleteSelection(item);
|
|
4311
|
+
};
|
|
4312
|
+
return list;
|
|
4121
4313
|
}
|
|
4122
4314
|
|
|
4123
4315
|
async #handleTabCompletion(): Promise<void> {
|
|
@@ -4246,8 +4438,19 @@ export class Editor implements Component, Focusable {
|
|
|
4246
4438
|
}
|
|
4247
4439
|
}
|
|
4248
4440
|
|
|
4441
|
+
/**
|
|
4442
|
+
* Whether an autocomplete popup is on screen. An `@` list narrowed to no match
|
|
4443
|
+
* while its refresh is pending stays open internally but is hidden, so it does
|
|
4444
|
+
* not claim keys (Escape, Vim mode switches) meant for the editor or app.
|
|
4445
|
+
*/
|
|
4249
4446
|
isShowingAutocomplete(): boolean {
|
|
4250
|
-
return this.#
|
|
4447
|
+
return this.#visibleAutocompleteList() !== undefined;
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
/** The open autocomplete list, unless it has no candidate to show. */
|
|
4451
|
+
#visibleAutocompleteList(): SelectList | undefined {
|
|
4452
|
+
if (this.#autocompleteState === null) return undefined;
|
|
4453
|
+
return this.#autocompleteList?.getSelectedItem() ? this.#autocompleteList : undefined;
|
|
4251
4454
|
}
|
|
4252
4455
|
|
|
4253
4456
|
async #updateAutocomplete(): Promise<void> {
|
package/src/components/form.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { getKeybindings } from "../keybindings";
|
|
2
2
|
import { matchesKey } from "../keys";
|
|
3
3
|
import type { MouseRoutable, SgrMouseEvent } from "../mouse";
|
|
4
|
+
import { col, node, span } from "../native/describe";
|
|
5
|
+
import { plainText } from "../native/spans";
|
|
6
|
+
import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../native/node";
|
|
7
|
+
import { type SelectPickerOptions, SelectListSheet } from "../native/picker";
|
|
4
8
|
import { Container, type Component, type Focusable } from "../tui";
|
|
5
9
|
import { replaceTabs, truncateToWidth } from "../utils";
|
|
6
10
|
import { Input } from "./input";
|
|
@@ -48,10 +52,13 @@ function hasMouseRouter(component: FormControl): component is FormControl & Mous
|
|
|
48
52
|
class StyledText implements Component {
|
|
49
53
|
readonly #text: Text;
|
|
50
54
|
#value: string;
|
|
55
|
+
#native: NativeNode | undefined;
|
|
51
56
|
|
|
52
57
|
constructor(
|
|
53
58
|
value: string,
|
|
54
59
|
private readonly style: (text: string) => string,
|
|
60
|
+
/** Span token standing in for `style` on a TSP terminal. */
|
|
61
|
+
private readonly token?: string,
|
|
55
62
|
) {
|
|
56
63
|
this.#value = value;
|
|
57
64
|
this.#text = new Text(this.style(value), 0, 0);
|
|
@@ -60,9 +67,15 @@ class StyledText implements Component {
|
|
|
60
67
|
setText(value: string): void {
|
|
61
68
|
if (value === this.#value) return;
|
|
62
69
|
this.#value = value;
|
|
70
|
+
this.#native = undefined;
|
|
63
71
|
this.#text.setText(this.style(value));
|
|
64
72
|
}
|
|
65
73
|
|
|
74
|
+
describe(_cx: DescribeContext): NativeNode {
|
|
75
|
+
this.#native ??= node("text", { spans: [span(plainText(this.#value), this.token)] });
|
|
76
|
+
return this.#native;
|
|
77
|
+
}
|
|
78
|
+
|
|
66
79
|
render(width: number): readonly string[] {
|
|
67
80
|
return this.#text.render(width);
|
|
68
81
|
}
|
|
@@ -77,9 +90,14 @@ class OptionalText implements Component {
|
|
|
77
90
|
readonly #text: StyledText;
|
|
78
91
|
#value = "";
|
|
79
92
|
readonly #empty: readonly string[] = [];
|
|
93
|
+
readonly #hidden = node("text", { text: "", hidden: true });
|
|
80
94
|
|
|
81
|
-
constructor(style: (text: string) => string) {
|
|
82
|
-
this.#text = new StyledText("", style);
|
|
95
|
+
constructor(style: (text: string) => string, token?: string) {
|
|
96
|
+
this.#text = new StyledText("", style, token);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
describe(cx: DescribeContext): NativeNode {
|
|
100
|
+
return this.#value ? this.#text.describe(cx) : this.#hidden;
|
|
83
101
|
}
|
|
84
102
|
|
|
85
103
|
setText(value: string): void {
|
|
@@ -114,37 +132,67 @@ export class FormField implements Component, Focusable, MouseRoutable {
|
|
|
114
132
|
#memoControl: readonly string[] | undefined;
|
|
115
133
|
#memoAfter: readonly string[] | undefined;
|
|
116
134
|
#memoLines: readonly string[] = [];
|
|
135
|
+
/** Fixed described structure: every child is a component or a static node, so it never changes. */
|
|
136
|
+
readonly #native: NativeNode;
|
|
117
137
|
|
|
118
138
|
constructor(control: FormControl, options: FormFieldOptions) {
|
|
119
139
|
this.control = control;
|
|
120
|
-
this.#error = new OptionalText(options.theme.error);
|
|
140
|
+
this.#error = new OptionalText(options.theme.error, "error");
|
|
141
|
+
// Spacing is the terminal's (`gap`); only content becomes native children.
|
|
142
|
+
const native: NativeChild[] = [];
|
|
121
143
|
|
|
122
144
|
if (options.leadingSpace) this.#beforeControl.addChild(new Spacer(1));
|
|
123
145
|
if (options.label) {
|
|
124
|
-
|
|
146
|
+
const label = new StyledText(options.label, options.theme.label, "strong");
|
|
147
|
+
this.#beforeControl.addChild(label);
|
|
148
|
+
native.push(label);
|
|
125
149
|
}
|
|
126
150
|
if (options.description) {
|
|
127
151
|
if (options.label) this.#beforeControl.addChild(new Spacer(1));
|
|
128
|
-
|
|
152
|
+
const description = new StyledText(options.description, options.theme.description, "muted");
|
|
153
|
+
this.#beforeControl.addChild(description);
|
|
154
|
+
native.push(description);
|
|
155
|
+
}
|
|
156
|
+
for (const detail of options.details ?? []) {
|
|
157
|
+
this.#beforeControl.addChild(detail);
|
|
158
|
+
native.push(detail);
|
|
129
159
|
}
|
|
130
|
-
for (const detail of options.details ?? []) this.#beforeControl.addChild(detail);
|
|
131
160
|
if (options.preview) {
|
|
132
161
|
this.#beforeControl.addChild(new Spacer(1));
|
|
133
162
|
if (options.previewLabel) {
|
|
134
|
-
|
|
163
|
+
const previewLabel = new StyledText(options.previewLabel, options.theme.description, "muted");
|
|
164
|
+
this.#beforeControl.addChild(previewLabel);
|
|
165
|
+
native.push(previewLabel);
|
|
135
166
|
}
|
|
136
167
|
this.#beforeControl.addChild(options.preview);
|
|
168
|
+
native.push(options.preview);
|
|
137
169
|
}
|
|
138
170
|
if (options.spaceBeforeControl !== false) this.#beforeControl.addChild(new Spacer(1));
|
|
171
|
+
native.push(control);
|
|
139
172
|
|
|
140
173
|
if (options.spaceAfterControl !== false) this.#afterControl.addChild(new Spacer(1));
|
|
141
174
|
this.#afterControl.addChild(this.#error);
|
|
142
|
-
|
|
143
|
-
|
|
175
|
+
native.push(this.#error);
|
|
176
|
+
for (const summary of options.summary ?? []) {
|
|
177
|
+
this.#afterControl.addChild(summary);
|
|
178
|
+
native.push(summary);
|
|
179
|
+
}
|
|
180
|
+
if (options.hint) {
|
|
181
|
+
const hint = new StyledText(options.hint, options.theme.hint, "muted");
|
|
182
|
+
this.#afterControl.addChild(hint);
|
|
183
|
+
native.push(hint);
|
|
184
|
+
}
|
|
144
185
|
if (options.footer) {
|
|
145
186
|
this.#afterControl.addChild(new Spacer(1));
|
|
146
187
|
this.#afterControl.addChild(options.footer);
|
|
188
|
+
native.push(options.footer);
|
|
147
189
|
}
|
|
190
|
+
this.#native = col(native, { gap: "sm", role: "omp.form.field" });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Label, description, details, preview, the control, error, summary, hint and footer as one column. */
|
|
194
|
+
describe(_cx: DescribeContext): NativeNode {
|
|
195
|
+
return this.#native;
|
|
148
196
|
}
|
|
149
197
|
|
|
150
198
|
get focused(): boolean {
|
|
@@ -346,14 +394,22 @@ export interface SelectFormFieldOptions extends Omit<FormFieldOptions, "preview"
|
|
|
346
394
|
onCancel(): void;
|
|
347
395
|
/** Schedule a frame after an asynchronous preview update settles. */
|
|
348
396
|
requestRender?: () => void;
|
|
397
|
+
/** The picker sheet a long choice (> {@link PICKER_MIN_ITEMS} items) describes as; defaults to the label. */
|
|
398
|
+
picker?: SelectPickerOptions;
|
|
349
399
|
}
|
|
350
400
|
|
|
401
|
+
/** Choices longer than this describe as a `picker md` sheet where the terminal draws one (spec §5 controls). */
|
|
402
|
+
const PICKER_MIN_ITEMS = 12;
|
|
403
|
+
|
|
351
404
|
/** SelectList field that centralizes selection, cancellation, preview refresh, and mouse routing. */
|
|
352
405
|
export class SelectFormField extends FormField {
|
|
353
406
|
readonly selectList: SelectList;
|
|
354
407
|
readonly #previewText: StyledText | undefined;
|
|
355
408
|
readonly #getPreview: (() => string) | undefined;
|
|
356
409
|
readonly #requestRender: (() => void) | undefined;
|
|
410
|
+
readonly #sheet: SelectListSheet;
|
|
411
|
+
/** Number of choices (before filtering). */
|
|
412
|
+
readonly itemCount: number;
|
|
357
413
|
#previewRequestId = 0;
|
|
358
414
|
|
|
359
415
|
constructor(options: SelectFormFieldOptions) {
|
|
@@ -375,6 +431,16 @@ export class SelectFormField extends FormField {
|
|
|
375
431
|
this.#previewText = previewText;
|
|
376
432
|
this.#getPreview = options.getPreview;
|
|
377
433
|
this.#requestRender = options.requestRender;
|
|
434
|
+
this.itemCount = options.items.length;
|
|
435
|
+
this.#sheet = new SelectListSheet(
|
|
436
|
+
selectList,
|
|
437
|
+
options.picker ?? {
|
|
438
|
+
title: options.label ?? "Select",
|
|
439
|
+
...(options.description ? { subtitle: options.description } : {}),
|
|
440
|
+
searchable: true,
|
|
441
|
+
},
|
|
442
|
+
{ docked: false },
|
|
443
|
+
);
|
|
378
444
|
|
|
379
445
|
selectList.onSelect = item => {
|
|
380
446
|
try {
|
|
@@ -420,9 +486,20 @@ export class SelectFormField extends FormField {
|
|
|
420
486
|
|
|
421
487
|
override invalidate(): void {
|
|
422
488
|
this.#updatePreview();
|
|
489
|
+
this.#sheet.invalidate();
|
|
423
490
|
super.invalidate();
|
|
424
491
|
}
|
|
425
492
|
|
|
493
|
+
/** Long choices describe as a picker sheet where supported; the host places it (layer or prefs editor). */
|
|
494
|
+
override describe(cx: DescribeContext): NativeNode {
|
|
495
|
+
return this.itemCount > PICKER_MIN_ITEMS && cx.supports("picker") ? this.#sheet.describe() : super.describe(cx);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/** Picker pointer events drive the list as its keys do (preview, pick, cancel). */
|
|
499
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
500
|
+
this.#sheet.handle(event);
|
|
501
|
+
}
|
|
502
|
+
|
|
426
503
|
#finishPreview(requestId: number): void {
|
|
427
504
|
if (requestId !== this.#previewRequestId) return;
|
|
428
505
|
this.setError(undefined);
|
|
@@ -467,13 +544,20 @@ export class Form implements Component, Focusable, MouseRoutable {
|
|
|
467
544
|
#memoWidth = -1;
|
|
468
545
|
#memoFieldLines: (readonly string[])[] = [];
|
|
469
546
|
#memoLines: readonly string[] = [];
|
|
547
|
+
readonly #native: NativeNode;
|
|
470
548
|
|
|
471
549
|
constructor(options: FormOptions) {
|
|
472
550
|
this.#options = options;
|
|
473
551
|
this.#fields = options.fields;
|
|
552
|
+
this.#native = col(this.#fields, { gap: "md", role: "omp.form" });
|
|
474
553
|
this.#syncFocus();
|
|
475
554
|
}
|
|
476
555
|
|
|
556
|
+
/** The fields as one column; focus traversal stays keyboard-driven. */
|
|
557
|
+
describe(_cx: DescribeContext): NativeNode {
|
|
558
|
+
return this.#native;
|
|
559
|
+
}
|
|
560
|
+
|
|
477
561
|
get focused(): boolean {
|
|
478
562
|
return this.#focused;
|
|
479
563
|
}
|
package/src/components/image.ts
CHANGED
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
renderImage,
|
|
9
9
|
TERMINAL,
|
|
10
10
|
} from "../terminal-capabilities";
|
|
11
|
+
import { registerNativeBlob } from "../native/blobs";
|
|
12
|
+
import { node } from "../native/describe";
|
|
13
|
+
import type { DescribeContext, NativeNode } from "../native/node";
|
|
11
14
|
import type { Component } from "../tui";
|
|
12
15
|
|
|
13
16
|
export interface ImageTheme {
|
|
@@ -731,6 +734,7 @@ export class Image implements Component {
|
|
|
731
734
|
// pads itself to this height so a budget demotion never shrinks the block
|
|
732
735
|
// (its rows may already be committed to native scrollback).
|
|
733
736
|
#renderedGraphicRows = 0;
|
|
737
|
+
#native?: NativeNode;
|
|
734
738
|
|
|
735
739
|
constructor(
|
|
736
740
|
base64Data: string,
|
|
@@ -764,6 +768,32 @@ export class Image implements Component {
|
|
|
764
768
|
this.#cachedWidth = undefined;
|
|
765
769
|
}
|
|
766
770
|
|
|
771
|
+
/**
|
|
772
|
+
* A native `image` backed by a content-addressed blob; the terminal fits
|
|
773
|
+
* it. Cell caps become `ch`/`lines` bounds. The inline-image budget and
|
|
774
|
+
* graphics protocols do not apply.
|
|
775
|
+
*/
|
|
776
|
+
describe(_cx: DescribeContext): NativeNode {
|
|
777
|
+
if (this.#native) return this.#native;
|
|
778
|
+
const blob = registerNativeBlob(Buffer.from(this.#base64Data, "base64"), this.#mimeType);
|
|
779
|
+
const maxW = this.#options.maxWidthCells;
|
|
780
|
+
const maxH = this.#options.maxHeightCells;
|
|
781
|
+
this.#native = node("image", {
|
|
782
|
+
blob,
|
|
783
|
+
alt: imageFallback(this.#mimeType, this.#dimensions, this.#options.filename),
|
|
784
|
+
w: this.#dimensions.widthPx,
|
|
785
|
+
h: this.#dimensions.heightPx,
|
|
786
|
+
max:
|
|
787
|
+
(maxW ?? 0) > 0 || (maxH ?? 0) > 0
|
|
788
|
+
? {
|
|
789
|
+
w: maxW && maxW > 0 ? `${maxW}ch` : undefined,
|
|
790
|
+
h: maxH && maxH > 0 ? `${maxH}lines` : undefined,
|
|
791
|
+
}
|
|
792
|
+
: undefined,
|
|
793
|
+
});
|
|
794
|
+
return this.#native;
|
|
795
|
+
}
|
|
796
|
+
|
|
767
797
|
render(width: number): readonly string[] {
|
|
768
798
|
const imageProtocol = TERMINAL.imageProtocol;
|
|
769
799
|
const hasProtocol = imageProtocol != null;
|