@simon_he/vue-tui 0.0.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/README.md +142 -30
  2. package/dist/TSelect-BwJJbuTt.js +6089 -0
  3. package/dist/TTree-DK_DQBYm.js +6480 -0
  4. package/dist/agent.cjs +39416 -0
  5. package/dist/agent.d.cts +44 -0
  6. package/dist/agent.d.ts +44 -0
  7. package/dist/agent.js +828 -0
  8. package/dist/ansi-palette-CNXqFciC.js +57 -0
  9. package/dist/ansi-styles.d.ts +200 -0
  10. package/dist/block-source-CKUOnkgT.js +1663 -0
  11. package/dist/cli/headless-renderer.d.ts +29 -0
  12. package/dist/cli/input.d.ts +49 -0
  13. package/dist/cli/node-file-writers.d.ts +13 -0
  14. package/dist/cli/node-module.d.ts +2 -0
  15. package/dist/cli/parse-kitty.d.ts +2 -0
  16. package/dist/cli/parse-mouse.d.ts +2 -0
  17. package/dist/cli/parse-utils.d.ts +14 -0
  18. package/dist/cli/parse-xterm.d.ts +2 -0
  19. package/dist/cli/path-provider-types.d.ts +1 -0
  20. package/dist/cli/path-provider.d.ts +4 -0
  21. package/dist/cli/path-suggest-core.d.ts +1 -0
  22. package/dist/cli/path-suggest.d.ts +15 -0
  23. package/dist/cli/recording.d.ts +4 -0
  24. package/dist/cli/stdin-buffer.d.ts +33 -0
  25. package/dist/cli.cjs +11061 -0
  26. package/dist/cli.d.cts +23 -0
  27. package/dist/cli.d.ts +23 -0
  28. package/dist/cli.js +9875 -0
  29. package/dist/core/ansi/capability.d.ts +20 -0
  30. package/dist/core/ansi/colors.d.ts +41 -0
  31. package/dist/core/ansi/sgr.d.ts +7 -0
  32. package/dist/core/ansi/theme.d.ts +6 -0
  33. package/dist/core/ansi-palette.d.ts +14 -0
  34. package/dist/core/buffer/buffer.d.ts +54 -0
  35. package/dist/core/buffer/width.d.ts +4 -0
  36. package/dist/core/debug-logger.d.ts +18 -0
  37. package/dist/core/hyperlink.d.ts +9 -0
  38. package/dist/core/index.d.ts +4 -0
  39. package/dist/core/path-provider-types.d.ts +24 -0
  40. package/dist/core/path-suggest.d.ts +35 -0
  41. package/dist/core/render-plane.d.ts +3 -0
  42. package/dist/core/terminal/create-terminal.d.ts +8 -0
  43. package/dist/core/terminal/emitter.d.ts +7 -0
  44. package/dist/core/types.d.ts +107 -0
  45. package/dist/core.cjs +3153 -0
  46. package/dist/core.d.cts +14 -0
  47. package/dist/core.d.ts +14 -0
  48. package/dist/core.js +424 -0
  49. package/dist/create-terminal-C2oiWFJU.js +1434 -0
  50. package/dist/create-terminal-app.d.ts +36 -0
  51. package/dist/dom-renderer-BqGijQID.js +1173 -0
  52. package/dist/env-Cl8qmNFN.js +19 -0
  53. package/dist/events/index.d.ts +6 -0
  54. package/dist/events/manager/cli-event-manager.d.ts +22 -0
  55. package/dist/events/manager/event-manager.d.ts +30 -0
  56. package/dist/events/manager/selection-suppression.d.ts +3 -0
  57. package/dist/events/manager/types.d.ts +108 -0
  58. package/dist/events/recording.d.ts +44 -0
  59. package/dist/experimental.cjs +4412 -1641
  60. package/dist/experimental.d.cts +42 -0
  61. package/dist/experimental.d.ts +42 -825
  62. package/dist/experimental.js +31 -7392
  63. package/dist/frame-perf-C6Xfg85O.js +24 -0
  64. package/dist/hyperlink-Bn02UXJb.js +419 -0
  65. package/dist/index.cjs +14765 -17582
  66. package/dist/index.d.cts +35 -0
  67. package/dist/index.d.ts +35 -1528
  68. package/dist/index.js +17 -20026
  69. package/dist/linkify-D_gzn9Xq.js +562 -0
  70. package/dist/markdown.cjs +9321 -7623
  71. package/dist/markdown.d.cts +11 -0
  72. package/dist/markdown.d.ts +11 -112
  73. package/dist/markdown.js +36 -1427
  74. package/dist/observability/cli-latency-node.d.ts +3 -0
  75. package/dist/observability/cli-latency-types.d.ts +41 -0
  76. package/dist/observability/cli-latency.d.ts +3 -0
  77. package/dist/observability/frame-perf-store.d.ts +18 -0
  78. package/dist/observability/frame-perf.d.ts +40 -0
  79. package/dist/observability/perf-sink.d.ts +56 -0
  80. package/dist/observability/trace.d.ts +40 -0
  81. package/dist/observability/tui-profiler.d.ts +33 -0
  82. package/dist/observability.cjs +221 -0
  83. package/dist/observability.d.cts +8 -0
  84. package/dist/observability.d.ts +8 -0
  85. package/dist/observability.js +4 -0
  86. package/dist/path-mnSgEpCm.js +81 -0
  87. package/dist/path-suggest-BNqcuE3-.js +274 -0
  88. package/dist/path-suggest-Dk9TRLh5.js +3 -0
  89. package/dist/{path-suggest-DmrmeueH.js → path-suggest-bvR9SY6Q.js} +86 -18
  90. package/dist/renderer/capabilities.d.ts +13 -0
  91. package/dist/renderer/cli/index.d.ts +2 -0
  92. package/dist/renderer/cli/stdout-metrics.d.ts +18 -0
  93. package/dist/renderer/cli/stdout-renderer.d.ts +48 -0
  94. package/dist/renderer/dom/dom-renderer.d.ts +157 -0
  95. package/dist/renderer/dom/index.d.ts +2 -0
  96. package/dist/renderer/index.d.ts +2 -0
  97. package/dist/renderer-dom.cjs +1505 -0
  98. package/dist/renderer-dom.d.cts +4 -0
  99. package/dist/renderer-dom.d.ts +4 -0
  100. package/dist/renderer-dom.js +7 -0
  101. package/dist/runtime/index.d.ts +36 -0
  102. package/dist/runtime/osc52.d.ts +9 -0
  103. package/dist/runtime-rfcZCyJq.js +1197 -0
  104. package/dist/runtime.cjs +1698 -0
  105. package/dist/runtime.d.cts +9 -0
  106. package/dist/runtime.d.ts +9 -0
  107. package/dist/runtime.js +4 -0
  108. package/dist/selection/terminal-selection.d.ts +123 -0
  109. package/dist/sgr-BmzxEjAO.js +304 -0
  110. package/dist/terminal-selection-DBinO6p5.js +330 -0
  111. package/dist/tlog-theme-qPBt5rge.js +9254 -0
  112. package/dist/trace-CjzYeIxN.js +182 -0
  113. package/dist/utils/env.d.ts +3 -0
  114. package/dist/utils/grapheme.d.ts +5 -0
  115. package/dist/utils/newlines.d.ts +1 -0
  116. package/dist/utils/path.d.ts +7 -0
  117. package/dist/utils/url-safety.d.ts +2 -0
  118. package/dist/vue/agent/view-models.d.ts +98 -0
  119. package/dist/vue/components/TAnchor.d.ts +108 -0
  120. package/dist/vue/components/TBox.d.ts +144 -0
  121. package/dist/vue/components/TCommandPalette.d.ts +587 -0
  122. package/dist/vue/components/TDataTable.d.ts +367 -0
  123. package/dist/vue/components/TDebugOverlay.d.ts +43 -0
  124. package/dist/vue/components/TDialog.d.ts +255 -0
  125. package/dist/vue/components/TFeedback.d.ts +635 -0
  126. package/dist/vue/components/TFlow.d.ts +85 -0
  127. package/dist/vue/components/TForm.d.ts +1230 -0
  128. package/dist/vue/components/TInput.d.ts +545 -0
  129. package/dist/vue/components/TInputBox.d.ts +158 -0
  130. package/dist/vue/components/TJsonEditor.d.ts +165 -0
  131. package/dist/vue/components/TLink.d.ts +239 -0
  132. package/dist/vue/components/TLinkifyText.d.ts +141 -0
  133. package/dist/vue/components/TList.d.ts +119 -0
  134. package/dist/vue/components/TLogLinksPanel.d.ts +238 -0
  135. package/dist/vue/components/TLogMinimap.d.ts +263 -0
  136. package/dist/vue/components/TLogScrollbar.d.ts +236 -0
  137. package/dist/vue/components/TLogSearchBar.d.ts +267 -0
  138. package/dist/vue/components/TLogSearchPager.d.ts +162 -0
  139. package/dist/vue/components/TLogSearchResults.d.ts +200 -0
  140. package/dist/vue/components/TLogView.d.ts +536 -0
  141. package/dist/vue/components/TLogVirtualLinksPanel.d.ts +141 -0
  142. package/dist/vue/components/TLogVirtualSearchResults.d.ts +146 -0
  143. package/dist/vue/components/TMarkdownText.d.ts +134 -0
  144. package/dist/vue/components/TMultilineModal.d.ts +62 -0
  145. package/dist/vue/components/TNavigation.d.ts +324 -0
  146. package/dist/vue/components/TOverlay.d.ts +366 -0
  147. package/dist/vue/components/TPanels.d.ts +244 -0
  148. package/dist/vue/components/TPathPicker.d.ts +213 -0
  149. package/dist/vue/components/TRenderLayer.d.ts +16 -0
  150. package/dist/vue/components/TRenderPlane.d.ts +17 -0
  151. package/dist/vue/components/TSelect.d.ts +335 -0
  152. package/dist/vue/components/TTable.d.ts +317 -0
  153. package/dist/vue/components/TText.d.ts +116 -0
  154. package/dist/vue/components/TThinkingView.d.ts +233 -0
  155. package/dist/vue/components/TToolCallView.d.ts +384 -0
  156. package/dist/vue/components/TTranscriptView.d.ts +221 -0
  157. package/dist/vue/components/TTransition.d.ts +83 -0
  158. package/dist/vue/components/TTree.d.ts +200 -0
  159. package/dist/vue/components/TUserMessageView.d.ts +344 -0
  160. package/dist/vue/components/TView.d.ts +127 -0
  161. package/dist/vue/components/TVirtualList.d.ts +182 -0
  162. package/dist/vue/components/TVirtualMarkdown.d.ts +168 -0
  163. package/dist/vue/components/TVirtualRows.d.ts +247 -0
  164. package/dist/vue/components/TerminalProvider.d.ts +218 -0
  165. package/dist/vue/components/input/host.d.ts +17 -0
  166. package/dist/vue/components/input/plugins/hostPlugin.d.ts +7 -0
  167. package/dist/vue/components/input/plugins/hostPlugin.node.d.ts +15 -0
  168. package/dist/vue/components/input/plugins/mentionUtils.d.ts +17 -0
  169. package/dist/vue/components/input/plugins/nodeMentionPathProvider.d.ts +2 -0
  170. package/dist/vue/components/input/plugins/promptMentionPlugin.d.ts +8 -0
  171. package/dist/vue/components/input/plugins/promptMentionState.d.ts +98 -0
  172. package/dist/vue/components/input/plugins/restrictText.d.ts +27 -0
  173. package/dist/vue/components/input/plugins/types.d.ts +90 -0
  174. package/dist/vue/components/input/utils/inlineText.d.ts +57 -0
  175. package/dist/vue/components/input/utils/inlineTextTokens.d.ts +34 -0
  176. package/dist/vue/components/input/utils/primitives.d.ts +3 -0
  177. package/dist/vue/components/input/utils/wordNavigation.d.ts +6 -0
  178. package/dist/vue/components/link/host.d.ts +15 -0
  179. package/dist/vue/components/list/list-geometry.d.ts +16 -0
  180. package/dist/vue/components/list/list-paint.d.ts +1 -0
  181. package/dist/vue/components/list/scroll-state.d.ts +25 -0
  182. package/dist/vue/components/list/selection-state.d.ts +6 -0
  183. package/dist/vue/components/simple-utils.d.ts +5 -0
  184. package/dist/vue/components/terminal-provider/copy-toast.d.ts +6 -0
  185. package/dist/vue/components/terminal-provider/portals.d.ts +17 -0
  186. package/dist/vue/components/terminal-provider/scheduler.d.ts +29 -0
  187. package/dist/vue/components/terminal-provider/selection-config.d.ts +15 -0
  188. package/dist/vue/components/terminal-provider/utils.d.ts +5 -0
  189. package/dist/vue/composables/use-layout.d.ts +2 -0
  190. package/dist/vue/composables/use-render-node.d.ts +19 -0
  191. package/dist/vue/composables/use-render-stack.d.ts +3 -0
  192. package/dist/vue/composables/use-runtime.d.ts +5 -0
  193. package/dist/vue/composables/use-terminal-node.d.ts +14 -0
  194. package/dist/vue/composables/use-terminal.d.ts +2 -0
  195. package/dist/vue/composables/use-visibility.d.ts +12 -0
  196. package/dist/vue/context.d.ts +153 -0
  197. package/dist/vue/index.d.ts +69 -0
  198. package/dist/vue/injection-key.d.ts +2 -0
  199. package/dist/vue/linkify.d.ts +11 -0
  200. package/dist/vue/log/append-only-log-store.d.ts +2 -0
  201. package/dist/vue/log/tlog-keymap.d.ts +28 -0
  202. package/dist/vue/log/tlog-plugins.d.ts +144 -0
  203. package/dist/vue/log/tlog-session.d.ts +81 -0
  204. package/dist/vue/log/tlog-theme.d.ts +68 -0
  205. package/dist/vue/log/types.d.ts +43 -0
  206. package/dist/vue/log/use-tlog-link-controller.d.ts +31 -0
  207. package/dist/vue/log/use-tlog-retained-index.d.ts +26 -0
  208. package/dist/vue/log/use-tlog-search-controller.d.ts +51 -0
  209. package/dist/vue/log/use-tlog-search-results-page.d.ts +31 -0
  210. package/dist/vue/log/use-tlog-virtual-search-results.d.ts +22 -0
  211. package/dist/vue/markdown/ast.d.ts +3 -0
  212. package/dist/vue/markdown/block-source.d.ts +22 -0
  213. package/dist/vue/markdown/document.d.ts +20 -0
  214. package/dist/vue/markdown/layout.d.ts +21 -0
  215. package/dist/vue/markdown/parser.d.ts +11 -0
  216. package/dist/vue/markdown/render.d.ts +10 -0
  217. package/dist/vue/markdown/theme.d.ts +186 -0
  218. package/dist/vue/markdown/types.d.ts +59 -0
  219. package/dist/vue/overlay.d.ts +27 -0
  220. package/dist/vue/render/context.d.ts +3 -0
  221. package/dist/vue/render/render-manager.d.ts +94 -0
  222. package/dist/vue/router/RouterView.d.ts +25 -0
  223. package/dist/vue/router/composables.d.ts +4 -0
  224. package/dist/vue/router/context.d.ts +4 -0
  225. package/dist/vue/router/router.d.ts +7 -0
  226. package/dist/vue/router/types.d.ts +29 -0
  227. package/dist/vue/scheduler/frame-mailbox.d.ts +55 -0
  228. package/dist/vue/scheduler/frame-scheduler.d.ts +51 -0
  229. package/dist/vue/theme.d.ts +48 -0
  230. package/dist/vue/transcript/hit-regions.d.ts +2 -0
  231. package/dist/vue/transcript/layout.d.ts +20 -0
  232. package/dist/vue/transcript/plain-text.d.ts +2 -0
  233. package/dist/vue/transcript/types.d.ts +122 -0
  234. package/dist/vue/utils/frame-task.d.ts +6 -0
  235. package/dist/vue/utils/rect.d.ts +4 -0
  236. package/dist/vue/utils/row-scroll.d.ts +25 -0
  237. package/dist/vue/utils/style-cache.d.ts +3 -0
  238. package/dist/vue/utils/text.d.ts +27 -0
  239. package/dist/vue/utils/wheel-scroll.d.ts +18 -0
  240. package/dist/vue.cjs +23668 -0
  241. package/dist/vue.d.cts +1 -0
  242. package/dist/vue.d.ts +1 -0
  243. package/dist/vue.js +3957 -0
  244. package/dist/{wheel-scroll-CiNsasLf.js → wheel-scroll-vBRaQ7p-.js} +404 -405
  245. package/package.json +185 -35
  246. package/dist/path-suggest-BeV6n7m-.js +0 -3
  247. package/dist/sgr-Tko2EQ0U.js +0 -484
  248. package/dist/theme-Bsm65g8k.d.ts +0 -32
  249. package/dist/types-ClIV2h1o.d.ts +0 -103
package/dist/vue.js ADDED
@@ -0,0 +1,3957 @@
1
+ import "./create-terminal-C2oiWFJU.js";
2
+ import { charCellWidth } from "./hyperlink-Bn02UXJb.js";
3
+ import "./sgr-BmzxEjAO.js";
4
+ import "./ansi-palette-CNXqFciC.js";
5
+ import "./dom-renderer-BqGijQID.js";
6
+ import { EventZIndexContextKey, LayoutContextKey, RenderStackKey, TInputPluginsContextKey, TPathPickerProviderContextKey, VisibilityContextKey, applyWheelScroll, createWheelScrollState, injectionKey, intersectRect, padEndByCells$1 as padEndByCells, repeatChar, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, textCellWidth$1 as textCellWidth, translateRect, useLayout, useRenderNode, useRenderStack, useTerminal, useTerminalNode, useVisibility, wrapByCells } from "./wheel-scroll-vBRaQ7p-.js";
7
+ import { TView, createTheme, linkifyTextSegments, tuiDefaultTheme } from "./linkify-D_gzn9Xq.js";
8
+ import "./runtime-rfcZCyJq.js";
9
+ import "./trace-CjzYeIxN.js";
10
+ import "./env-Cl8qmNFN.js";
11
+ import { TAutocompleteInput, TBadge, TCheckbox, TCode, TDataTable, TDivider, TForm, TFormContextKey, TFormField, TLink, TLinkifyText, TList, TPasswordInput, TProgress, TRadioGroup, TSlider, TSpinner, TSwitch, TTable, TTag, TToastViewport, TTree, TerminalProvider, createTInputHostPlugin, useTForm } from "./TTree-DK_DQBYm.js";
12
+ import "./terminal-selection-DBinO6p5.js";
13
+ import { TBox, TCommandPalette, TDialog, TInput, TRenderPlane, TSelect, TText, clamp as clamp$1, clamp$1 as clamp, computeCommandPaletteMatchRanges, createOverlayFocusStack, fitCellText, isCommitMention, isWhitespace, mentionChipStyle, mergeStyle, padEndByCells as padEndByCells$1, resolveOverlayPlacement, sliceByCellsWindow, textCellWidth as textCellWidth$1 } from "./TSelect-BwJJbuTt.js";
14
+ import "./frame-perf-C6Xfg85O.js";
15
+ import { normalizePath, stripTrailingSlash } from "./path-mnSgEpCm.js";
16
+ import { parsePathQuery, resolveUserPath, suggestPaths } from "./path-suggest-BNqcuE3-.js";
17
+ import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, onUnmounted, provide, reactive, ref, shallowReactive, shallowRef, watch, watchEffect } from "vue";
18
+
19
+ //#region src/observability/cli-latency.ts
20
+ const GLOBAL_PROFILER_KEY = "__vueTuiCliLatencyProfiler";
21
+ function getCliLatencyProfiler() {
22
+ const getProfiler = globalThis[GLOBAL_PROFILER_KEY];
23
+ return typeof getProfiler === "function" ? getProfiler() : null;
24
+ }
25
+
26
+ //#endregion
27
+ //#region src/vue/components/input/plugins/promptMentionState.ts
28
+ const MENTION_SUGGEST_DEBOUNCE_MS = 80;
29
+ function fuzzyScore(query, candidate) {
30
+ const q = query.trim().toLowerCase();
31
+ const c = candidate.toLowerCase();
32
+ if (!q) return 0;
33
+ if (c === q) return 1e4;
34
+ let score = 0;
35
+ if (c.startsWith(q)) score += 1e3;
36
+ let qi = 0;
37
+ let streak = 0;
38
+ for (let ci = 0; ci < c.length && qi < q.length; ci++) if (c[ci] === q[qi]) {
39
+ qi++;
40
+ streak++;
41
+ score += 10 + streak * 5;
42
+ } else streak = 0;
43
+ if (qi < q.length) return null;
44
+ score += Math.max(0, 40 - c.length);
45
+ return score;
46
+ }
47
+ function isMentionBoundary(ch, multilineToken, mentionToken) {
48
+ if (ch === multilineToken || ch === mentionToken) return true;
49
+ if (isWhitespace(ch)) return true;
50
+ return /[,;:!?,。!?、()[\]{}<>]/.test(ch);
51
+ }
52
+ function isMentionStart(text, index, trigger, multilineToken, mentionToken) {
53
+ if (!trigger || text[index] !== trigger) return false;
54
+ if (index <= 0) return true;
55
+ const prev = text[index - 1];
56
+ return isMentionBoundary(prev, multilineToken, mentionToken) || !/\w/.test(prev);
57
+ }
58
+ function isMentionChar(ch) {
59
+ return /^[\p{L}\p{M}\p{N}_./~\\:-]$/u.test(ch);
60
+ }
61
+ function computePromptContext(value, cursorIndex, triggers) {
62
+ if (!triggers.length) return null;
63
+ const idx = clamp(cursorIndex, 0, value.length);
64
+ const lineStart = value.lastIndexOf("\n", Math.max(0, idx - 1)) + 1;
65
+ let matchedTrigger = null;
66
+ for (const t of triggers) if (t && value.slice(lineStart, lineStart + t.length) === t) {
67
+ matchedTrigger = t;
68
+ break;
69
+ }
70
+ if (!matchedTrigger) return null;
71
+ let tokenEnd = value.length;
72
+ for (let i = lineStart; i < value.length; i++) if (isWhitespace(value[i])) {
73
+ tokenEnd = i;
74
+ break;
75
+ }
76
+ if (idx < lineStart || idx > tokenEnd) return null;
77
+ const tokenText = value.slice(lineStart, tokenEnd);
78
+ const query = tokenText.slice(matchedTrigger.length);
79
+ const key = `${lineStart}:${tokenText}`;
80
+ return {
81
+ tokenStart: lineStart,
82
+ tokenEnd,
83
+ tokenText,
84
+ query,
85
+ key,
86
+ trigger: matchedTrigger
87
+ };
88
+ }
89
+ function computeMentionContext(value, cursorIndex, trigger, multilineToken, mentionToken) {
90
+ if (!trigger) return null;
91
+ const idx = clamp(cursorIndex, 0, value.length);
92
+ let start = -1;
93
+ for (let i = idx - 1; i >= 0; i--) {
94
+ const ch = value[i];
95
+ if (isMentionStart(value, i, trigger, multilineToken, mentionToken)) {
96
+ start = i;
97
+ break;
98
+ }
99
+ if (isMentionBoundary(ch, multilineToken, mentionToken)) break;
100
+ }
101
+ if (start < 0) return null;
102
+ let end = start + trigger.length;
103
+ const next = value[end];
104
+ if (next === "\"" || next === "'") {
105
+ const quote = next;
106
+ end += 1;
107
+ while (end < value.length && value[end] !== quote) end++;
108
+ if (end < value.length && value[end] === quote) end++;
109
+ } else while (end < value.length && isMentionChar(value[end])) end++;
110
+ if (idx < start || idx > end) return null;
111
+ const tokenText = value.slice(start, end);
112
+ const queryEnd = clamp(idx, start + trigger.length, end);
113
+ const query = value.slice(start + trigger.length, queryEnd);
114
+ const key = `${start}:${tokenText}`;
115
+ return {
116
+ tokenStart: start,
117
+ tokenEnd: end,
118
+ tokenText,
119
+ query,
120
+ key,
121
+ trigger
122
+ };
123
+ }
124
+ function usePromptMentionState(options) {
125
+ const { props, mentionSuggestionProviders, mentionPathProvider, focused, cursor, getValue, rawAbsRect, terminal, scheduler, multilineToken, mentionToken } = options;
126
+ const promptActive = ref(0);
127
+ const promptSuppressedKey = ref(null);
128
+ const providerList = mentionSuggestionProviders ?? [];
129
+ const mentionKindVersion = ref(0);
130
+ const mentionKindByPath = new Map();
131
+ let mentionKindSeq = 0;
132
+ function clearMentionKinds() {
133
+ if (mentionKindByPath.size === 0) return;
134
+ mentionKindByPath.clear();
135
+ mentionKindVersion.value++;
136
+ scheduler.invalidate();
137
+ }
138
+ watchEffect(() => {
139
+ const list = (props.mentions ?? []).map((p) => String(p ?? "")).filter(Boolean).filter((p) => !isCommitMention(p));
140
+ const statPath = mentionPathProvider?.stat;
141
+ if (!statPath || list.length === 0) {
142
+ clearMentionKinds();
143
+ return;
144
+ }
145
+ const seq = ++mentionKindSeq;
146
+ Promise.allSettled(list.map(async (absPath) => {
147
+ const kind = await Promise.resolve(statPath(absPath));
148
+ return {
149
+ absPath,
150
+ kind
151
+ };
152
+ })).then((results) => {
153
+ if (seq !== mentionKindSeq) return;
154
+ mentionKindByPath.clear();
155
+ for (const r of results) {
156
+ if (r.status !== "fulfilled") continue;
157
+ if (!r.value.kind) continue;
158
+ mentionKindByPath.set(r.value.absPath, r.value.kind);
159
+ }
160
+ mentionKindVersion.value++;
161
+ scheduler.invalidate();
162
+ }).catch(() => {
163
+ if (seq !== mentionKindSeq) return;
164
+ clearMentionKinds();
165
+ });
166
+ });
167
+ const promptContext = computed(() => {
168
+ if (!focused.value) return null;
169
+ if (!props.promptSuggestions?.length) return null;
170
+ const triggers = props.promptTriggers?.length ? props.promptTriggers : [props.promptTrigger || "/"];
171
+ return computePromptContext(getValue(), cursor.value, triggers);
172
+ });
173
+ const mentionContext = computed(() => {
174
+ if (!focused.value) return null;
175
+ const hasStatic = props.mentionSuggestions?.length > 0;
176
+ const hasDynamic = providerList.length > 0 || Boolean(mentionPathProvider?.suggest);
177
+ if (!hasStatic && !hasDynamic) return null;
178
+ return computeMentionContext(getValue(), cursor.value, props.mentionTrigger || "@", multilineToken, mentionToken);
179
+ });
180
+ const skillContext = computed(() => {
181
+ if (!focused.value) return null;
182
+ const trigger = props.skillTrigger;
183
+ if (!trigger || !props.skillSuggestions?.length) return null;
184
+ return computeMentionContext(getValue(), cursor.value, trigger, multilineToken, mentionToken);
185
+ });
186
+ const activeContext = computed(() => mentionContext.value ?? skillContext.value ?? promptContext.value);
187
+ watch(() => activeContext.value?.key ?? null, (next, prev) => {
188
+ if (prev && next !== prev) promptSuppressedKey.value = null;
189
+ });
190
+ const mentionPathItems = ref([]);
191
+ let mentionSeq = 0;
192
+ watchEffect((onCleanup) => {
193
+ const ctx = mentionContext.value;
194
+ const suggestPathsForMention = mentionPathProvider?.suggest;
195
+ if (!ctx || !suggestPathsForMention) {
196
+ mentionPathItems.value = [];
197
+ return;
198
+ }
199
+ const seq = ++mentionSeq;
200
+ const max = Math.max(0, Math.floor(props.mentionMaxItems));
201
+ const q = ctx.query.trim();
202
+ const maxDepth = q.length <= 1 ? 2 : q.length === 2 ? 4 : 8;
203
+ let done = false;
204
+ const timer = setTimeout(() => {
205
+ Promise.resolve(suggestPathsForMention({
206
+ workspaceAbs: props.mentionWorkspace,
207
+ input: ctx.query,
208
+ mode: props.mentionMode,
209
+ max,
210
+ showHidden: props.mentionShowHidden,
211
+ maxDepth
212
+ })).then((res) => {
213
+ if (done || seq !== mentionSeq) return;
214
+ mentionPathItems.value = (res ?? []).map((s) => ({
215
+ value: `${props.mentionTrigger}${s.completion}`,
216
+ insert: `${props.mentionTrigger}${s.completion} `,
217
+ detail: s.kind,
218
+ mentionValue: s.absPath
219
+ }));
220
+ scheduler.invalidate();
221
+ }).catch(() => {
222
+ if (done || seq !== mentionSeq) return;
223
+ mentionPathItems.value = [];
224
+ scheduler.invalidate();
225
+ });
226
+ }, MENTION_SUGGEST_DEBOUNCE_MS);
227
+ onCleanup(() => {
228
+ done = true;
229
+ clearTimeout(timer);
230
+ });
231
+ });
232
+ const mentionProviderItems = ref([]);
233
+ let mentionProviderSeq = 0;
234
+ watchEffect((onCleanup) => {
235
+ const ctx = mentionContext.value;
236
+ if (!ctx || providerList.length === 0) {
237
+ mentionProviderItems.value = [];
238
+ return;
239
+ }
240
+ const seq = ++mentionProviderSeq;
241
+ const max = Math.max(0, Math.floor(props.mentionMaxItems));
242
+ const trigger = props.mentionTrigger || "@";
243
+ let done = false;
244
+ const timer = setTimeout(() => {
245
+ Promise.all(providerList.map((provider) => Promise.resolve(provider({
246
+ query: ctx.query,
247
+ tokenText: ctx.tokenText,
248
+ trigger,
249
+ workspace: props.mentionWorkspace,
250
+ maxItems: max
251
+ })).catch(() => []))).then((results) => {
252
+ if (done || seq !== mentionProviderSeq) return;
253
+ const merged = [];
254
+ for (const list of results) {
255
+ if (!list?.length) continue;
256
+ merged.push(...list);
257
+ }
258
+ mentionProviderItems.value = merged;
259
+ scheduler.invalidate();
260
+ }).catch(() => {
261
+ if (done || seq !== mentionProviderSeq) return;
262
+ mentionProviderItems.value = [];
263
+ scheduler.invalidate();
264
+ });
265
+ }, MENTION_SUGGEST_DEBOUNCE_MS);
266
+ onCleanup(() => {
267
+ done = true;
268
+ clearTimeout(timer);
269
+ });
270
+ });
271
+ const promptMatches = computed(() => {
272
+ const ctx = activeContext.value;
273
+ if (!ctx) return [];
274
+ const mentionTrigger = props.mentionTrigger || "@";
275
+ const skillTrigger = props.skillTrigger || "";
276
+ const isMention = ctx.tokenText.startsWith(mentionTrigger);
277
+ const isSkill = !isMention && Boolean(skillTrigger && ctx.tokenText.startsWith(skillTrigger));
278
+ const trigger = isMention ? mentionTrigger : isSkill ? skillTrigger : ctx.trigger;
279
+ const pathItems = isMention ? mentionPathItems.value : [];
280
+ const candidates = isMention ? [...props.mentionSuggestions ?? [], ...mentionProviderItems.value] : isSkill ? props.skillSuggestions ?? [] : props.promptSuggestions ?? [];
281
+ const q = ctx.query.trim();
282
+ const pathMatches = [];
283
+ for (let i = 0; i < pathItems.length; i++) {
284
+ const s = pathItems[i];
285
+ const value = s.value || "";
286
+ if (!value.startsWith(trigger)) continue;
287
+ pathMatches.push({
288
+ item: s,
289
+ score: 0,
290
+ order: i
291
+ });
292
+ }
293
+ const otherMatches = [];
294
+ for (let i = 0; i < candidates.length; i++) {
295
+ const s = candidates[i];
296
+ const value = s.value || "";
297
+ if (!value.startsWith(trigger)) continue;
298
+ if (!q) {
299
+ otherMatches.push({
300
+ item: s,
301
+ score: 0,
302
+ order: i
303
+ });
304
+ continue;
305
+ }
306
+ const commandText = value.slice(trigger.length);
307
+ const valueScore = fuzzyScore(q, commandText);
308
+ if (valueScore != null) {
309
+ otherMatches.push({
310
+ item: s,
311
+ score: valueScore + 1e3,
312
+ order: i
313
+ });
314
+ continue;
315
+ }
316
+ if (!/[^\u0000-\u007F]/.test(q)) continue;
317
+ const metaText = [
318
+ s.label ?? "",
319
+ s.detail ?? "",
320
+ ...s.keywords ?? []
321
+ ].join(" ");
322
+ const metaScore = fuzzyScore(q, metaText);
323
+ if (metaScore != null) otherMatches.push({
324
+ item: s,
325
+ score: metaScore,
326
+ order: i
327
+ });
328
+ }
329
+ if (!q) return [...pathMatches, ...otherMatches];
330
+ otherMatches.sort((a, b) => b.score - a.score || a.order - b.order);
331
+ return [...pathMatches, ...otherMatches];
332
+ });
333
+ watch(() => promptMatches.value.length, (len) => {
334
+ promptActive.value = clamp(promptActive.value, 0, Math.max(0, len - 1));
335
+ });
336
+ const promptMaxVisible = computed(() => {
337
+ const ctx = activeContext.value;
338
+ if (!ctx) return 0;
339
+ const mentionTrigger = props.mentionTrigger || "@";
340
+ const isMention = ctx.tokenText.startsWith(mentionTrigger);
341
+ return Math.max(0, Math.floor(isMention ? props.mentionMaxItems : props.promptMaxItems));
342
+ });
343
+ const promptWindowStart = computed(() => {
344
+ const total = promptMatches.value.length;
345
+ const maxVisible = promptMaxVisible.value;
346
+ if (total <= 0 || maxVisible <= 0) return 0;
347
+ const visible = Math.min(maxVisible, total);
348
+ const maxStart = Math.max(0, total - visible);
349
+ return clamp(promptActive.value - (visible - 1), 0, maxStart);
350
+ });
351
+ const promptMatchesVisible = computed(() => {
352
+ const total = promptMatches.value.length;
353
+ const maxVisible = promptMaxVisible.value;
354
+ if (total <= 0 || maxVisible <= 0) return [];
355
+ const visible = Math.min(maxVisible, total);
356
+ const start = promptWindowStart.value;
357
+ return promptMatches.value.slice(start, start + visible);
358
+ });
359
+ const promptActiveVisible = computed(() => {
360
+ const start = promptWindowStart.value;
361
+ const rel = promptActive.value - start;
362
+ return clamp(rel, 0, Math.max(0, promptMatchesVisible.value.length - 1));
363
+ });
364
+ const promptVisible = computed(() => {
365
+ const ctx = activeContext.value;
366
+ if (!ctx) return false;
367
+ if (promptSuppressedKey.value && promptSuppressedKey.value === ctx.key) return false;
368
+ return true;
369
+ });
370
+ const promptRect = computed(() => {
371
+ const base = rawAbsRect.value;
372
+ const s = terminal.size();
373
+ const clip = {
374
+ x: 0,
375
+ y: 0,
376
+ w: s.cols,
377
+ h: s.rows
378
+ };
379
+ const listH = Math.max(1, promptMatchesVisible.value.length || 1);
380
+ const h$1 = clamp(2 + listH, 3, Math.max(3, Math.floor(clip.h)));
381
+ const w = clamp(Math.floor(base.w), 0, Math.max(0, Math.floor(clip.w)));
382
+ const preferAboveY = Math.floor(base.y) - h$1;
383
+ const preferBelowY = Math.floor(base.y) + Math.floor(base.h);
384
+ const aboveFits = preferAboveY >= Math.floor(clip.y);
385
+ const belowFits = preferBelowY + h$1 <= Math.floor(clip.y) + Math.floor(clip.h);
386
+ const yPref = aboveFits ? preferAboveY : belowFits ? preferBelowY : preferAboveY;
387
+ const y = clamp(yPref, Math.floor(clip.y), Math.floor(clip.y) + Math.floor(clip.h) - h$1);
388
+ const align = props.promptAlign || "input";
389
+ const baseX = Math.floor(base.x);
390
+ const centeredX = Math.floor(Math.floor(clip.x) + Math.floor((Math.floor(clip.w) - w) / 2));
391
+ const preferX = align === "center" ? centeredX : baseX;
392
+ const x = clamp(preferX, Math.floor(clip.x), Math.floor(clip.x) + Math.floor(clip.w) - w);
393
+ return {
394
+ x,
395
+ y,
396
+ w,
397
+ h: h$1
398
+ };
399
+ });
400
+ return {
401
+ promptActive,
402
+ promptSuppressedKey,
403
+ mentionKindByPath,
404
+ mentionKindVersion,
405
+ promptContext,
406
+ mentionContext,
407
+ activeContext,
408
+ promptMatches,
409
+ promptMatchesVisible,
410
+ promptWindowStart,
411
+ promptActiveVisible,
412
+ promptVisible,
413
+ promptRect
414
+ };
415
+ }
416
+
417
+ //#endregion
418
+ //#region src/vue/components/input/plugins/promptMentionPlugin.ts
419
+ function omitInverse(style) {
420
+ if (!style) return {};
421
+ const { inverse: _inverse,...rest } = style;
422
+ return rest;
423
+ }
424
+ function resolveSelectedPromptStyle(popupBase, selectedOverride) {
425
+ if (!selectedOverride) return {
426
+ ...popupBase,
427
+ inverse: true,
428
+ bold: true,
429
+ dim: false
430
+ };
431
+ if (selectedOverride.bg == null) return {
432
+ ...omitInverse(popupBase),
433
+ ...omitInverse(selectedOverride),
434
+ inverse: true,
435
+ bold: true,
436
+ dim: false
437
+ };
438
+ return {
439
+ ...popupBase,
440
+ ...selectedOverride,
441
+ dim: false
442
+ };
443
+ }
444
+ function computeHighlightRanges$1(text, query) {
445
+ const q = query.trim().toLowerCase();
446
+ if (!q) return [];
447
+ const t = text.toLowerCase();
448
+ const idx = t.indexOf(q);
449
+ if (idx >= 0) return [{
450
+ start: idx,
451
+ end: idx + q.length
452
+ }];
453
+ const positions = [];
454
+ let qi = 0;
455
+ for (let i = 0; i < t.length && qi < q.length; i++) if (t[i] === q[qi]) {
456
+ positions.push(i);
457
+ qi++;
458
+ }
459
+ if (qi < q.length) return [];
460
+ const ranges = [];
461
+ let start = positions[0];
462
+ let prev = positions[0];
463
+ for (let i = 1; i < positions.length; i++) {
464
+ const pos = positions[i];
465
+ if (pos === prev + 1) {
466
+ prev = pos;
467
+ continue;
468
+ }
469
+ ranges.push({
470
+ start,
471
+ end: prev + 1
472
+ });
473
+ start = pos;
474
+ prev = pos;
475
+ }
476
+ ranges.push({
477
+ start,
478
+ end: prev + 1
479
+ });
480
+ return ranges;
481
+ }
482
+ function writeHighlightedText$1(opts) {
483
+ const { text, ranges, x, y, maxCells, baseStyle, highlightStyle, terminal } = opts;
484
+ const safeMax = Math.max(0, Math.floor(maxCells));
485
+ if (!text || safeMax <= 0) return 0;
486
+ let rangeIndex = 0;
487
+ let activeRange = ranges[rangeIndex];
488
+ let cellPos = 0;
489
+ let cursorX = x;
490
+ let buffer = "";
491
+ let currentStyle = baseStyle;
492
+ const flush = () => {
493
+ if (!buffer) return;
494
+ terminal.write(buffer, {
495
+ x: cursorX,
496
+ y,
497
+ style: currentStyle
498
+ });
499
+ cursorX += textCellWidth$1(buffer);
500
+ buffer = "";
501
+ };
502
+ for (let i = 0; i < text.length && cellPos < safeMax;) {
503
+ const code = text.charCodeAt(i);
504
+ const seg = code <= 127 ? text[i] : String.fromCodePoint(text.codePointAt(i) ?? 0);
505
+ const segLen = seg.length;
506
+ const segWidth = charCellWidth(seg);
507
+ if (cellPos + segWidth > safeMax) break;
508
+ while (activeRange && activeRange.end <= i) {
509
+ rangeIndex++;
510
+ activeRange = ranges[rangeIndex];
511
+ }
512
+ const isHighlighted = Boolean(activeRange && i < activeRange.end && i + segLen > activeRange.start);
513
+ const nextStyle = isHighlighted ? highlightStyle : baseStyle;
514
+ if (nextStyle !== currentStyle) {
515
+ flush();
516
+ currentStyle = nextStyle;
517
+ }
518
+ buffer += seg;
519
+ cellPos += segWidth;
520
+ i += segLen;
521
+ }
522
+ flush();
523
+ return cellPos;
524
+ }
525
+ function buildPromptMatchHighlightStyle(baseStyle, overrideStyle) {
526
+ return {
527
+ ...baseStyle,
528
+ ...overrideStyle ?? {
529
+ fg: "yellow",
530
+ bold: true,
531
+ dim: false
532
+ }
533
+ };
534
+ }
535
+ function countMentionTokens(value, mentionToken, endIndex = value.length) {
536
+ let count = 0;
537
+ const limit = clamp(endIndex, 0, value.length);
538
+ for (let i = 0; i < limit; i++) if (value[i] === mentionToken) count++;
539
+ return count;
540
+ }
541
+ function mentionIndexAt(value, mentionToken, index) {
542
+ return countMentionTokens(value, mentionToken, index);
543
+ }
544
+ function createPromptMentionPlugin(options = {}) {
545
+ const latency = getCliLatencyProfiler();
546
+ return {
547
+ name: "promptMention",
548
+ install: (ctx) => {
549
+ const getProps = () => ctx.getProps();
550
+ const promptOverlayStack = ctx.render.createStack(ctx.render.rootStack, 1e4);
551
+ let lastTopClampedRect = null;
552
+ let lastPromptRect = null;
553
+ const derivedStyleCache = new WeakMap();
554
+ const reactiveProps = reactive({
555
+ promptSuggestions: getProps().promptSuggestions,
556
+ promptTrigger: getProps().promptTrigger,
557
+ promptTriggers: getProps().promptTriggers,
558
+ promptMaxItems: getProps().promptMaxItems,
559
+ promptAlign: getProps().promptAlign,
560
+ mentionTrigger: getProps().mentionTrigger,
561
+ mentionWorkspace: getProps().mentionWorkspace,
562
+ mentionMode: getProps().mentionMode,
563
+ mentionShowHidden: getProps().mentionShowHidden,
564
+ mentionSuggestions: getProps().mentionSuggestions,
565
+ mentionMaxItems: getProps().mentionMaxItems,
566
+ mentions: getProps().mentions,
567
+ skillTrigger: getProps().skillTrigger,
568
+ skillSuggestions: getProps().skillSuggestions
569
+ });
570
+ watchEffect(() => {
571
+ const p = getProps();
572
+ reactiveProps.promptSuggestions = p.promptSuggestions;
573
+ reactiveProps.promptTrigger = p.promptTrigger;
574
+ reactiveProps.promptTriggers = p.promptTriggers;
575
+ reactiveProps.promptMaxItems = p.promptMaxItems;
576
+ reactiveProps.promptAlign = p.promptAlign;
577
+ reactiveProps.mentionTrigger = p.mentionTrigger;
578
+ reactiveProps.mentionWorkspace = p.mentionWorkspace;
579
+ reactiveProps.mentionMode = p.mentionMode;
580
+ reactiveProps.mentionShowHidden = p.mentionShowHidden;
581
+ reactiveProps.mentionSuggestions = p.mentionSuggestions;
582
+ reactiveProps.mentionMaxItems = p.mentionMaxItems;
583
+ reactiveProps.mentions = p.mentions;
584
+ reactiveProps.skillTrigger = p.skillTrigger;
585
+ reactiveProps.skillSuggestions = p.skillSuggestions;
586
+ });
587
+ const promptMention = usePromptMentionState({
588
+ props: reactiveProps,
589
+ mentionSuggestionProviders: options.mentionSuggestionProviders,
590
+ mentionPathProvider: options.mentionPathProvider,
591
+ focused: ctx.focused,
592
+ cursor: ctx.cursor,
593
+ getValue: ctx.getValue,
594
+ rawAbsRect: ctx.rawAbsRect,
595
+ terminal: ctx.terminal,
596
+ scheduler: ctx.scheduler,
597
+ multilineToken: "",
598
+ mentionToken: ctx.mentionToken
599
+ });
600
+ watch(() => {
601
+ if (!ctx.visible.value || !promptMention.promptVisible.value) return null;
602
+ const rect = promptMention.promptRect.value;
603
+ return [
604
+ Math.floor(rect.x),
605
+ Math.floor(rect.y),
606
+ Math.floor(rect.w),
607
+ Math.floor(rect.h)
608
+ ].join(":");
609
+ }, (nextRectKey, prevRectKey) => {
610
+ if (!prevRectKey || nextRectKey === prevRectKey) return;
611
+ ctx.render.invalidatePlane("default");
612
+ ctx.scheduler.invalidate({ priority: "high" });
613
+ });
614
+ ctx.registerChipStyleProvider({
615
+ getStyle: (baseStyle, chip) => {
616
+ if (chip.kind !== "mention") return null;
617
+ const absPath = String(chip.absPath ?? "");
618
+ if (!absPath) return null;
619
+ const fsKind = promptMention.mentionKindByPath.get(absPath);
620
+ return {
621
+ ...mentionChipStyle(baseStyle, absPath, fsKind),
622
+ ...getProps().mentionChipStyle ?? {}
623
+ };
624
+ },
625
+ version: promptMention.mentionKindVersion
626
+ });
627
+ function replaceMentionInContext(absPath, tokenStart, tokenEnd) {
628
+ const cleaned = String(absPath || "").trim();
629
+ if (!cleaned) return;
630
+ const value = ctx.getValue();
631
+ const start = clamp(tokenStart, 0, value.length);
632
+ const end = clamp(tokenEnd, start, value.length);
633
+ const currentMentions = getProps().mentions ?? [];
634
+ const nextMentions = [...currentMentions];
635
+ let before = value.slice(0, start);
636
+ let after = value.slice(end);
637
+ const closeMatch = after.match(/^[\s\u200B]*\]+/u);
638
+ if (closeMatch) {
639
+ after = after.slice(closeMatch[0].length);
640
+ let i = before.length - 1;
641
+ while (i >= 0 && /[\s\u200B]/u.test(before[i])) i--;
642
+ if (i >= 0 && before[i] === "[") before = before.slice(0, i) + before.slice(i + 1);
643
+ }
644
+ const insertIndex = mentionIndexAt(value, ctx.mentionToken, start);
645
+ nextMentions.splice(insertIndex, 0, cleaned);
646
+ ctx.emit("update:mentions", nextMentions);
647
+ let nextAfter = after;
648
+ if (nextAfter.startsWith(" ")) nextAfter = nextAfter.slice(1);
649
+ const nextValue = `${before}${ctx.mentionToken} ${nextAfter}`;
650
+ const nextCursor = before.length + 2;
651
+ ctx.pushUndoSnapshot(nextValue);
652
+ ctx.applyEdit(nextValue, nextCursor);
653
+ }
654
+ function acceptPrompt(index) {
655
+ const ctx0 = promptMention.activeContext.value;
656
+ if (!ctx0) return;
657
+ const list = promptMention.promptMatches.value;
658
+ const match = list[clamp(index, 0, Math.max(0, list.length - 1))];
659
+ if (!match) return;
660
+ const suggestion = match.item;
661
+ const mentionTrigger = getProps().mentionTrigger || "@";
662
+ const isMention = ctx0.tokenText.startsWith(mentionTrigger);
663
+ if (isMention) {
664
+ if (!getProps().collectMentions || suggestion.mentionBehavior === "inline") {
665
+ const insert$1 = suggestion.insert ?? (suggestion.value.endsWith(" ") ? suggestion.value : `${suggestion.value} `);
666
+ const before$1 = ctx.getValue().slice(0, ctx0.tokenStart);
667
+ let after$1 = ctx.getValue().slice(ctx0.tokenEnd);
668
+ if (insert$1.endsWith(" ") && after$1.startsWith(" ")) after$1 = after$1.slice(1);
669
+ const nextValue$1 = `${before$1}${insert$1}${after$1}`;
670
+ const nextCursor$1 = ctx0.tokenStart + insert$1.length;
671
+ promptMention.promptSuppressedKey.value = null;
672
+ ctx.pushUndoSnapshot(nextValue$1);
673
+ ctx.applyEdit(nextValue$1, nextCursor$1);
674
+ return;
675
+ }
676
+ const mentionValue = typeof suggestion.mentionValue === "string" ? String(suggestion.mentionValue) : "";
677
+ const raw = mentionValue || (String(suggestion.value || "").startsWith(mentionTrigger) ? String(suggestion.value).slice(mentionTrigger.length) : String(suggestion.value));
678
+ const absPath = mentionValue ? raw : getProps().mentionWorkspace ? ctx.resolvePath(raw) : raw;
679
+ if (!absPath) {
680
+ promptMention.promptSuppressedKey.value = null;
681
+ return;
682
+ }
683
+ replaceMentionInContext(absPath, ctx0.tokenStart, ctx0.tokenEnd);
684
+ promptMention.promptSuppressedKey.value = null;
685
+ ctx.scheduler.invalidate();
686
+ return;
687
+ }
688
+ if (typeof suggestion.onSelect === "function") {
689
+ const handled = suggestion.onSelect({
690
+ value: suggestion.value,
691
+ query: ctx0.query
692
+ });
693
+ if (handled !== false) {
694
+ const value = ctx.getValue();
695
+ const before$1 = value.slice(0, ctx0.tokenStart);
696
+ const after$1 = value.slice(ctx0.tokenEnd);
697
+ const nextValue$1 = `${before$1}${after$1}`;
698
+ ctx.pushUndoSnapshot(nextValue$1);
699
+ ctx.applyEdit(nextValue$1, ctx0.tokenStart);
700
+ promptMention.promptSuppressedKey.value = ctx0.key;
701
+ ctx.scheduler.invalidate();
702
+ return;
703
+ }
704
+ }
705
+ const insert = suggestion.insert ?? (suggestion.value.endsWith(" ") ? suggestion.value : `${suggestion.value} `);
706
+ const before = ctx.getValue().slice(0, ctx0.tokenStart);
707
+ let after = ctx.getValue().slice(ctx0.tokenEnd);
708
+ if (insert.endsWith(" ") && after.startsWith(" ")) after = after.slice(1);
709
+ const nextValue = `${before}${insert}${after}`;
710
+ const nextCursor = ctx0.tokenStart + insert.length;
711
+ promptMention.promptSuppressedKey.value = null;
712
+ ctx.pushUndoSnapshot(nextValue);
713
+ ctx.applyEdit(nextValue, nextCursor);
714
+ }
715
+ function completeMentionDirectory(suggestion, ctx0) {
716
+ const mentionTrigger = getProps().mentionTrigger || "@";
717
+ if (!ctx0.tokenText.startsWith(mentionTrigger)) return false;
718
+ if (String(suggestion.detail ?? "") !== "directory") return false;
719
+ let insert = String(suggestion.value ?? "");
720
+ if (!insert.startsWith(mentionTrigger)) return false;
721
+ if (!insert.endsWith("/") && !insert.endsWith("\\")) insert = `${insert}/`;
722
+ const value = ctx.getValue();
723
+ const before = value.slice(0, clamp(ctx0.tokenStart, 0, value.length));
724
+ const after = value.slice(clamp(ctx0.tokenEnd, 0, value.length));
725
+ const nextValue = `${before}${insert}${after}`;
726
+ const nextCursor = before.length + insert.length;
727
+ promptMention.promptSuppressedKey.value = null;
728
+ promptMention.promptActive.value = 0;
729
+ ctx.pushUndoSnapshot(nextValue);
730
+ ctx.applyEdit(nextValue, nextCursor);
731
+ ctx.scheduler.invalidate();
732
+ return true;
733
+ }
734
+ function handlePromptKeydown(e) {
735
+ if (!promptMention.promptVisible.value) return false;
736
+ const markPromptOperation = (suffix) => {
737
+ const ctx0 = promptMention.activeContext.value;
738
+ const mentionTrigger = getProps().mentionTrigger || "@";
739
+ const skillTrigger = getProps().skillTrigger || "";
740
+ const tokenText = String(ctx0?.tokenText ?? "");
741
+ const scope = tokenText.startsWith(mentionTrigger) ? "prompt.mention" : skillTrigger && tokenText.startsWith(skillTrigger) ? "prompt.skill" : "prompt.command";
742
+ latency?.markOperation(`${scope}.${suffix}`);
743
+ };
744
+ const len = promptMention.promptMatches.value.length;
745
+ if (e.key === "ArrowDown") {
746
+ markPromptOperation("navigate.next");
747
+ e.preventDefault();
748
+ if (len <= 0) promptMention.promptActive.value = 0;
749
+ else if (promptMention.promptActive.value >= len - 1) promptMention.promptActive.value = 0;
750
+ else promptMention.promptActive.value = clamp(promptMention.promptActive.value + 1, 0, len - 1);
751
+ ctx.scheduler.invalidate();
752
+ return true;
753
+ }
754
+ if (e.key === "ArrowUp") {
755
+ markPromptOperation("navigate.prev");
756
+ e.preventDefault();
757
+ if (len <= 0) promptMention.promptActive.value = 0;
758
+ else if (promptMention.promptActive.value <= 0) promptMention.promptActive.value = len - 1;
759
+ else promptMention.promptActive.value = clamp(promptMention.promptActive.value - 1, 0, len - 1);
760
+ ctx.scheduler.invalidate();
761
+ return true;
762
+ }
763
+ if (e.key === "Tab" || e.key === "Enter" && !e.shiftKey) {
764
+ const ctx0 = promptMention.activeContext.value;
765
+ const mentionTrigger = getProps().mentionTrigger || "@";
766
+ const skillTrigger = getProps().skillTrigger || "";
767
+ const isMention = Boolean(ctx0?.tokenText?.startsWith(mentionTrigger));
768
+ const isSkill = Boolean(skillTrigger && ctx0?.tokenText?.startsWith(skillTrigger) && !isMention);
769
+ if (e.key === "Enter" && !e.shiftKey && !isMention && !isSkill) {
770
+ if (len === 0) return false;
771
+ const match = promptMention.promptMatches.value[clamp(promptMention.promptActive.value, 0, Math.max(0, promptMention.promptMatches.value.length - 1))];
772
+ const typed = String(ctx0?.tokenText ?? "");
773
+ const candidate = String(match?.item?.value ?? "");
774
+ if (!typed || !candidate.startsWith(typed)) return false;
775
+ markPromptOperation("accept");
776
+ e.preventDefault();
777
+ acceptPrompt(promptMention.promptActive.value);
778
+ return true;
779
+ }
780
+ if (e.key === "Tab" && (isMention || isSkill)) {
781
+ markPromptOperation("accept");
782
+ e.preventDefault();
783
+ if (len === 0) return true;
784
+ const list = promptMention.promptMatches.value;
785
+ const match = list[clamp(promptMention.promptActive.value, 0, Math.max(0, list.length - 1))];
786
+ if (isMention && match && ctx0 && completeMentionDirectory(match.item, ctx0)) return true;
787
+ acceptPrompt(promptMention.promptActive.value);
788
+ return true;
789
+ }
790
+ if (len === 0) return false;
791
+ markPromptOperation("accept");
792
+ e.preventDefault();
793
+ acceptPrompt(promptMention.promptActive.value);
794
+ return true;
795
+ }
796
+ if (e.key === "Escape") {
797
+ markPromptOperation("dismiss");
798
+ e.preventDefault();
799
+ promptMention.promptSuppressedKey.value = promptMention.activeContext.value?.key ?? null;
800
+ ctx.scheduler.invalidate();
801
+ return true;
802
+ }
803
+ return false;
804
+ }
805
+ ctx.registerKeydownInterceptor(handlePromptKeydown);
806
+ useRenderNode(() => ({
807
+ zIndex: getProps().zIndex + 5,
808
+ stack: promptOverlayStack,
809
+ dirtyRowsHint: (() => {
810
+ const currentRect = ctx.visible.value && promptMention.promptVisible.value ? {
811
+ y: Math.floor(promptMention.promptRect.value.y),
812
+ h: Math.max(0, Math.floor(promptMention.promptRect.value.h))
813
+ } : null;
814
+ const rects = [lastPromptRect, currentRect].filter(Boolean);
815
+ if (!rects.length) return void 0;
816
+ const maxRows = ctx.terminal.size().rows;
817
+ const start = Math.max(0, Math.min(...rects.map((rect) => rect.y)) - 1);
818
+ const end = Math.min(maxRows, Math.max(...rects.map((rect) => rect.y + rect.h)) + 1);
819
+ if (end <= start) return void 0;
820
+ return Array.from({ length: end - start }, (_, index) => start + index);
821
+ })(),
822
+ priority: "high",
823
+ rect: ctx.visible.value && promptMention.promptVisible.value ? promptMention.promptRect.value : {
824
+ x: 0,
825
+ y: 0,
826
+ w: 0,
827
+ h: 0
828
+ },
829
+ deps: [
830
+ ctx.visible.value,
831
+ promptMention.promptVisible.value,
832
+ promptMention.promptRect.value,
833
+ promptMention.promptMatches.value,
834
+ promptMention.promptMatchesVisible.value,
835
+ promptMention.promptWindowStart.value,
836
+ promptMention.promptActive.value,
837
+ promptMention.promptActiveVisible.value,
838
+ getProps().style,
839
+ getProps().promptPopupStyle,
840
+ getProps().promptPopupBorderStyle,
841
+ getProps().promptPopupMatchStyle,
842
+ getProps().promptSelectedStyle,
843
+ getProps().zIndex,
844
+ ctx.defaultStyle.value,
845
+ promptMention.mentionKindVersion.value
846
+ ],
847
+ paint: () => {
848
+ if (!ctx.visible.value || !promptMention.promptVisible.value) return;
849
+ const r = promptMention.promptRect.value;
850
+ if (r.w < 3 || r.h < 3) return;
851
+ lastPromptRect = {
852
+ y: Math.floor(r.y),
853
+ h: Math.max(0, Math.floor(r.h))
854
+ };
855
+ const popupBase = getProps().promptPopupStyle ?? getProps().style ?? ctx.defaultStyle.value;
856
+ const popupBorderStyle = getProps().promptPopupBorderStyle;
857
+ const popupMatchStyle = getProps().promptPopupMatchStyle;
858
+ const selectedOverride = getProps().promptSelectedStyle;
859
+ const styleKey = popupBase ?? null;
860
+ const cacheKey = selectedOverride ? null : styleKey;
861
+ let derived = cacheKey ? derivedStyleCache.get(cacheKey) : null;
862
+ if (!derived) {
863
+ const borderStyle$1 = popupBorderStyle ? {
864
+ ...popupBase,
865
+ ...popupBorderStyle
866
+ } : {
867
+ ...popupBase,
868
+ dim: true
869
+ };
870
+ const itemStyle = {
871
+ ...popupBase,
872
+ dim: false
873
+ };
874
+ const selectedStyle = resolveSelectedPromptStyle(popupBase, selectedOverride);
875
+ const detailStyle = {
876
+ ...popupBase,
877
+ dim: true
878
+ };
879
+ const selectedDetailStyle = {
880
+ ...selectedStyle,
881
+ dim: true
882
+ };
883
+ const emptyStyle = {
884
+ ...popupBase,
885
+ dim: true
886
+ };
887
+ derived = {
888
+ borderStyle: borderStyle$1,
889
+ itemStyle,
890
+ selectedStyle,
891
+ detailStyle,
892
+ selectedDetailStyle,
893
+ emptyStyle
894
+ };
895
+ if (cacheKey) derivedStyleCache.set(cacheKey, derived);
896
+ }
897
+ const x0 = Math.floor(r.x);
898
+ const y0 = Math.floor(r.y);
899
+ const w = Math.max(0, Math.floor(r.w));
900
+ const h$1 = Math.max(0, Math.floor(r.h));
901
+ const innerW = Math.max(0, w - 2);
902
+ const sidePad = innerW >= 4 ? 1 : 0;
903
+ const contentW = Math.max(0, innerW - sidePad * 2);
904
+ const contentX = x0 + 1 + sidePad;
905
+ const borderStyle = derived.borderStyle;
906
+ if (lastTopClampedRect && y0 > 0) {
907
+ ctx.terminal.write(spaces(lastTopClampedRect.w), {
908
+ x: lastTopClampedRect.x,
909
+ y: 0,
910
+ style: popupBase
911
+ });
912
+ lastTopClampedRect = null;
913
+ }
914
+ if (y0 === 0) lastTopClampedRect = {
915
+ x: x0,
916
+ w
917
+ };
918
+ else lastTopClampedRect = null;
919
+ ctx.terminal.write(`┌${repeatChar("─", innerW)}┐`, {
920
+ x: x0,
921
+ y: y0,
922
+ style: borderStyle
923
+ });
924
+ ctx.terminal.write(`└${repeatChar("─", innerW)}┘`, {
925
+ x: x0,
926
+ y: y0 + h$1 - 1,
927
+ style: borderStyle
928
+ });
929
+ const totalList = promptMention.promptMatches.value;
930
+ const start = promptMention.promptWindowStart.value;
931
+ const list = promptMention.promptMatchesVisible.value;
932
+ const query = promptMention.activeContext.value?.query ?? "";
933
+ const total = totalList.length;
934
+ const visible = list.length;
935
+ const hasAbove = start > 0;
936
+ const hasBelow = start + visible < total;
937
+ const contentH = Math.max(0, h$1 - 2);
938
+ for (let row = 0; row < contentH; row++) {
939
+ const y = y0 + 1 + row;
940
+ ctx.terminal.put(x0, y, "│", borderStyle);
941
+ const rightBorderChar = row === 0 && hasAbove ? "▲" : row === contentH - 1 && hasBelow ? "▼" : "│";
942
+ ctx.terminal.put(x0 + w - 1, y, rightBorderChar, borderStyle);
943
+ if (row >= list.length) {
944
+ ctx.terminal.write(spaces(innerW), {
945
+ x: x0 + 1,
946
+ y,
947
+ style: borderStyle
948
+ });
949
+ continue;
950
+ }
951
+ const match = list[row];
952
+ const isSelected = row === promptMention.promptActiveVisible.value;
953
+ const rawValue = sanitizeInlineText(match.item.value);
954
+ const rawDetail = match.item.detail ? sanitizeInlineText(match.item.detail) : "";
955
+ const highlightRanges = query ? computeHighlightRanges$1(rawValue, query) : [];
956
+ const valueCells = textCellWidth$1(rawValue);
957
+ const detailCells = rawDetail ? textCellWidth$1(rawDetail) : 0;
958
+ const minGap = 2;
959
+ const availableForDetail = contentW - valueCells - minGap;
960
+ if (rawDetail && availableForDetail >= 4) {
961
+ const valueStyle = isSelected ? derived.selectedStyle : derived.itemStyle;
962
+ const highlightStyle = buildPromptMatchHighlightStyle(valueStyle, popupMatchStyle);
963
+ const rowStyle = valueStyle;
964
+ if (sidePad > 0) ctx.terminal.write(spaces(sidePad), {
965
+ x: x0 + 1,
966
+ y,
967
+ style: rowStyle
968
+ });
969
+ writeHighlightedText$1({
970
+ text: rawValue,
971
+ ranges: highlightRanges,
972
+ x: contentX,
973
+ y,
974
+ maxCells: valueCells,
975
+ baseStyle: valueStyle,
976
+ highlightStyle,
977
+ terminal: ctx.terminal
978
+ });
979
+ const gapWidth = contentW - valueCells - Math.min(detailCells, availableForDetail);
980
+ const gapStyle = isSelected ? derived.selectedStyle : derived.itemStyle;
981
+ ctx.terminal.write(spaces(gapWidth), {
982
+ x: contentX + valueCells,
983
+ y,
984
+ style: gapStyle
985
+ });
986
+ const detailText = sliceByCellsWindow(rawDetail, 0, availableForDetail);
987
+ const dStyle = isSelected ? derived.selectedDetailStyle : derived.detailStyle;
988
+ ctx.terminal.write(detailText, {
989
+ x: contentX + valueCells + gapWidth,
990
+ y,
991
+ style: dStyle
992
+ });
993
+ if (sidePad > 0) ctx.terminal.write(spaces(sidePad), {
994
+ x: contentX + contentW,
995
+ y,
996
+ style: rowStyle
997
+ });
998
+ } else {
999
+ const style = isSelected ? derived.selectedStyle : derived.itemStyle;
1000
+ const highlightStyle = buildPromptMatchHighlightStyle(style, popupMatchStyle);
1001
+ if (sidePad > 0) ctx.terminal.write(spaces(sidePad), {
1002
+ x: x0 + 1,
1003
+ y,
1004
+ style
1005
+ });
1006
+ const clippedValue = sliceByCellsWindow(rawValue, 0, contentW);
1007
+ const usedCells = writeHighlightedText$1({
1008
+ text: clippedValue,
1009
+ ranges: highlightRanges,
1010
+ x: contentX,
1011
+ y,
1012
+ maxCells: contentW,
1013
+ baseStyle: style,
1014
+ highlightStyle,
1015
+ terminal: ctx.terminal
1016
+ });
1017
+ if (usedCells < contentW) ctx.terminal.write(spaces(contentW - usedCells), {
1018
+ x: contentX + usedCells,
1019
+ y,
1020
+ style
1021
+ });
1022
+ if (sidePad > 0) ctx.terminal.write(spaces(sidePad), {
1023
+ x: contentX + contentW,
1024
+ y,
1025
+ style
1026
+ });
1027
+ }
1028
+ }
1029
+ if (list.length === 0 && contentH > 0) {
1030
+ const y = y0 + 1;
1031
+ ctx.terminal.put(x0, y, "│", borderStyle);
1032
+ ctx.terminal.put(x0 + w - 1, y, "│", borderStyle);
1033
+ const msg = padEndByCells$1(sliceByCellsWindow("(no matches)", 0, contentW), contentW);
1034
+ if (sidePad > 0) ctx.terminal.write(spaces(sidePad), {
1035
+ x: x0 + 1,
1036
+ y,
1037
+ style: derived.emptyStyle
1038
+ });
1039
+ ctx.terminal.write(msg, {
1040
+ x: contentX,
1041
+ y,
1042
+ style: derived.emptyStyle
1043
+ });
1044
+ if (sidePad > 0) ctx.terminal.write(spaces(sidePad), {
1045
+ x: contentX + contentW,
1046
+ y,
1047
+ style: derived.emptyStyle
1048
+ });
1049
+ }
1050
+ }
1051
+ }));
1052
+ useTerminalNode(() => ({
1053
+ rect: promptMention.promptVisible.value ? promptMention.promptRect.value : {
1054
+ x: 0,
1055
+ y: 0,
1056
+ w: 0,
1057
+ h: 0
1058
+ },
1059
+ zIndex: ctx.eventZ.value + 1e4,
1060
+ visible: ctx.visible.value && promptMention.promptVisible.value,
1061
+ focusable: false,
1062
+ handlers: { click: (e) => {
1063
+ const r = promptMention.promptRect.value;
1064
+ const y = e.cellY - r.y;
1065
+ if (y <= 0 || y >= r.h - 1) return;
1066
+ const idx = y - 1;
1067
+ const start = promptMention.promptWindowStart.value;
1068
+ const globalIdx = start + idx;
1069
+ promptMention.promptActive.value = clamp(globalIdx, 0, Math.max(0, promptMention.promptMatches.value.length - 1));
1070
+ acceptPrompt(promptMention.promptActive.value);
1071
+ } }
1072
+ }));
1073
+ watchEffect(() => {
1074
+ getProps().mentions;
1075
+ promptMention.mentionKindVersion.value;
1076
+ });
1077
+ }
1078
+ };
1079
+ }
1080
+
1081
+ //#endregion
1082
+ //#region src/vue/components/input/plugins/restrictText.ts
1083
+ function computeProposedValue(info, text) {
1084
+ const start = info.selection ? info.selection.start : info.cursor;
1085
+ const end = info.selection ? info.selection.end : info.cursor;
1086
+ return info.value.slice(0, start) + text + info.value.slice(end);
1087
+ }
1088
+ function applyRule(rule, info) {
1089
+ if ("filter" in rule) return rule.filter(info);
1090
+ if ("replace" in rule) return info.text.replace(rule.replace.from, rule.replace.to);
1091
+ if ("allowChars" in rule) {
1092
+ let out = "";
1093
+ for (const ch of info.text) if (rule.allowChars.test(ch)) out += ch;
1094
+ return out;
1095
+ }
1096
+ if ("denyChars" in rule) return info.text.replace(rule.denyChars, "");
1097
+ if ("allow" in rule) {
1098
+ const next = computeProposedValue(info, info.text);
1099
+ return rule.allow.test(next) ? info.text : "";
1100
+ }
1101
+ return info.text;
1102
+ }
1103
+ function createTextRestrictionPlugin(options) {
1104
+ const name = options.name ?? "restrictText";
1105
+ const rules = options.rules ?? [];
1106
+ return {
1107
+ name,
1108
+ install(ctx) {
1109
+ ctx.registerTextFilter((info) => {
1110
+ const originalText = info.text;
1111
+ let text = info.text;
1112
+ for (const rule of rules) {
1113
+ text = applyRule(rule, {
1114
+ ...info,
1115
+ text
1116
+ });
1117
+ if (!text) {
1118
+ if (originalText) ctx.emit("validationError", {
1119
+ plugin: name,
1120
+ kind: "reject",
1121
+ originalText,
1122
+ acceptedText: "",
1123
+ value: info.value,
1124
+ cursor: info.cursor,
1125
+ selection: info.selection
1126
+ });
1127
+ return "";
1128
+ }
1129
+ }
1130
+ if (originalText && text !== originalText) ctx.emit("validationError", {
1131
+ plugin: name,
1132
+ kind: "filter",
1133
+ originalText,
1134
+ acceptedText: text,
1135
+ value: info.value,
1136
+ cursor: info.cursor,
1137
+ selection: info.selection
1138
+ });
1139
+ return text;
1140
+ });
1141
+ }
1142
+ };
1143
+ }
1144
+
1145
+ //#endregion
1146
+ //#region src/vue/components/TAnchor.ts
1147
+ const EMPTY_RECT = Object.freeze({
1148
+ x: 0,
1149
+ y: 0,
1150
+ w: 0,
1151
+ h: 0
1152
+ });
1153
+ const TAnchor = defineComponent({
1154
+ name: "TAnchor",
1155
+ props: {
1156
+ left: {
1157
+ type: Number,
1158
+ default: void 0
1159
+ },
1160
+ top: {
1161
+ type: Number,
1162
+ default: void 0
1163
+ },
1164
+ right: {
1165
+ type: Number,
1166
+ default: void 0
1167
+ },
1168
+ bottom: {
1169
+ type: Number,
1170
+ default: void 0
1171
+ },
1172
+ w: {
1173
+ type: Number,
1174
+ default: void 0
1175
+ },
1176
+ h: {
1177
+ type: Number,
1178
+ default: void 0
1179
+ },
1180
+ zIndex: {
1181
+ type: Number,
1182
+ default: 0
1183
+ },
1184
+ focusable: {
1185
+ type: Boolean,
1186
+ default: false
1187
+ },
1188
+ selectable: {
1189
+ type: Boolean,
1190
+ default: void 0
1191
+ }
1192
+ },
1193
+ emits: [
1194
+ "clickCapture",
1195
+ "click",
1196
+ "dblclickCapture",
1197
+ "dblclick",
1198
+ "pointerdownCapture",
1199
+ "pointerdown",
1200
+ "pointerupCapture",
1201
+ "pointerup",
1202
+ "pointermoveCapture",
1203
+ "pointermove",
1204
+ "wheelCapture",
1205
+ "wheel",
1206
+ "keydownCapture",
1207
+ "keydown",
1208
+ "keyupCapture",
1209
+ "keyup",
1210
+ "focusCapture",
1211
+ "focus",
1212
+ "blurCapture",
1213
+ "blur"
1214
+ ],
1215
+ setup(props, { emit, slots }) {
1216
+ const parent = useLayout();
1217
+ const { render } = useTerminal();
1218
+ const parentStack = useRenderStack();
1219
+ const { visible, rootProps } = useVisibility({ provide: true });
1220
+ const parentEventZ = inject(EventZIndexContextKey, computed(() => 0));
1221
+ const eventZ = computed(() => (parentEventZ.value ?? 0) + (props.zIndex ?? 0));
1222
+ const rawRect = computed(() => {
1223
+ const base = parent.clipRect ?? {
1224
+ x: parent.originX,
1225
+ y: parent.originY,
1226
+ w: 0,
1227
+ h: 0
1228
+ };
1229
+ const left = props.left;
1230
+ const right = props.right;
1231
+ const top = props.top;
1232
+ const bottom = props.bottom;
1233
+ const width = props.w;
1234
+ const height = props.h;
1235
+ let w = width;
1236
+ let h$1 = height;
1237
+ if (w == null && left != null && right != null) w = base.w - left - right;
1238
+ if (h$1 == null && top != null && bottom != null) h$1 = base.h - top - bottom;
1239
+ w = Math.max(0, Math.floor(w ?? 0));
1240
+ h$1 = Math.max(0, Math.floor(h$1 ?? 0));
1241
+ let x = base.x;
1242
+ let y = base.y;
1243
+ if (left != null) x = base.x + Math.floor(left);
1244
+ else if (right != null) x = base.x + base.w - Math.floor(right) - w;
1245
+ if (top != null) y = base.y + Math.floor(top);
1246
+ else if (bottom != null) y = base.y + base.h - Math.floor(bottom) - h$1;
1247
+ return translateRect({
1248
+ x,
1249
+ y,
1250
+ w,
1251
+ h: h$1
1252
+ }, 0, 0);
1253
+ });
1254
+ const rect = computed(() => {
1255
+ const translated = rawRect.value;
1256
+ return parent.clipRect ? intersectRect(translated, parent.clipRect) ?? EMPTY_RECT : translated;
1257
+ });
1258
+ useTerminalNode(() => ({
1259
+ rect: rect.value,
1260
+ zIndex: eventZ.value,
1261
+ visible: visible.value,
1262
+ focusable: props.focusable,
1263
+ selectable: props.selectable,
1264
+ handlers: {
1265
+ clickCapture: (e) => emit("clickCapture", e),
1266
+ click: (e) => emit("click", e),
1267
+ dblclickCapture: (e) => emit("dblclickCapture", e),
1268
+ dblclick: (e) => emit("dblclick", e),
1269
+ pointerdownCapture: (e) => emit("pointerdownCapture", e),
1270
+ pointerdown: (e) => emit("pointerdown", e),
1271
+ pointerupCapture: (e) => emit("pointerupCapture", e),
1272
+ pointerup: (e) => emit("pointerup", e),
1273
+ pointermoveCapture: (e) => emit("pointermoveCapture", e),
1274
+ pointermove: (e) => emit("pointermove", e),
1275
+ wheelCapture: (e) => emit("wheelCapture", e),
1276
+ wheel: (e) => emit("wheel", e),
1277
+ keydownCapture: (e) => emit("keydownCapture", e),
1278
+ keydown: (e) => emit("keydown", e),
1279
+ keyupCapture: (e) => emit("keyupCapture", e),
1280
+ keyup: (e) => emit("keyup", e),
1281
+ focusCapture: (e) => emit("focusCapture", e),
1282
+ focus: (e) => emit("focus", e),
1283
+ blurCapture: (e) => emit("blurCapture", e),
1284
+ blur: (e) => emit("blur", e)
1285
+ }
1286
+ }));
1287
+ const childLayout = shallowReactive({
1288
+ originX: 0,
1289
+ originY: 0,
1290
+ clipRect: null
1291
+ });
1292
+ const childStack = computed(() => render.createStack(parentStack.value, props.zIndex));
1293
+ watchEffect(() => {
1294
+ const translated = rawRect.value;
1295
+ childLayout.originX = translated.x;
1296
+ childLayout.originY = translated.y;
1297
+ childLayout.clipRect = rect.value;
1298
+ });
1299
+ provide(LayoutContextKey, childLayout);
1300
+ provide(RenderStackKey, childStack);
1301
+ provide(EventZIndexContextKey, eventZ);
1302
+ return () => h("div", rootProps, slots.default?.());
1303
+ }
1304
+ });
1305
+
1306
+ //#endregion
1307
+ //#region src/vue/components/TDebugOverlay.ts
1308
+ const TDebugOverlay = defineComponent({
1309
+ name: "TDebugOverlay",
1310
+ props: {
1311
+ mode: {
1312
+ type: String,
1313
+ default: "focus"
1314
+ },
1315
+ panel: {
1316
+ type: Boolean,
1317
+ default: true
1318
+ },
1319
+ maxRects: {
1320
+ type: Number,
1321
+ default: 40
1322
+ },
1323
+ zIndex: {
1324
+ type: Number,
1325
+ default: 90
1326
+ }
1327
+ },
1328
+ setup(props) {
1329
+ const { terminal, events, observability, scheduler } = useTerminal();
1330
+ const trace = observability.trace;
1331
+ const framePerf = observability.framePerf;
1332
+ const releasePerf = framePerf.acquire("debug-overlay");
1333
+ const latestPerf = shallowRef(framePerf.latest());
1334
+ let timer = null;
1335
+ function refreshLatestPerf() {
1336
+ const next = framePerf.latest();
1337
+ if (!next) return;
1338
+ if (next.reason === "manual") return;
1339
+ if (latestPerf.value?.frameId === next.frameId) return;
1340
+ latestPerf.value = next;
1341
+ scheduler.invalidate({
1342
+ priority: "low",
1343
+ reason: "manual"
1344
+ });
1345
+ }
1346
+ onMounted(() => {
1347
+ refreshLatestPerf();
1348
+ timer = setInterval(refreshLatestPerf, 250);
1349
+ });
1350
+ onUnmounted(() => {
1351
+ releasePerf();
1352
+ if (timer) clearInterval(timer);
1353
+ timer = null;
1354
+ });
1355
+ function boxStyle(kind) {
1356
+ if (kind === "panel") return {
1357
+ fg: "whiteBright",
1358
+ bg: "black"
1359
+ };
1360
+ if (kind === "focus") return { fg: "cyanBright" };
1361
+ return { fg: "magentaBright" };
1362
+ }
1363
+ return () => {
1364
+ const { cols, rows } = terminal.size();
1365
+ if (cols <= 0 || rows <= 0) return null;
1366
+ const mgr = events.value;
1367
+ const debugNodes = (() => {
1368
+ const nodes = typeof mgr?.debugNodes === "function" ? mgr.debugNodes() : [];
1369
+ return nodes.filter((n) => n && n.rect && n.visible);
1370
+ })();
1371
+ const focused = typeof mgr?.getFocused === "function" ? mgr.getFocused() : null;
1372
+ const focusedRect = debugNodes.find((n) => n.id === focused)?.rect ?? null;
1373
+ const panelText = (() => {
1374
+ if (!props.panel) return "";
1375
+ const records = trace.records;
1376
+ const last = [...records].reverse().find((r) => r.type === "commit");
1377
+ const perf = latestPerf.value ?? framePerf.latest();
1378
+ const dirty = last ? last.dirtyRows === null ? "all" : String(last.dirtyRows?.length ?? 0) : "0";
1379
+ const lines = [
1380
+ `trace: ${trace.enabled.value ? "ON" : "OFF"}`,
1381
+ `focus: ${focused ?? "null"}`,
1382
+ last ? `last commit: dirtyRows=${dirty}` : "last commit: -"
1383
+ ];
1384
+ if (perf) lines.push(`frame: ${perf.durationMs.toFixed(1)}ms`, `reason: ${perf.reason}`, `dirtyRows: ${perf.dirtyRows === null ? "all" : perf.dirtyRows}`, `scannedNodes: ${perf.scannedNodes}`, `paintedNodes: ${perf.paintedNodes}`, `commit: ${perf.commitMs.toFixed(1)}ms`, `domFlush: ${perf.domFlushMs == null ? "-" : `${perf.domFlushMs.toFixed(1)}ms`}`, `coalescedInvalidates: ${perf.coalescedInvalidates}`, `frameTasks: ${perf.frameTaskCount} queue:${perf.frameTaskQueueDepthBeforeRun}->${perf.frameTaskQueueDepthAfterRun}`, `coalescedTasks: ${perf.coalescedFrameTasks}`, `droppedUpdates: ${perf.droppedUpdates}`, `queueDepth: ${perf.queueDepth}`);
1385
+ else lines.push("frame: -");
1386
+ return lines.join("\n");
1387
+ })();
1388
+ const children = [];
1389
+ if (props.mode === "all") for (const n of debugNodes.slice(0, Math.max(0, Math.floor(props.maxRects)))) {
1390
+ const r = n.rect;
1391
+ if (!r || r.w < 2 || r.h < 2) continue;
1392
+ children.push(h(TBox, {
1393
+ x: r.x,
1394
+ y: r.y,
1395
+ w: r.w,
1396
+ h: r.h,
1397
+ zIndex: props.zIndex,
1398
+ clear: false,
1399
+ padding: 0,
1400
+ title: n.id,
1401
+ style: boxStyle("rect")
1402
+ }));
1403
+ }
1404
+ const fr = focusedRect;
1405
+ if (fr && fr.w >= 2 && fr.h >= 2) children.push(h(TBox, {
1406
+ x: fr.x,
1407
+ y: fr.y,
1408
+ w: fr.w,
1409
+ h: fr.h,
1410
+ zIndex: props.zIndex,
1411
+ clear: false,
1412
+ padding: 0,
1413
+ title: `focus:${focused ?? ""}`,
1414
+ style: boxStyle("focus")
1415
+ }));
1416
+ if (props.panel) {
1417
+ const panelW = Math.min(cols, 42);
1418
+ const panelH = rows >= 16 ? Math.min(rows, 17) : Math.min(rows, 6);
1419
+ children.push(h(TBox, {
1420
+ x: 0,
1421
+ y: 0,
1422
+ w: panelW,
1423
+ h: panelH,
1424
+ zIndex: props.zIndex,
1425
+ clear: true,
1426
+ padding: 0,
1427
+ title: "debug",
1428
+ style: boxStyle("panel")
1429
+ }, () => h(TText, {
1430
+ x: 0,
1431
+ y: 0,
1432
+ w: panelW - 2,
1433
+ h: panelH - 2,
1434
+ wrap: true,
1435
+ value: panelText
1436
+ })));
1437
+ }
1438
+ return h(TView, {
1439
+ x: 0,
1440
+ y: 0,
1441
+ w: cols,
1442
+ h: rows,
1443
+ zIndex: props.zIndex
1444
+ }, () => children);
1445
+ };
1446
+ }
1447
+ });
1448
+
1449
+ //#endregion
1450
+ //#region src/vue/components/TFlow.ts
1451
+ const TFlow = defineComponent({
1452
+ name: "TFlow",
1453
+ props: {
1454
+ x: {
1455
+ type: Number,
1456
+ required: true
1457
+ },
1458
+ y: {
1459
+ type: Number,
1460
+ required: true
1461
+ },
1462
+ w: {
1463
+ type: Number,
1464
+ required: true
1465
+ },
1466
+ h: {
1467
+ type: Number,
1468
+ required: true
1469
+ },
1470
+ items: {
1471
+ type: Array,
1472
+ required: true
1473
+ },
1474
+ direction: {
1475
+ type: String,
1476
+ default: "vertical"
1477
+ },
1478
+ gap: {
1479
+ type: Number,
1480
+ default: 0
1481
+ },
1482
+ itemSize: {
1483
+ type: Number,
1484
+ default: 1
1485
+ },
1486
+ zIndex: {
1487
+ type: Number,
1488
+ default: 0
1489
+ }
1490
+ },
1491
+ setup(props, { slots }) {
1492
+ return () => h(TView, {
1493
+ x: props.x,
1494
+ y: props.y,
1495
+ w: props.w,
1496
+ h: props.h,
1497
+ zIndex: props.zIndex
1498
+ }, () => props.items.map((item, index) => {
1499
+ const step = Math.max(0, Math.floor(props.itemSize)) + Math.max(0, Math.floor(props.gap));
1500
+ const offset = index * step;
1501
+ const childProps = props.direction === "vertical" ? {
1502
+ x: 0,
1503
+ y: offset,
1504
+ w: props.w,
1505
+ h: Math.max(0, Math.floor(props.itemSize))
1506
+ } : {
1507
+ x: offset,
1508
+ y: 0,
1509
+ w: Math.max(0, Math.floor(props.itemSize)),
1510
+ h: props.h
1511
+ };
1512
+ return h(TView, {
1513
+ key: index,
1514
+ ...childProps
1515
+ }, () => slots.item?.({
1516
+ item,
1517
+ index
1518
+ }) ?? null);
1519
+ }));
1520
+ }
1521
+ });
1522
+
1523
+ //#endregion
1524
+ //#region src/vue/components/TPanels.ts
1525
+ function normalizeCellCount(value) {
1526
+ const n = Math.floor(Number(value));
1527
+ return Number.isFinite(n) ? Math.max(0, n) : 0;
1528
+ }
1529
+ function normalizePaneSize(value, fallback = 0) {
1530
+ const n = Math.floor(Number(value));
1531
+ if (Number.isFinite(n)) return Math.max(0, n);
1532
+ return normalizeCellCount(fallback);
1533
+ }
1534
+ function findEnabledTabIndex(items, start, delta) {
1535
+ const total = items.length;
1536
+ if (total <= 0) return null;
1537
+ for (let step = 1; step <= total; step++) {
1538
+ const index = (start + step * delta + total) % total;
1539
+ if (!items[index]?.disabled) return index;
1540
+ }
1541
+ return null;
1542
+ }
1543
+ function edgeEnabledTabIndex(items, edge) {
1544
+ if (edge === "first") {
1545
+ for (let index = 0; index < items.length; index++) if (!items[index]?.disabled) return index;
1546
+ return null;
1547
+ }
1548
+ for (let index = items.length - 1; index >= 0; index--) if (!items[index]?.disabled) return index;
1549
+ return null;
1550
+ }
1551
+ const TTabs = defineComponent({
1552
+ name: "TTabs",
1553
+ props: {
1554
+ x: {
1555
+ type: Number,
1556
+ required: true
1557
+ },
1558
+ y: {
1559
+ type: Number,
1560
+ required: true
1561
+ },
1562
+ w: {
1563
+ type: Number,
1564
+ required: true
1565
+ },
1566
+ zIndex: {
1567
+ type: Number,
1568
+ default: 0
1569
+ },
1570
+ items: {
1571
+ type: Array,
1572
+ required: true
1573
+ },
1574
+ activeKey: {
1575
+ type: String,
1576
+ required: true
1577
+ },
1578
+ style: {
1579
+ type: Object,
1580
+ default: void 0
1581
+ },
1582
+ activeStyle: {
1583
+ type: Object,
1584
+ default: () => ({ inverse: true })
1585
+ },
1586
+ disabledStyle: {
1587
+ type: Object,
1588
+ default: () => ({ dim: true })
1589
+ }
1590
+ },
1591
+ emits: {
1592
+ "update:activeKey": (_key) => true,
1593
+ change: (_item) => true
1594
+ },
1595
+ setup(props, { emit }) {
1596
+ const { defaultStyle } = useTerminal();
1597
+ const focusedKey = ref(null);
1598
+ const baseStyle = computed(() => mergeStyle(defaultStyle.value, props.style));
1599
+ function activate(item) {
1600
+ if (item.disabled) return;
1601
+ if (item.key === props.activeKey) return;
1602
+ emit("update:activeKey", item.key);
1603
+ emit("change", item);
1604
+ }
1605
+ function enabledTabIndexByKey(key) {
1606
+ if (!key) return -1;
1607
+ return props.items.findIndex((item) => item.key === key && !item.disabled);
1608
+ }
1609
+ function activateIndex(index, opts = {}) {
1610
+ const item = props.items[index];
1611
+ if (!item) return;
1612
+ if (opts.trackFocus && !item.disabled) focusedKey.value = item.key;
1613
+ activate(item);
1614
+ }
1615
+ function navigationBaseIndex(fallbackIndex) {
1616
+ const activeIndex = enabledTabIndexByKey(props.activeKey);
1617
+ return activeIndex >= 0 ? activeIndex : fallbackIndex;
1618
+ }
1619
+ function activationBaseIndex(fallbackIndex) {
1620
+ const focusedIndex = enabledTabIndexByKey(focusedKey.value);
1621
+ return focusedIndex >= 0 ? focusedIndex : fallbackIndex;
1622
+ }
1623
+ function onTabKeydown(event, index) {
1624
+ const key = event?.key;
1625
+ if (key === "Enter" || key === " ") {
1626
+ event.preventDefault?.();
1627
+ activateIndex(activationBaseIndex(index));
1628
+ return;
1629
+ }
1630
+ const baseIndex = navigationBaseIndex(index);
1631
+ const next = key === "ArrowRight" ? findEnabledTabIndex(props.items, baseIndex, 1) : key === "ArrowLeft" ? findEnabledTabIndex(props.items, baseIndex, -1) : key === "Home" ? edgeEnabledTabIndex(props.items, "first") : key === "End" ? edgeEnabledTabIndex(props.items, "last") : null;
1632
+ if (next == null) return;
1633
+ event.preventDefault?.();
1634
+ activateIndex(next, { trackFocus: true });
1635
+ }
1636
+ return () => {
1637
+ const width = normalizeCellCount(props.w);
1638
+ let x = 0;
1639
+ const children = [h(TText, {
1640
+ x: 0,
1641
+ y: 0,
1642
+ w: width,
1643
+ value: " ".repeat(width),
1644
+ style: baseStyle.value
1645
+ })];
1646
+ for (let index = 0; index < props.items.length; index++) {
1647
+ const item = props.items[index];
1648
+ const label = item.badge == null ? item.label : `${item.label} ${item.badge}`;
1649
+ const text = ` ${label} `;
1650
+ const itemWidth = Math.min(width - x, textCellWidth(text));
1651
+ if (itemWidth <= 0) break;
1652
+ const active = item.key === props.activeKey;
1653
+ children.push(h(TText, {
1654
+ key: `text:${item.key}`,
1655
+ x,
1656
+ y: 0,
1657
+ w: itemWidth,
1658
+ value: fitCellText(text, itemWidth),
1659
+ style: item.disabled ? mergeStyle(baseStyle.value, props.disabledStyle) : active ? mergeStyle(baseStyle.value, props.activeStyle) : baseStyle.value
1660
+ }), h(TView, {
1661
+ key: `hit:${item.key}`,
1662
+ x,
1663
+ y: 0,
1664
+ w: itemWidth,
1665
+ h: 1,
1666
+ focusable: !item.disabled,
1667
+ onClick: () => {
1668
+ if (!item.disabled) focusedKey.value = item.key;
1669
+ activate(item);
1670
+ },
1671
+ onFocus: () => {
1672
+ if (!item.disabled) focusedKey.value = item.key;
1673
+ },
1674
+ onKeydown: (event) => onTabKeydown(event, index)
1675
+ }));
1676
+ x += itemWidth;
1677
+ }
1678
+ return h(TView, {
1679
+ x: props.x,
1680
+ y: props.y,
1681
+ w: width,
1682
+ h: 1,
1683
+ zIndex: props.zIndex
1684
+ }, () => children);
1685
+ };
1686
+ }
1687
+ });
1688
+ function resolvePaneSizes(sizes, minSizes, available) {
1689
+ const count = sizes.length;
1690
+ if (count === 0) return [];
1691
+ if (available <= 0) return sizes.map(() => 0);
1692
+ const mins = sizes.map((_, index) => normalizePaneSize(minSizes[index], 1));
1693
+ const minTotal = mins.reduce((sum, min) => sum + min, 0);
1694
+ if (minTotal >= available) {
1695
+ if (minTotal === 0) return sizes.map(() => 0);
1696
+ const out$1 = mins.map((min) => Math.floor(available * min / minTotal));
1697
+ let remaining = available - out$1.reduce((sum, size) => sum + size, 0);
1698
+ const order = mins.map((min, index) => ({
1699
+ index,
1700
+ fraction: available * min / minTotal - Math.floor(available * min / minTotal)
1701
+ })).sort((a, b) => b.fraction - a.fraction || a.index - b.index);
1702
+ for (let i = 0; remaining > 0 && i < order.length; i++, remaining--) out$1[order[i].index] += 1;
1703
+ return out$1;
1704
+ }
1705
+ const out = sizes.map((size, index) => Math.max(mins[index], normalizePaneSize(size, mins[index])));
1706
+ const used = out.reduce((sum, size) => sum + size, 0);
1707
+ if (used > available) {
1708
+ let overflow = used - available;
1709
+ for (let i = out.length - 1; i >= 0 && overflow > 0; i--) {
1710
+ const shrink = Math.min(out[i] - mins[i], overflow);
1711
+ out[i] -= shrink;
1712
+ overflow -= shrink;
1713
+ }
1714
+ return out;
1715
+ }
1716
+ if (used < available) out[out.length - 1] += available - used;
1717
+ return out;
1718
+ }
1719
+ const TSplitPane = defineComponent({
1720
+ name: "TSplitPane",
1721
+ props: {
1722
+ x: {
1723
+ type: Number,
1724
+ required: true
1725
+ },
1726
+ y: {
1727
+ type: Number,
1728
+ required: true
1729
+ },
1730
+ w: {
1731
+ type: Number,
1732
+ required: true
1733
+ },
1734
+ h: {
1735
+ type: Number,
1736
+ required: true
1737
+ },
1738
+ zIndex: {
1739
+ type: Number,
1740
+ default: 0
1741
+ },
1742
+ direction: {
1743
+ type: String,
1744
+ default: "horizontal"
1745
+ },
1746
+ sizes: {
1747
+ type: Array,
1748
+ required: true
1749
+ },
1750
+ minSizes: {
1751
+ type: Array,
1752
+ default: () => []
1753
+ },
1754
+ separatorStyle: {
1755
+ type: Object,
1756
+ default: () => ({ dim: true })
1757
+ }
1758
+ },
1759
+ emits: {
1760
+ "update:sizes": (_sizes) => true,
1761
+ resize: (_sizes) => true
1762
+ },
1763
+ setup(props, { emit, slots }) {
1764
+ const { defaultStyle } = useTerminal();
1765
+ const panes = computed(() => {
1766
+ const width = normalizeCellCount(props.w);
1767
+ const height = normalizeCellCount(props.h);
1768
+ const sizes = props.sizes.length ? props.sizes : [1];
1769
+ const count = Math.max(1, sizes.length);
1770
+ const total = props.direction === "horizontal" ? width : height;
1771
+ const separatorTotal = Math.max(0, count - 1);
1772
+ const available = Math.max(0, total - separatorTotal);
1773
+ const paneSizes = resolvePaneSizes(sizes, props.minSizes, available);
1774
+ let cursor = 0;
1775
+ return paneSizes.map((paneSize) => {
1776
+ const rect = props.direction === "horizontal" ? {
1777
+ x: cursor,
1778
+ y: 0,
1779
+ w: paneSize,
1780
+ h: height
1781
+ } : {
1782
+ x: 0,
1783
+ y: cursor,
1784
+ w: width,
1785
+ h: paneSize
1786
+ };
1787
+ cursor += paneSize + 1;
1788
+ return rect;
1789
+ });
1790
+ });
1791
+ function resizeAt(index, delta) {
1792
+ const count = Math.max(1, props.sizes.length);
1793
+ const total = props.direction === "horizontal" ? normalizeCellCount(props.w) : normalizeCellCount(props.h);
1794
+ const separatorTotal = Math.max(0, count - 1);
1795
+ const available = Math.max(0, total - separatorTotal);
1796
+ const sizes = props.sizes.length ? props.sizes : [1];
1797
+ const next = resolvePaneSizes(sizes, props.minSizes, available);
1798
+ if (index < 0 || index >= next.length - 1) return;
1799
+ const left0 = next[index];
1800
+ const right0 = next[index + 1];
1801
+ const leftMin = normalizePaneSize(props.minSizes[index], 1);
1802
+ const rightMin = normalizePaneSize(props.minSizes[index + 1], 1);
1803
+ const applied = Math.max(leftMin - left0, Math.min(right0 - rightMin, delta));
1804
+ next[index] = left0 + applied;
1805
+ next[index + 1] = right0 - applied;
1806
+ emit("update:sizes", next);
1807
+ emit("resize", next);
1808
+ }
1809
+ return () => {
1810
+ const paneChildren = slots.default?.({ panes: panes.value }) ?? [];
1811
+ const separatorChildren = panes.value.slice(0, -1).map((pane, index) => {
1812
+ const separator = props.direction === "horizontal" ? {
1813
+ x: pane.x + pane.w,
1814
+ y: 0,
1815
+ w: 1,
1816
+ h: pane.h,
1817
+ text: "|"
1818
+ } : {
1819
+ x: 0,
1820
+ y: pane.y + pane.h,
1821
+ w: pane.w,
1822
+ h: 1,
1823
+ text: "-".repeat(pane.w)
1824
+ };
1825
+ return h(TView, {
1826
+ key: `separator:${index}`,
1827
+ x: separator.x,
1828
+ y: separator.y,
1829
+ w: separator.w,
1830
+ h: separator.h,
1831
+ focusable: true,
1832
+ onKeydown: (event) => {
1833
+ const forward = props.direction === "horizontal" ? event.key === "ArrowRight" : event.key === "ArrowDown";
1834
+ const backward = props.direction === "horizontal" ? event.key === "ArrowLeft" : event.key === "ArrowUp";
1835
+ if (!forward && !backward) return;
1836
+ event.preventDefault?.();
1837
+ resizeAt(index, forward ? 1 : -1);
1838
+ }
1839
+ }, () => props.direction === "horizontal" ? Array.from({ length: separator.h }, (_, row) => h(TText, {
1840
+ key: `separator-line:${row}`,
1841
+ x: 0,
1842
+ y: row,
1843
+ w: 1,
1844
+ value: separator.text,
1845
+ style: mergeStyle(defaultStyle.value, props.separatorStyle)
1846
+ })) : h(TText, {
1847
+ x: 0,
1848
+ y: 0,
1849
+ w: separator.w,
1850
+ h: separator.h,
1851
+ value: separator.text,
1852
+ style: mergeStyle(defaultStyle.value, props.separatorStyle)
1853
+ }));
1854
+ });
1855
+ const children = [...paneChildren, ...separatorChildren];
1856
+ return h(TView, {
1857
+ x: props.x,
1858
+ y: props.y,
1859
+ w: normalizeCellCount(props.w),
1860
+ h: normalizeCellCount(props.h),
1861
+ zIndex: props.zIndex
1862
+ }, () => children);
1863
+ };
1864
+ }
1865
+ });
1866
+
1867
+ //#endregion
1868
+ //#region src/vue/components/TInputBox.ts
1869
+ const TInputBox = defineComponent({
1870
+ name: "TInputBox",
1871
+ props: {
1872
+ x: {
1873
+ type: Number,
1874
+ required: true
1875
+ },
1876
+ y: {
1877
+ type: Number,
1878
+ required: true
1879
+ },
1880
+ w: {
1881
+ type: Number,
1882
+ required: true
1883
+ },
1884
+ h: {
1885
+ type: Number,
1886
+ required: true
1887
+ },
1888
+ zIndex: {
1889
+ type: Number,
1890
+ default: 0
1891
+ },
1892
+ title: {
1893
+ type: String,
1894
+ default: ""
1895
+ },
1896
+ padding: {
1897
+ type: Number,
1898
+ default: 0
1899
+ },
1900
+ modelValue: {
1901
+ type: String,
1902
+ required: true
1903
+ },
1904
+ placeholder: {
1905
+ type: String,
1906
+ default: ""
1907
+ },
1908
+ style: {
1909
+ type: Object,
1910
+ default: void 0
1911
+ },
1912
+ autoFocus: {
1913
+ type: Boolean,
1914
+ default: false
1915
+ },
1916
+ plugins: {
1917
+ type: Array,
1918
+ default: () => []
1919
+ },
1920
+ cursorBlink: {
1921
+ type: Boolean,
1922
+ default: true
1923
+ },
1924
+ cursorShape: {
1925
+ type: String,
1926
+ default: "block"
1927
+ },
1928
+ blinkInterval: {
1929
+ type: Number,
1930
+ default: 500
1931
+ }
1932
+ },
1933
+ emits: [
1934
+ "update:modelValue",
1935
+ "input",
1936
+ "change",
1937
+ "keydown",
1938
+ "focus",
1939
+ "blur"
1940
+ ],
1941
+ setup(props, { emit }) {
1942
+ const innerW = computed(() => Math.max(0, Math.floor(props.w) - 2 - Math.max(0, Math.floor(props.padding)) * 2));
1943
+ const innerH = computed(() => Math.max(1, Math.floor(props.h) - 2 - Math.max(0, Math.floor(props.padding)) * 2));
1944
+ return () => h(TBox, {
1945
+ x: props.x,
1946
+ y: props.y,
1947
+ w: props.w,
1948
+ h: props.h,
1949
+ zIndex: props.zIndex,
1950
+ border: true,
1951
+ title: props.title,
1952
+ padding: props.padding,
1953
+ style: props.style
1954
+ }, () => h(TInput, {
1955
+ x: 0,
1956
+ y: 0,
1957
+ w: innerW.value,
1958
+ h: innerH.value,
1959
+ modelValue: props.modelValue,
1960
+ "onUpdate:modelValue": (v) => emit("update:modelValue", v),
1961
+ placeholder: props.placeholder,
1962
+ style: props.style,
1963
+ autoFocus: props.autoFocus,
1964
+ plugins: props.plugins,
1965
+ cursorBlink: props.cursorBlink,
1966
+ cursorShape: props.cursorShape,
1967
+ blinkInterval: props.blinkInterval,
1968
+ onInput: (v) => emit("input", v),
1969
+ onChange: (v) => emit("change", v),
1970
+ onKeydown: (e) => emit("keydown", e),
1971
+ onFocus: () => emit("focus"),
1972
+ onBlur: () => emit("blur")
1973
+ }));
1974
+ }
1975
+ });
1976
+
1977
+ //#endregion
1978
+ //#region src/vue/components/TJsonEditor.ts
1979
+ function indexToLineColumn(text, index) {
1980
+ const capped = Math.max(0, Math.min(text.length, Math.floor(index)));
1981
+ let line = 1;
1982
+ let column = 1;
1983
+ for (let i = 0; i < capped; i += 1) if (text[i] === "\n") {
1984
+ line += 1;
1985
+ column = 1;
1986
+ } else column += 1;
1987
+ return {
1988
+ line,
1989
+ column
1990
+ };
1991
+ }
1992
+ function parseJsonErrorPosition(message) {
1993
+ const m = /position\s+(\d+)/iu.exec(String(message ?? ""));
1994
+ if (!m?.[1]) return null;
1995
+ const n = Number(m[1]);
1996
+ if (!Number.isFinite(n)) return null;
1997
+ return Math.max(0, Math.floor(n));
1998
+ }
1999
+ function lintJsonText(input) {
2000
+ const text = String(input ?? "");
2001
+ if (!text.trim()) return { state: "idle" };
2002
+ try {
2003
+ JSON.parse(text);
2004
+ return {
2005
+ state: "success",
2006
+ message: "JSON syntax OK"
2007
+ };
2008
+ } catch (error) {
2009
+ const raw = error instanceof Error ? error.message : String(error);
2010
+ const short = raw.replace(/\s*at position\s+\d.*$/iu, "").trim() || raw;
2011
+ const pos = parseJsonErrorPosition(raw);
2012
+ if (pos != null) {
2013
+ const { line, column } = indexToLineColumn(text, pos);
2014
+ return {
2015
+ state: "error",
2016
+ message: short,
2017
+ line,
2018
+ column
2019
+ };
2020
+ }
2021
+ return {
2022
+ state: "error",
2023
+ message: short
2024
+ };
2025
+ }
2026
+ }
2027
+ const DEFAULT_GUIDE_COLORS = [
2028
+ "cyanBright",
2029
+ "yellowBright",
2030
+ "greenBright",
2031
+ "magentaBright",
2032
+ "blueBright",
2033
+ "redBright"
2034
+ ];
2035
+ function computeJsonIndentGuideDepths(input) {
2036
+ const lines = String(input ?? "").replace(/\r/g, "").split("\n");
2037
+ const depths = [];
2038
+ let depth = 0;
2039
+ let inString = false;
2040
+ let escaping = false;
2041
+ for (const line of lines) {
2042
+ const trimmed = line.trimStart();
2043
+ const startsWithCloser = trimmed.startsWith("}") || trimmed.startsWith("]");
2044
+ const visualDepth = startsWithCloser ? Math.max(0, depth - 1) : depth;
2045
+ depths.push(visualDepth);
2046
+ for (let i = 0; i < line.length; i += 1) {
2047
+ const ch = line[i];
2048
+ if (inString) {
2049
+ if (escaping) {
2050
+ escaping = false;
2051
+ continue;
2052
+ }
2053
+ if (ch === "\\") {
2054
+ escaping = true;
2055
+ continue;
2056
+ }
2057
+ if (ch === "\"") inString = false;
2058
+ continue;
2059
+ }
2060
+ if (ch === "\"") {
2061
+ inString = true;
2062
+ continue;
2063
+ }
2064
+ if (ch === "{" || ch === "[") {
2065
+ depth += 1;
2066
+ continue;
2067
+ }
2068
+ if (ch === "}" || ch === "]") depth = Math.max(0, depth - 1);
2069
+ }
2070
+ }
2071
+ return depths;
2072
+ }
2073
+ const TJsonEditor = defineComponent({
2074
+ name: "TJsonEditor",
2075
+ props: {
2076
+ x: {
2077
+ type: Number,
2078
+ required: true
2079
+ },
2080
+ y: {
2081
+ type: Number,
2082
+ required: true
2083
+ },
2084
+ w: {
2085
+ type: Number,
2086
+ required: true
2087
+ },
2088
+ h: {
2089
+ type: Number,
2090
+ default: 8
2091
+ },
2092
+ zIndex: {
2093
+ type: Number,
2094
+ default: 0
2095
+ },
2096
+ modelValue: {
2097
+ type: String,
2098
+ required: true
2099
+ },
2100
+ placeholder: {
2101
+ type: String,
2102
+ default: ""
2103
+ },
2104
+ style: {
2105
+ type: Object,
2106
+ default: void 0
2107
+ },
2108
+ showIndentGuides: {
2109
+ type: Boolean,
2110
+ default: true
2111
+ },
2112
+ indentSize: {
2113
+ type: Number,
2114
+ default: 2
2115
+ },
2116
+ guideColors: {
2117
+ type: Array,
2118
+ default: () => [...DEFAULT_GUIDE_COLORS]
2119
+ },
2120
+ autoFocus: {
2121
+ type: Boolean,
2122
+ default: false
2123
+ },
2124
+ cursorToEndOnFirstFocus: {
2125
+ type: Boolean,
2126
+ default: true
2127
+ },
2128
+ cursorToEndOnExternalUpdate: {
2129
+ type: Boolean,
2130
+ default: true
2131
+ },
2132
+ submitOnEnter: {
2133
+ type: Boolean,
2134
+ default: false
2135
+ }
2136
+ },
2137
+ emits: [
2138
+ "update:modelValue",
2139
+ "keydown",
2140
+ "focus",
2141
+ "blur",
2142
+ "undo",
2143
+ "redo",
2144
+ "lintChange",
2145
+ "validationError"
2146
+ ],
2147
+ setup(props, { emit }) {
2148
+ let cachedLintText = null;
2149
+ let cachedLintStatus = { state: "idle" };
2150
+ let lastPublishedLintText = null;
2151
+ function normalizeText(value) {
2152
+ return String(value ?? "").replace(/\r/g, "");
2153
+ }
2154
+ function getLintStatus(value) {
2155
+ const normalized = normalizeText(value);
2156
+ if (cachedLintText === normalized) return cachedLintStatus;
2157
+ cachedLintText = normalized;
2158
+ cachedLintStatus = lintJsonText(normalized);
2159
+ return cachedLintStatus;
2160
+ }
2161
+ function publishLint(value) {
2162
+ const normalized = normalizeText(value);
2163
+ if (lastPublishedLintText === normalized) return;
2164
+ lastPublishedLintText = normalized;
2165
+ emit("lintChange", getLintStatus(normalized));
2166
+ }
2167
+ watch(() => props.modelValue, (value) => {
2168
+ publishLint(value);
2169
+ }, { immediate: true });
2170
+ return () => {
2171
+ const text = normalizeText(props.modelValue);
2172
+ const lines = text.split("\n");
2173
+ const lint = getLintStatus(text);
2174
+ const indentSize = Math.max(1, Math.floor(props.indentSize ?? 2));
2175
+ const contentW = Math.max(0, Math.floor(props.w) - 2);
2176
+ const visibleLines = Math.max(0, Math.floor(props.h));
2177
+ const colors = props.guideColors?.length ? props.guideColors : DEFAULT_GUIDE_COLORS;
2178
+ const guideNodes = [];
2179
+ if (props.showIndentGuides && contentW > 0 && visibleLines > 0) {
2180
+ const depths = computeJsonIndentGuideDepths(text);
2181
+ const lineCount = Math.min(visibleLines, lines.length, depths.length);
2182
+ for (let row = 0; row < lineCount; row += 1) {
2183
+ const line = lines[row] ?? "";
2184
+ const leadingSpaces = line.match(/^ +/u)?.[0]?.length ?? 0;
2185
+ const depth = depths[row] ?? 0;
2186
+ const guides = Math.min(depth, Math.floor(leadingSpaces / indentSize));
2187
+ const maxGuidesByWidth = Math.floor(contentW / indentSize);
2188
+ const guideCount = Math.min(guides, maxGuidesByWidth);
2189
+ for (let i = 0; i < guideCount; i += 1) {
2190
+ const x = props.x + 1 + i * indentSize;
2191
+ const y = props.y + row;
2192
+ const color = colors[i % colors.length] ?? "cyanBright";
2193
+ guideNodes.push(h(TText, {
2194
+ key: `guide-${row}-${i}`,
2195
+ x,
2196
+ y,
2197
+ w: 1,
2198
+ h: 1,
2199
+ zIndex: (props.zIndex ?? 0) + 1,
2200
+ value: "│",
2201
+ clear: false,
2202
+ style: {
2203
+ fg: color,
2204
+ dim: true
2205
+ }
2206
+ }));
2207
+ }
2208
+ }
2209
+ }
2210
+ const markerNodes = [];
2211
+ if (lint.state === "error" && typeof lint.line === "number" && typeof lint.column === "number") {
2212
+ const row = lint.line - 1;
2213
+ const col = lint.column - 1;
2214
+ if (row >= 0 && row < visibleLines && col >= 0 && col < contentW) {
2215
+ const line = lines[row] ?? "";
2216
+ const ch = line[col] ?? " ";
2217
+ markerNodes.push(h(TText, {
2218
+ key: `marker-${row}-${col}`,
2219
+ x: props.x + 1 + col,
2220
+ y: props.y + row,
2221
+ w: 1,
2222
+ h: 1,
2223
+ zIndex: (props.zIndex ?? 0) + 2,
2224
+ value: ch,
2225
+ clear: false,
2226
+ style: {
2227
+ fg: "redBright",
2228
+ bold: true,
2229
+ underline: true
2230
+ }
2231
+ }));
2232
+ }
2233
+ }
2234
+ const inputNode = h(TInput, {
2235
+ x: props.x,
2236
+ y: props.y,
2237
+ w: props.w,
2238
+ h: props.h,
2239
+ zIndex: props.zIndex,
2240
+ modelValue: props.modelValue,
2241
+ "onUpdate:modelValue": (v) => {
2242
+ emit("update:modelValue", v);
2243
+ publishLint(v);
2244
+ },
2245
+ placeholder: props.placeholder,
2246
+ style: props.style,
2247
+ autoFocus: props.autoFocus,
2248
+ cursorToEndOnFirstFocus: props.cursorToEndOnFirstFocus,
2249
+ cursorToEndOnExternalUpdate: props.cursorToEndOnExternalUpdate,
2250
+ submitOnEnter: props.submitOnEnter,
2251
+ onKeydown: (e) => {
2252
+ emit("keydown", e);
2253
+ if (e?.defaultPrevented) return;
2254
+ const isShortcut = Boolean((e.metaKey || e.ctrlKey) && !e.altKey);
2255
+ if (!isShortcut) return;
2256
+ if (e.key === "z" || e.key === "Z") {
2257
+ e.preventDefault?.();
2258
+ e.stopPropagation?.();
2259
+ if (e.shiftKey) emit("redo");
2260
+ else emit("undo");
2261
+ return;
2262
+ }
2263
+ if (e.key === "y" || e.key === "Y") {
2264
+ e.preventDefault?.();
2265
+ e.stopPropagation?.();
2266
+ emit("redo");
2267
+ }
2268
+ },
2269
+ onFocus: () => emit("focus"),
2270
+ onBlur: () => emit("blur"),
2271
+ onValidationError: (info) => emit("validationError", info)
2272
+ });
2273
+ return h("div", null, [
2274
+ inputNode,
2275
+ ...guideNodes,
2276
+ ...markerNodes
2277
+ ]);
2278
+ };
2279
+ }
2280
+ });
2281
+
2282
+ //#endregion
2283
+ //#region src/vue/components/TMultilineModal.ts
2284
+ const BORDER = {
2285
+ tl: "┌",
2286
+ tr: "┐",
2287
+ bl: "└",
2288
+ br: "┘",
2289
+ h: "─",
2290
+ v: "│"
2291
+ };
2292
+ const TMultilineModal = defineComponent({
2293
+ name: "TMultilineModal",
2294
+ props: {
2295
+ visible: {
2296
+ type: Boolean,
2297
+ required: true
2298
+ },
2299
+ content: {
2300
+ type: String,
2301
+ required: true
2302
+ },
2303
+ title: {
2304
+ type: String,
2305
+ default: "Multiline Text"
2306
+ },
2307
+ style: {
2308
+ type: Object,
2309
+ default: void 0
2310
+ },
2311
+ zIndex: {
2312
+ type: Number,
2313
+ default: 1e3
2314
+ }
2315
+ },
2316
+ emits: ["close"],
2317
+ setup(props, { emit }) {
2318
+ const { terminal, scheduler, defaultStyle, events } = useTerminal();
2319
+ const layout = useLayout();
2320
+ const { visible: parentVisible, rootProps } = useVisibility();
2321
+ const parentEventZ = inject(EventZIndexContextKey, computed(() => 0));
2322
+ const eventZ = computed(() => (parentEventZ.value ?? 0) + (props.zIndex ?? 0));
2323
+ const isVisible = computed(() => parentVisible.value && props.visible);
2324
+ const modalRect = computed(() => {
2325
+ const size = terminal.size();
2326
+ const termW = size.cols;
2327
+ const termH = size.rows;
2328
+ const w = Math.floor(termW * .8);
2329
+ const h$1 = Math.floor(termH * .7);
2330
+ const x = Math.floor((termW - w) / 2);
2331
+ const y = Math.floor((termH - h$1) / 2);
2332
+ return translateRect({
2333
+ x,
2334
+ y,
2335
+ w,
2336
+ h: h$1
2337
+ }, layout.originX, layout.originY);
2338
+ });
2339
+ const contentLines = computed(() => {
2340
+ const text = sanitizeTextBlock(String(props.content || ""));
2341
+ return text.split("\n");
2342
+ });
2343
+ const scrollY = computed(() => 0);
2344
+ function onKeydown(e) {
2345
+ e.preventDefault();
2346
+ e.stopPropagation();
2347
+ if (e.key === "Escape") {
2348
+ emit("close");
2349
+ scheduler.invalidate();
2350
+ }
2351
+ }
2352
+ const backdropNode = useTerminalNode(() => ({
2353
+ rect: isVisible.value ? {
2354
+ x: 0,
2355
+ y: 0,
2356
+ w: terminal.size().cols,
2357
+ h: terminal.size().rows
2358
+ } : {
2359
+ x: 0,
2360
+ y: 0,
2361
+ w: 0,
2362
+ h: 0
2363
+ },
2364
+ zIndex: eventZ.value,
2365
+ visible: isVisible.value,
2366
+ focusable: true,
2367
+ handlers: {
2368
+ click: (e) => {
2369
+ e.preventDefault();
2370
+ e.stopPropagation();
2371
+ emit("close");
2372
+ scheduler.invalidate();
2373
+ },
2374
+ keydown: onKeydown
2375
+ }
2376
+ }));
2377
+ const contentNode = useTerminalNode(() => ({
2378
+ rect: isVisible.value ? modalRect.value : {
2379
+ x: 0,
2380
+ y: 0,
2381
+ w: 0,
2382
+ h: 0
2383
+ },
2384
+ zIndex: eventZ.value + 1,
2385
+ visible: isVisible.value,
2386
+ focusable: true,
2387
+ handlers: {
2388
+ click: (e) => {
2389
+ e.preventDefault();
2390
+ e.stopPropagation();
2391
+ const manager = events.value;
2392
+ const nodeId = contentNode.id.value;
2393
+ if (manager && nodeId) manager.focus(nodeId);
2394
+ },
2395
+ keydown: onKeydown
2396
+ }
2397
+ }));
2398
+ watchEffect(() => {
2399
+ if (!isVisible.value) return;
2400
+ const manager = events.value;
2401
+ const nodeId = contentNode.id.value || backdropNode.id.value;
2402
+ if (!manager || !nodeId) return;
2403
+ manager.focus(nodeId);
2404
+ });
2405
+ useRenderNode(() => ({
2406
+ zIndex: props.zIndex,
2407
+ rect: isVisible.value ? {
2408
+ x: 0,
2409
+ y: 0,
2410
+ w: terminal.size().cols,
2411
+ h: terminal.size().rows
2412
+ } : {
2413
+ x: 0,
2414
+ y: 0,
2415
+ w: 0,
2416
+ h: 0
2417
+ },
2418
+ deps: [
2419
+ isVisible.value,
2420
+ modalRect.value,
2421
+ props.content,
2422
+ props.title,
2423
+ props.style,
2424
+ defaultStyle.value
2425
+ ],
2426
+ paint: () => {
2427
+ if (!isVisible.value) return;
2428
+ const snapshot = terminal.size();
2429
+ const style = props.style ?? defaultStyle.value;
2430
+ const backdropStyle = {
2431
+ ...style,
2432
+ bg: defaultStyle.value.bg ?? style.bg,
2433
+ dim: true
2434
+ };
2435
+ const backdropRow = spaces(snapshot.cols);
2436
+ for (let y = 0; y < snapshot.rows; y++) terminal.write(backdropRow, {
2437
+ x: 0,
2438
+ y,
2439
+ style: backdropStyle
2440
+ });
2441
+ const r = modalRect.value;
2442
+ const fallbackFg = style.fg ?? defaultStyle.value.fg;
2443
+ const fallbackBg = style.bg ?? defaultStyle.value.bg;
2444
+ const borderStyle = {
2445
+ ...style,
2446
+ fg: defaultStyle.value.fg ?? style.fg
2447
+ };
2448
+ const contentStyle = {
2449
+ ...style,
2450
+ fg: fallbackFg,
2451
+ bg: fallbackBg
2452
+ };
2453
+ const footerStyle = {
2454
+ ...style,
2455
+ dim: true
2456
+ };
2457
+ terminal.put(r.x, r.y, BORDER.tl, borderStyle);
2458
+ terminal.put(r.x + r.w - 1, r.y, BORDER.tr, borderStyle);
2459
+ terminal.put(r.x, r.y + r.h - 1, BORDER.bl, borderStyle);
2460
+ terminal.put(r.x + r.w - 1, r.y + r.h - 1, BORDER.br, borderStyle);
2461
+ const innerW = Math.max(0, r.w - 2);
2462
+ const titleText = ` ${sanitizeInlineText(props.title)} `;
2463
+ const titleW = Math.min(titleText.length, innerW);
2464
+ const titleX = r.x + 1;
2465
+ terminal.write(titleText.slice(0, titleW), {
2466
+ x: titleX,
2467
+ y: r.y,
2468
+ style: borderStyle
2469
+ });
2470
+ const remainingTop = innerW - titleW;
2471
+ if (remainingTop > 0) terminal.write(BORDER.h.repeat(remainingTop), {
2472
+ x: titleX + titleW,
2473
+ y: r.y,
2474
+ style: borderStyle
2475
+ });
2476
+ const footer = " Press ESC to close ";
2477
+ const footerW = Math.min(footer.length, innerW);
2478
+ const footerX = r.x + Math.floor((r.w - footerW) / 2);
2479
+ const leftBorder = footerX - r.x - 1;
2480
+ const rightBorder = innerW - leftBorder - footerW;
2481
+ if (leftBorder > 0) terminal.write(BORDER.h.repeat(leftBorder), {
2482
+ x: r.x + 1,
2483
+ y: r.y + r.h - 1,
2484
+ style: borderStyle
2485
+ });
2486
+ terminal.write(footer, {
2487
+ x: footerX,
2488
+ y: r.y + r.h - 1,
2489
+ style: footerStyle
2490
+ });
2491
+ if (rightBorder > 0) terminal.write(BORDER.h.repeat(rightBorder), {
2492
+ x: footerX + footerW,
2493
+ y: r.y + r.h - 1,
2494
+ style: borderStyle
2495
+ });
2496
+ for (let y = 1; y < r.h - 1; y++) {
2497
+ terminal.put(r.x, r.y + y, BORDER.v, borderStyle);
2498
+ terminal.put(r.x + r.w - 1, r.y + y, BORDER.v, borderStyle);
2499
+ }
2500
+ const contentH = Math.max(0, r.h - 2);
2501
+ const lines = contentLines.value;
2502
+ const startLine = scrollY.value;
2503
+ for (let row = 0; row < contentH; row++) {
2504
+ const lineIndex = startLine + row;
2505
+ const line = lines[lineIndex] ?? "";
2506
+ const visible = sliceByCells(line, innerW);
2507
+ const padded = padEndByCells(visible, innerW);
2508
+ terminal.write(padded, {
2509
+ x: r.x + 1,
2510
+ y: r.y + 1 + row,
2511
+ style: contentStyle
2512
+ });
2513
+ }
2514
+ }
2515
+ }));
2516
+ return () => h("span", rootProps);
2517
+ }
2518
+ });
2519
+
2520
+ //#endregion
2521
+ //#region src/vue/components/TNavigation.ts
2522
+ const TKeyHint = defineComponent({
2523
+ name: "TKeyHint",
2524
+ props: {
2525
+ x: {
2526
+ type: Number,
2527
+ required: true
2528
+ },
2529
+ y: {
2530
+ type: Number,
2531
+ required: true
2532
+ },
2533
+ w: {
2534
+ type: Number,
2535
+ default: void 0
2536
+ },
2537
+ zIndex: {
2538
+ type: Number,
2539
+ default: 0
2540
+ },
2541
+ combo: {
2542
+ type: String,
2543
+ required: true
2544
+ },
2545
+ label: {
2546
+ type: String,
2547
+ required: true
2548
+ },
2549
+ style: {
2550
+ type: Object,
2551
+ default: void 0
2552
+ },
2553
+ comboStyle: {
2554
+ type: Object,
2555
+ default: () => ({ inverse: true })
2556
+ }
2557
+ },
2558
+ setup(props) {
2559
+ const { defaultStyle } = useTerminal();
2560
+ const baseStyle = computed(() => mergeStyle(defaultStyle.value, props.style));
2561
+ const comboStyle = computed(() => mergeStyle(baseStyle.value, props.comboStyle));
2562
+ return () => {
2563
+ const comboW = textCellWidth(props.combo);
2564
+ const gap = props.label ? 1 : 0;
2565
+ const comboRenderW = props.w == null ? comboW : Math.min(comboW, Math.max(0, props.w));
2566
+ const gapW = props.w == null ? gap : Math.min(gap, Math.max(0, props.w - comboW));
2567
+ const labelW = props.w == null ? void 0 : Math.max(0, props.w - comboW - gap);
2568
+ const children = [h(TText, {
2569
+ x: props.x,
2570
+ y: props.y,
2571
+ zIndex: props.zIndex,
2572
+ w: comboRenderW,
2573
+ value: props.combo,
2574
+ style: comboStyle.value
2575
+ })];
2576
+ if (gapW > 0) children.push(h(TText, {
2577
+ x: props.x + comboW,
2578
+ y: props.y,
2579
+ zIndex: props.zIndex,
2580
+ w: gapW,
2581
+ value: " ",
2582
+ style: baseStyle.value
2583
+ }));
2584
+ children.push(h(TText, {
2585
+ x: props.x + comboW + gap,
2586
+ y: props.y,
2587
+ zIndex: props.zIndex,
2588
+ w: labelW,
2589
+ value: props.label,
2590
+ style: baseStyle.value
2591
+ }));
2592
+ return children;
2593
+ };
2594
+ }
2595
+ });
2596
+ const TBreadcrumb = defineComponent({
2597
+ name: "TBreadcrumb",
2598
+ props: {
2599
+ x: {
2600
+ type: Number,
2601
+ required: true
2602
+ },
2603
+ y: {
2604
+ type: Number,
2605
+ required: true
2606
+ },
2607
+ w: {
2608
+ type: Number,
2609
+ required: true
2610
+ },
2611
+ zIndex: {
2612
+ type: Number,
2613
+ default: 0
2614
+ },
2615
+ items: {
2616
+ type: Array,
2617
+ required: true
2618
+ },
2619
+ separator: {
2620
+ type: String,
2621
+ default: "/"
2622
+ },
2623
+ style: {
2624
+ type: Object,
2625
+ default: void 0
2626
+ },
2627
+ activeStyle: {
2628
+ type: Object,
2629
+ default: () => ({ bold: true })
2630
+ },
2631
+ disabledStyle: {
2632
+ type: Object,
2633
+ default: () => ({ dim: true })
2634
+ }
2635
+ },
2636
+ emits: { select: (_payload) => true },
2637
+ setup(props, { emit }) {
2638
+ const { defaultStyle } = useTerminal();
2639
+ const baseStyle = computed(() => mergeStyle(defaultStyle.value, props.style));
2640
+ return () => {
2641
+ let x = 0;
2642
+ const children = [];
2643
+ for (let index = 0; index < props.items.length; index++) {
2644
+ const item = props.items[index];
2645
+ const suffix = index < props.items.length - 1 ? ` ${props.separator} ` : "";
2646
+ const text = `${item.label}${suffix}`;
2647
+ const remaining = props.w - x;
2648
+ const cellW = textCellWidth(text);
2649
+ const w = Math.min(remaining, cellW);
2650
+ if (w <= 0) break;
2651
+ children.push(h(TView, {
2652
+ key: item.id,
2653
+ x,
2654
+ y: 0,
2655
+ w,
2656
+ h: 1,
2657
+ focusable: !item.disabled,
2658
+ onClick: () => {
2659
+ if (!item.disabled) emit("select", {
2660
+ item,
2661
+ index
2662
+ });
2663
+ },
2664
+ onKeydown: (event) => {
2665
+ if (item.disabled || event.key !== "Enter" && event.key !== " ") return;
2666
+ event.preventDefault?.();
2667
+ emit("select", {
2668
+ item,
2669
+ index
2670
+ });
2671
+ }
2672
+ }, () => h(TText, {
2673
+ x: 0,
2674
+ y: 0,
2675
+ w,
2676
+ value: fitCellText(text, w),
2677
+ style: item.disabled ? mergeStyle(baseStyle.value, props.disabledStyle) : index === props.items.length - 1 ? mergeStyle(baseStyle.value, props.activeStyle) : baseStyle.value
2678
+ })));
2679
+ x += w;
2680
+ if (w < cellW) break;
2681
+ }
2682
+ return h(TView, {
2683
+ x: props.x,
2684
+ y: props.y,
2685
+ w: props.w,
2686
+ h: 1,
2687
+ zIndex: props.zIndex
2688
+ }, () => children);
2689
+ };
2690
+ }
2691
+ });
2692
+ const TStatusBar = defineComponent({
2693
+ name: "TStatusBar",
2694
+ props: {
2695
+ x: {
2696
+ type: Number,
2697
+ required: true
2698
+ },
2699
+ y: {
2700
+ type: Number,
2701
+ required: true
2702
+ },
2703
+ w: {
2704
+ type: Number,
2705
+ required: true
2706
+ },
2707
+ zIndex: {
2708
+ type: Number,
2709
+ default: 0
2710
+ },
2711
+ left: {
2712
+ type: String,
2713
+ default: ""
2714
+ },
2715
+ center: {
2716
+ type: String,
2717
+ default: ""
2718
+ },
2719
+ right: {
2720
+ type: String,
2721
+ default: ""
2722
+ },
2723
+ style: {
2724
+ type: Object,
2725
+ default: () => ({ inverse: true })
2726
+ }
2727
+ },
2728
+ setup(props, { slots }) {
2729
+ const { defaultStyle } = useTerminal();
2730
+ const baseStyle = computed(() => mergeStyle(defaultStyle.value, props.style));
2731
+ return () => {
2732
+ const children = slots.default?.();
2733
+ if (children?.length) return h(TView, {
2734
+ x: props.x,
2735
+ y: props.y,
2736
+ w: props.w,
2737
+ h: 1,
2738
+ zIndex: props.zIndex
2739
+ }, () => children);
2740
+ const leftW = Math.max(0, Math.floor(props.w / 3));
2741
+ const rightW = leftW;
2742
+ const centerW = Math.max(0, props.w - leftW - rightW);
2743
+ return h(TView, {
2744
+ x: props.x,
2745
+ y: props.y,
2746
+ w: props.w,
2747
+ h: 1,
2748
+ zIndex: props.zIndex
2749
+ }, () => [
2750
+ h(TText, {
2751
+ x: 0,
2752
+ y: 0,
2753
+ w: leftW,
2754
+ value: props.left,
2755
+ style: baseStyle.value
2756
+ }),
2757
+ h(TText, {
2758
+ x: leftW,
2759
+ y: 0,
2760
+ w: centerW,
2761
+ value: props.center,
2762
+ style: baseStyle.value
2763
+ }),
2764
+ h(TText, {
2765
+ x: leftW + centerW,
2766
+ y: 0,
2767
+ w: rightW,
2768
+ value: props.right,
2769
+ style: baseStyle.value
2770
+ })
2771
+ ]);
2772
+ };
2773
+ }
2774
+ });
2775
+
2776
+ //#endregion
2777
+ //#region src/vue/components/TOverlay.ts
2778
+ const TContextMenu = defineComponent({
2779
+ name: "TContextMenu",
2780
+ props: {
2781
+ modelValue: {
2782
+ type: Boolean,
2783
+ required: true
2784
+ },
2785
+ x: {
2786
+ type: Number,
2787
+ required: true
2788
+ },
2789
+ y: {
2790
+ type: Number,
2791
+ required: true
2792
+ },
2793
+ w: {
2794
+ type: Number,
2795
+ default: 24
2796
+ },
2797
+ zIndex: {
2798
+ type: Number,
2799
+ default: 20
2800
+ },
2801
+ items: {
2802
+ type: Array,
2803
+ required: true
2804
+ },
2805
+ selectedIndex: {
2806
+ type: Number,
2807
+ default: void 0
2808
+ },
2809
+ closeOnOutside: {
2810
+ type: Boolean,
2811
+ default: true
2812
+ },
2813
+ style: {
2814
+ type: Object,
2815
+ default: void 0
2816
+ },
2817
+ activeStyle: {
2818
+ type: Object,
2819
+ default: () => ({ inverse: true })
2820
+ },
2821
+ disabledStyle: {
2822
+ type: Object,
2823
+ default: () => ({ dim: true })
2824
+ }
2825
+ },
2826
+ emits: {
2827
+ "update:modelValue": (_value) => true,
2828
+ "update:selectedIndex": (_index) => true,
2829
+ select: (_payload) => true,
2830
+ close: () => true
2831
+ },
2832
+ setup(props, { emit }) {
2833
+ const { terminal, defaultStyle } = useTerminal();
2834
+ const innerSelectedIndex = ref(0);
2835
+ const baseStyle = computed(() => mergeStyle(defaultStyle.value, props.style));
2836
+ function close() {
2837
+ emit("update:modelValue", false);
2838
+ emit("close");
2839
+ }
2840
+ function select(index) {
2841
+ const item = props.items[index];
2842
+ if (!item || item.disabled) return;
2843
+ emit("select", {
2844
+ item,
2845
+ index
2846
+ });
2847
+ close();
2848
+ }
2849
+ function firstEnabledIndex() {
2850
+ return props.items.findIndex((item) => !item.disabled);
2851
+ }
2852
+ function selectedIndex() {
2853
+ if (!props.items.length) return 0;
2854
+ const clamped = clamp$1(props.selectedIndex ?? innerSelectedIndex.value, 0, props.items.length - 1);
2855
+ if (!props.items[clamped]?.disabled) return clamped;
2856
+ const first = firstEnabledIndex();
2857
+ return first >= 0 ? first : clamped;
2858
+ }
2859
+ function nextEnabledIndex(index, direction) {
2860
+ let next = index + direction;
2861
+ while (next >= 0 && next < props.items.length) {
2862
+ if (!props.items[next]?.disabled) return next;
2863
+ next += direction;
2864
+ }
2865
+ return index;
2866
+ }
2867
+ function setSelected(index) {
2868
+ innerSelectedIndex.value = index;
2869
+ emit("update:selectedIndex", index);
2870
+ }
2871
+ function handleMenuKeydown(event) {
2872
+ if (event.key === "Escape") {
2873
+ event.preventDefault?.();
2874
+ close();
2875
+ } else if (event.key === "Enter") {
2876
+ event.preventDefault?.();
2877
+ select(selectedIndex());
2878
+ } else if (event.key === "ArrowDown") {
2879
+ event.preventDefault?.();
2880
+ setSelected(nextEnabledIndex(selectedIndex(), 1));
2881
+ } else if (event.key === "ArrowUp") {
2882
+ event.preventDefault?.();
2883
+ setSelected(nextEnabledIndex(selectedIndex(), -1));
2884
+ }
2885
+ }
2886
+ function closeFromOutside(event) {
2887
+ event.preventDefault?.();
2888
+ event.stopPropagation?.();
2889
+ close();
2890
+ }
2891
+ function stopInsideClick(event) {
2892
+ event.stopPropagation?.();
2893
+ }
2894
+ return () => {
2895
+ if (!props.modelValue) return null;
2896
+ const size = terminal.size();
2897
+ const hgt = Math.max(2, props.items.length + 2);
2898
+ const activeIndex = selectedIndex();
2899
+ const hasEnabledItem = props.items.some((item) => !item.disabled);
2900
+ const menu = h(TView, {
2901
+ key: "menu",
2902
+ x: props.x,
2903
+ y: props.y,
2904
+ w: props.w,
2905
+ h: hgt,
2906
+ zIndex: props.closeOnOutside ? props.zIndex + 1 : props.zIndex,
2907
+ focusable: !hasEnabledItem,
2908
+ autoFocus: !hasEnabledItem,
2909
+ onClick: props.closeOnOutside ? stopInsideClick : void 0,
2910
+ onKeydown: handleMenuKeydown
2911
+ }, () => h(TBox, {
2912
+ x: 0,
2913
+ y: 0,
2914
+ w: props.w,
2915
+ h: hgt,
2916
+ style: baseStyle.value
2917
+ }, () => props.items.map((item, index) => {
2918
+ const active = index === activeIndex;
2919
+ const text = item.shortcut ? `${item.label} ${item.shortcut}` : item.label;
2920
+ return h(TView, {
2921
+ key: item.id,
2922
+ x: 0,
2923
+ y: index,
2924
+ w: Math.max(1, props.w - 2),
2925
+ h: 1,
2926
+ focusable: !item.disabled,
2927
+ autoFocus: active && !item.disabled,
2928
+ onClick: () => select(index)
2929
+ }, () => h(TText, {
2930
+ x: 0,
2931
+ y: 0,
2932
+ w: Math.max(1, props.w - 2),
2933
+ value: fitCellText(text, Math.max(1, props.w - 2)),
2934
+ style: item.disabled ? mergeStyle(baseStyle.value, props.disabledStyle) : active ? mergeStyle(baseStyle.value, props.activeStyle) : baseStyle.value
2935
+ }));
2936
+ })));
2937
+ if (!props.closeOnOutside) return menu;
2938
+ return [h(TView, {
2939
+ key: "outside",
2940
+ x: 0,
2941
+ y: 0,
2942
+ w: size.cols,
2943
+ h: size.rows,
2944
+ zIndex: props.zIndex,
2945
+ onClick: closeFromOutside
2946
+ }), menu];
2947
+ };
2948
+ }
2949
+ });
2950
+ const TPopover = defineComponent({
2951
+ name: "TPopover",
2952
+ props: {
2953
+ modelValue: {
2954
+ type: Boolean,
2955
+ required: true
2956
+ },
2957
+ x: {
2958
+ type: Number,
2959
+ required: true
2960
+ },
2961
+ y: {
2962
+ type: Number,
2963
+ required: true
2964
+ },
2965
+ w: {
2966
+ type: Number,
2967
+ required: true
2968
+ },
2969
+ h: {
2970
+ type: Number,
2971
+ required: true
2972
+ },
2973
+ zIndex: {
2974
+ type: Number,
2975
+ default: 15
2976
+ },
2977
+ title: {
2978
+ type: String,
2979
+ default: ""
2980
+ },
2981
+ content: {
2982
+ type: String,
2983
+ default: ""
2984
+ },
2985
+ style: {
2986
+ type: Object,
2987
+ default: void 0
2988
+ },
2989
+ contentStyle: {
2990
+ type: Object,
2991
+ default: void 0
2992
+ }
2993
+ },
2994
+ setup(props, { slots }) {
2995
+ const { defaultStyle } = useTerminal();
2996
+ const baseStyle = computed(() => mergeStyle(defaultStyle.value, props.style));
2997
+ const contentStyle = computed(() => mergeStyle(defaultStyle.value, props.contentStyle));
2998
+ return () => props.modelValue ? h(TBox, {
2999
+ x: props.x,
3000
+ y: props.y,
3001
+ w: props.w,
3002
+ h: props.h,
3003
+ zIndex: props.zIndex,
3004
+ title: props.title,
3005
+ style: baseStyle.value
3006
+ }, () => slots.default?.() ?? h(TText, {
3007
+ x: 0,
3008
+ y: 0,
3009
+ w: Math.max(1, props.w - 2),
3010
+ h: Math.max(1, props.h - 2),
3011
+ value: props.content,
3012
+ wrap: true,
3013
+ style: contentStyle.value
3014
+ })) : null;
3015
+ }
3016
+ });
3017
+ const TTooltip = defineComponent({
3018
+ name: "TTooltip",
3019
+ props: {
3020
+ modelValue: {
3021
+ type: Boolean,
3022
+ default: true
3023
+ },
3024
+ x: {
3025
+ type: Number,
3026
+ required: true
3027
+ },
3028
+ y: {
3029
+ type: Number,
3030
+ required: true
3031
+ },
3032
+ w: {
3033
+ type: Number,
3034
+ default: void 0
3035
+ },
3036
+ zIndex: {
3037
+ type: Number,
3038
+ default: 30
3039
+ },
3040
+ content: {
3041
+ type: String,
3042
+ required: true
3043
+ },
3044
+ style: {
3045
+ type: Object,
3046
+ default: () => ({ inverse: true })
3047
+ }
3048
+ },
3049
+ setup(props) {
3050
+ const { defaultStyle } = useTerminal();
3051
+ const baseStyle = computed(() => mergeStyle(defaultStyle.value, props.style));
3052
+ return () => props.modelValue ? h(TText, {
3053
+ x: props.x,
3054
+ y: props.y,
3055
+ zIndex: props.zIndex,
3056
+ w: props.w,
3057
+ value: props.content,
3058
+ style: baseStyle.value
3059
+ }) : null;
3060
+ }
3061
+ });
3062
+
3063
+ //#endregion
3064
+ //#region src/vue/components/TPathPicker.ts
3065
+ function clamp$2(n, min, max) {
3066
+ return Math.max(min, Math.min(max, n));
3067
+ }
3068
+ function getWheelScrollInput(e) {
3069
+ const deltaY = Number(e.deltaY ?? 0);
3070
+ const deltaMode = typeof e.deltaMode === "number" ? e.deltaMode : void 0;
3071
+ if (Number.isInteger(deltaY) && deltaY !== 0 && Math.abs(deltaY) >= 100 && Math.abs(deltaY) % 100 === 0 && deltaMode == null) return {
3072
+ deltaY: deltaY / 100,
3073
+ mode: "line"
3074
+ };
3075
+ if (deltaMode === 1) return {
3076
+ deltaY,
3077
+ mode: "line"
3078
+ };
3079
+ if (deltaMode === 0) return {
3080
+ deltaY,
3081
+ mode: "pixel"
3082
+ };
3083
+ return {
3084
+ deltaY,
3085
+ mode: "auto"
3086
+ };
3087
+ }
3088
+ function isCtrlLike(e) {
3089
+ return Boolean(e.ctrlKey || e.metaKey);
3090
+ }
3091
+ function computeHighlightRanges(text, query) {
3092
+ const q = query.trim().toLowerCase();
3093
+ if (!q) return [];
3094
+ const t = text.toLowerCase();
3095
+ const idx = t.indexOf(q);
3096
+ if (idx >= 0) return [{
3097
+ start: idx,
3098
+ end: idx + q.length
3099
+ }];
3100
+ const positions = [];
3101
+ let qi = 0;
3102
+ for (let i = 0; i < t.length && qi < q.length; i++) if (t[i] === q[qi]) {
3103
+ positions.push(i);
3104
+ qi++;
3105
+ }
3106
+ if (qi < q.length) return [];
3107
+ const ranges = [];
3108
+ let start = positions[0];
3109
+ let prev = positions[0];
3110
+ for (let i = 1; i < positions.length; i++) {
3111
+ const pos = positions[i];
3112
+ if (pos === prev + 1) {
3113
+ prev = pos;
3114
+ continue;
3115
+ }
3116
+ ranges.push({
3117
+ start,
3118
+ end: prev + 1
3119
+ });
3120
+ start = pos;
3121
+ prev = pos;
3122
+ }
3123
+ ranges.push({
3124
+ start,
3125
+ end: prev + 1
3126
+ });
3127
+ return ranges;
3128
+ }
3129
+ function writeHighlightedText(opts) {
3130
+ const { text, ranges, x, y, maxCells, baseStyle, highlightStyle, terminal } = opts;
3131
+ const safeMax = Math.max(0, Math.floor(maxCells));
3132
+ if (!text || safeMax <= 0) return 0;
3133
+ let rangeIndex = 0;
3134
+ let activeRange = ranges[rangeIndex];
3135
+ let cellPos = 0;
3136
+ let cursorX = x;
3137
+ let buffer = "";
3138
+ let currentStyle = baseStyle;
3139
+ const flush = () => {
3140
+ if (!buffer) return;
3141
+ terminal.write(buffer, {
3142
+ x: cursorX,
3143
+ y,
3144
+ style: currentStyle
3145
+ });
3146
+ cursorX += textCellWidth(buffer);
3147
+ buffer = "";
3148
+ };
3149
+ for (let i = 0; i < text.length && cellPos < safeMax;) {
3150
+ const code = text.charCodeAt(i);
3151
+ const seg = code <= 127 ? text[i] : String.fromCodePoint(text.codePointAt(i) ?? 0);
3152
+ const segLen = seg.length;
3153
+ const segWidth = charCellWidth(seg);
3154
+ if (cellPos + segWidth > safeMax) break;
3155
+ while (activeRange && activeRange.end <= i) {
3156
+ rangeIndex++;
3157
+ activeRange = ranges[rangeIndex];
3158
+ }
3159
+ const isHighlighted = Boolean(activeRange && i < activeRange.end && i + segLen > activeRange.start);
3160
+ const nextStyle = isHighlighted ? highlightStyle : baseStyle;
3161
+ if (nextStyle !== currentStyle) {
3162
+ flush();
3163
+ currentStyle = nextStyle;
3164
+ }
3165
+ buffer += seg;
3166
+ cellPos += segWidth;
3167
+ i += segLen;
3168
+ }
3169
+ flush();
3170
+ return cellPos;
3171
+ }
3172
+ const TPathPicker = defineComponent({
3173
+ name: "TPathPicker",
3174
+ props: {
3175
+ x: {
3176
+ type: Number,
3177
+ required: true
3178
+ },
3179
+ y: {
3180
+ type: Number,
3181
+ required: true
3182
+ },
3183
+ w: {
3184
+ type: Number,
3185
+ required: true
3186
+ },
3187
+ h: {
3188
+ type: Number,
3189
+ required: true
3190
+ },
3191
+ zIndex: {
3192
+ type: Number,
3193
+ default: 0
3194
+ },
3195
+ workspace: {
3196
+ type: String,
3197
+ required: true
3198
+ },
3199
+ mode: {
3200
+ type: String,
3201
+ default: "any"
3202
+ },
3203
+ modelValue: {
3204
+ type: String,
3205
+ required: true
3206
+ },
3207
+ placeholder: {
3208
+ type: String,
3209
+ default: ""
3210
+ },
3211
+ style: {
3212
+ type: Object,
3213
+ default: void 0
3214
+ },
3215
+ inputStyle: {
3216
+ type: Object,
3217
+ default: void 0
3218
+ },
3219
+ activeStyle: {
3220
+ type: Object,
3221
+ default: void 0
3222
+ },
3223
+ matchStyle: {
3224
+ type: Object,
3225
+ default: void 0
3226
+ },
3227
+ autoFocus: {
3228
+ type: Boolean,
3229
+ default: false
3230
+ },
3231
+ showHidden: {
3232
+ type: Boolean,
3233
+ default: false
3234
+ },
3235
+ maxSuggestions: {
3236
+ type: Number,
3237
+ default: 50
3238
+ },
3239
+ provider: {
3240
+ type: Object,
3241
+ default: void 0
3242
+ }
3243
+ },
3244
+ emits: [
3245
+ "update:modelValue",
3246
+ "select",
3247
+ "invalid",
3248
+ "keydown",
3249
+ "focus",
3250
+ "blur"
3251
+ ],
3252
+ setup(props, { emit }) {
3253
+ const { terminal, scheduler, defaultStyle } = useTerminal();
3254
+ const layout = useLayout();
3255
+ const { visible, rootProps } = useVisibility();
3256
+ const injectedProvider = inject(TPathPickerProviderContextKey, null);
3257
+ const parentEventZ = inject(EventZIndexContextKey, computed(() => 0));
3258
+ const eventZ = computed(() => (parentEventZ.value ?? 0) + (props.zIndex ?? 0));
3259
+ const provider = computed(() => props.provider ?? injectedProvider?.value ?? null);
3260
+ const suggestions = ref([]);
3261
+ const active = ref(0);
3262
+ const scrollTop = ref(0);
3263
+ const error = ref(null);
3264
+ const inputH = 1;
3265
+ const listH = computed(() => Math.max(0, Math.floor(props.h) - inputH));
3266
+ const absListRect = computed(() => {
3267
+ const raw = {
3268
+ x: props.x,
3269
+ y: props.y + inputH,
3270
+ w: props.w,
3271
+ h: listH.value
3272
+ };
3273
+ const translated = translateRect(raw, layout.originX, layout.originY);
3274
+ if (!layout.clipRect) return translated;
3275
+ return intersectRect(translated, layout.clipRect) ?? {
3276
+ x: 0,
3277
+ y: 0,
3278
+ w: 0,
3279
+ h: 0
3280
+ };
3281
+ });
3282
+ function ensureActiveVisible() {
3283
+ const h$1 = Math.max(0, listH.value);
3284
+ if (h$1 <= 0) {
3285
+ scrollTop.value = 0;
3286
+ return;
3287
+ }
3288
+ const maxTop = Math.max(0, suggestions.value.length - h$1);
3289
+ scrollTop.value = clamp$2(scrollTop.value, 0, maxTop);
3290
+ if (active.value < scrollTop.value) scrollTop.value = active.value;
3291
+ else if (active.value >= scrollTop.value + h$1) scrollTop.value = clamp$2(active.value - (h$1 - 1), 0, maxTop);
3292
+ }
3293
+ watch([
3294
+ () => active.value,
3295
+ () => suggestions.value.length,
3296
+ () => listH.value
3297
+ ], () => {
3298
+ ensureActiveVisible();
3299
+ });
3300
+ let refreshSeq = 0;
3301
+ async function refresh(seq) {
3302
+ const currentProvider = provider.value;
3303
+ if (!currentProvider) {
3304
+ if (seq !== refreshSeq) return;
3305
+ suggestions.value = [];
3306
+ active.value = 0;
3307
+ scheduler.invalidate();
3308
+ return;
3309
+ }
3310
+ const limit = Math.max(0, Math.floor(props.maxSuggestions));
3311
+ const res = currentProvider.suggest ? await currentProvider.suggest({
3312
+ workspaceAbs: props.workspace,
3313
+ input: props.modelValue,
3314
+ mode: props.mode,
3315
+ max: limit,
3316
+ showHidden: props.showHidden,
3317
+ gitignore: "nonBlocking"
3318
+ }) : await suggestPaths({
3319
+ workspaceAbs: props.workspace,
3320
+ input: props.modelValue,
3321
+ mode: props.mode,
3322
+ max: limit,
3323
+ showHidden: props.showHidden,
3324
+ listDir: currentProvider.listDir
3325
+ });
3326
+ if (seq !== refreshSeq) return;
3327
+ suggestions.value = res.suggestions;
3328
+ active.value = clamp$2(active.value, 0, Math.max(0, suggestions.value.length - 1));
3329
+ ensureActiveVisible();
3330
+ scheduler.invalidate();
3331
+ }
3332
+ watchEffect(() => {
3333
+ if (!visible.value) return;
3334
+ props.workspace;
3335
+ props.mode;
3336
+ props.showHidden;
3337
+ props.modelValue;
3338
+ listH.value;
3339
+ error.value = null;
3340
+ const seq = ++refreshSeq;
3341
+ refresh(seq).catch((e) => {
3342
+ if (seq !== refreshSeq) return;
3343
+ suggestions.value = [];
3344
+ error.value = e instanceof Error ? e.message : String(e);
3345
+ scheduler.invalidate();
3346
+ });
3347
+ });
3348
+ function setValue(next) {
3349
+ const cleaned = next.replace(/\r/g, "").replace(/\n/g, " ");
3350
+ emit("update:modelValue", cleaned);
3351
+ }
3352
+ function moveActive(delta) {
3353
+ const len = suggestions.value.length;
3354
+ if (len <= 0) return;
3355
+ const next = clamp$2(active.value + delta, 0, len - 1);
3356
+ if (next !== active.value) {
3357
+ active.value = next;
3358
+ ensureActiveVisible();
3359
+ scheduler.invalidate();
3360
+ }
3361
+ }
3362
+ function applyCompletion() {
3363
+ const s = suggestions.value[active.value];
3364
+ if (!s) return;
3365
+ setValue(s.completion);
3366
+ }
3367
+ async function trySelect(absPath) {
3368
+ const currentProvider = provider.value;
3369
+ if (!currentProvider) {
3370
+ error.value = "Path provider unavailable";
3371
+ emit("invalid", {
3372
+ reason: "provider_missing",
3373
+ absPath
3374
+ });
3375
+ scheduler.invalidate();
3376
+ return;
3377
+ }
3378
+ const stat = await currentProvider.stat(absPath);
3379
+ if (!stat.exists) {
3380
+ error.value = "Not found";
3381
+ emit("invalid", {
3382
+ reason: "not_found",
3383
+ absPath
3384
+ });
3385
+ scheduler.invalidate();
3386
+ return;
3387
+ }
3388
+ if (props.mode === "file" && stat.kind === "directory") {
3389
+ const abs = normalizePath(absPath);
3390
+ const workspaceAbs = normalizePath(props.workspace);
3391
+ const rel = abs === workspaceAbs ? "" : abs.startsWith(`${workspaceAbs}/`) ? abs.slice(workspaceAbs.length + 1) : abs;
3392
+ setValue(rel ? `${rel}/` : "");
3393
+ error.value = null;
3394
+ scheduler.invalidate();
3395
+ return;
3396
+ }
3397
+ if (props.mode === "file" && stat.kind !== "file") {
3398
+ error.value = "Not a file";
3399
+ emit("invalid", {
3400
+ reason: "not_file",
3401
+ absPath
3402
+ });
3403
+ scheduler.invalidate();
3404
+ return;
3405
+ }
3406
+ if (props.mode === "directory" && stat.kind !== "directory") {
3407
+ error.value = "Not a directory";
3408
+ emit("invalid", {
3409
+ reason: "not_directory",
3410
+ absPath
3411
+ });
3412
+ scheduler.invalidate();
3413
+ return;
3414
+ }
3415
+ emit("select", stripTrailingSlash(absPath));
3416
+ }
3417
+ async function onCommit() {
3418
+ const currentProvider = provider.value;
3419
+ const typedAbs = currentProvider?.resolvePath ? await currentProvider.resolvePath(props.workspace, props.modelValue) : resolveUserPath(props.workspace, props.modelValue);
3420
+ if (!currentProvider) {
3421
+ error.value = "Path provider unavailable";
3422
+ emit("invalid", {
3423
+ reason: "provider_missing",
3424
+ absPath: typedAbs
3425
+ });
3426
+ scheduler.invalidate();
3427
+ return;
3428
+ }
3429
+ const typedStat = await currentProvider.stat(typedAbs);
3430
+ if (typedStat.exists) {
3431
+ if (props.mode === "file" && typedStat.kind === "directory") {
3432
+ const base = props.modelValue.replace(/\r/g, "").replace(/\\/g, "/");
3433
+ const next = base.endsWith("/") ? base : `${base}/`;
3434
+ setValue(next);
3435
+ error.value = null;
3436
+ scheduler.invalidate();
3437
+ return;
3438
+ }
3439
+ await trySelect(typedAbs);
3440
+ return;
3441
+ }
3442
+ const s = suggestions.value[active.value];
3443
+ if (s) {
3444
+ if (props.mode === "file" && s.kind === "directory") {
3445
+ setValue(s.completion);
3446
+ error.value = null;
3447
+ scheduler.invalidate();
3448
+ return;
3449
+ }
3450
+ await trySelect(s.absPath);
3451
+ return;
3452
+ }
3453
+ error.value = "Not found";
3454
+ emit("invalid", {
3455
+ reason: "not_found",
3456
+ absPath: typedAbs
3457
+ });
3458
+ scheduler.invalidate();
3459
+ }
3460
+ function onKeydown(e) {
3461
+ emit("keydown", e);
3462
+ if (e.key === "Tab") {
3463
+ e.preventDefault();
3464
+ applyCompletion();
3465
+ return;
3466
+ }
3467
+ if (e.key === "ArrowUp") {
3468
+ e.preventDefault();
3469
+ moveActive(-1);
3470
+ return;
3471
+ }
3472
+ if (e.key === "ArrowDown") {
3473
+ e.preventDefault();
3474
+ moveActive(1);
3475
+ return;
3476
+ }
3477
+ if (isCtrlLike(e) && (e.key === "p" || e.key === "P")) {
3478
+ e.preventDefault();
3479
+ moveActive(-1);
3480
+ return;
3481
+ }
3482
+ if (isCtrlLike(e) && (e.key === "n" || e.key === "N")) {
3483
+ e.preventDefault();
3484
+ moveActive(1);
3485
+ }
3486
+ }
3487
+ const wheelState = createWheelScrollState();
3488
+ useTerminalNode(() => ({
3489
+ rect: absListRect.value,
3490
+ zIndex: eventZ.value,
3491
+ visible: visible.value,
3492
+ focusable: false,
3493
+ handlers: {
3494
+ click: (e) => {
3495
+ const r = absListRect.value;
3496
+ const idx = scrollTop.value + (e.cellY - r.y);
3497
+ if (idx >= 0 && idx < suggestions.value.length) {
3498
+ active.value = idx;
3499
+ ensureActiveVisible();
3500
+ scheduler.invalidate();
3501
+ }
3502
+ },
3503
+ dblclick: async (e) => {
3504
+ const r = absListRect.value;
3505
+ const idx = scrollTop.value + (e.cellY - r.y);
3506
+ const s = suggestions.value[idx];
3507
+ if (!s) return;
3508
+ if (props.mode === "file" && s.kind === "directory") {
3509
+ setValue(s.completion);
3510
+ error.value = null;
3511
+ scheduler.invalidate();
3512
+ return;
3513
+ }
3514
+ await trySelect(s.absPath);
3515
+ },
3516
+ wheel: (e) => {
3517
+ const { deltaY, mode } = getWheelScrollInput(e);
3518
+ const delta = deltaY;
3519
+ if (!delta) return;
3520
+ const h$1 = Math.max(0, listH.value);
3521
+ const maxTop = Math.max(0, suggestions.value.length - h$1);
3522
+ const { nextTop, dir } = applyWheelScroll(wheelState, delta, scrollTop.value, maxTop, Date.now(), mode, { disableAcceleration: mode === "pixel" });
3523
+ if (!dir || nextTop === scrollTop.value) return;
3524
+ scrollTop.value = nextTop;
3525
+ const visibleStart = nextTop;
3526
+ const visibleEnd = nextTop + h$1 - 1;
3527
+ if (active.value < visibleStart || active.value > visibleEnd) {
3528
+ const newActive = dir > 0 ? visibleEnd : visibleStart;
3529
+ active.value = clamp$2(newActive, 0, Math.max(0, suggestions.value.length - 1));
3530
+ }
3531
+ scheduler.invalidate({ reason: "scroll" });
3532
+ }
3533
+ }
3534
+ }));
3535
+ useRenderNode(() => ({
3536
+ zIndex: props.zIndex,
3537
+ rect: visible.value ? absListRect.value : {
3538
+ x: 0,
3539
+ y: 0,
3540
+ w: 0,
3541
+ h: 0
3542
+ },
3543
+ deps: [
3544
+ visible.value,
3545
+ absListRect.value,
3546
+ props.w,
3547
+ listH.value,
3548
+ props.style,
3549
+ props.activeStyle,
3550
+ props.matchStyle,
3551
+ defaultStyle.value,
3552
+ suggestions.value,
3553
+ active.value,
3554
+ scrollTop.value,
3555
+ error.value
3556
+ ],
3557
+ paint: () => {
3558
+ if (!visible.value) return;
3559
+ const r = absListRect.value;
3560
+ if (r.w <= 0 || r.h <= 0) return;
3561
+ const base = props.style ?? defaultStyle.value;
3562
+ const query = parsePathQuery(String(props.modelValue ?? "")).query;
3563
+ const top = clamp$2(scrollTop.value, 0, Math.max(0, suggestions.value.length - r.h));
3564
+ for (let i = 0; i < r.h; i++) {
3565
+ const idx = top + i;
3566
+ const s = suggestions.value[idx];
3567
+ const raw = s ? sanitizeInlineText(s.display) : "";
3568
+ const clipped = sliceByCells(raw, r.w);
3569
+ const rowStyle = idx === active.value ? {
3570
+ ...base,
3571
+ ...props.activeStyle ?? { inverse: true }
3572
+ } : base;
3573
+ const rowMatchStyle = {
3574
+ ...rowStyle,
3575
+ ...props.matchStyle ?? {
3576
+ bold: true,
3577
+ dim: false,
3578
+ underline: true
3579
+ }
3580
+ };
3581
+ const ranges = query ? computeHighlightRanges(raw, query) : [];
3582
+ const used = writeHighlightedText({
3583
+ text: clipped,
3584
+ ranges,
3585
+ x: r.x,
3586
+ y: r.y + i,
3587
+ maxCells: r.w,
3588
+ baseStyle: rowStyle,
3589
+ highlightStyle: rowMatchStyle,
3590
+ terminal
3591
+ });
3592
+ if (used < r.w) terminal.write(spaces(r.w - used), {
3593
+ x: r.x + used,
3594
+ y: r.y + i,
3595
+ style: rowStyle
3596
+ });
3597
+ }
3598
+ if (suggestions.value.length === 0 && r.h > 0) {
3599
+ const msg = error.value ? `(${sanitizeInlineText(error.value)})` : "(no matches)";
3600
+ terminal.write(padEndByCells(sliceByCells(msg, r.w), r.w), {
3601
+ x: r.x,
3602
+ y: r.y,
3603
+ style: {
3604
+ ...base,
3605
+ dim: true
3606
+ }
3607
+ });
3608
+ }
3609
+ }
3610
+ }));
3611
+ return () => h("span", rootProps, [h(TInput, {
3612
+ x: props.x,
3613
+ y: props.y,
3614
+ w: props.w,
3615
+ h: inputH,
3616
+ zIndex: props.zIndex,
3617
+ modelValue: props.modelValue,
3618
+ "onUpdate:modelValue": (v) => setValue(v),
3619
+ cursorToEndOnExternalUpdate: true,
3620
+ placeholder: props.placeholder,
3621
+ style: props.inputStyle ?? props.style,
3622
+ autoFocus: props.autoFocus,
3623
+ onKeydown: (e) => onKeydown(e),
3624
+ onChange: () => void onCommit(),
3625
+ onFocus: () => emit("focus"),
3626
+ onBlur: () => emit("blur")
3627
+ })]);
3628
+ }
3629
+ });
3630
+
3631
+ //#endregion
3632
+ //#region src/vue/components/TRenderLayer.ts
3633
+ const TRenderLayer = defineComponent({
3634
+ name: "TRenderLayer",
3635
+ props: { zIndex: {
3636
+ type: Number,
3637
+ default: 0
3638
+ } },
3639
+ setup(props, { slots }) {
3640
+ const { render } = useTerminal();
3641
+ const parentStack = useRenderStack();
3642
+ const stack = computed(() => render.createStack(parentStack.value, props.zIndex));
3643
+ provide(RenderStackKey, stack);
3644
+ return () => slots.default?.() ?? null;
3645
+ }
3646
+ });
3647
+
3648
+ //#endregion
3649
+ //#region src/vue/components/TTransition.ts
3650
+ const TTransition = defineComponent({
3651
+ name: "TTransition",
3652
+ props: {
3653
+ show: {
3654
+ type: Boolean,
3655
+ required: true
3656
+ },
3657
+ duration: {
3658
+ type: Number,
3659
+ default: 200
3660
+ },
3661
+ beforeEnter: {
3662
+ type: Function,
3663
+ default: void 0
3664
+ },
3665
+ enter: {
3666
+ type: Function,
3667
+ default: void 0
3668
+ },
3669
+ afterEnter: {
3670
+ type: Function,
3671
+ default: void 0
3672
+ },
3673
+ beforeLeave: {
3674
+ type: Function,
3675
+ default: void 0
3676
+ },
3677
+ leave: {
3678
+ type: Function,
3679
+ default: void 0
3680
+ },
3681
+ afterLeave: {
3682
+ type: Function,
3683
+ default: void 0
3684
+ }
3685
+ },
3686
+ setup(props, { slots }) {
3687
+ const { scheduler } = useTerminal();
3688
+ let raf = 0;
3689
+ let runToken = 0;
3690
+ const phase = ref("idle");
3691
+ const progress = ref(props.show ? 1 : 0);
3692
+ const rendered = ref(props.show);
3693
+ const visible = ref(props.show);
3694
+ provide(VisibilityContextKey, visible);
3695
+ function cancel() {
3696
+ if (raf > 0) {
3697
+ cancelAnimationFrame(raf);
3698
+ raf = 0;
3699
+ }
3700
+ runToken += 1;
3701
+ }
3702
+ async function runHook(hook, phaseName, p) {
3703
+ if (!hook) return;
3704
+ await hook({
3705
+ phase: phaseName,
3706
+ progress: p
3707
+ });
3708
+ }
3709
+ function animate(from, to) {
3710
+ const duration = Math.max(0, Math.floor(props.duration));
3711
+ if (duration === 0) {
3712
+ progress.value = to;
3713
+ scheduler.invalidate();
3714
+ return Promise.resolve();
3715
+ }
3716
+ const token = runToken;
3717
+ const t0 = typeof performance !== "undefined" ? performance.now() : Date.now();
3718
+ return new Promise((resolve) => {
3719
+ const schedule = (fn) => {
3720
+ raf = -1;
3721
+ const id = requestAnimationFrame(fn);
3722
+ if (raf === -1) raf = id;
3723
+ };
3724
+ const tick = () => {
3725
+ if (token !== runToken) {
3726
+ raf = 0;
3727
+ resolve();
3728
+ return;
3729
+ }
3730
+ const t = typeof performance !== "undefined" ? performance.now() : Date.now();
3731
+ const p = Math.min(1, (t - t0) / duration);
3732
+ progress.value = from + (to - from) * p;
3733
+ scheduler.invalidate();
3734
+ if (p >= 1) {
3735
+ raf = 0;
3736
+ resolve();
3737
+ return;
3738
+ }
3739
+ schedule(tick);
3740
+ };
3741
+ schedule(tick);
3742
+ });
3743
+ }
3744
+ async function enter() {
3745
+ cancel();
3746
+ rendered.value = true;
3747
+ visible.value = true;
3748
+ phase.value = "enter";
3749
+ progress.value = 0;
3750
+ scheduler.invalidate();
3751
+ await runHook(props.beforeEnter, "enter", 0);
3752
+ await runHook(props.enter, "enter", 0);
3753
+ await animate(0, 1);
3754
+ progress.value = 1;
3755
+ phase.value = "idle";
3756
+ scheduler.invalidate();
3757
+ await runHook(props.afterEnter, "enter", 1);
3758
+ }
3759
+ async function leave() {
3760
+ cancel();
3761
+ rendered.value = true;
3762
+ visible.value = true;
3763
+ phase.value = "leave";
3764
+ progress.value = 1;
3765
+ scheduler.invalidate();
3766
+ await runHook(props.beforeLeave, "leave", 1);
3767
+ await runHook(props.leave, "leave", 1);
3768
+ await animate(1, 0);
3769
+ progress.value = 0;
3770
+ phase.value = "idle";
3771
+ visible.value = false;
3772
+ rendered.value = false;
3773
+ scheduler.invalidate();
3774
+ await runHook(props.afterLeave, "leave", 0);
3775
+ }
3776
+ watch(() => props.show, (next, prev) => {
3777
+ if (next === prev) return;
3778
+ next ? enter() : leave();
3779
+ });
3780
+ onBeforeUnmount(() => cancel());
3781
+ return () => {
3782
+ if (!rendered.value) return null;
3783
+ return slots.default?.({
3784
+ phase: phase.value,
3785
+ progress: progress.value
3786
+ }) ?? null;
3787
+ };
3788
+ }
3789
+ });
3790
+
3791
+ //#endregion
3792
+ //#region src/vue/composables/use-runtime.ts
3793
+ function useTerminalRuntime() {
3794
+ return useTerminal().runtime;
3795
+ }
3796
+
3797
+ //#endregion
3798
+ //#region src/vue/router/context.ts
3799
+ const TerminalRouterKey = injectionKey("TerminalRouter");
3800
+ const TerminalRouteKey = injectionKey("TerminalRoute");
3801
+
3802
+ //#endregion
3803
+ //#region src/vue/router/composables.ts
3804
+ function useRouter() {
3805
+ const r = inject(TerminalRouterKey, null);
3806
+ if (!r) throw new Error("TerminalRouter is missing");
3807
+ return r;
3808
+ }
3809
+ function useRoute() {
3810
+ const route = inject(TerminalRouteKey, null);
3811
+ if (!route) throw new Error("TerminalRoute is missing");
3812
+ return computed(() => route.value);
3813
+ }
3814
+
3815
+ //#endregion
3816
+ //#region src/vue/router/router.ts
3817
+ function normalize(to, records) {
3818
+ const raw = typeof to === "string" ? { name: to } : to;
3819
+ const record = records.get(raw.name);
3820
+ return {
3821
+ name: raw.name,
3822
+ params: raw.params,
3823
+ meta: record?.meta
3824
+ };
3825
+ }
3826
+ function isRedirect(v) {
3827
+ return typeof v === "string" || typeof v === "object" && v != null && "name" in v;
3828
+ }
3829
+ function createTerminalRouter(options) {
3830
+ const records = new Map(options.routes.map((r) => [r.name, r]));
3831
+ const currentRoute = ref(normalize(options.initialRoute, records));
3832
+ const history = [currentRoute.value];
3833
+ let index = 0;
3834
+ const befores = [];
3835
+ const resolves = [];
3836
+ const afters = [];
3837
+ async function runGuards(list, to, from) {
3838
+ for (const guard of list) {
3839
+ const r = await guard(to, from);
3840
+ if (r === false) return false;
3841
+ if (isRedirect(r)) return r;
3842
+ }
3843
+ return true;
3844
+ }
3845
+ async function navigate(toRaw, mode) {
3846
+ const from = currentRoute.value;
3847
+ const to = normalize(toRaw, records);
3848
+ const fromRecord = records.get(from.name) ?? null;
3849
+ const toRecord = records.get(to.name) ?? null;
3850
+ const r1 = await runGuards(befores, to, from);
3851
+ if (r1 === false) return;
3852
+ if (isRedirect(r1)) return navigate(r1, mode);
3853
+ const r2 = await runGuards(resolves, to, from);
3854
+ if (r2 === false) return;
3855
+ if (isRedirect(r2)) return navigate(r2, mode);
3856
+ if (fromRecord?.onLeave) await fromRecord.onLeave(to, from);
3857
+ currentRoute.value = to;
3858
+ if (mode === "replace") history[index] = to;
3859
+ else if (mode === "push") {
3860
+ history.splice(index + 1);
3861
+ history.push(to);
3862
+ index = history.length - 1;
3863
+ }
3864
+ if (toRecord?.onEnter) await toRecord.onEnter(to, from);
3865
+ for (const hook of afters) hook(to, from);
3866
+ }
3867
+ const router = {
3868
+ currentRoute,
3869
+ async push(to) {
3870
+ await navigate(to, "push");
3871
+ },
3872
+ async replace(to) {
3873
+ await navigate(to, "replace");
3874
+ },
3875
+ async back() {
3876
+ if (index <= 0) return;
3877
+ const from = currentRoute.value;
3878
+ const to = history[index - 1];
3879
+ const fromRecord = records.get(from.name) ?? null;
3880
+ const toRecord = records.get(to.name) ?? null;
3881
+ const r1 = await runGuards(befores, to, from);
3882
+ if (r1 === false) return;
3883
+ if (isRedirect(r1)) return navigate(r1, "push");
3884
+ const r2 = await runGuards(resolves, to, from);
3885
+ if (r2 === false) return;
3886
+ if (isRedirect(r2)) return navigate(r2, "push");
3887
+ if (fromRecord?.onLeave) await fromRecord.onLeave(to, from);
3888
+ index -= 1;
3889
+ currentRoute.value = to;
3890
+ if (toRecord?.onEnter) await toRecord.onEnter(to, from);
3891
+ for (const hook of afters) hook(to, from);
3892
+ },
3893
+ beforeEach(guard) {
3894
+ befores.push(guard);
3895
+ return () => {
3896
+ const idx = befores.indexOf(guard);
3897
+ if (idx >= 0) befores.splice(idx, 1);
3898
+ };
3899
+ },
3900
+ beforeResolve(guard) {
3901
+ resolves.push(guard);
3902
+ return () => {
3903
+ const idx = resolves.indexOf(guard);
3904
+ if (idx >= 0) resolves.splice(idx, 1);
3905
+ };
3906
+ },
3907
+ afterEach(hook) {
3908
+ afters.push(hook);
3909
+ return () => {
3910
+ const idx = afters.indexOf(hook);
3911
+ if (idx >= 0) afters.splice(idx, 1);
3912
+ };
3913
+ },
3914
+ install(app) {
3915
+ app.provide(TerminalRouterKey, router);
3916
+ app.provide(TerminalRouteKey, currentRoute);
3917
+ }
3918
+ };
3919
+ return router;
3920
+ }
3921
+ function resolveTerminalRouteComponent(router, routes) {
3922
+ const cur = router.currentRoute.value;
3923
+ const rec = routes.find((r) => r.name === cur.name);
3924
+ return rec?.component ?? null;
3925
+ }
3926
+
3927
+ //#endregion
3928
+ //#region src/vue/router/RouterView.ts
3929
+ const TRouterView = defineComponent({
3930
+ name: "TRouterView",
3931
+ props: {
3932
+ routes: {
3933
+ type: Array,
3934
+ required: true
3935
+ },
3936
+ forceRemount: {
3937
+ type: Boolean,
3938
+ default: true
3939
+ }
3940
+ },
3941
+ setup(props) {
3942
+ const router = inject(TerminalRouterKey, null);
3943
+ if (!router) throw new Error("TerminalRouter is missing (did you forget to app.use(router)?)");
3944
+ const key = ref(0);
3945
+ watch(() => router.currentRoute.value, () => {
3946
+ if (props.forceRemount) key.value++;
3947
+ }, { deep: true });
3948
+ const component = computed(() => resolveTerminalRouteComponent(router, props.routes));
3949
+ return () => {
3950
+ const C = component.value;
3951
+ return C ? h(C, { key: props.forceRemount ? key.value : void 0 }) : null;
3952
+ };
3953
+ }
3954
+ });
3955
+
3956
+ //#endregion
3957
+ export { TAnchor, TAutocompleteInput, TBadge, TBox, TBreadcrumb, TCheckbox, TCode, TCommandPalette, TContextMenu, TDataTable, TDebugOverlay, TDialog, TDivider, TFlow, TForm, TFormContextKey, TFormField, TInput, TInputBox, TInputPluginsContextKey, TJsonEditor, TKeyHint, TLink, TLinkifyText, TList, TMultilineModal, TPasswordInput, TPathPicker, TPopover, TProgress, TRadioGroup, TRenderLayer, TRenderPlane, TRouterView, TSelect, TSlider, TSpinner, TSplitPane, TStatusBar, TSwitch, TTable, TTabs, TTag, TText, TToastViewport, TTooltip, TTransition, TTree, TView, TerminalProvider, computeCommandPaletteMatchRanges, createOverlayFocusStack, createPromptMentionPlugin, createTInputHostPlugin, createTerminalRouter, createTextRestrictionPlugin, createTheme, linkifyTextSegments, lintJsonText, padEndByCells, resolveOverlayPlacement, sliceByCells, sliceByCellsRange, spaces, textCellWidth, tuiDefaultTheme, useLayout, useRenderNode, useRoute, useRouter, useTForm, useTerminal, useTerminalNode, useTerminalRuntime, useVisibility, wrapByCells };