@oh-my-pi/pi-tui 18.2.4 → 18.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (748) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +43 -0
  3. package/dist/types/app-keybindings.d.ts +395 -0
  4. package/dist/types/apps/autoresearch-dashboard.d.ts +43 -0
  5. package/dist/types/apps/autoresearch-data.d.ts +15 -0
  6. package/dist/types/apps/cleanse-board.d.ts +66 -0
  7. package/dist/types/apps/cleanse-picker.d.ts +23 -0
  8. package/dist/types/apps/debug/log-formatting.d.ts +6 -0
  9. package/dist/types/apps/debug/log-viewer.d.ts +81 -0
  10. package/dist/types/apps/debug/protocol-probe.d.ts +42 -0
  11. package/dist/types/apps/debug/raw-sse-buffer.d.ts +58 -0
  12. package/dist/types/apps/debug/raw-sse.d.ts +26 -0
  13. package/dist/types/apps/debug/terminal-info.d.ts +34 -0
  14. package/dist/types/apps/debug/viewer-frame.d.ts +52 -0
  15. package/dist/types/apps/git/avatar.d.ts +9 -0
  16. package/dist/types/apps/git/colors.d.ts +49 -0
  17. package/dist/types/apps/git/diff-pane.d.ts +188 -0
  18. package/dist/types/apps/git/git-tui.d.ts +66 -0
  19. package/dist/types/apps/git/sidebar.d.ts +149 -0
  20. package/dist/types/apps/git/state.d.ts +117 -0
  21. package/dist/types/apps/if-bench-board.d.ts +75 -0
  22. package/dist/types/apps/live-visualizer.d.ts +33 -0
  23. package/dist/types/apps/ps-data.d.ts +51 -0
  24. package/dist/types/apps/ps-top.d.ts +33 -0
  25. package/dist/types/apps/session-picker.d.ts +26 -0
  26. package/dist/types/apps/setup-model-picker.d.ts +13 -0
  27. package/dist/types/apps/standalone-picker.d.ts +42 -0
  28. package/dist/types/autocomplete.d.ts +4 -0
  29. package/dist/types/chat/advisor-message.d.ts +11 -0
  30. package/dist/types/chat/assistant-message.d.ts +106 -0
  31. package/dist/types/chat/background-tan-message.d.ts +9 -0
  32. package/dist/types/chat/bash-execution.d.ts +47 -0
  33. package/dist/types/chat/cache-invalidation-marker.d.ts +50 -0
  34. package/dist/types/chat/chat-transcript-builder.d.ts +50 -0
  35. package/dist/types/chat/collab-prompt-message.d.ts +10 -0
  36. package/dist/types/chat/compaction-summary-message.d.ts +54 -0
  37. package/dist/types/chat/custom-message.d.ts +10 -0
  38. package/dist/types/chat/display-preferences.d.ts +13 -0
  39. package/dist/types/chat/eval-execution.d.ts +29 -0
  40. package/dist/types/chat/execution-shared.d.ts +51 -0
  41. package/dist/types/chat/extension-types.d.ts +28 -0
  42. package/dist/types/chat/hook-message.d.ts +10 -0
  43. package/dist/types/chat/image-loading.d.ts +46 -0
  44. package/dist/types/chat/late-diagnostics-message.d.ts +21 -0
  45. package/dist/types/chat/messages.d.ts +189 -0
  46. package/dist/types/chat/reaction.d.ts +30 -0
  47. package/dist/types/chat/read-target.d.ts +4 -0
  48. package/dist/types/chat/read-tool-group.d.ts +67 -0
  49. package/dist/types/chat/served-model-marker.d.ts +47 -0
  50. package/dist/types/chat/skill-message.d.ts +33 -0
  51. package/dist/types/chat/skill-title-input.d.ts +14 -0
  52. package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +12 -0
  53. package/dist/types/chat/thinking-display.d.ts +12 -0
  54. package/dist/types/chat/todo-reminder.d.ts +13 -0
  55. package/dist/types/chat/tool-execution.d.ts +138 -0
  56. package/dist/types/chat/transcript-browser.d.ts +93 -0
  57. package/dist/types/chat/transcript-entry.d.ts +45 -0
  58. package/dist/types/chat/transcript-outline.d.ts +86 -0
  59. package/dist/types/chat/transcript-render-helpers.d.ts +92 -0
  60. package/dist/types/chat/ttsr-notification.d.ts +23 -0
  61. package/dist/types/chat/user-message.d.ts +52 -0
  62. package/dist/types/chrome/chat-block.d.ts +64 -0
  63. package/dist/types/chrome/collab-qrcode.d.ts +28 -0
  64. package/dist/types/chrome/context-thresholds.d.ts +10 -0
  65. package/dist/types/chrome/countdown-timer.d.ts +14 -0
  66. package/dist/types/chrome/diff.d.ts +14 -0
  67. package/dist/types/chrome/dynamic-border.d.ts +16 -0
  68. package/dist/types/chrome/error-block.d.ts +17 -0
  69. package/dist/types/chrome/form-theme.d.ts +3 -0
  70. package/dist/types/chrome/format.d.ts +12 -0
  71. package/dist/types/chrome/index.d.ts +20 -0
  72. package/dist/types/chrome/keybinding-hints.d.ts +40 -0
  73. package/dist/types/chrome/live-board.d.ts +23 -0
  74. package/dist/types/chrome/local-date.d.ts +4 -0
  75. package/dist/types/chrome/message-divider.d.ts +22 -0
  76. package/dist/types/chrome/message-frame.d.ts +52 -0
  77. package/dist/types/chrome/message-notice.d.ts +35 -0
  78. package/dist/types/chrome/overlay-box.d.ts +74 -0
  79. package/dist/types/chrome/qrcode.d.ts +48 -0
  80. package/dist/types/chrome/segment-track.d.ts +27 -0
  81. package/dist/types/chrome/select-list-mouse-routing.d.ts +4 -0
  82. package/dist/types/chrome/selector-helpers.d.ts +52 -0
  83. package/dist/types/chrome/shared.d.ts +5 -0
  84. package/dist/types/chrome/streaming-panel.d.ts +19 -0
  85. package/dist/types/chrome/tool-activity.d.ts +17 -0
  86. package/dist/types/chrome/transcript-container.d.ts +129 -0
  87. package/dist/types/chrome/transcript-status.d.ts +12 -0
  88. package/dist/types/chrome/visual-truncate.d.ts +19 -0
  89. package/dist/types/components/disclosure.d.ts +42 -0
  90. package/dist/types/components/form.d.ts +130 -0
  91. package/dist/types/components/key-value-list.d.ts +24 -0
  92. package/dist/types/components/layout/geometry.d.ts +73 -0
  93. package/dist/types/components/layout/row.d.ts +55 -0
  94. package/dist/types/components/layout/split-pane.d.ts +80 -0
  95. package/dist/types/components/layout/stack.d.ts +50 -0
  96. package/dist/types/components/menu-selection.d.ts +71 -0
  97. package/dist/types/components/metric.d.ts +44 -0
  98. package/dist/types/components/progress-bar.d.ts +36 -0
  99. package/dist/types/components/scroll-view.d.ts +53 -19
  100. package/dist/types/components/scroll-viewport.d.ts +46 -0
  101. package/dist/types/components/section.d.ts +19 -0
  102. package/dist/types/components/select-list.d.ts +46 -2
  103. package/dist/types/components/settings-list.d.ts +20 -0
  104. package/dist/types/components/table.d.ts +32 -0
  105. package/dist/types/components/tree-view.d.ts +130 -0
  106. package/dist/types/components/wizard-step.d.ts +60 -0
  107. package/dist/types/hotkeys-markdown.d.ts +7 -0
  108. package/dist/types/index.d.ts +17 -0
  109. package/dist/types/keybinding-matchers.d.ts +35 -0
  110. package/dist/types/keys.d.ts +2 -2
  111. package/dist/types/lang-from-path.d.ts +9 -0
  112. package/dist/types/overlays/advisor-config.d.ts +114 -0
  113. package/dist/types/overlays/agent-activity.d.ts +41 -0
  114. package/dist/types/overlays/agent-hub-projection.d.ts +33 -0
  115. package/dist/types/overlays/agent-hub-renderer.d.ts +53 -0
  116. package/dist/types/overlays/agent-hub-types.d.ts +99 -0
  117. package/dist/types/overlays/agent-hub.d.ts +126 -0
  118. package/dist/types/overlays/agent-transcript-viewer.d.ts +71 -0
  119. package/dist/types/overlays/agents-hub.d.ts +72 -0
  120. package/dist/types/overlays/ask-dialog.d.ts +88 -0
  121. package/dist/types/overlays/bordered-loader.d.ts +11 -0
  122. package/dist/types/overlays/btw-history-panel.d.ts +29 -0
  123. package/dist/types/overlays/btw-history.d.ts +17 -0
  124. package/dist/types/overlays/btw-panel.d.ts +26 -0
  125. package/dist/types/overlays/cleanse-panel.d.ts +36 -0
  126. package/dist/types/overlays/codex-reset-fireworks.d.ts +52 -0
  127. package/dist/types/overlays/composer-shape-preview.d.ts +47 -0
  128. package/dist/types/overlays/composer-shape-registry.d.ts +50 -0
  129. package/dist/types/overlays/copy-selector.d.ts +48 -0
  130. package/dist/types/overlays/copy-targets.d.ts +63 -0
  131. package/dist/types/overlays/error-banner.d.ts +13 -0
  132. package/dist/types/overlays/extensions/display-text.d.ts +10 -0
  133. package/dist/types/overlays/extensions/extension-dashboard.d.ts +63 -0
  134. package/dist/types/overlays/extensions/extension-list.d.ts +54 -0
  135. package/dist/types/overlays/extensions/inspector-model.d.ts +109 -0
  136. package/dist/types/overlays/extensions/inspector-panel.d.ts +17 -0
  137. package/dist/types/overlays/extensions/live-tool-session.d.ts +28 -0
  138. package/dist/types/overlays/extensions/mcp-runtime.d.ts +107 -0
  139. package/dist/types/overlays/extensions/state-manager.d.ts +42 -0
  140. package/dist/types/overlays/extensions/types.d.ts +165 -0
  141. package/dist/types/overlays/history-search.d.ts +16 -0
  142. package/dist/types/overlays/hook-editor.d.ts +44 -0
  143. package/dist/types/overlays/hook-input.d.ts +20 -0
  144. package/dist/types/overlays/hook-selector.d.ts +71 -0
  145. package/dist/types/overlays/hub-frame.d.ts +77 -0
  146. package/dist/types/overlays/login-dialog.d.ts +43 -0
  147. package/dist/types/overlays/logout-account-selector.d.ts +15 -0
  148. package/dist/types/overlays/mcp-add-wizard.d.ts +87 -0
  149. package/dist/types/overlays/model-browser.d.ts +213 -0
  150. package/dist/types/overlays/model-hub.d.ts +72 -0
  151. package/dist/types/overlays/model-picker.d.ts +74 -0
  152. package/dist/types/overlays/model-selector.d.ts +52 -0
  153. package/dist/types/overlays/move-overlay.d.ts +39 -0
  154. package/dist/types/overlays/oauth-selector.d.ts +41 -0
  155. package/dist/types/overlays/omfg-panel.d.ts +20 -0
  156. package/dist/types/overlays/pause-screen.d.ts +43 -0
  157. package/dist/types/overlays/plan-review-overlay.d.ts +89 -0
  158. package/dist/types/overlays/plan-save-overlay.d.ts +19 -0
  159. package/dist/types/overlays/plan-toc.d.ts +41 -0
  160. package/dist/types/overlays/plugin-selector.d.ts +28 -0
  161. package/dist/types/overlays/plugin-settings.d.ts +180 -0
  162. package/dist/types/overlays/queue-mode-selector.d.ts +11 -0
  163. package/dist/types/overlays/reset-usage-selector.d.ts +23 -0
  164. package/dist/types/overlays/rewind-selector.d.ts +61 -0
  165. package/dist/types/overlays/running-subagent-badge.d.ts +6 -0
  166. package/dist/types/overlays/session-account-selector.d.ts +24 -0
  167. package/dist/types/overlays/session-info-overlay.d.ts +17 -0
  168. package/dist/types/overlays/session-observer-registry.d.ts +77 -0
  169. package/dist/types/overlays/session-selector.d.ts +131 -0
  170. package/dist/types/overlays/settings-defs.d.ts +119 -0
  171. package/dist/types/overlays/settings-selector.d.ts +73 -0
  172. package/dist/types/overlays/show-images-selector.d.ts +11 -0
  173. package/dist/types/overlays/snapcompact-shape-preview.d.ts +31 -0
  174. package/dist/types/overlays/theme-selector.d.ts +12 -0
  175. package/dist/types/overlays/thinking-selector.d.ts +12 -0
  176. package/dist/types/overlays/tiny-title-download-progress.d.ts +21 -0
  177. package/dist/types/overlays/tree-selector.d.ts +92 -0
  178. package/dist/types/overlays/usage-dashboard.d.ts +94 -0
  179. package/dist/types/overlays/usage-display.d.ts +5 -0
  180. package/dist/types/overlays/usage-row.d.ts +17 -0
  181. package/dist/types/prompt/attachment-chips.d.ts +19 -0
  182. package/dist/types/prompt/composer-attachments.d.ts +71 -0
  183. package/dist/types/prompt/composer-cache.d.ts +37 -0
  184. package/dist/types/prompt/composer.d.ts +159 -0
  185. package/dist/types/prompt/custom-editor.d.ts +261 -0
  186. package/dist/types/prompt/editor-top-gap.d.ts +18 -0
  187. package/dist/types/prompt/emoji-autocomplete.d.ts +16 -0
  188. package/dist/types/prompt/github-ref-autocomplete.d.ts +35 -0
  189. package/dist/types/prompt/gradient-highlight.d.ts +32 -0
  190. package/dist/types/prompt/image-format.d.ts +4 -0
  191. package/dist/types/prompt/image-references.d.ts +26 -0
  192. package/dist/types/prompt/interactive-context-helpers.d.ts +43 -0
  193. package/dist/types/prompt/internal-url-autocomplete.d.ts +56 -0
  194. package/dist/types/prompt/macos-spelling.d.ts +44 -0
  195. package/dist/types/prompt/magic-keyword-boundary.d.ts +9 -0
  196. package/dist/types/prompt/magic-keywords.d.ts +26 -0
  197. package/dist/types/prompt/markdown-prose.d.ts +15 -0
  198. package/dist/types/prompt/model-mention-autocomplete.d.ts +25 -0
  199. package/dist/types/prompt/model-mention-syntax.d.ts +24 -0
  200. package/dist/types/prompt/orchestrate.d.ts +13 -0
  201. package/dist/types/prompt/prompt-action-autocomplete.d.ts +56 -0
  202. package/dist/types/prompt/queue-input.d.ts +8 -0
  203. package/dist/types/prompt/skill-tokens.d.ts +13 -0
  204. package/dist/types/prompt/tools-markdown.d.ts +12 -0
  205. package/dist/types/prompt/ultrathink.d.ts +13 -0
  206. package/dist/types/prompt/usage-amounts.d.ts +26 -0
  207. package/dist/types/prompt/video.d.ts +18 -0
  208. package/dist/types/prompt/welcome.d.ts +83 -0
  209. package/dist/types/prompt/workflow.d.ts +13 -0
  210. package/dist/types/render/code-cell.d.ts +51 -0
  211. package/dist/types/render/file-list.d.ts +22 -0
  212. package/dist/types/render/hyperlink.d.ts +80 -0
  213. package/dist/types/render/index.d.ts +16 -0
  214. package/dist/types/render/output-block.d.ts +54 -0
  215. package/dist/types/render/output-pane.d.ts +80 -0
  216. package/dist/types/render/render-utils.d.ts +312 -0
  217. package/dist/types/render/sixel.d.ts +21 -0
  218. package/dist/types/render/status-line.d.ts +23 -0
  219. package/dist/types/render/tool-card.d.ts +71 -0
  220. package/dist/types/render/tree-list.d.ts +29 -0
  221. package/dist/types/render/types.d.ts +17 -0
  222. package/dist/types/render/utils.d.ts +43 -0
  223. package/dist/types/render/width-aware-text.d.ts +23 -0
  224. package/dist/types/setup/lazy.d.ts +3 -0
  225. package/dist/types/setup/scenes/composer.d.ts +3 -0
  226. package/dist/types/setup/scenes/glyph.d.ts +3 -0
  227. package/dist/types/setup/scenes/model.d.ts +3 -0
  228. package/dist/types/setup/scenes/outro.d.ts +2 -0
  229. package/dist/types/setup/scenes/providers.d.ts +3 -0
  230. package/dist/types/setup/scenes/sign-in.d.ts +21 -0
  231. package/dist/types/setup/scenes/splash.d.ts +11 -0
  232. package/dist/types/setup/scenes/theme.d.ts +3 -0
  233. package/dist/types/setup/scenes/types.d.ts +110 -0
  234. package/dist/types/setup/scenes/web-search.d.ts +22 -0
  235. package/dist/types/setup/setup-version.d.ts +11 -0
  236. package/dist/types/setup/startup-splash.d.ts +9 -0
  237. package/dist/types/setup/wizard-overlay.d.ts +16 -0
  238. package/dist/types/setup/wizard.d.ts +25 -0
  239. package/dist/types/status-line/component.d.ts +182 -0
  240. package/dist/types/status-line/context-usage.d.ts +156 -0
  241. package/dist/types/status-line/footer.d.ts +30 -0
  242. package/dist/types/status-line/git-utils.d.ts +22 -0
  243. package/dist/types/status-line/host.d.ts +129 -0
  244. package/dist/types/status-line/index.d.ts +6 -0
  245. package/dist/types/status-line/loop.d.ts +18 -0
  246. package/dist/types/status-line/metrics.d.ts +21 -0
  247. package/dist/types/status-line/presets.d.ts +3 -0
  248. package/dist/types/status-line/schema.d.ts +15 -0
  249. package/dist/types/status-line/segments.d.ts +5 -0
  250. package/dist/types/status-line/separators.d.ts +3 -0
  251. package/dist/types/status-line/types.d.ts +236 -0
  252. package/dist/types/stdin-buffer.d.ts +4 -0
  253. package/dist/types/theme/color.d.ts +24 -0
  254. package/dist/types/theme/defaults/index.d.ts +9489 -0
  255. package/dist/types/theme/index.d.ts +4 -0
  256. package/dist/types/theme/loader.d.ts +23 -0
  257. package/dist/types/theme/mermaid-cache.d.ts +26 -0
  258. package/dist/types/theme/schema-validation.d.ts +3 -0
  259. package/dist/types/theme/schema.d.ts +25 -0
  260. package/dist/types/theme/session-color.d.ts +43 -0
  261. package/dist/types/theme/shimmer.d.ts +44 -0
  262. package/dist/types/theme/symbols.d.ts +34 -0
  263. package/dist/types/theme/theme-class.d.ts +299 -0
  264. package/dist/types/theme/theme.d.ts +111 -0
  265. package/dist/types/theme/tui-adapters.d.ts +30 -0
  266. package/dist/types/thinking.d.ts +165 -0
  267. package/dist/types/tools/agent-tree.d.ts +36 -0
  268. package/dist/types/tools/ask.d.ts +67 -0
  269. package/dist/types/tools/ast-edit.d.ts +53 -0
  270. package/dist/types/tools/ast-grep.d.ts +52 -0
  271. package/dist/types/tools/autoresearch.d.ts +156 -0
  272. package/dist/types/tools/bash-interactive.d.ts +28 -0
  273. package/dist/types/tools/bash.d.ts +103 -0
  274. package/dist/types/tools/conflict-detect.d.ts +43 -0
  275. package/dist/types/tools/debug.d.ts +60 -0
  276. package/dist/types/tools/default-renderer.d.ts +24 -0
  277. package/dist/types/tools/edit.d.ts +158 -0
  278. package/dist/types/tools/eval-format/code-mode-declarations.d.ts +5 -0
  279. package/dist/types/tools/eval-format/index.d.ts +5 -0
  280. package/dist/types/tools/eval-format/javascript.d.ts +2 -0
  281. package/dist/types/tools/eval-format/python.d.ts +2 -0
  282. package/dist/types/tools/eval.d.ts +94 -0
  283. package/dist/types/tools/fetch.d.ts +42 -0
  284. package/dist/types/tools/gh-format.d.ts +8 -0
  285. package/dist/types/tools/github.d.ts +144 -0
  286. package/dist/types/tools/glob.d.ts +44 -0
  287. package/dist/types/tools/goal.d.ts +42 -0
  288. package/dist/types/tools/grep.d.ts +64 -0
  289. package/dist/types/tools/grouped-file-output.d.ts +71 -0
  290. package/dist/types/tools/hashline-format.d.ts +28 -0
  291. package/dist/types/tools/hub.d.ts +340 -0
  292. package/dist/types/tools/index.d.ts +4 -0
  293. package/dist/types/tools/json-tree.d.ts +59 -0
  294. package/dist/types/tools/line-ranges.d.ts +29 -0
  295. package/dist/types/tools/list-limit.d.ts +15 -0
  296. package/dist/types/tools/lsp.d.ts +72 -0
  297. package/dist/types/tools/match-line-format.d.ts +11 -0
  298. package/dist/types/tools/mcp.d.ts +81 -0
  299. package/dist/types/tools/memory.d.ts +67 -0
  300. package/dist/types/tools/output-meta.d.ts +151 -0
  301. package/dist/types/tools/read.d.ts +139 -0
  302. package/dist/types/tools/renderer.d.ts +98 -0
  303. package/dist/types/tools/report-tool-issue.d.ts +8 -0
  304. package/dist/types/tools/resolve.d.ts +47 -0
  305. package/dist/types/tools/streaming-output.d.ts +282 -0
  306. package/dist/types/tools/subprocess.d.ts +24 -0
  307. package/dist/types/tools/task-repair-args.d.ts +53 -0
  308. package/dist/types/tools/task-yield-assembly.d.ts +20 -0
  309. package/dist/types/tools/task.d.ts +425 -0
  310. package/dist/types/tools/terminal-output.d.ts +8 -0
  311. package/dist/types/tools/think.d.ts +13 -0
  312. package/dist/types/tools/todo.d.ts +118 -0
  313. package/dist/types/tools/tool-errors.d.ts +7 -0
  314. package/dist/types/tools/vibe.d.ts +120 -0
  315. package/dist/types/tools/web-search.d.ts +195 -0
  316. package/dist/types/tools/write.d.ts +76 -0
  317. package/dist/types/tools/xd-url.d.ts +13 -0
  318. package/dist/types/tools/xdev.d.ts +52 -0
  319. package/dist/types/tui.d.ts +18 -0
  320. package/dist/types/utils.d.ts +2 -0
  321. package/package.json +37 -3
  322. package/src/app-keybindings.ts +760 -0
  323. package/src/apps/autoresearch-dashboard.ts +500 -0
  324. package/src/apps/autoresearch-data.ts +64 -0
  325. package/src/apps/cleanse-board.ts +341 -0
  326. package/src/apps/cleanse-picker.ts +57 -0
  327. package/src/apps/debug/log-formatting.ts +53 -0
  328. package/src/apps/debug/log-viewer.ts +868 -0
  329. package/src/apps/debug/protocol-probe.ts +267 -0
  330. package/src/apps/debug/raw-sse-buffer.ts +449 -0
  331. package/src/apps/debug/raw-sse.ts +282 -0
  332. package/src/apps/debug/terminal-info.ts +115 -0
  333. package/src/apps/debug/viewer-frame.ts +174 -0
  334. package/src/apps/git/avatar.ts +52 -0
  335. package/src/apps/git/colors.ts +109 -0
  336. package/src/apps/git/diff-pane.ts +1512 -0
  337. package/src/apps/git/git-tui.ts +889 -0
  338. package/src/apps/git/sidebar.ts +1204 -0
  339. package/src/apps/git/state.ts +113 -0
  340. package/src/apps/if-bench-board.ts +324 -0
  341. package/src/apps/live-visualizer.ts +238 -0
  342. package/src/apps/ps-data.ts +116 -0
  343. package/src/apps/ps-top.ts +422 -0
  344. package/src/apps/session-picker.ts +95 -0
  345. package/src/apps/setup-model-picker.ts +21 -0
  346. package/src/apps/standalone-picker.ts +111 -0
  347. package/src/autocomplete.ts +9 -13
  348. package/src/chat/advisor-message.ts +175 -0
  349. package/src/chat/assistant-message.ts +1214 -0
  350. package/src/chat/background-tan-message.ts +35 -0
  351. package/src/chat/bash-execution.ts +394 -0
  352. package/src/chat/cache-invalidation-marker.ts +94 -0
  353. package/src/chat/chat-transcript-builder.ts +593 -0
  354. package/src/chat/collab-prompt-message.ts +34 -0
  355. package/src/chat/compaction-summary-message.ts +261 -0
  356. package/src/chat/custom-message.ts +23 -0
  357. package/src/chat/display-preferences.ts +24 -0
  358. package/src/chat/eval-execution.ts +172 -0
  359. package/src/chat/execution-shared.ts +113 -0
  360. package/src/chat/extension-types.ts +46 -0
  361. package/src/chat/hook-message.ts +20 -0
  362. package/src/chat/image-loading.ts +122 -0
  363. package/src/chat/late-diagnostics-message.ts +92 -0
  364. package/src/chat/messages.ts +305 -0
  365. package/src/chat/reaction.ts +65 -0
  366. package/src/chat/read-target.ts +7 -0
  367. package/src/chat/read-tool-group.ts +873 -0
  368. package/src/chat/served-model-marker.ts +91 -0
  369. package/src/chat/skill-message.ts +220 -0
  370. package/src/chat/skill-title-input.ts +41 -0
  371. package/src/chat/stripped-tool-calls-placeholder.ts +35 -0
  372. package/src/chat/thinking-display.ts +312 -0
  373. package/src/chat/todo-reminder.ts +33 -0
  374. package/src/chat/tool-execution.ts +1395 -0
  375. package/src/chat/transcript-browser.ts +268 -0
  376. package/src/chat/transcript-entry.ts +96 -0
  377. package/src/chat/transcript-outline.ts +260 -0
  378. package/src/chat/transcript-render-helpers.ts +315 -0
  379. package/src/chat/ttsr-notification.ts +123 -0
  380. package/src/chat/user-message.ts +287 -0
  381. package/src/chrome/chat-block.ts +110 -0
  382. package/src/chrome/collab-qrcode.ts +74 -0
  383. package/src/chrome/context-thresholds.ts +85 -0
  384. package/src/chrome/countdown-timer.ts +74 -0
  385. package/src/chrome/diff.ts +266 -0
  386. package/src/chrome/dynamic-border.ts +36 -0
  387. package/src/chrome/error-block.ts +63 -0
  388. package/src/chrome/form-theme.ts +10 -0
  389. package/src/chrome/format.ts +66 -0
  390. package/src/chrome/index.ts +21 -0
  391. package/src/chrome/keybinding-hints.ts +55 -0
  392. package/src/chrome/live-board.ts +123 -0
  393. package/src/chrome/local-date.ts +20 -0
  394. package/src/chrome/message-divider.ts +51 -0
  395. package/src/chrome/message-frame.ts +164 -0
  396. package/src/chrome/message-notice.ts +103 -0
  397. package/src/chrome/overlay-box.ts +301 -0
  398. package/src/chrome/qrcode.ts +539 -0
  399. package/src/chrome/segment-track.ts +86 -0
  400. package/src/chrome/select-list-mouse-routing.ts +11 -0
  401. package/src/chrome/selector-helpers.ts +119 -0
  402. package/src/chrome/shared.ts +27 -0
  403. package/src/chrome/streaming-panel.ts +72 -0
  404. package/src/chrome/tool-activity.ts +44 -0
  405. package/src/chrome/transcript-container.ts +902 -0
  406. package/src/chrome/transcript-status.ts +27 -0
  407. package/src/chrome/visual-truncate.ts +70 -0
  408. package/src/components/disclosure.ts +235 -0
  409. package/src/components/editor.ts +10 -12
  410. package/src/components/form.ts +566 -0
  411. package/src/components/input.ts +6 -27
  412. package/src/components/key-value-list.ts +88 -0
  413. package/src/components/layout/geometry.ts +202 -0
  414. package/src/components/layout/row.ts +283 -0
  415. package/src/components/layout/split-pane.ts +349 -0
  416. package/src/components/layout/stack.ts +261 -0
  417. package/src/components/markdown.ts +16 -12
  418. package/src/components/menu-selection.ts +248 -0
  419. package/src/components/metric.ts +132 -0
  420. package/src/components/progress-bar.ts +140 -0
  421. package/src/components/scroll-view.ts +372 -70
  422. package/src/components/scroll-viewport.ts +154 -0
  423. package/src/components/section.ts +77 -0
  424. package/src/components/select-list.ts +238 -159
  425. package/src/components/settings-list.ts +103 -80
  426. package/src/components/table.ts +127 -0
  427. package/src/components/tree-view.ts +481 -0
  428. package/src/components/wizard-step.ts +229 -0
  429. package/src/deccara.ts +1 -3
  430. package/src/hotkeys-markdown.ts +100 -0
  431. package/src/index.ts +18 -0
  432. package/src/keybinding-matchers.ts +99 -0
  433. package/src/keys.ts +2 -2
  434. package/src/lang-from-path.ts +252 -0
  435. package/src/overlays/advisor-config.ts +761 -0
  436. package/src/overlays/agent-activity.ts +113 -0
  437. package/src/overlays/agent-hub-projection.ts +250 -0
  438. package/src/overlays/agent-hub-renderer.ts +281 -0
  439. package/src/overlays/agent-hub-types.ts +74 -0
  440. package/src/overlays/agent-hub.ts +1562 -0
  441. package/src/overlays/agent-transcript-viewer.ts +669 -0
  442. package/src/overlays/agents-hub.ts +1203 -0
  443. package/src/overlays/ask-dialog.ts +1202 -0
  444. package/src/overlays/bordered-loader.ts +41 -0
  445. package/src/overlays/btw-history-panel.ts +591 -0
  446. package/src/overlays/btw-history.ts +33 -0
  447. package/src/overlays/btw-panel.ts +167 -0
  448. package/src/overlays/cleanse-panel.ts +167 -0
  449. package/src/overlays/codex-reset-fireworks.ts +375 -0
  450. package/src/overlays/composer-shape-preview.ts +137 -0
  451. package/src/overlays/composer-shape-registry.ts +82 -0
  452. package/src/overlays/copy-selector.ts +618 -0
  453. package/src/overlays/copy-targets.ts +210 -0
  454. package/src/overlays/error-banner.ts +39 -0
  455. package/src/overlays/extensions/display-text.ts +39 -0
  456. package/src/overlays/extensions/extension-dashboard.ts +645 -0
  457. package/src/overlays/extensions/extension-list.ts +667 -0
  458. package/src/overlays/extensions/inspector-model.ts +484 -0
  459. package/src/overlays/extensions/inspector-panel.ts +669 -0
  460. package/src/overlays/extensions/live-tool-session.ts +67 -0
  461. package/src/overlays/extensions/mcp-runtime.ts +289 -0
  462. package/src/overlays/extensions/state-manager.ts +337 -0
  463. package/src/overlays/extensions/types.ts +208 -0
  464. package/src/overlays/history-search.ts +268 -0
  465. package/src/overlays/hook-editor.ts +272 -0
  466. package/src/overlays/hook-input.ts +84 -0
  467. package/src/overlays/hook-selector.ts +635 -0
  468. package/src/overlays/hub-frame.ts +262 -0
  469. package/src/overlays/login-dialog.ts +231 -0
  470. package/src/overlays/logout-account-selector.ts +115 -0
  471. package/src/overlays/mcp-add-wizard.ts +1436 -0
  472. package/src/overlays/model-browser.ts +1176 -0
  473. package/src/overlays/model-hub.ts +2279 -0
  474. package/src/overlays/model-picker.ts +285 -0
  475. package/src/overlays/model-selector.ts +107 -0
  476. package/src/overlays/move-overlay.ts +197 -0
  477. package/src/overlays/oauth-selector.ts +446 -0
  478. package/src/overlays/omfg-panel.ts +136 -0
  479. package/src/overlays/pause-screen.ts +198 -0
  480. package/src/overlays/plan-review-overlay.ts +1227 -0
  481. package/src/overlays/plan-save-overlay.ts +74 -0
  482. package/src/overlays/plan-toc.ts +139 -0
  483. package/src/overlays/plugin-selector.ts +97 -0
  484. package/src/overlays/plugin-settings.ts +839 -0
  485. package/src/overlays/queue-mode-selector.ts +55 -0
  486. package/src/overlays/reset-usage-selector.ts +170 -0
  487. package/src/overlays/rewind-selector.ts +499 -0
  488. package/src/overlays/running-subagent-badge.ts +19 -0
  489. package/src/overlays/session-account-selector.ts +68 -0
  490. package/src/overlays/session-info-overlay.ts +96 -0
  491. package/src/overlays/session-observer-registry.ts +289 -0
  492. package/src/overlays/session-selector.ts +1137 -0
  493. package/src/overlays/settings-defs.ts +315 -0
  494. package/src/overlays/settings-selector.ts +1415 -0
  495. package/src/overlays/show-images-selector.ts +44 -0
  496. package/src/overlays/snapcompact-shape-preview-doc.md +14 -0
  497. package/src/overlays/snapcompact-shape-preview.ts +192 -0
  498. package/src/overlays/theme-selector.ts +62 -0
  499. package/src/overlays/thinking-selector.ts +51 -0
  500. package/src/overlays/tiny-title-download-progress.ts +102 -0
  501. package/src/overlays/tree-selector.ts +1121 -0
  502. package/src/overlays/usage-dashboard.ts +629 -0
  503. package/src/overlays/usage-display.ts +45 -0
  504. package/src/overlays/usage-row.ts +118 -0
  505. package/src/prompt/attachment-chips.ts +201 -0
  506. package/src/prompt/composer-attachments.ts +280 -0
  507. package/src/prompt/composer-cache.ts +304 -0
  508. package/src/prompt/composer.ts +934 -0
  509. package/src/prompt/custom-editor.ts +1392 -0
  510. package/src/prompt/data/emojis.json +1 -0
  511. package/src/prompt/editor-top-gap.ts +28 -0
  512. package/src/prompt/emoji-autocomplete.ts +285 -0
  513. package/src/prompt/github-ref-autocomplete.ts +75 -0
  514. package/src/prompt/gradient-highlight.ts +101 -0
  515. package/src/prompt/image-format.ts +28 -0
  516. package/src/prompt/image-references.ts +102 -0
  517. package/src/prompt/interactive-context-helpers.ts +126 -0
  518. package/src/prompt/internal-url-autocomplete.ts +155 -0
  519. package/src/prompt/macos-spelling.ts +456 -0
  520. package/src/prompt/magic-keyword-boundary.ts +23 -0
  521. package/src/prompt/magic-keywords.ts +42 -0
  522. package/src/prompt/markdown-prose.ts +245 -0
  523. package/src/prompt/model-mention-autocomplete.ts +94 -0
  524. package/src/prompt/model-mention-syntax.ts +41 -0
  525. package/src/prompt/orchestrate.ts +26 -0
  526. package/src/prompt/prompt-action-autocomplete.ts +337 -0
  527. package/src/prompt/queue-input.ts +132 -0
  528. package/src/prompt/skill-tokens.ts +36 -0
  529. package/src/prompt/tips.txt +27 -0
  530. package/src/prompt/tools-markdown.ts +29 -0
  531. package/src/prompt/ultrathink.ts +26 -0
  532. package/src/prompt/usage-amounts.ts +99 -0
  533. package/src/prompt/video.ts +47 -0
  534. package/src/prompt/welcome.ts +605 -0
  535. package/src/prompt/workflow.ts +26 -0
  536. package/src/render/code-cell.ts +244 -0
  537. package/src/render/file-list.ts +58 -0
  538. package/src/render/hyperlink.ts +192 -0
  539. package/src/render/index.ts +17 -0
  540. package/src/render/output-block.ts +267 -0
  541. package/src/render/output-pane.ts +299 -0
  542. package/src/render/render-utils.ts +1182 -0
  543. package/src/render/sixel.ts +69 -0
  544. package/src/render/status-line.ts +55 -0
  545. package/src/render/tool-card.ts +272 -0
  546. package/src/render/tree-list.ts +188 -0
  547. package/src/render/types.ts +19 -0
  548. package/src/render/utils.ts +109 -0
  549. package/src/render/width-aware-text.ts +60 -0
  550. package/src/setup/lazy.ts +17 -0
  551. package/src/setup/scenes/composer.ts +127 -0
  552. package/src/setup/scenes/glyph.ts +120 -0
  553. package/src/setup/scenes/model.ts +138 -0
  554. package/src/setup/scenes/outro.ts +24 -0
  555. package/src/setup/scenes/providers.ts +107 -0
  556. package/src/setup/scenes/sign-in.ts +373 -0
  557. package/src/setup/scenes/splash.ts +192 -0
  558. package/src/setup/scenes/theme.ts +343 -0
  559. package/src/setup/scenes/types.ts +111 -0
  560. package/src/setup/scenes/web-search.ts +165 -0
  561. package/src/setup/setup-version.ts +11 -0
  562. package/src/setup/startup-splash.ts +107 -0
  563. package/src/setup/wizard-overlay.ts +319 -0
  564. package/src/setup/wizard.ts +101 -0
  565. package/src/status-line/component.ts +3003 -0
  566. package/src/status-line/context-usage.ts +688 -0
  567. package/src/status-line/footer.ts +323 -0
  568. package/src/status-line/git-utils.ts +42 -0
  569. package/src/status-line/host.ts +97 -0
  570. package/src/status-line/index.ts +6 -0
  571. package/src/status-line/loop.ts +28 -0
  572. package/src/status-line/metrics.ts +94 -0
  573. package/src/status-line/presets.ts +107 -0
  574. package/src/status-line/schema.ts +57 -0
  575. package/src/status-line/segments.ts +934 -0
  576. package/src/status-line/separators.ts +55 -0
  577. package/src/status-line/types.ts +227 -0
  578. package/src/stdin-buffer.ts +4 -2
  579. package/src/theme/color.ts +95 -0
  580. package/src/theme/dark.json +95 -0
  581. package/src/theme/defaults/alabaster.json +93 -0
  582. package/src/theme/defaults/amethyst.json +96 -0
  583. package/src/theme/defaults/anthracite.json +93 -0
  584. package/src/theme/defaults/basalt.json +91 -0
  585. package/src/theme/defaults/birch.json +95 -0
  586. package/src/theme/defaults/dark-abyss.json +91 -0
  587. package/src/theme/defaults/dark-arctic.json +104 -0
  588. package/src/theme/defaults/dark-aurora.json +95 -0
  589. package/src/theme/defaults/dark-catppuccin.json +107 -0
  590. package/src/theme/defaults/dark-cavern.json +91 -0
  591. package/src/theme/defaults/dark-celestial.json +106 -0
  592. package/src/theme/defaults/dark-copper.json +95 -0
  593. package/src/theme/defaults/dark-cosmos.json +90 -0
  594. package/src/theme/defaults/dark-cyberpunk.json +102 -0
  595. package/src/theme/defaults/dark-dracula.json +98 -0
  596. package/src/theme/defaults/dark-eclipse.json +91 -0
  597. package/src/theme/defaults/dark-ember.json +95 -0
  598. package/src/theme/defaults/dark-equinox.json +90 -0
  599. package/src/theme/defaults/dark-forest.json +96 -0
  600. package/src/theme/defaults/dark-github.json +105 -0
  601. package/src/theme/defaults/dark-gruvbox.json +112 -0
  602. package/src/theme/defaults/dark-lavender.json +95 -0
  603. package/src/theme/defaults/dark-lunar.json +89 -0
  604. package/src/theme/defaults/dark-midnight.json +95 -0
  605. package/src/theme/defaults/dark-monochrome.json +94 -0
  606. package/src/theme/defaults/dark-monokai.json +98 -0
  607. package/src/theme/defaults/dark-nebula.json +90 -0
  608. package/src/theme/defaults/dark-nord.json +98 -0
  609. package/src/theme/defaults/dark-ocean.json +101 -0
  610. package/src/theme/defaults/dark-one.json +100 -0
  611. package/src/theme/defaults/dark-poimandres.json +115 -0
  612. package/src/theme/defaults/dark-rainforest.json +91 -0
  613. package/src/theme/defaults/dark-reef.json +91 -0
  614. package/src/theme/defaults/dark-retro.json +92 -0
  615. package/src/theme/defaults/dark-rose-pine.json +96 -0
  616. package/src/theme/defaults/dark-sakura.json +95 -0
  617. package/src/theme/defaults/dark-slate.json +95 -0
  618. package/src/theme/defaults/dark-solarized.json +97 -0
  619. package/src/theme/defaults/dark-solstice.json +90 -0
  620. package/src/theme/defaults/dark-starfall.json +91 -0
  621. package/src/theme/defaults/dark-sunset.json +99 -0
  622. package/src/theme/defaults/dark-swamp.json +90 -0
  623. package/src/theme/defaults/dark-synthwave.json +103 -0
  624. package/src/theme/defaults/dark-taiga.json +91 -0
  625. package/src/theme/defaults/dark-terminal.json +95 -0
  626. package/src/theme/defaults/dark-tokyo-night.json +101 -0
  627. package/src/theme/defaults/dark-tundra.json +91 -0
  628. package/src/theme/defaults/dark-twilight.json +91 -0
  629. package/src/theme/defaults/dark-volcanic.json +91 -0
  630. package/src/theme/defaults/graphite.json +92 -0
  631. package/src/theme/defaults/index.ts +201 -0
  632. package/src/theme/defaults/light-arctic.json +107 -0
  633. package/src/theme/defaults/light-aurora-day.json +91 -0
  634. package/src/theme/defaults/light-canyon.json +91 -0
  635. package/src/theme/defaults/light-catppuccin.json +106 -0
  636. package/src/theme/defaults/light-cirrus.json +90 -0
  637. package/src/theme/defaults/light-coral.json +95 -0
  638. package/src/theme/defaults/light-cyberpunk.json +96 -0
  639. package/src/theme/defaults/light-dawn.json +90 -0
  640. package/src/theme/defaults/light-dunes.json +91 -0
  641. package/src/theme/defaults/light-eucalyptus.json +95 -0
  642. package/src/theme/defaults/light-forest.json +100 -0
  643. package/src/theme/defaults/light-frost.json +95 -0
  644. package/src/theme/defaults/light-github.json +115 -0
  645. package/src/theme/defaults/light-glacier.json +91 -0
  646. package/src/theme/defaults/light-gruvbox.json +108 -0
  647. package/src/theme/defaults/light-haze.json +90 -0
  648. package/src/theme/defaults/light-honeycomb.json +95 -0
  649. package/src/theme/defaults/light-lagoon.json +91 -0
  650. package/src/theme/defaults/light-lavender.json +95 -0
  651. package/src/theme/defaults/light-meadow.json +91 -0
  652. package/src/theme/defaults/light-mint.json +95 -0
  653. package/src/theme/defaults/light-monochrome.json +101 -0
  654. package/src/theme/defaults/light-ocean.json +99 -0
  655. package/src/theme/defaults/light-one.json +99 -0
  656. package/src/theme/defaults/light-opal.json +91 -0
  657. package/src/theme/defaults/light-orchard.json +91 -0
  658. package/src/theme/defaults/light-paper.json +95 -0
  659. package/src/theme/defaults/light-poimandres.json +115 -0
  660. package/src/theme/defaults/light-prism.json +90 -0
  661. package/src/theme/defaults/light-retro.json +98 -0
  662. package/src/theme/defaults/light-sand.json +95 -0
  663. package/src/theme/defaults/light-savanna.json +91 -0
  664. package/src/theme/defaults/light-solarized.json +102 -0
  665. package/src/theme/defaults/light-soleil.json +90 -0
  666. package/src/theme/defaults/light-sunset.json +99 -0
  667. package/src/theme/defaults/light-synthwave.json +98 -0
  668. package/src/theme/defaults/light-tokyo-night.json +111 -0
  669. package/src/theme/defaults/light-wetland.json +91 -0
  670. package/src/theme/defaults/light-zenith.json +89 -0
  671. package/src/theme/defaults/limestone.json +94 -0
  672. package/src/theme/defaults/mahogany.json +97 -0
  673. package/src/theme/defaults/marble.json +93 -0
  674. package/src/theme/defaults/obsidian.json +91 -0
  675. package/src/theme/defaults/onyx.json +91 -0
  676. package/src/theme/defaults/pearl.json +93 -0
  677. package/src/theme/defaults/porcelain.json +91 -0
  678. package/src/theme/defaults/quartz.json +96 -0
  679. package/src/theme/defaults/sandstone.json +95 -0
  680. package/src/theme/defaults/titanium.json +90 -0
  681. package/src/theme/index.ts +5 -0
  682. package/src/theme/light.json +93 -0
  683. package/src/theme/loader.ts +200 -0
  684. package/src/theme/mermaid-cache.ts +92 -0
  685. package/src/theme/schema-validation.ts +119 -0
  686. package/src/theme/schema.ts +168 -0
  687. package/src/theme/session-color.ts +253 -0
  688. package/src/theme/shimmer.ts +307 -0
  689. package/src/theme/symbols.ts +1433 -0
  690. package/src/theme/theme-class.ts +787 -0
  691. package/src/theme/theme-schema.json +463 -0
  692. package/src/theme/theme.ts +810 -0
  693. package/src/theme/tui-adapters.ts +339 -0
  694. package/src/thinking.ts +380 -0
  695. package/src/tools/agent-tree.ts +128 -0
  696. package/src/tools/ask.ts +482 -0
  697. package/src/tools/ast-edit.ts +210 -0
  698. package/src/tools/ast-grep.ts +171 -0
  699. package/src/tools/autoresearch.ts +287 -0
  700. package/src/tools/bash-interactive.ts +295 -0
  701. package/src/tools/bash.ts +468 -0
  702. package/src/tools/conflict-detect.ts +77 -0
  703. package/src/tools/debug.ts +167 -0
  704. package/src/tools/default-renderer.ts +172 -0
  705. package/src/tools/edit.ts +1258 -0
  706. package/src/tools/eval-format/code-mode-declarations.ts +61 -0
  707. package/src/tools/eval-format/index.ts +16 -0
  708. package/src/tools/eval-format/javascript.ts +952 -0
  709. package/src/tools/eval-format/python.ts +544 -0
  710. package/src/tools/eval.ts +835 -0
  711. package/src/tools/fetch.ts +226 -0
  712. package/src/tools/gh-format.ts +18 -0
  713. package/src/tools/github.ts +686 -0
  714. package/src/tools/glob.ts +213 -0
  715. package/src/tools/goal.ts +153 -0
  716. package/src/tools/grep.ts +385 -0
  717. package/src/tools/grouped-file-output.ts +211 -0
  718. package/src/tools/hashline-format.ts +59 -0
  719. package/src/tools/hub.ts +1488 -0
  720. package/src/tools/index.ts +71 -0
  721. package/src/tools/json-tree.ts +388 -0
  722. package/src/tools/line-ranges.ts +98 -0
  723. package/src/tools/list-limit.ts +43 -0
  724. package/src/tools/lsp.ts +702 -0
  725. package/src/tools/match-line-format.ts +20 -0
  726. package/src/tools/mcp.ts +309 -0
  727. package/src/tools/memory.ts +220 -0
  728. package/src/tools/output-meta.ts +367 -0
  729. package/src/tools/read.ts +628 -0
  730. package/src/tools/renderer.ts +107 -0
  731. package/src/tools/report-tool-issue.ts +13 -0
  732. package/src/tools/resolve.ts +139 -0
  733. package/src/tools/streaming-output.ts +1576 -0
  734. package/src/tools/subprocess.ts +39 -0
  735. package/src/tools/task-repair-args.ts +118 -0
  736. package/src/tools/task-yield-assembly.ts +147 -0
  737. package/src/tools/task.ts +2110 -0
  738. package/src/tools/terminal-output.ts +153 -0
  739. package/src/tools/think.ts +28 -0
  740. package/src/tools/todo.ts +580 -0
  741. package/src/tools/tool-errors.ts +15 -0
  742. package/src/tools/vibe.ts +420 -0
  743. package/src/tools/web-search.ts +409 -0
  744. package/src/tools/write.ts +511 -0
  745. package/src/tools/xd-url.ts +28 -0
  746. package/src/tools/xdev.ts +201 -0
  747. package/src/tui.ts +57 -4
  748. package/src/utils.ts +8 -0
@@ -1,7 +1,7 @@
1
1
  import { popLoopPhase, pushLoopPhase } from "@oh-my-pi/pi-utils";
2
- import { fuzzyFilter } from "../fuzzy";
2
+ import { getMenuWindow, MenuSelection } from "./menu-selection";
3
3
  import { getKeybindings } from "../keybindings";
4
- import { extractPrintableText } from "../keys";
4
+ import { extractPrintableText, matchesKey } from "../keys";
5
5
  import { type MouseRoutable, routeSelectListMouse, type SgrMouseEvent } from "../mouse";
6
6
  import type { SymbolTheme } from "../symbols";
7
7
  import type { Component } from "../tui";
@@ -31,6 +31,12 @@ export interface SelectItem {
31
31
  icon?: string;
32
32
  /** Dim hint text shown inline after cursor when this item is selected */
33
33
  hint?: string;
34
+ /** Disabled rows stay visible but are skipped by navigation and cannot activate. */
35
+ disabled?: boolean;
36
+ /** When set, activation requires a second Enter/click and this text becomes the status line. */
37
+ confirmation?: string;
38
+ /** Additional text included by the default fuzzy filter without being rendered. */
39
+ searchText?: string;
34
40
  }
35
41
 
36
42
  export interface SelectListTheme {
@@ -54,12 +60,48 @@ export interface SelectListTruncatePrimaryContext {
54
60
  isSelected: boolean;
55
61
  }
56
62
 
63
+ /** State supplied to a rich SelectList row renderer or measurer. */
64
+ export interface SelectListRenderItemContext {
65
+ item: SelectItem;
66
+ index: number;
67
+ width: number;
68
+ selected: boolean;
69
+ hovered: boolean;
70
+ pendingConfirmation: boolean;
71
+ theme: SelectListTheme;
72
+ }
73
+
74
+ /** Current controlled menu state supplied to a custom status renderer. */
75
+ export interface SelectListStatusContext {
76
+ query: string;
77
+ selectedIndex: number;
78
+ visibleCount: number;
79
+ totalCount: number;
80
+ pendingItem: SelectItem | undefined;
81
+ }
82
+
57
83
  export interface SelectListLayoutOptions {
58
84
  minPrimaryColumnWidth?: number;
59
85
  maxPrimaryColumnWidth?: number;
60
86
  truncatePrimary?: (context: SelectListTruncatePrimaryContext) => string;
61
87
  /** Enable type-to-filter search when the item count exceeds maxVisible. Defaults to true. */
62
88
  overflowSearch?: boolean;
89
+ /** Search activation policy. `overflowSearch` remains authoritative when this is omitted. */
90
+ search?: "overflow" | "always" | "never";
91
+ /** Domain-specific filtering/ranking. Selection is retained by item value when possible. */
92
+ filterItems?: (items: readonly SelectItem[], query: string) => readonly SelectItem[];
93
+ /** Custom rich-row renderer. Every returned line is mouse-hit-tested as the same item. */
94
+ renderItem?: (context: SelectListRenderItemContext) => readonly string[];
95
+ /** Cheap row measurement for custom renderers; defaults to calling renderItem and reading its length. */
96
+ measureItem?: (context: SelectListRenderItemContext) => number;
97
+ /** Empty-list message (before a query is entered). */
98
+ emptyText?: string;
99
+ /** No-match message (after filtering). */
100
+ noMatchText?: string;
101
+ /** Optional status renderer. Return undefined to omit the status row. */
102
+ statusText?: (context: SelectListStatusContext) => string | undefined;
103
+ /** Whether single-step keyboard navigation wraps at the edges. Defaults to true. */
104
+ wrapNavigation?: boolean;
63
105
  /**
64
106
  * Wrap long descriptions onto continuation rows indented under the
65
107
  * description column instead of truncating. Defaults to false so existing
@@ -95,10 +137,19 @@ type SelectItemLayout =
95
137
  };
96
138
 
97
139
  export class SelectList implements Component, MouseRoutable {
140
+ /**
141
+ * Sanitized `{label, description}` per item object. `sanitizeSingleLine`
142
+ * is 3 passes + 2 regex execs per call and render() used to run it up to
143
+ * 3x per item per frame (column widths, row counts, item render). Items
144
+ * are host-owned and stable across frames; the map is cleared when the
145
+ * visible item list identity changes.
146
+ */
147
+ #sanitized = new WeakMap<
148
+ SelectItem,
149
+ { sourceLabel: string; sourceDescription: string | undefined; label: string; description: string | undefined }
150
+ >();
98
151
  #maxVisible: number;
99
- #filteredItems: ReadonlyArray<SelectItem>;
100
- #filterQuery = "";
101
- #selectedIndex: number = 0;
152
+ #selection: MenuSelection<SelectItem>;
102
153
  #hoveredIndex: number | null = null;
103
154
  /** Per-render map of 0-based output line → filtered-item index. */
104
155
  #hitRows: (number | undefined)[] = [];
@@ -108,24 +159,31 @@ export class SelectList implements Component, MouseRoutable {
108
159
  onSelectionChange?: (item: SelectItem) => void;
109
160
 
110
161
  constructor(
111
- private readonly items: ReadonlyArray<SelectItem>,
162
+ items: ReadonlyArray<SelectItem>,
112
163
  maxVisible: number,
113
164
  private readonly theme: SelectListTheme,
114
165
  private readonly layout: SelectListLayoutOptions = {},
115
166
  ) {
116
167
  this.#maxVisible = Math.max(1, Math.trunc(maxVisible));
117
- this.#filteredItems = items;
168
+ this.#selection = new MenuSelection(items, {
169
+ getKey: item => item.value,
170
+ getSearchText: item => this.#getFilterText(item),
171
+ isDisabled: item => item.disabled === true,
172
+ requiresConfirmation: item => item.confirmation !== undefined,
173
+ filter: layout.filterItems,
174
+ });
118
175
  }
119
176
  /** Return item, selection, and filter state for debug inspection. */
120
177
  debugState(): Record<string, unknown> {
121
- const selected = this.#filteredItems[this.#selectedIndex];
178
+ const selected = this.#selection.selectedItem;
122
179
  return {
123
- itemCount: this.items.length,
124
- filteredItemCount: this.#filteredItems.length,
125
- selectedIndex: this.#filteredItems.length > 0 ? this.#selectedIndex : -1,
180
+ itemCount: this.#selection.items.length,
181
+ filteredItemCount: this.#selection.visibleItems.length,
182
+ selectedIndex: this.#selection.selectedIndex,
126
183
  selectedItemId: selected?.value ?? null,
127
184
  selectedItemLabel: selected?.label ?? null,
128
- filterText: this.#filterQuery,
185
+ filterText: this.#selection.query,
186
+ pendingItemId: this.#selection.pendingKey ?? null,
129
187
  maxVisible: this.#maxVisible,
130
188
  };
131
189
  }
@@ -139,8 +197,22 @@ export class SelectList implements Component, MouseRoutable {
139
197
  this.#setFilter(filter, true);
140
198
  }
141
199
 
200
+ /** Replace controlled items while retaining the selected value when possible. */
201
+ setItems(items: readonly SelectItem[]): void {
202
+ if (this.#selection.setItems(items)) this.#notifySelectionChange();
203
+ }
204
+
142
205
  setSelectedIndex(index: number): void {
143
- this.#selectedIndex = Math.max(0, Math.min(index, this.#filteredItems.length - 1));
206
+ this.#selection.setSelectedIndex(index);
207
+ }
208
+
209
+ /** Select a visible item by its stable value. */
210
+ setSelectedValue(value: string): void {
211
+ this.#selection.setSelectedKey(value);
212
+ }
213
+
214
+ getFilter(): string {
215
+ return this.#selection.query;
144
216
  }
145
217
 
146
218
  /** Resolve a 0-based rendered-line index to a filtered-item index. */
@@ -155,22 +227,15 @@ export class SelectList implements Component, MouseRoutable {
155
227
 
156
228
  /** Move the selection one step for a wheel notch. */
157
229
  handleWheel(delta: -1 | 1): void {
158
- if (this.#filteredItems.length === 0) return;
159
- const next = clamp(this.#selectedIndex + delta, 0, this.#filteredItems.length - 1);
160
- if (next === this.#selectedIndex) return;
161
- this.#selectedIndex = next;
162
- this.#notifySelectionChange();
230
+ if (this.#selection.move(delta)) this.#notifySelectionChange();
163
231
  }
164
232
 
165
- /** Mouse click: select the item under the pointer and confirm it. */
233
+ /** Mouse click: select the item under the pointer and request activation. */
166
234
  clickItem(index: number): void {
167
- const item = this.#filteredItems[index];
168
- if (!item) return;
169
- if (index !== this.#selectedIndex) {
170
- this.#selectedIndex = index;
171
- this.#notifySelectionChange();
172
- }
173
- this.onSelect?.(item);
235
+ const item = this.#selection.visibleItems[index];
236
+ if (!item || item.disabled) return;
237
+ if (this.#selection.setSelectedIndex(index)) this.#notifySelectionChange();
238
+ this.#activateSelected();
174
239
  }
175
240
 
176
241
  routeMouse(event: SgrMouseEvent, line: number, _col: number): void {
@@ -184,14 +249,18 @@ export class SelectList implements Component, MouseRoutable {
184
249
  render(width: number): readonly string[] {
185
250
  const lines: string[] = [];
186
251
  this.#hitRows = [];
187
- const showSearchStatus = this.#shouldRenderSearchStatus();
252
+ let showSearchStatus = this.#shouldRenderSearchStatus();
188
253
 
189
- // If no items match filter, show message
190
- if (this.#filteredItems.length === 0) {
254
+ // If no items match filter, distinguish an empty data set from no search matches.
255
+ if (this.#selection.visibleItems.length === 0) {
191
256
  if (showSearchStatus) {
192
257
  lines.push(this.#renderStatusLine(width));
193
258
  }
194
- lines.push(this.theme.noMatch(" No matching items"));
259
+ const message =
260
+ this.#selection.query.trim().length > 0
261
+ ? (this.layout.noMatchText ?? "No matching items")
262
+ : (this.layout.emptyText ?? "No items");
263
+ lines.push(this.theme.noMatch(` ${message}`));
195
264
  return lines;
196
265
  }
197
266
 
@@ -204,31 +273,35 @@ export class SelectList implements Component, MouseRoutable {
204
273
 
205
274
  // Compute per-item visual row counts at the conservative width (i.e.
206
275
  // assume the scrollbar column might be reserved). For non-wrap layouts
207
- // every count is 1, so visualTotal == #filteredItems and overflow falls
208
- // back to the original `N > maxVisible` predicate exactly.
276
+ // every count is 1, so total visual rows equal the visible item count.
209
277
  const conservativeRowWidth = Math.max(0, width - 1);
210
278
  // oxlint-disable-next-line unicorn/no-new-array -- length preallocation
211
- const rowCounts = new Array<number>(this.#filteredItems.length);
212
- let visualTotal = 0;
213
- for (let i = 0; i < this.#filteredItems.length; i++) {
214
- const item = this.#filteredItems[i];
279
+ const rowCounts = new Array<number>(this.#selection.visibleItems.length);
280
+ for (let i = 0; i < this.#selection.visibleItems.length; i++) {
281
+ const item = this.#selection.visibleItems[i];
215
282
  if (!item) {
216
283
  rowCounts[i] = 0;
217
284
  continue;
218
285
  }
219
- rowCounts[i] = wrapEnabled
220
- ? this.#computeItemRowCount(item, conservativeRowWidth, primaryColumnWidth, iconColumnWidth)
221
- : 1;
222
- visualTotal += rowCounts[i];
286
+ const context = this.#renderContext(item, i, conservativeRowWidth);
287
+ rowCounts[i] = this.layout.measureItem
288
+ ? Math.max(1, Math.trunc(this.layout.measureItem(context)))
289
+ : this.layout.renderItem
290
+ ? Math.max(1, this.layout.renderItem(context).length)
291
+ : wrapEnabled
292
+ ? this.#computeItemRowCount(item, conservativeRowWidth, primaryColumnWidth, iconColumnWidth)
293
+ : 1;
223
294
  }
224
295
 
225
- const overflow = visualTotal > visualBudget;
296
+ const window = getMenuWindow(rowCounts, this.#selection.selectedIndex, visualBudget);
297
+ const overflow = window.totalRows > visualBudget;
298
+ showSearchStatus = this.#shouldRenderSearchStatus();
226
299
  const rowWidth = Math.max(0, width - (overflow ? 1 : 0));
227
300
 
228
301
  // Pick a window centered on the selected item that fits in visualBudget
229
302
  // rows. Falls through to the original item-count window when every row
230
303
  // count is 1.
231
- const { startIndex, endIndex, visualOffset } = this.#pickWindow(rowCounts, visualBudget);
304
+ const { startIndex, endIndex, rowOffset } = window;
232
305
 
233
306
  // Render visible items. Cap rows at the budget so a single item that
234
307
  // wraps to more than `visualBudget` rows (pathological — e.g. a 5-row
@@ -236,30 +309,36 @@ export class SelectList implements Component, MouseRoutable {
236
309
  // scrollbar carries the offscreen rows.
237
310
  const rows: string[] = [];
238
311
  for (let i = startIndex; i < endIndex && rows.length < visualBudget; i++) {
239
- const item = this.#filteredItems[i];
312
+ const item = this.#selection.visibleItems[i];
240
313
  if (!item) continue;
241
- const hovered = this.theme.hovered !== undefined && i === this.#hoveredIndex && i !== this.#selectedIndex;
242
- const itemRows = this.#renderItem(
243
- item,
244
- i === this.#selectedIndex,
245
- rowWidth,
246
- primaryColumnWidth,
247
- iconColumnWidth,
248
- );
314
+ const isSelected = i === this.#selection.selectedIndex;
315
+ const hovered = i === this.#hoveredIndex && !isSelected;
316
+ const context = this.#renderContext(item, i, rowWidth);
317
+ const itemRows = this.layout.renderItem
318
+ ? [...this.layout.renderItem(context)]
319
+ : this.#renderItem(item, isSelected, rowWidth, primaryColumnWidth, iconColumnWidth);
249
320
  for (const row of itemRows) {
250
321
  if (rows.length >= visualBudget) break;
251
322
  this.#hitRows[rows.length] = i;
252
- rows.push(hovered && this.theme.hovered ? this.theme.hovered(row) : row);
323
+ const styled =
324
+ this.layout.renderItem !== undefined
325
+ ? row
326
+ : item.disabled
327
+ ? this.theme.description(row)
328
+ : hovered && this.theme.hovered
329
+ ? this.theme.hovered(row)
330
+ : row;
331
+ rows.push(styled);
253
332
  }
254
333
  }
255
334
 
256
335
  const sv = new ScrollView(rows, {
257
336
  height: rows.length,
258
337
  scrollbar: "auto",
259
- totalRows: visualTotal,
338
+ totalRows: window.totalRows,
260
339
  theme: { track: t => this.theme.scrollInfo(t), thumb: t => this.theme.selectedPrefix(t) },
261
340
  });
262
- sv.setScrollOffset(visualOffset);
341
+ sv.setScrollOffset(rowOffset);
263
342
  lines.push(...sv.render(width));
264
343
 
265
344
  // Add search status when relevant (scrollbar now indicates overflow)
@@ -272,46 +351,31 @@ export class SelectList implements Component, MouseRoutable {
272
351
 
273
352
  handleInput(keyData: string): void {
274
353
  const kb = getKeybindings();
275
- // Escape or Ctrl+C
276
354
  if (kb.matches(keyData, "tui.select.cancel")) {
277
- if (this.onCancel) {
278
- this.onCancel();
279
- }
355
+ if (!this.#selection.cancelConfirmation()) this.onCancel?.();
280
356
  return;
281
357
  }
282
358
 
283
- if (this.#handleSearchInput(keyData)) {
284
- return;
285
- }
359
+ if (this.#handleSearchInput(keyData)) return;
360
+ if (this.#selection.visibleItems.length === 0) return;
286
361
 
287
- if (this.#filteredItems.length === 0) return;
288
- // Up arrow - wrap to bottom when at top
362
+ let selectionChanged = false;
289
363
  if (kb.matches(keyData, "tui.select.up")) {
290
- this.#selectedIndex = this.#selectedIndex === 0 ? this.#filteredItems.length - 1 : this.#selectedIndex - 1;
291
- this.#notifySelectionChange();
292
- }
293
- // Down arrow - wrap to top when at bottom
294
- else if (kb.matches(keyData, "tui.select.down")) {
295
- this.#selectedIndex = this.#selectedIndex === this.#filteredItems.length - 1 ? 0 : this.#selectedIndex + 1;
296
- this.#notifySelectionChange();
297
- }
298
- // PageUp - jump up by one visible page
299
- else if (kb.matches(keyData, "tui.select.pageUp")) {
300
- this.#selectedIndex = Math.max(0, this.#selectedIndex - this.#maxVisible);
301
- this.#notifySelectionChange();
302
- }
303
- // PageDown - jump down by one visible page
304
- else if (kb.matches(keyData, "tui.select.pageDown")) {
305
- this.#selectedIndex = Math.min(this.#filteredItems.length - 1, this.#selectedIndex + this.#maxVisible);
306
- this.#notifySelectionChange();
307
- }
308
- // Enter
309
- else if (kb.matches(keyData, "tui.select.confirm") || keyData === "\n") {
310
- const selectedItem = this.#filteredItems[this.#selectedIndex];
311
- if (selectedItem && this.onSelect) {
312
- this.onSelect(selectedItem);
313
- }
364
+ selectionChanged = this.#selection.move(-1, this.layout.wrapNavigation !== false);
365
+ } else if (kb.matches(keyData, "tui.select.down")) {
366
+ selectionChanged = this.#selection.move(1, this.layout.wrapNavigation !== false);
367
+ } else if (kb.matches(keyData, "tui.select.pageUp")) {
368
+ selectionChanged = this.#selection.move(-this.#maxVisible);
369
+ } else if (kb.matches(keyData, "tui.select.pageDown")) {
370
+ selectionChanged = this.#selection.move(this.#maxVisible);
371
+ } else if (matchesKey(keyData, "home")) {
372
+ selectionChanged = this.#selection.moveToBoundary("first");
373
+ } else if (matchesKey(keyData, "end")) {
374
+ selectionChanged = this.#selection.moveToBoundary("last");
375
+ } else if (kb.matches(keyData, "tui.select.confirm") || keyData === "\n") {
376
+ this.#activateSelected();
314
377
  }
378
+ if (selectionChanged) this.#notifySelectionChange();
315
379
  }
316
380
 
317
381
  #renderItem(
@@ -378,54 +442,6 @@ export class SelectList implements Component, MouseRoutable {
378
442
  return kept;
379
443
  }
380
444
 
381
- /**
382
- * Pick a contiguous window of items containing `selectedIndex` such that
383
- * their visual rows fit within `budget`. Centers the selection roughly
384
- * mid-window: first expands up by ⌊budget/2⌋ rows, then fills downward,
385
- * then back upward with any remaining budget. For non-wrap layouts (every
386
- * `rowCounts[i] === 1`) this resolves to the same `[start, start+maxVisible)`
387
- * window the prior arithmetic produced.
388
- */
389
- #pickWindow(
390
- rowCounts: ReadonlyArray<number>,
391
- budget: number,
392
- ): { startIndex: number; endIndex: number; visualOffset: number } {
393
- const n = rowCounts.length;
394
- const selected = Math.max(0, Math.min(this.#selectedIndex, n - 1));
395
- if (n === 0) return { startIndex: 0, endIndex: 0, visualOffset: 0 };
396
-
397
- const half = Math.floor(budget / 2);
398
- let lo = selected;
399
- let rowsAboveSelected = 0;
400
- // Step 1: expand upward up to `half` rows above the selection so it
401
- // lands near the visual middle, matching the prior centering.
402
- while (lo > 0 && rowsAboveSelected + (rowCounts[lo - 1] ?? 0) <= half) {
403
- lo--;
404
- rowsAboveSelected += rowCounts[lo] ?? 0;
405
- }
406
-
407
- // Step 2: expand downward until the budget is filled. The selected
408
- // item's own rows are always counted; if it alone exceeds `budget`
409
- // the surplus is clipped at render time and the scrollbar carries it.
410
- let hi = selected + 1;
411
- let used = rowsAboveSelected + (rowCounts[selected] ?? 0);
412
- while (hi < n && used + (rowCounts[hi] ?? 0) <= budget) {
413
- used += rowCounts[hi] ?? 0;
414
- hi++;
415
- }
416
-
417
- // Step 3: if room remains (selection sat near the bottom), keep
418
- // expanding upward.
419
- while (lo > 0 && used + (rowCounts[lo - 1] ?? 0) <= budget) {
420
- lo--;
421
- used += rowCounts[lo] ?? 0;
422
- }
423
-
424
- let visualOffset = 0;
425
- for (let i = 0; i < lo; i++) visualOffset += rowCounts[i] ?? 0;
426
- return { startIndex: lo, endIndex: hi, visualOffset };
427
- }
428
-
429
445
  #computeItemLayout(
430
446
  item: SelectItem,
431
447
  isSelected: boolean,
@@ -440,7 +456,7 @@ export class SelectList implements Component, MouseRoutable {
440
456
  const iconWidth = item.icon ? visibleWidth(item.icon) : 0;
441
457
  const iconCell = iconColumnWidth > 0 ? (item.icon ?? "") + padding(iconColumnWidth - iconWidth + 1) : "";
442
458
  const prefixWidth = visibleWidth(prefix) + (iconColumnWidth > 0 ? iconColumnWidth + 1 : 0);
443
- const descriptionSingleLine = item.description ? sanitizeSingleLine(item.description) : undefined;
459
+ const descriptionSingleLine = this.#sanitizedDescription(item);
444
460
 
445
461
  if (descriptionSingleLine && width > 40) {
446
462
  const effectivePrimaryColumnWidth = Math.max(1, Math.min(primaryColumnWidth, width - prefixWidth - 4));
@@ -478,7 +494,7 @@ export class SelectList implements Component, MouseRoutable {
478
494
 
479
495
  #getIconColumnWidth(): number {
480
496
  let widest = 0;
481
- for (const item of this.#filteredItems) {
497
+ for (const item of this.#selection.visibleItems) {
482
498
  if (item.icon) widest = Math.max(widest, visibleWidth(item.icon));
483
499
  }
484
500
  return widest;
@@ -486,7 +502,7 @@ export class SelectList implements Component, MouseRoutable {
486
502
 
487
503
  #getPrimaryColumnWidth(): number {
488
504
  const { min, max } = this.#getPrimaryColumnBounds();
489
- const widestPrimary = this.#filteredItems.reduce((widest, item) => {
505
+ const widestPrimary = this.#selection.visibleItems.reduce((widest, item) => {
490
506
  return Math.max(widest, visibleWidth(this.#getDisplayValue(item)) + PRIMARY_COLUMN_GAP);
491
507
  }, 0);
492
508
 
@@ -521,23 +537,72 @@ export class SelectList implements Component, MouseRoutable {
521
537
  }
522
538
 
523
539
  #getDisplayValue(item: SelectItem): string {
524
- return sanitizeSingleLine(item.label || item.value);
540
+ return this.#sanitizedLabel(item);
541
+ }
542
+
543
+ #sanitizedLabel(item: SelectItem): string {
544
+ return this.#sanitizedEntry(item).label;
545
+ }
546
+
547
+ #sanitizedDescription(item: SelectItem): string | undefined {
548
+ return this.#sanitizedEntry(item).description;
549
+ }
550
+
551
+ #sanitizedEntry(item: SelectItem): { label: string; description: string | undefined } {
552
+ const sourceLabel = item.label || item.value;
553
+ const sourceDescription = item.description;
554
+ const cached = this.#sanitized.get(item);
555
+ if (
556
+ cached !== undefined &&
557
+ cached.sourceLabel === sourceLabel &&
558
+ cached.sourceDescription === sourceDescription
559
+ ) {
560
+ return cached;
561
+ }
562
+ const entry = {
563
+ sourceLabel,
564
+ sourceDescription,
565
+ label: sanitizeSingleLine(sourceLabel),
566
+ description: sourceDescription ? sanitizeSingleLine(sourceDescription) : undefined,
567
+ };
568
+ this.#sanitized.set(item, entry);
569
+ return entry;
525
570
  }
526
571
 
527
572
  #renderStatusLine(width: number): string {
528
- const query = sanitizeSingleLine(this.#filterQuery);
529
- const statusText = query ? ` Search: ${query}` : " Type to search";
573
+ const pendingItem =
574
+ this.#selection.pendingKey === undefined
575
+ ? undefined
576
+ : this.#selection.visibleItems.find(item => item.value === this.#selection.pendingKey);
577
+ const query = sanitizeSingleLine(this.#selection.query);
578
+ const custom = this.layout.statusText?.({
579
+ query,
580
+ selectedIndex: this.#selection.selectedIndex,
581
+ visibleCount: this.#selection.visibleItems.length,
582
+ totalCount: this.#selection.items.length,
583
+ pendingItem,
584
+ });
585
+ const statusText =
586
+ this.layout.statusText !== undefined
587
+ ? (custom ?? "")
588
+ : (pendingItem?.confirmation ??
589
+ (query ? ` Search: ${query}` : this.#canEditSearch() ? " Type to search" : ""));
530
590
  return this.theme.scrollInfo(truncateToWidth(statusText, Math.max(1, width - 2), Ellipsis.Omit));
531
591
  }
532
592
 
533
593
  #shouldRenderSearchStatus(): boolean {
594
+ const policy = this.layout.search ?? (this.layout.overflowSearch === false ? "never" : "overflow");
534
595
  return (
535
- this.layout.overflowSearch !== false && (this.items.length > this.#maxVisible || this.#filterQuery.length > 0)
596
+ this.#selection.pendingKey !== undefined ||
597
+ this.layout.statusText !== undefined ||
598
+ (policy !== "never" && this.#selection.query.length > 0) ||
599
+ (this.#canEditSearch() && this.#selection.items.length > this.#maxVisible)
536
600
  );
537
601
  }
538
602
 
539
603
  #canEditSearch(): boolean {
540
- return this.layout.overflowSearch !== false && this.items.length > this.#maxVisible;
604
+ const policy = this.layout.search ?? (this.layout.overflowSearch === false ? "never" : "overflow");
605
+ return policy === "always" || (policy === "overflow" && this.#selection.items.length > this.#maxVisible);
541
606
  }
542
607
 
543
608
  #handleSearchInput(keyData: string): boolean {
@@ -545,8 +610,8 @@ export class SelectList implements Component, MouseRoutable {
545
610
 
546
611
  const kb = getKeybindings();
547
612
  if (kb.matches(keyData, "tui.editor.deleteCharBackward")) {
548
- if (this.#filterQuery.length === 0) return false;
549
- const chars = [...this.#filterQuery];
613
+ if (this.#selection.query.length === 0) return false;
614
+ const chars = [...this.#selection.query];
550
615
  chars.pop();
551
616
  this.#setFilter(chars.join(""), true);
552
617
  return true;
@@ -554,30 +619,25 @@ export class SelectList implements Component, MouseRoutable {
554
619
 
555
620
  const printableText = extractPrintableText(keyData);
556
621
  if (printableText === undefined) return false;
557
- if (this.#filterQuery.length === 0 && printableText.trim().length === 0) return false;
622
+ if (this.#selection.query.length === 0 && printableText.trim().length === 0) return false;
558
623
 
559
- this.#setFilter(this.#filterQuery + printableText, true);
624
+ this.#setFilter(this.#selection.query + printableText, true);
560
625
  return true;
561
626
  }
562
627
 
563
628
  #setFilter(filter: string, notify: boolean): void {
564
- this.#filterQuery = filter;
629
+ let changed: boolean;
565
630
  if (filter.trim()) {
566
- // Breadcrumb the fuzzy match so the loop watchdog can attribute a
567
- // large-list filter stall instead of logging it as "unknown".
568
631
  pushLoopPhase("ui.select-filter");
569
632
  try {
570
- this.#filteredItems = fuzzyFilter([...this.items], filter, item => this.#getFilterText(item));
633
+ changed = this.#selection.setQuery(filter);
571
634
  } finally {
572
635
  popLoopPhase();
573
636
  }
574
637
  } else {
575
- this.#filteredItems = this.items;
576
- }
577
- this.#selectedIndex = 0;
578
- if (notify) {
579
- this.#notifySelectionChange();
638
+ changed = this.#selection.setQuery(filter);
580
639
  }
640
+ if (notify && changed) this.#notifySelectionChange();
581
641
  }
582
642
 
583
643
  #getFilterText(item: SelectItem): string {
@@ -588,18 +648,37 @@ export class SelectList implements Component, MouseRoutable {
588
648
  if (item.hint) {
589
649
  text += ` ${item.hint}`;
590
650
  }
651
+ if (item.searchText) {
652
+ text += ` ${item.searchText}`;
653
+ }
591
654
  return sanitizeSingleLine(text);
592
655
  }
593
656
 
657
+ #renderContext(item: SelectItem, index: number, width: number): SelectListRenderItemContext {
658
+ return {
659
+ item,
660
+ index,
661
+ width,
662
+ selected: index === this.#selection.selectedIndex,
663
+ hovered: index === this.#hoveredIndex,
664
+ pendingConfirmation: this.#selection.isPending(item),
665
+ theme: this.theme,
666
+ };
667
+ }
668
+
669
+ #activateSelected(): void {
670
+ const activation = this.#selection.requestActivation();
671
+ if (activation.kind === "confirmed") this.onSelect?.(activation.item);
672
+ }
673
+
594
674
  #notifySelectionChange(): void {
595
- const selectedItem = this.#filteredItems[this.#selectedIndex];
675
+ const selectedItem = this.#selection.selectedItem;
596
676
  if (selectedItem && this.onSelectionChange) {
597
677
  this.onSelectionChange(selectedItem);
598
678
  }
599
679
  }
600
680
 
601
681
  getSelectedItem(): SelectItem | null {
602
- const item = this.#filteredItems[this.#selectedIndex];
603
- return item || null;
682
+ return this.#selection.selectedItem ?? null;
604
683
  }
605
684
  }