@dst0/p-tui 0.4.41 → 5.0.2

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 (387) hide show
  1. package/dist/autocomplete.d.ts.map +1 -1
  2. package/dist/autocomplete.js.map +1 -1
  3. package/dist/components/box.d.ts +3 -1
  4. package/dist/components/box.d.ts.map +1 -1
  5. package/dist/components/box.js +19 -10
  6. package/dist/components/box.js.map +1 -1
  7. package/dist/components/cancellable-loader.d.ts.map +1 -1
  8. package/dist/components/cancellable-loader.js.map +1 -1
  9. package/dist/components/editor/constants.d.ts +9 -0
  10. package/dist/components/editor/constants.d.ts.map +1 -0
  11. package/dist/components/editor/constants.js +12 -0
  12. package/dist/components/editor/constants.js.map +1 -0
  13. package/dist/components/editor/editor-methods/autocomplete-matching.d.ts +29 -0
  14. package/dist/components/editor/editor-methods/autocomplete-matching.d.ts.map +1 -0
  15. package/dist/components/editor/editor-methods/autocomplete-matching.js +104 -0
  16. package/dist/components/editor/editor-methods/autocomplete-matching.js.map +1 -0
  17. package/dist/components/editor/editor-methods/autocomplete-request.d.ts +14 -0
  18. package/dist/components/editor/editor-methods/autocomplete-request.d.ts.map +1 -0
  19. package/dist/components/editor/editor-methods/autocomplete-request.js +72 -0
  20. package/dist/components/editor/editor-methods/autocomplete-request.js.map +1 -0
  21. package/dist/components/editor/editor-methods/backspace-cursor.d.ts +9 -0
  22. package/dist/components/editor/editor-methods/backspace-cursor.d.ts.map +1 -0
  23. package/dist/components/editor/editor-methods/backspace-cursor.js +122 -0
  24. package/dist/components/editor/editor-methods/backspace-cursor.js.map +1 -0
  25. package/dist/components/editor/editor-methods/configuration.d.ts +17 -0
  26. package/dist/components/editor/editor-methods/configuration.d.ts.map +1 -0
  27. package/dist/components/editor/editor-methods/configuration.js +107 -0
  28. package/dist/components/editor/editor-methods/configuration.js.map +1 -0
  29. package/dist/components/editor/editor-methods/cursor-movement.d.ts +7 -0
  30. package/dist/components/editor/editor-methods/cursor-movement.d.ts.map +1 -0
  31. package/dist/components/editor/editor-methods/cursor-movement.js +112 -0
  32. package/dist/components/editor/editor-methods/cursor-movement.js.map +1 -0
  33. package/dist/components/editor/editor-methods/input-handling.d.ts +3 -0
  34. package/dist/components/editor/editor-methods/input-handling.d.ts.map +1 -0
  35. package/dist/components/editor/editor-methods/input-handling.js +257 -0
  36. package/dist/components/editor/editor-methods/input-handling.js.map +1 -0
  37. package/dist/components/editor/editor-methods/paste-submit.d.ts +7 -0
  38. package/dist/components/editor/editor-methods/paste-submit.d.ts.map +1 -0
  39. package/dist/components/editor/editor-methods/paste-submit.js +105 -0
  40. package/dist/components/editor/editor-methods/paste-submit.js.map +1 -0
  41. package/dist/components/editor/editor-methods/render.d.ts +3 -0
  42. package/dist/components/editor/editor-methods/render.d.ts.map +1 -0
  43. package/dist/components/editor/editor-methods/render.js +114 -0
  44. package/dist/components/editor/editor-methods/render.js.map +1 -0
  45. package/dist/components/editor/editor-methods/text-insertion.d.ts +4 -0
  46. package/dist/components/editor/editor-methods/text-insertion.d.ts.map +1 -0
  47. package/dist/components/editor/editor-methods/text-insertion.js +91 -0
  48. package/dist/components/editor/editor-methods/text-insertion.js.map +1 -0
  49. package/dist/components/editor/editor-methods/text-layout.d.ts +15 -0
  50. package/dist/components/editor/editor-methods/text-layout.d.ts.map +1 -0
  51. package/dist/components/editor/editor-methods/text-layout.js +129 -0
  52. package/dist/components/editor/editor-methods/text-layout.js.map +1 -0
  53. package/dist/components/editor/editor-methods/vertical-movement.d.ts +8 -0
  54. package/dist/components/editor/editor-methods/vertical-movement.d.ts.map +1 -0
  55. package/dist/components/editor/editor-methods/vertical-movement.js +123 -0
  56. package/dist/components/editor/editor-methods/vertical-movement.js.map +1 -0
  57. package/dist/components/editor/editor-methods/word-operations.d.ts +19 -0
  58. package/dist/components/editor/editor-methods/word-operations.d.ts.map +1 -0
  59. package/dist/components/editor/editor-methods/word-operations.js +122 -0
  60. package/dist/components/editor/editor-methods/word-operations.js.map +1 -0
  61. package/dist/components/editor/editor-methods/yank-undo.d.ts +11 -0
  62. package/dist/components/editor/editor-methods/yank-undo.d.ts.map +1 -0
  63. package/dist/components/editor/editor-methods/yank-undo.js +132 -0
  64. package/dist/components/editor/editor-methods/yank-undo.js.map +1 -0
  65. package/dist/components/editor/editor.d.ts +67 -0
  66. package/dist/components/editor/editor.d.ts.map +1 -0
  67. package/dist/components/editor/editor.js +93 -0
  68. package/dist/components/editor/editor.js.map +1 -0
  69. package/dist/components/editor/helpers.d.ts +3 -0
  70. package/dist/components/editor/helpers.d.ts.map +1 -0
  71. package/dist/components/editor/helpers.js +3 -0
  72. package/dist/components/editor/helpers.js.map +1 -0
  73. package/dist/components/editor/index.d.ts +4 -0
  74. package/dist/components/editor/index.d.ts.map +1 -0
  75. package/dist/components/editor/index.js +3 -0
  76. package/dist/components/editor/index.js.map +1 -0
  77. package/dist/components/editor/paste-marker.d.ts +5 -0
  78. package/dist/components/editor/paste-marker.d.ts.map +1 -0
  79. package/dist/components/editor/paste-marker.js +134 -0
  80. package/dist/components/editor/paste-marker.js.map +1 -0
  81. package/dist/components/editor/trigger-patterns.d.ts +4 -0
  82. package/dist/components/editor/trigger-patterns.d.ts.map +1 -0
  83. package/dist/components/editor/trigger-patterns.js +11 -0
  84. package/dist/components/editor/trigger-patterns.js.map +1 -0
  85. package/dist/components/editor/types.d.ts +25 -0
  86. package/dist/components/editor/types.d.ts.map +1 -0
  87. package/dist/components/editor/types.js +2 -0
  88. package/dist/components/editor/types.js.map +1 -0
  89. package/dist/components/editor.d.ts +1 -253
  90. package/dist/components/editor.d.ts.map +1 -1
  91. package/dist/components/editor.js +1 -1915
  92. package/dist/components/editor.js.map +1 -1
  93. package/dist/components/image.d.ts.map +1 -1
  94. package/dist/components/image.js.map +1 -1
  95. package/dist/components/input/constants.d.ts +2 -0
  96. package/dist/components/input/constants.d.ts.map +1 -0
  97. package/dist/components/input/constants.js +3 -0
  98. package/dist/components/input/constants.js.map +1 -0
  99. package/dist/components/input/index.d.ts +2 -0
  100. package/dist/components/input/index.d.ts.map +1 -0
  101. package/dist/components/input/index.js +2 -0
  102. package/dist/components/input/index.js.map +1 -0
  103. package/dist/components/input/input-methods/input-handling.d.ts +3 -0
  104. package/dist/components/input/input-methods/input-handling.d.ts.map +1 -0
  105. package/dist/components/input/input-methods/input-handling.js +145 -0
  106. package/dist/components/input/input-methods/input-handling.js.map +1 -0
  107. package/dist/components/input/input-methods/render.d.ts +3 -0
  108. package/dist/components/input/input-methods/render.d.ts.map +1 -0
  109. package/dist/components/input/input-methods/render.js +62 -0
  110. package/dist/components/input/input-methods/render.js.map +1 -0
  111. package/dist/components/input/input-methods/text-editing.d.ts +17 -0
  112. package/dist/components/input/input-methods/text-editing.d.ts.map +1 -0
  113. package/dist/components/input/input-methods/text-editing.js +145 -0
  114. package/dist/components/input/input-methods/text-editing.js.map +1 -0
  115. package/dist/components/input/input-methods/value-access.d.ts +4 -0
  116. package/dist/components/input/input-methods/value-access.d.ts.map +1 -0
  117. package/dist/components/input/input-methods/value-access.js +20 -0
  118. package/dist/components/input/input-methods/value-access.js.map +1 -0
  119. package/dist/components/input/input.d.ts +37 -0
  120. package/dist/components/input/input.d.ts.map +1 -0
  121. package/dist/components/input/input.js +77 -0
  122. package/dist/components/input/input.js.map +1 -0
  123. package/dist/components/input/types.d.ts +5 -0
  124. package/dist/components/input/types.d.ts.map +1 -0
  125. package/dist/components/input/types.js +2 -0
  126. package/dist/components/input/types.js.map +1 -0
  127. package/dist/components/input.d.ts +1 -36
  128. package/dist/components/input.d.ts.map +1 -1
  129. package/dist/components/input.js +1 -377
  130. package/dist/components/input.js.map +1 -1
  131. package/dist/components/loader.d.ts.map +1 -1
  132. package/dist/components/loader.js.map +1 -1
  133. package/dist/components/markdown/constants.d.ts +4 -0
  134. package/dist/components/markdown/constants.d.ts.map +1 -0
  135. package/dist/components/markdown/constants.js +8 -0
  136. package/dist/components/markdown/constants.js.map +1 -0
  137. package/dist/components/markdown/index.d.ts +3 -0
  138. package/dist/components/markdown/index.d.ts.map +1 -0
  139. package/dist/components/markdown/index.js +2 -0
  140. package/dist/components/markdown/index.js.map +1 -0
  141. package/dist/components/markdown/markdown-methods/inline-rendering.d.ts +7 -0
  142. package/dist/components/markdown/markdown-methods/inline-rendering.d.ts.map +1 -0
  143. package/dist/components/markdown/markdown-methods/inline-rendering.js +95 -0
  144. package/dist/components/markdown/markdown-methods/inline-rendering.js.map +1 -0
  145. package/dist/components/markdown/markdown-methods/list-table-helpers.d.ts +7 -0
  146. package/dist/components/markdown/markdown-methods/list-table-helpers.d.ts.map +1 -0
  147. package/dist/components/markdown/markdown-methods/list-table-helpers.js +61 -0
  148. package/dist/components/markdown/markdown-methods/list-table-helpers.js.map +1 -0
  149. package/dist/components/markdown/markdown-methods/table-rendering.d.ts +5 -0
  150. package/dist/components/markdown/markdown-methods/table-rendering.d.ts.map +1 -0
  151. package/dist/components/markdown/markdown-methods/table-rendering.js +146 -0
  152. package/dist/components/markdown/markdown-methods/table-rendering.js.map +1 -0
  153. package/dist/components/markdown/markdown-methods/text-rendering.d.ts +6 -0
  154. package/dist/components/markdown/markdown-methods/text-rendering.d.ts.map +1 -0
  155. package/dist/components/markdown/markdown-methods/text-rendering.js +115 -0
  156. package/dist/components/markdown/markdown-methods/text-rendering.js.map +1 -0
  157. package/dist/components/markdown/markdown-methods/theming.d.ts +6 -0
  158. package/dist/components/markdown/markdown-methods/theming.d.ts.map +1 -0
  159. package/dist/components/markdown/markdown-methods/theming.js +41 -0
  160. package/dist/components/markdown/markdown-methods/theming.js.map +1 -0
  161. package/dist/components/markdown/markdown-methods/token-rendering.d.ts +5 -0
  162. package/dist/components/markdown/markdown-methods/token-rendering.d.ts.map +1 -0
  163. package/dist/components/markdown/markdown-methods/token-rendering.js +142 -0
  164. package/dist/components/markdown/markdown-methods/token-rendering.js.map +1 -0
  165. package/dist/components/markdown/markdown.d.ts +32 -0
  166. package/dist/components/markdown/markdown.d.ts.map +1 -0
  167. package/dist/components/markdown/markdown.js +72 -0
  168. package/dist/components/markdown/markdown.js.map +1 -0
  169. package/dist/components/markdown/strictstrikethroughtokenizer.d.ts +6 -0
  170. package/dist/components/markdown/strictstrikethroughtokenizer.d.ts.map +1 -0
  171. package/dist/components/markdown/strictstrikethroughtokenizer.js +18 -0
  172. package/dist/components/markdown/strictstrikethroughtokenizer.js.map +1 -0
  173. package/dist/components/markdown/types.d.ts +42 -0
  174. package/dist/components/markdown/types.d.ts.map +1 -0
  175. package/dist/components/markdown/types.js +2 -0
  176. package/dist/components/markdown/types.js.map +1 -0
  177. package/dist/components/markdown.d.ts +1 -96
  178. package/dist/components/markdown.d.ts.map +1 -1
  179. package/dist/components/markdown.js +1 -653
  180. package/dist/components/markdown.js.map +1 -1
  181. package/dist/components/select-list.d.ts.map +1 -1
  182. package/dist/components/select-list.js +8 -3
  183. package/dist/components/select-list.js.map +1 -1
  184. package/dist/components/settings-list.d.ts.map +1 -1
  185. package/dist/components/settings-list.js +2 -6
  186. package/dist/components/settings-list.js.map +1 -1
  187. package/dist/components/spacer.d.ts.map +1 -1
  188. package/dist/components/spacer.js.map +1 -1
  189. package/dist/components/text.d.ts.map +1 -1
  190. package/dist/components/text.js +2 -2
  191. package/dist/components/text.js.map +1 -1
  192. package/dist/components/truncated-text.d.ts.map +1 -1
  193. package/dist/components/truncated-text.js.map +1 -1
  194. package/dist/editor-component.d.ts.map +1 -1
  195. package/dist/editor-component.js.map +1 -1
  196. package/dist/fuzzy.d.ts.map +1 -1
  197. package/dist/fuzzy.js.map +1 -1
  198. package/dist/index.d.ts +1 -1
  199. package/dist/index.d.ts.map +1 -1
  200. package/dist/index.js +1 -1
  201. package/dist/index.js.map +1 -1
  202. package/dist/keybindings.d.ts.map +1 -1
  203. package/dist/keybindings.js.map +1 -1
  204. package/dist/keys.d.ts.map +1 -1
  205. package/dist/keys.js +145 -14
  206. package/dist/keys.js.map +1 -1
  207. package/dist/kill-ring.d.ts.map +1 -1
  208. package/dist/kill-ring.js.map +1 -1
  209. package/dist/native-modifiers.d.ts +9 -0
  210. package/dist/native-modifiers.d.ts.map +1 -1
  211. package/dist/native-modifiers.js +5 -0
  212. package/dist/native-modifiers.js.map +1 -1
  213. package/dist/stdin-buffer.d.ts +3 -0
  214. package/dist/stdin-buffer.d.ts.map +1 -1
  215. package/dist/stdin-buffer.js +24 -21
  216. package/dist/stdin-buffer.js.map +1 -1
  217. package/dist/terminal/constants.d.ts +9 -0
  218. package/dist/terminal/constants.d.ts.map +1 -0
  219. package/dist/terminal/constants.js +10 -0
  220. package/dist/terminal/constants.js.map +1 -0
  221. package/dist/terminal/helpers.d.ts +6 -0
  222. package/dist/terminal/helpers.d.ts.map +1 -0
  223. package/dist/terminal/helpers.js +23 -0
  224. package/dist/terminal/helpers.js.map +1 -0
  225. package/dist/terminal/index.d.ts +4 -0
  226. package/dist/terminal/index.d.ts.map +1 -0
  227. package/dist/terminal/index.js +3 -0
  228. package/dist/terminal/index.js.map +1 -0
  229. package/dist/terminal/processterminal-methods/cursor-screen.d.ts +11 -0
  230. package/dist/terminal/processterminal-methods/cursor-screen.d.ts.map +1 -0
  231. package/dist/terminal/processterminal-methods/cursor-screen.js +50 -0
  232. package/dist/terminal/processterminal-methods/cursor-screen.js.map +1 -0
  233. package/dist/terminal/processterminal-methods/keyboard-protocol.d.ts +14 -0
  234. package/dist/terminal/processterminal-methods/keyboard-protocol.d.ts.map +1 -0
  235. package/dist/terminal/processterminal-methods/keyboard-protocol.js +147 -0
  236. package/dist/terminal/processterminal-methods/keyboard-protocol.js.map +1 -0
  237. package/dist/terminal/processterminal-methods/terminal-io.d.ts +9 -0
  238. package/dist/terminal/processterminal-methods/terminal-io.d.ts.map +1 -0
  239. package/dist/terminal/processterminal-methods/terminal-io.js +153 -0
  240. package/dist/terminal/processterminal-methods/terminal-io.js.map +1 -0
  241. package/dist/terminal/processterminal.d.ts +49 -0
  242. package/dist/terminal/processterminal.d.ts.map +1 -0
  243. package/dist/terminal/processterminal.js +129 -0
  244. package/dist/terminal/processterminal.js.map +1 -0
  245. package/dist/terminal/types.d.ts +31 -0
  246. package/dist/terminal/types.d.ts.map +1 -0
  247. package/dist/terminal/types.js +2 -0
  248. package/dist/terminal/types.js.map +1 -0
  249. package/dist/terminal-colors.d.ts +2 -0
  250. package/dist/terminal-colors.d.ts.map +1 -1
  251. package/dist/terminal-colors.js +17 -5
  252. package/dist/terminal-colors.js.map +1 -1
  253. package/dist/terminal-image.d.ts.map +1 -1
  254. package/dist/terminal-image.js.map +1 -1
  255. package/dist/terminal.d.ts +1 -109
  256. package/dist/terminal.d.ts.map +1 -1
  257. package/dist/terminal.js +1 -432
  258. package/dist/terminal.js.map +1 -1
  259. package/dist/tui/constants.d.ts +3 -0
  260. package/dist/tui/constants.d.ts.map +1 -0
  261. package/dist/tui/constants.js +3 -0
  262. package/dist/tui/constants.js.map +1 -0
  263. package/dist/tui/container.d.ts +10 -0
  264. package/dist/tui/container.d.ts.map +1 -0
  265. package/dist/tui/container.js +31 -0
  266. package/dist/tui/container.js.map +1 -0
  267. package/dist/tui/helpers.d.ts +8 -0
  268. package/dist/tui/helpers.d.ts.map +1 -0
  269. package/dist/tui/helpers.js +53 -0
  270. package/dist/tui/helpers.js.map +1 -0
  271. package/dist/tui/index.d.ts +6 -0
  272. package/dist/tui/index.d.ts.map +1 -0
  273. package/dist/tui/index.js +5 -0
  274. package/dist/tui/index.js.map +1 -0
  275. package/dist/tui/tui-methods/configuration.d.ts +20 -0
  276. package/dist/tui/tui-methods/configuration.d.ts.map +1 -0
  277. package/dist/tui/tui-methods/configuration.js +131 -0
  278. package/dist/tui/tui-methods/configuration.js.map +1 -0
  279. package/dist/tui/tui-methods/cursor-background.d.ts +10 -0
  280. package/dist/tui/tui-methods/cursor-background.d.ts.map +1 -0
  281. package/dist/tui/tui-methods/cursor-background.js +52 -0
  282. package/dist/tui/tui-methods/cursor-background.js.map +1 -0
  283. package/dist/tui/tui-methods/incremental-render.d.ts +17 -0
  284. package/dist/tui/tui-methods/incremental-render.d.ts.map +1 -0
  285. package/dist/tui/tui-methods/incremental-render.js +259 -0
  286. package/dist/tui/tui-methods/incremental-render.js.map +1 -0
  287. package/dist/tui/tui-methods/input-handling.d.ts +5 -0
  288. package/dist/tui/tui-methods/input-handling.d.ts.map +1 -0
  289. package/dist/tui/tui-methods/input-handling.js +111 -0
  290. package/dist/tui/tui-methods/input-handling.js.map +1 -0
  291. package/dist/tui/tui-methods/line-compositing.d.ts +7 -0
  292. package/dist/tui/tui-methods/line-compositing.d.ts.map +1 -0
  293. package/dist/tui/tui-methods/line-compositing.js +61 -0
  294. package/dist/tui/tui-methods/line-compositing.js.map +1 -0
  295. package/dist/tui/tui-methods/overlay-compositing.d.ts +12 -0
  296. package/dist/tui/tui-methods/overlay-compositing.d.ts.map +1 -0
  297. package/dist/tui/tui-methods/overlay-compositing.js +123 -0
  298. package/dist/tui/tui-methods/overlay-compositing.js.map +1 -0
  299. package/dist/tui/tui-methods/overlay-layout.d.ts +11 -0
  300. package/dist/tui/tui-methods/overlay-layout.d.ts.map +1 -0
  301. package/dist/tui/tui-methods/overlay-layout.js +124 -0
  302. package/dist/tui/tui-methods/overlay-layout.js.map +1 -0
  303. package/dist/tui/tui-methods/overlay-management.d.ts +11 -0
  304. package/dist/tui/tui-methods/overlay-management.d.ts.map +1 -0
  305. package/dist/tui/tui-methods/overlay-management.js +152 -0
  306. package/dist/tui/tui-methods/overlay-management.js.map +1 -0
  307. package/dist/tui/tui-methods/render-pipeline.d.ts +3 -0
  308. package/dist/tui/tui-methods/render-pipeline.d.ts.map +1 -0
  309. package/dist/tui/tui-methods/render-pipeline.js +176 -0
  310. package/dist/tui/tui-methods/render-pipeline.js.map +1 -0
  311. package/dist/tui/tui-methods/render-width-error.d.ts +3 -0
  312. package/dist/tui/tui-methods/render-width-error.d.ts.map +1 -0
  313. package/dist/tui/tui-methods/render-width-error.js +28 -0
  314. package/dist/tui/tui-methods/render-width-error.js.map +1 -0
  315. package/dist/tui/tui-methods/terminal-control.d.ts +8 -0
  316. package/dist/tui/tui-methods/terminal-control.d.ts.map +1 -0
  317. package/dist/tui/tui-methods/terminal-control.js +101 -0
  318. package/dist/tui/tui-methods/terminal-control.js.map +1 -0
  319. package/dist/tui/tui.d.ts +59 -0
  320. package/dist/tui/tui.d.ts.map +1 -0
  321. package/dist/tui/tui.js +78 -0
  322. package/dist/tui/tui.js.map +1 -0
  323. package/dist/tui/types.d.ts +124 -0
  324. package/dist/tui/types.d.ts.map +1 -0
  325. package/dist/tui/types.js +2 -0
  326. package/dist/tui/types.js.map +1 -0
  327. package/dist/tui.d.ts +1 -254
  328. package/dist/tui.d.ts.map +1 -1
  329. package/dist/tui.js +1 -1344
  330. package/dist/tui.js.map +1 -1
  331. package/dist/undo-stack.d.ts.map +1 -1
  332. package/dist/undo-stack.js.map +1 -1
  333. package/dist/utils/ansi-wrapping.d.ts +5 -0
  334. package/dist/utils/ansi-wrapping.d.ts.map +1 -0
  335. package/dist/utils/ansi-wrapping.js +52 -0
  336. package/dist/utils/ansi-wrapping.js.map +1 -0
  337. package/dist/utils/ansicodetracker.d.ts +27 -0
  338. package/dist/utils/ansicodetracker.d.ts.map +1 -0
  339. package/dist/utils/ansicodetracker.js +222 -0
  340. package/dist/utils/ansicodetracker.js.map +1 -0
  341. package/dist/utils/column-slicing.d.ts +12 -0
  342. package/dist/utils/column-slicing.d.ts.map +1 -0
  343. package/dist/utils/column-slicing.js +111 -0
  344. package/dist/utils/column-slicing.js.map +1 -0
  345. package/dist/utils/column-truncation.d.ts +2 -0
  346. package/dist/utils/column-truncation.d.ts.map +1 -0
  347. package/dist/utils/column-truncation.js +129 -0
  348. package/dist/utils/column-truncation.js.map +1 -0
  349. package/dist/utils/constants.d.ts +12 -0
  350. package/dist/utils/constants.d.ts.map +1 -0
  351. package/dist/utils/constants.js +12 -0
  352. package/dist/utils/constants.js.map +1 -0
  353. package/dist/utils/index.d.ts +8 -0
  354. package/dist/utils/index.d.ts.map +1 -0
  355. package/dist/utils/index.js +8 -0
  356. package/dist/utils/index.js.map +1 -0
  357. package/dist/utils/install-delegated-methods.d.ts +5 -0
  358. package/dist/utils/install-delegated-methods.d.ts.map +1 -0
  359. package/dist/utils/install-delegated-methods.js +27 -0
  360. package/dist/utils/install-delegated-methods.js.map +1 -0
  361. package/dist/utils/segmentation.d.ts +10 -0
  362. package/dist/utils/segmentation.d.ts.map +1 -0
  363. package/dist/utils/segmentation.js +111 -0
  364. package/dist/utils/segmentation.js.map +1 -0
  365. package/dist/utils/terminal-output.d.ts +10 -0
  366. package/dist/utils/terminal-output.d.ts.map +1 -0
  367. package/dist/utils/terminal-output.js +122 -0
  368. package/dist/utils/terminal-output.js.map +1 -0
  369. package/dist/utils/types.d.ts +7 -0
  370. package/dist/utils/types.d.ts.map +1 -0
  371. package/dist/utils/types.js +2 -0
  372. package/dist/utils/types.js.map +1 -0
  373. package/dist/utils/width-truncation.d.ts +6 -0
  374. package/dist/utils/width-truncation.d.ts.map +1 -0
  375. package/dist/utils/width-truncation.js +121 -0
  376. package/dist/utils/width-truncation.js.map +1 -0
  377. package/dist/utils/word-wrapping.d.ts +4 -0
  378. package/dist/utils/word-wrapping.d.ts.map +1 -0
  379. package/dist/utils/word-wrapping.js +139 -0
  380. package/dist/utils/word-wrapping.js.map +1 -0
  381. package/dist/utils.d.ts +1 -84
  382. package/dist/utils.d.ts.map +1 -1
  383. package/dist/utils.js +1 -1059
  384. package/dist/utils.js.map +1 -1
  385. package/dist/word-navigation.d.ts.map +1 -1
  386. package/dist/word-navigation.js.map +1 -1
  387. package/package.json +2 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/tui/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAgC;IAChF,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC1D,IAAI,aAAa,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAE3C,MAAM,WAAW,GAAG,aAAa,GAAG,qBAAqB,CAAC,MAAM,CAAC;IACjE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACjD,IAAI,SAAS,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAEvC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACzC,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,WAAW,IAAI,CAAC,IAAI,WAAW,GAAG,UAAU;YAAE,SAAS;QAC7F,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxB,CAAC;aAAM,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;YACvB,IAAI,GAAG,WAAW,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAAA,CACtB;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAY;IAC3D,OAAO,qBAAqB,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC;AAAA,CAC/C;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAU;IAC1D,OAAO,qBAAqB,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;AAAA,CAC/C;AAED,MAAM,UAAU,WAAW,CAAC,SAA2B,EAAsC;IAC3F,OAAO,SAAS,KAAK,IAAI,IAAI,SAAS,IAAI,SAAS,CAAC;AAAA,CACrD;AAED,MAAM,UAAU,cAAc,CAAC,KAA4B,EAAE,aAAqB,EAAsB;IACtG,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,qCAAqC;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAChD,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CAClB;AAED,MAAM,UAAU,eAAe,GAAY;IACzC,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAAA,CAC5C","sourcesContent":["import { KITTY_SEQUENCE_PREFIX } from \"./constants.ts\";\nimport type { Component, Focusable, KittyImageHeader, SizeValue } from \"./types.ts\";\n\nexport function parseKittyImageHeader(line: string): KittyImageHeader | undefined {\n const sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n if (sequenceStart === -1) return undefined;\n\n const paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n const paramsEnd = line.indexOf(\";\", paramsStart);\n if (paramsEnd === -1) return undefined;\n\n const ids: number[] = [];\n let rows = 1;\n const params = line.slice(paramsStart, paramsEnd);\n for (const param of params.split(\",\")) {\n const [key, value] = param.split(\"=\", 2);\n if (value === undefined) continue;\n const numberValue = Number(value);\n if (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff) continue;\n if (key === \"i\") {\n ids.push(numberValue);\n } else if (key === \"r\") {\n rows = numberValue;\n }\n }\n return { ids, rows };\n}\n\nexport function extractKittyImageIds(line: string): number[] {\n return parseKittyImageHeader(line)?.ids ?? [];\n}\n\nexport function extractKittyImageRows(line: string): number {\n return parseKittyImageHeader(line)?.rows ?? 1;\n}\n\nexport function isFocusable(component: Component | null): component is Component & Focusable {\n return component !== null && \"focused\" in component;\n}\n\nexport function parseSizeValue(value: SizeValue | undefined, referenceSize: number): number | undefined {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n // Parse percentage string like \"50%\"\n const match = value.match(/^(\\d+(?:\\.\\d+)?)%$/);\n if (match) {\n return Math.floor((referenceSize * parseFloat(match[1])) / 100);\n }\n return undefined;\n}\n\nexport function isTermuxSession(): boolean {\n return Boolean(process.env.TERMUX_VERSION);\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export { CURSOR_MARKER } from "./constants.ts";
2
+ export { Container } from "./container.ts";
3
+ export { isFocusable } from "./helpers.ts";
4
+ export { TUI } from "./tui.ts";
5
+ export type { Component, Focusable, OverlayAnchor, OverlayHandle, OverlayMargin, OverlayOptions, OverlayUnfocusOptions, SizeValue, } from "./types.ts";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,YAAY,EACV,SAAS,EACT,SAAS,EACT,aAAa,EACb,aAAa,EACb,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,SAAS,GACV,MAAM,YAAY,CAAC","sourcesContent":["export { CURSOR_MARKER } from \"./constants.ts\";\nexport { Container } from \"./container.ts\";\nexport { isFocusable } from \"./helpers.ts\";\nexport { TUI } from \"./tui.ts\";\nexport type {\n Component,\n Focusable,\n OverlayAnchor,\n OverlayHandle,\n OverlayMargin,\n OverlayOptions,\n OverlayUnfocusOptions,\n SizeValue,\n} from \"./types.ts\";\n"]}
@@ -0,0 +1,5 @@
1
+ export { CURSOR_MARKER } from "./constants.js";
2
+ export { Container } from "./container.js";
3
+ export { isFocusable } from "./helpers.js";
4
+ export { TUI } from "./tui.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export { CURSOR_MARKER } from \"./constants.ts\";\nexport { Container } from \"./container.ts\";\nexport { isFocusable } from \"./helpers.ts\";\nexport { TUI } from \"./tui.ts\";\nexport type {\n Component,\n Focusable,\n OverlayAnchor,\n OverlayHandle,\n OverlayMargin,\n OverlayOptions,\n OverlayUnfocusOptions,\n SizeValue,\n} from \"./types.ts\";\n"]}
@@ -0,0 +1,20 @@
1
+ import type { TUI } from "../tui.ts";
2
+ import type { BlockedOverlayFocusRestoreState, Component, OverlayFocusRestorePolicy, OverlayFocusRestoreState, OverlayStackEntry } from "../types.ts";
3
+ export declare function do_getShowHardwareCursor(self: TUI): boolean;
4
+ export declare function do_setShowHardwareCursor(self: TUI, enabled: boolean): void;
5
+ export declare function do_getClearOnShrink(self: TUI): boolean;
6
+ export declare function do_setClearOnShrink(self: TUI, enabled: boolean): void;
7
+ export declare function do_setFocus(self: TUI, component: Component | null): void;
8
+ export declare function do_setFocusInternal(self: TUI, { component, overlayFocusRestore }: {
9
+ component: Component | null;
10
+ overlayFocusRestore: OverlayFocusRestorePolicy;
11
+ }): void;
12
+ export declare function do_clearOverlayFocusRestore(self: TUI): void;
13
+ export declare function do_clearOverlayFocusRestoreFor(self: TUI, overlay: OverlayStackEntry): void;
14
+ export declare function do_resolveBlockedOverlayFocusResume(self: TUI, restoreState: BlockedOverlayFocusRestoreState): Component | null;
15
+ export declare function do_getVisibleOverlayFocusRestore(self: TUI): OverlayFocusRestoreState;
16
+ export declare function do_isOverlayFocusAncestor(self: TUI, entry: OverlayStackEntry, component: Component): boolean;
17
+ export declare function do_retargetOverlayPreFocus(self: TUI, removed: OverlayStackEntry): void;
18
+ export declare function do_isComponentMounted(self: TUI, component: Component): boolean;
19
+ export declare function do_containsComponent(self: TUI, root: Component, target: Component): boolean;
20
+ //# sourceMappingURL=configuration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration.d.ts","sourceRoot":"","sources":["../../../src/tui/tui-methods/configuration.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,EACV,+BAA+B,EAC/B,SAAS,EACT,yBAAyB,EACzB,wBAAwB,EACxB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAErB,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAE3D;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAO1E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAEtD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAErE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAExE;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,GAAG,EACT,EACE,SAAS,EACT,mBAAmB,EACpB,EAAE;IACD,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,mBAAmB,EAAE,yBAAyB,CAAC;CAChD,GACA,IAAI,CAyDN;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAE3D;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAI1F;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,+BAA+B,GAC5C,SAAS,GAAG,IAAI,CAIlB;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,GAAG,GAAG,wBAAwB,CAOpF;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAS5G;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAMtF;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAE9E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAI3F","sourcesContent":["import { Container } from \"../container.ts\";\nimport { isFocusable } from \"../helpers.ts\";\nimport type { TUI } from \"../tui.ts\";\nimport type {\n BlockedOverlayFocusRestoreState,\n Component,\n OverlayFocusRestorePolicy,\n OverlayFocusRestoreState,\n OverlayStackEntry,\n} from \"../types.ts\";\n\nexport function do_getShowHardwareCursor(self: TUI): boolean {\n return self.showHardwareCursor;\n}\n\nexport function do_setShowHardwareCursor(self: TUI, enabled: boolean): void {\n if (self.showHardwareCursor === enabled) return;\n self.showHardwareCursor = enabled;\n if (!enabled) {\n self.terminal.hideCursor();\n }\n self.requestRender();\n}\n\nexport function do_getClearOnShrink(self: TUI): boolean {\n return self.clearOnShrink;\n}\n\nexport function do_setClearOnShrink(self: TUI, enabled: boolean): void {\n self.clearOnShrink = enabled;\n}\n\nexport function do_setFocus(self: TUI, component: Component | null): void {\n self.setFocusInternal({ component, overlayFocusRestore: \"clear\" });\n}\n\nexport function do_setFocusInternal(\n self: TUI,\n {\n component,\n overlayFocusRestore,\n }: {\n component: Component | null;\n overlayFocusRestore: OverlayFocusRestorePolicy;\n },\n): void {\n const previousFocus = self.focusedComponent;\n let nextFocus = component;\n const previousFocusedOverlay = previousFocus\n ? self.overlayStack.find((entry) => entry.component === previousFocus && self.isOverlayVisible(entry))\n : undefined;\n const nextFocusIsOverlay = nextFocus ? self.overlayStack.some((entry) => entry.component === nextFocus) : false;\n const restoreState = self.getVisibleOverlayFocusRestore();\n if (nextFocus && !nextFocusIsOverlay) {\n if (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n if (restoreState.resume.status === \"focus-target\" || !self.isComponentMounted(restoreState.blockedBy)) {\n nextFocus = self.resolveBlockedOverlayFocusResume(restoreState);\n } else {\n self.overlayFocusRestore = {\n status: \"blocked\",\n overlay: restoreState.overlay,\n blockedBy: nextFocus,\n resume: restoreState.resume,\n };\n }\n } else if (\n previousFocusedOverlay &&\n restoreState.status !== \"inactive\" &&\n restoreState.overlay === previousFocusedOverlay &&\n !self.isOverlayFocusAncestor(previousFocusedOverlay, nextFocus)\n ) {\n self.overlayFocusRestore = {\n status: \"blocked\",\n overlay: previousFocusedOverlay,\n blockedBy: nextFocus,\n resume: { status: \"restore-overlay\" },\n };\n }\n } else if (nextFocus === null) {\n if (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n nextFocus = self.resolveBlockedOverlayFocusResume(restoreState);\n } else if (overlayFocusRestore === \"clear\") {\n self.clearOverlayFocusRestore();\n }\n }\n\n if (isFocusable(self.focusedComponent)) {\n self.focusedComponent.focused = false;\n }\n\n self.focusedComponent = nextFocus;\n\n if (isFocusable(nextFocus)) {\n nextFocus.focused = true;\n }\n\n const focusedOverlay = nextFocus\n ? self.overlayStack.find((entry) => entry.component === nextFocus && self.isOverlayVisible(entry))\n : undefined;\n if (focusedOverlay) {\n self.overlayFocusRestore = { status: \"eligible\", overlay: focusedOverlay };\n }\n}\n\nexport function do_clearOverlayFocusRestore(self: TUI): void {\n self.overlayFocusRestore = { status: \"inactive\" };\n}\n\nexport function do_clearOverlayFocusRestoreFor(self: TUI, overlay: OverlayStackEntry): void {\n if (self.overlayFocusRestore.status !== \"inactive\" && self.overlayFocusRestore.overlay === overlay) {\n self.clearOverlayFocusRestore();\n }\n}\n\nexport function do_resolveBlockedOverlayFocusResume(\n self: TUI,\n restoreState: BlockedOverlayFocusRestoreState,\n): Component | null {\n if (restoreState.resume.status === \"restore-overlay\") return restoreState.overlay.component;\n self.clearOverlayFocusRestore();\n return restoreState.resume.target;\n}\n\nexport function do_getVisibleOverlayFocusRestore(self: TUI): OverlayFocusRestoreState {\n const restoreState = self.overlayFocusRestore;\n if (restoreState.status === \"inactive\") return restoreState;\n if (!self.overlayStack.includes(restoreState.overlay) || !self.isOverlayVisible(restoreState.overlay)) {\n return { status: \"inactive\" };\n }\n return restoreState;\n}\n\nexport function do_isOverlayFocusAncestor(self: TUI, entry: OverlayStackEntry, component: Component): boolean {\n const visited = new Set<Component>();\n let current = entry.preFocus;\n while (current && !visited.has(current)) {\n visited.add(current);\n if (current === component) return true;\n current = self.overlayStack.find((overlay) => overlay.component === current)?.preFocus ?? null;\n }\n return false;\n}\n\nexport function do_retargetOverlayPreFocus(self: TUI, removed: OverlayStackEntry): void {\n for (const overlay of self.overlayStack) {\n if (overlay !== removed && overlay.preFocus === removed.component) {\n overlay.preFocus = removed.preFocus;\n }\n }\n}\n\nexport function do_isComponentMounted(self: TUI, component: Component): boolean {\n return self.children.some((child) => self.containsComponent(child, component));\n}\n\nexport function do_containsComponent(self: TUI, root: Component, target: Component): boolean {\n if (root === target) return true;\n if (!(root instanceof Container)) return false;\n return root.children.some((child) => self.containsComponent(child, target));\n}\n"]}
@@ -0,0 +1,131 @@
1
+ import { Container } from "../container.js";
2
+ import { isFocusable } from "../helpers.js";
3
+ export function do_getShowHardwareCursor(self) {
4
+ return self.showHardwareCursor;
5
+ }
6
+ export function do_setShowHardwareCursor(self, enabled) {
7
+ if (self.showHardwareCursor === enabled)
8
+ return;
9
+ self.showHardwareCursor = enabled;
10
+ if (!enabled) {
11
+ self.terminal.hideCursor();
12
+ }
13
+ self.requestRender();
14
+ }
15
+ export function do_getClearOnShrink(self) {
16
+ return self.clearOnShrink;
17
+ }
18
+ export function do_setClearOnShrink(self, enabled) {
19
+ self.clearOnShrink = enabled;
20
+ }
21
+ export function do_setFocus(self, component) {
22
+ self.setFocusInternal({ component, overlayFocusRestore: "clear" });
23
+ }
24
+ export function do_setFocusInternal(self, { component, overlayFocusRestore, }) {
25
+ const previousFocus = self.focusedComponent;
26
+ let nextFocus = component;
27
+ const previousFocusedOverlay = previousFocus
28
+ ? self.overlayStack.find((entry) => entry.component === previousFocus && self.isOverlayVisible(entry))
29
+ : undefined;
30
+ const nextFocusIsOverlay = nextFocus ? self.overlayStack.some((entry) => entry.component === nextFocus) : false;
31
+ const restoreState = self.getVisibleOverlayFocusRestore();
32
+ if (nextFocus && !nextFocusIsOverlay) {
33
+ if (restoreState.status === "blocked" && restoreState.blockedBy === previousFocus) {
34
+ if (restoreState.resume.status === "focus-target" || !self.isComponentMounted(restoreState.blockedBy)) {
35
+ nextFocus = self.resolveBlockedOverlayFocusResume(restoreState);
36
+ }
37
+ else {
38
+ self.overlayFocusRestore = {
39
+ status: "blocked",
40
+ overlay: restoreState.overlay,
41
+ blockedBy: nextFocus,
42
+ resume: restoreState.resume,
43
+ };
44
+ }
45
+ }
46
+ else if (previousFocusedOverlay &&
47
+ restoreState.status !== "inactive" &&
48
+ restoreState.overlay === previousFocusedOverlay &&
49
+ !self.isOverlayFocusAncestor(previousFocusedOverlay, nextFocus)) {
50
+ self.overlayFocusRestore = {
51
+ status: "blocked",
52
+ overlay: previousFocusedOverlay,
53
+ blockedBy: nextFocus,
54
+ resume: { status: "restore-overlay" },
55
+ };
56
+ }
57
+ }
58
+ else if (nextFocus === null) {
59
+ if (restoreState.status === "blocked" && restoreState.blockedBy === previousFocus) {
60
+ nextFocus = self.resolveBlockedOverlayFocusResume(restoreState);
61
+ }
62
+ else if (overlayFocusRestore === "clear") {
63
+ self.clearOverlayFocusRestore();
64
+ }
65
+ }
66
+ if (isFocusable(self.focusedComponent)) {
67
+ self.focusedComponent.focused = false;
68
+ }
69
+ self.focusedComponent = nextFocus;
70
+ if (isFocusable(nextFocus)) {
71
+ nextFocus.focused = true;
72
+ }
73
+ const focusedOverlay = nextFocus
74
+ ? self.overlayStack.find((entry) => entry.component === nextFocus && self.isOverlayVisible(entry))
75
+ : undefined;
76
+ if (focusedOverlay) {
77
+ self.overlayFocusRestore = { status: "eligible", overlay: focusedOverlay };
78
+ }
79
+ }
80
+ export function do_clearOverlayFocusRestore(self) {
81
+ self.overlayFocusRestore = { status: "inactive" };
82
+ }
83
+ export function do_clearOverlayFocusRestoreFor(self, overlay) {
84
+ if (self.overlayFocusRestore.status !== "inactive" && self.overlayFocusRestore.overlay === overlay) {
85
+ self.clearOverlayFocusRestore();
86
+ }
87
+ }
88
+ export function do_resolveBlockedOverlayFocusResume(self, restoreState) {
89
+ if (restoreState.resume.status === "restore-overlay")
90
+ return restoreState.overlay.component;
91
+ self.clearOverlayFocusRestore();
92
+ return restoreState.resume.target;
93
+ }
94
+ export function do_getVisibleOverlayFocusRestore(self) {
95
+ const restoreState = self.overlayFocusRestore;
96
+ if (restoreState.status === "inactive")
97
+ return restoreState;
98
+ if (!self.overlayStack.includes(restoreState.overlay) || !self.isOverlayVisible(restoreState.overlay)) {
99
+ return { status: "inactive" };
100
+ }
101
+ return restoreState;
102
+ }
103
+ export function do_isOverlayFocusAncestor(self, entry, component) {
104
+ const visited = new Set();
105
+ let current = entry.preFocus;
106
+ while (current && !visited.has(current)) {
107
+ visited.add(current);
108
+ if (current === component)
109
+ return true;
110
+ current = self.overlayStack.find((overlay) => overlay.component === current)?.preFocus ?? null;
111
+ }
112
+ return false;
113
+ }
114
+ export function do_retargetOverlayPreFocus(self, removed) {
115
+ for (const overlay of self.overlayStack) {
116
+ if (overlay !== removed && overlay.preFocus === removed.component) {
117
+ overlay.preFocus = removed.preFocus;
118
+ }
119
+ }
120
+ }
121
+ export function do_isComponentMounted(self, component) {
122
+ return self.children.some((child) => self.containsComponent(child, component));
123
+ }
124
+ export function do_containsComponent(self, root, target) {
125
+ if (root === target)
126
+ return true;
127
+ if (!(root instanceof Container))
128
+ return false;
129
+ return root.children.some((child) => self.containsComponent(child, target));
130
+ }
131
+ //# sourceMappingURL=configuration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration.js","sourceRoot":"","sources":["../../../src/tui/tui-methods/configuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAU5C,MAAM,UAAU,wBAAwB,CAAC,IAAS,EAAW;IAC3D,OAAO,IAAI,CAAC,kBAAkB,CAAC;AAAA,CAChC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAS,EAAE,OAAgB,EAAQ;IAC1E,IAAI,IAAI,CAAC,kBAAkB,KAAK,OAAO;QAAE,OAAO;IAChD,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC;IAClC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,aAAa,EAAE,CAAC;AAAA,CACtB;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAS,EAAW;IACtD,OAAO,IAAI,CAAC,aAAa,CAAC;AAAA,CAC3B;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAS,EAAE,OAAgB,EAAQ;IACrE,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;AAAA,CAC9B;AAED,MAAM,UAAU,WAAW,CAAC,IAAS,EAAE,SAA2B,EAAQ;IACxE,IAAI,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAC,CAAC;AAAA,CACpE;AAED,MAAM,UAAU,mBAAmB,CACjC,IAAS,EACT,EACE,SAAS,EACT,mBAAmB,GAIpB,EACK;IACN,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC;IAC5C,IAAI,SAAS,GAAG,SAAS,CAAC;IAC1B,MAAM,sBAAsB,GAAG,aAAa;QAC1C,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,aAAa,IAAI,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACtG,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,kBAAkB,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAChH,MAAM,YAAY,GAAG,IAAI,CAAC,6BAA6B,EAAE,CAAC;IAC1D,IAAI,SAAS,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACrC,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,IAAI,YAAY,CAAC,SAAS,KAAK,aAAa,EAAE,CAAC;YAClF,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,KAAK,cAAc,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;gBACtG,SAAS,GAAG,IAAI,CAAC,gCAAgC,CAAC,YAAY,CAAC,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,mBAAmB,GAAG;oBACzB,MAAM,EAAE,SAAS;oBACjB,OAAO,EAAE,YAAY,CAAC,OAAO;oBAC7B,SAAS,EAAE,SAAS;oBACpB,MAAM,EAAE,YAAY,CAAC,MAAM;iBAC5B,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,IACL,sBAAsB;YACtB,YAAY,CAAC,MAAM,KAAK,UAAU;YAClC,YAAY,CAAC,OAAO,KAAK,sBAAsB;YAC/C,CAAC,IAAI,CAAC,sBAAsB,CAAC,sBAAsB,EAAE,SAAS,CAAC,EAC/D,CAAC;YACD,IAAI,CAAC,mBAAmB,GAAG;gBACzB,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,sBAAsB;gBAC/B,SAAS,EAAE,SAAS;gBACpB,MAAM,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE;aACtC,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QAC9B,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,IAAI,YAAY,CAAC,SAAS,KAAK,aAAa,EAAE,CAAC;YAClF,SAAS,GAAG,IAAI,CAAC,gCAAgC,CAAC,YAAY,CAAC,CAAC;QAClE,CAAC;aAAM,IAAI,mBAAmB,KAAK,OAAO,EAAE,CAAC;YAC3C,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IAED,IAAI,WAAW,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,gBAAgB,CAAC,OAAO,GAAG,KAAK,CAAC;IACxC,CAAC;IAED,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;IAElC,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,MAAM,cAAc,GAAG,SAAS;QAC9B,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAClG,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,cAAc,EAAE,CAAC;QACnB,IAAI,CAAC,mBAAmB,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;IAC7E,CAAC;AAAA,CACF;AAED,MAAM,UAAU,2BAA2B,CAAC,IAAS,EAAQ;IAC3D,IAAI,CAAC,mBAAmB,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAAA,CACnD;AAED,MAAM,UAAU,8BAA8B,CAAC,IAAS,EAAE,OAA0B,EAAQ;IAC1F,IAAI,IAAI,CAAC,mBAAmB,CAAC,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,mBAAmB,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QACnG,IAAI,CAAC,wBAAwB,EAAE,CAAC;IAClC,CAAC;AAAA,CACF;AAED,MAAM,UAAU,mCAAmC,CACjD,IAAS,EACT,YAA6C,EAC3B;IAClB,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,KAAK,iBAAiB;QAAE,OAAO,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC;IAC5F,IAAI,CAAC,wBAAwB,EAAE,CAAC;IAChC,OAAO,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC;AAAA,CACnC;AAED,MAAM,UAAU,gCAAgC,CAAC,IAAS,EAA4B;IACpF,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,CAAC;IAC9C,IAAI,YAAY,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC;IAC5D,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;QACtG,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,YAAY,CAAC;AAAA,CACrB;AAED,MAAM,UAAU,yBAAyB,CAAC,IAAS,EAAE,KAAwB,EAAE,SAAoB,EAAW;IAC5G,MAAM,OAAO,GAAG,IAAI,GAAG,EAAa,CAAC;IACrC,IAAI,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC7B,OAAO,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACvC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IACjG,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACd;AAED,MAAM,UAAU,0BAA0B,CAAC,IAAS,EAAE,OAA0B,EAAQ;IACtF,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACxC,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC;YAClE,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACtC,CAAC;IACH,CAAC;AAAA,CACF;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAS,EAAE,SAAoB,EAAW;IAC9E,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;AAAA,CAChF;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAS,EAAE,IAAe,EAAE,MAAiB,EAAW;IAC3F,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,CAAC,CAAC,IAAI,YAAY,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAAA,CAC7E","sourcesContent":["import { Container } from \"../container.ts\";\nimport { isFocusable } from \"../helpers.ts\";\nimport type { TUI } from \"../tui.ts\";\nimport type {\n BlockedOverlayFocusRestoreState,\n Component,\n OverlayFocusRestorePolicy,\n OverlayFocusRestoreState,\n OverlayStackEntry,\n} from \"../types.ts\";\n\nexport function do_getShowHardwareCursor(self: TUI): boolean {\n return self.showHardwareCursor;\n}\n\nexport function do_setShowHardwareCursor(self: TUI, enabled: boolean): void {\n if (self.showHardwareCursor === enabled) return;\n self.showHardwareCursor = enabled;\n if (!enabled) {\n self.terminal.hideCursor();\n }\n self.requestRender();\n}\n\nexport function do_getClearOnShrink(self: TUI): boolean {\n return self.clearOnShrink;\n}\n\nexport function do_setClearOnShrink(self: TUI, enabled: boolean): void {\n self.clearOnShrink = enabled;\n}\n\nexport function do_setFocus(self: TUI, component: Component | null): void {\n self.setFocusInternal({ component, overlayFocusRestore: \"clear\" });\n}\n\nexport function do_setFocusInternal(\n self: TUI,\n {\n component,\n overlayFocusRestore,\n }: {\n component: Component | null;\n overlayFocusRestore: OverlayFocusRestorePolicy;\n },\n): void {\n const previousFocus = self.focusedComponent;\n let nextFocus = component;\n const previousFocusedOverlay = previousFocus\n ? self.overlayStack.find((entry) => entry.component === previousFocus && self.isOverlayVisible(entry))\n : undefined;\n const nextFocusIsOverlay = nextFocus ? self.overlayStack.some((entry) => entry.component === nextFocus) : false;\n const restoreState = self.getVisibleOverlayFocusRestore();\n if (nextFocus && !nextFocusIsOverlay) {\n if (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n if (restoreState.resume.status === \"focus-target\" || !self.isComponentMounted(restoreState.blockedBy)) {\n nextFocus = self.resolveBlockedOverlayFocusResume(restoreState);\n } else {\n self.overlayFocusRestore = {\n status: \"blocked\",\n overlay: restoreState.overlay,\n blockedBy: nextFocus,\n resume: restoreState.resume,\n };\n }\n } else if (\n previousFocusedOverlay &&\n restoreState.status !== \"inactive\" &&\n restoreState.overlay === previousFocusedOverlay &&\n !self.isOverlayFocusAncestor(previousFocusedOverlay, nextFocus)\n ) {\n self.overlayFocusRestore = {\n status: \"blocked\",\n overlay: previousFocusedOverlay,\n blockedBy: nextFocus,\n resume: { status: \"restore-overlay\" },\n };\n }\n } else if (nextFocus === null) {\n if (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n nextFocus = self.resolveBlockedOverlayFocusResume(restoreState);\n } else if (overlayFocusRestore === \"clear\") {\n self.clearOverlayFocusRestore();\n }\n }\n\n if (isFocusable(self.focusedComponent)) {\n self.focusedComponent.focused = false;\n }\n\n self.focusedComponent = nextFocus;\n\n if (isFocusable(nextFocus)) {\n nextFocus.focused = true;\n }\n\n const focusedOverlay = nextFocus\n ? self.overlayStack.find((entry) => entry.component === nextFocus && self.isOverlayVisible(entry))\n : undefined;\n if (focusedOverlay) {\n self.overlayFocusRestore = { status: \"eligible\", overlay: focusedOverlay };\n }\n}\n\nexport function do_clearOverlayFocusRestore(self: TUI): void {\n self.overlayFocusRestore = { status: \"inactive\" };\n}\n\nexport function do_clearOverlayFocusRestoreFor(self: TUI, overlay: OverlayStackEntry): void {\n if (self.overlayFocusRestore.status !== \"inactive\" && self.overlayFocusRestore.overlay === overlay) {\n self.clearOverlayFocusRestore();\n }\n}\n\nexport function do_resolveBlockedOverlayFocusResume(\n self: TUI,\n restoreState: BlockedOverlayFocusRestoreState,\n): Component | null {\n if (restoreState.resume.status === \"restore-overlay\") return restoreState.overlay.component;\n self.clearOverlayFocusRestore();\n return restoreState.resume.target;\n}\n\nexport function do_getVisibleOverlayFocusRestore(self: TUI): OverlayFocusRestoreState {\n const restoreState = self.overlayFocusRestore;\n if (restoreState.status === \"inactive\") return restoreState;\n if (!self.overlayStack.includes(restoreState.overlay) || !self.isOverlayVisible(restoreState.overlay)) {\n return { status: \"inactive\" };\n }\n return restoreState;\n}\n\nexport function do_isOverlayFocusAncestor(self: TUI, entry: OverlayStackEntry, component: Component): boolean {\n const visited = new Set<Component>();\n let current = entry.preFocus;\n while (current && !visited.has(current)) {\n visited.add(current);\n if (current === component) return true;\n current = self.overlayStack.find((overlay) => overlay.component === current)?.preFocus ?? null;\n }\n return false;\n}\n\nexport function do_retargetOverlayPreFocus(self: TUI, removed: OverlayStackEntry): void {\n for (const overlay of self.overlayStack) {\n if (overlay !== removed && overlay.preFocus === removed.component) {\n overlay.preFocus = removed.preFocus;\n }\n }\n}\n\nexport function do_isComponentMounted(self: TUI, component: Component): boolean {\n return self.children.some((child) => self.containsComponent(child, component));\n}\n\nexport function do_containsComponent(self: TUI, root: Component, target: Component): boolean {\n if (root === target) return true;\n if (!(root instanceof Container)) return false;\n return root.children.some((child) => self.containsComponent(child, target));\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { RgbColor } from "../../terminal-colors.ts";
2
+ import type { TUI } from "../tui.ts";
3
+ export declare function do_positionHardwareCursor(self: TUI, cursorPos: {
4
+ row: number;
5
+ col: number;
6
+ } | null, totalLines: number): void;
7
+ export declare function do_queryTerminalBackgroundColor(self: TUI, { timeoutMs }: {
8
+ timeoutMs: number;
9
+ }): Promise<RgbColor | undefined>;
10
+ //# sourceMappingURL=cursor-background.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-background.d.ts","sourceRoot":"","sources":["../../../src/tui/tui-methods/cursor-background.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,GAAG,EACT,SAAS,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC9C,UAAU,EAAE,MAAM,GACjB,IAAI,CA+BN;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,GAAG,EACT,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GACnC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAqB/B","sourcesContent":["import type { RgbColor } from \"../../terminal-colors.ts\";\nimport type { TUI } from \"../tui.ts\";\nimport type { PendingOsc11BackgroundQuery } from \"../types.ts\";\n\nexport function do_positionHardwareCursor(\n self: TUI,\n cursorPos: { row: number; col: number } | null,\n totalLines: number,\n): void {\n if (!cursorPos || totalLines <= 0) {\n self.terminal.hideCursor();\n return;\n }\n\n // Clamp cursor position to valid range\n const targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n const targetCol = Math.max(0, cursorPos.col);\n\n // Move cursor from current position to target\n const rowDelta = targetRow - self.hardwareCursorRow;\n let buffer = \"\";\n if (rowDelta > 0) {\n buffer += `\\x1b[${rowDelta}B`; // Move down\n } else if (rowDelta < 0) {\n buffer += `\\x1b[${-rowDelta}A`; // Move up\n }\n // Move to absolute column (1-indexed)\n buffer += `\\x1b[${targetCol + 1}G`;\n\n if (buffer) {\n self.terminal.write(buffer);\n }\n\n self.hardwareCursorRow = targetRow;\n if (self.showHardwareCursor) {\n self.terminal.showCursor();\n } else {\n self.terminal.hideCursor();\n }\n}\n\nexport function do_queryTerminalBackgroundColor(\n self: TUI,\n { timeoutMs }: { timeoutMs: number },\n): Promise<RgbColor | undefined> {\n return new Promise((resolve) => {\n const query: PendingOsc11BackgroundQuery = {\n settled: false,\n resolve,\n timer: undefined,\n };\n\n query.timer = setTimeout(() => {\n if (query.settled) {\n return;\n }\n query.settled = true;\n query.timer = undefined;\n query.resolve?.(undefined);\n query.resolve = undefined;\n }, timeoutMs);\n self.pendingOsc11BackgroundQueries.push(query);\n self.pendingOsc11BackgroundReplies += 1;\n self.terminal.write(\"\\x1b]11;?\\x07\");\n });\n}\n"]}
@@ -0,0 +1,52 @@
1
+ export function do_positionHardwareCursor(self, cursorPos, totalLines) {
2
+ if (!cursorPos || totalLines <= 0) {
3
+ self.terminal.hideCursor();
4
+ return;
5
+ }
6
+ // Clamp cursor position to valid range
7
+ const targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));
8
+ const targetCol = Math.max(0, cursorPos.col);
9
+ // Move cursor from current position to target
10
+ const rowDelta = targetRow - self.hardwareCursorRow;
11
+ let buffer = "";
12
+ if (rowDelta > 0) {
13
+ buffer += `\x1b[${rowDelta}B`; // Move down
14
+ }
15
+ else if (rowDelta < 0) {
16
+ buffer += `\x1b[${-rowDelta}A`; // Move up
17
+ }
18
+ // Move to absolute column (1-indexed)
19
+ buffer += `\x1b[${targetCol + 1}G`;
20
+ if (buffer) {
21
+ self.terminal.write(buffer);
22
+ }
23
+ self.hardwareCursorRow = targetRow;
24
+ if (self.showHardwareCursor) {
25
+ self.terminal.showCursor();
26
+ }
27
+ else {
28
+ self.terminal.hideCursor();
29
+ }
30
+ }
31
+ export function do_queryTerminalBackgroundColor(self, { timeoutMs }) {
32
+ return new Promise((resolve) => {
33
+ const query = {
34
+ settled: false,
35
+ resolve,
36
+ timer: undefined,
37
+ };
38
+ query.timer = setTimeout(() => {
39
+ if (query.settled) {
40
+ return;
41
+ }
42
+ query.settled = true;
43
+ query.timer = undefined;
44
+ query.resolve?.(undefined);
45
+ query.resolve = undefined;
46
+ }, timeoutMs);
47
+ self.pendingOsc11BackgroundQueries.push(query);
48
+ self.pendingOsc11BackgroundReplies += 1;
49
+ self.terminal.write("\x1b]11;?\x07");
50
+ });
51
+ }
52
+ //# sourceMappingURL=cursor-background.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-background.js","sourceRoot":"","sources":["../../../src/tui/tui-methods/cursor-background.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,yBAAyB,CACvC,IAAS,EACT,SAA8C,EAC9C,UAAkB,EACZ;IACN,IAAI,CAAC,SAAS,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IAE7C,8CAA8C;IAC9C,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC;IACpD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,MAAM,IAAI,QAAQ,QAAQ,GAAG,CAAC,CAAC,YAAY;IAC7C,CAAC;SAAM,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC,QAAQ,GAAG,CAAC,CAAC,UAAU;IAC5C,CAAC;IACD,sCAAsC;IACtC,MAAM,IAAI,QAAQ,SAAS,GAAG,CAAC,GAAG,CAAC;IAEnC,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;IACnC,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;AAAA,CACF;AAED,MAAM,UAAU,+BAA+B,CAC7C,IAAS,EACT,EAAE,SAAS,EAAyB,EACL;IAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAgC;YACzC,OAAO,EAAE,KAAK;YACd,OAAO;YACP,KAAK,EAAE,SAAS;SACjB,CAAC;QAEF,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,OAAO;YACT,CAAC;YACD,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;YACrB,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC;YACxB,KAAK,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;YAC3B,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;QAAA,CAC3B,EAAE,SAAS,CAAC,CAAC;QACd,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,6BAA6B,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAAA,CACtC,CAAC,CAAC;AAAA,CACJ","sourcesContent":["import type { RgbColor } from \"../../terminal-colors.ts\";\nimport type { TUI } from \"../tui.ts\";\nimport type { PendingOsc11BackgroundQuery } from \"../types.ts\";\n\nexport function do_positionHardwareCursor(\n self: TUI,\n cursorPos: { row: number; col: number } | null,\n totalLines: number,\n): void {\n if (!cursorPos || totalLines <= 0) {\n self.terminal.hideCursor();\n return;\n }\n\n // Clamp cursor position to valid range\n const targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n const targetCol = Math.max(0, cursorPos.col);\n\n // Move cursor from current position to target\n const rowDelta = targetRow - self.hardwareCursorRow;\n let buffer = \"\";\n if (rowDelta > 0) {\n buffer += `\\x1b[${rowDelta}B`; // Move down\n } else if (rowDelta < 0) {\n buffer += `\\x1b[${-rowDelta}A`; // Move up\n }\n // Move to absolute column (1-indexed)\n buffer += `\\x1b[${targetCol + 1}G`;\n\n if (buffer) {\n self.terminal.write(buffer);\n }\n\n self.hardwareCursorRow = targetRow;\n if (self.showHardwareCursor) {\n self.terminal.showCursor();\n } else {\n self.terminal.hideCursor();\n }\n}\n\nexport function do_queryTerminalBackgroundColor(\n self: TUI,\n { timeoutMs }: { timeoutMs: number },\n): Promise<RgbColor | undefined> {\n return new Promise((resolve) => {\n const query: PendingOsc11BackgroundQuery = {\n settled: false,\n resolve,\n timer: undefined,\n };\n\n query.timer = setTimeout(() => {\n if (query.settled) {\n return;\n }\n query.settled = true;\n query.timer = undefined;\n query.resolve?.(undefined);\n query.resolve = undefined;\n }, timeoutMs);\n self.pendingOsc11BackgroundQueries.push(query);\n self.pendingOsc11BackgroundReplies += 1;\n self.terminal.write(\"\\x1b]11;?\\x07\");\n });\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import type { TUI } from "../tui.ts";
2
+ export declare function renderIncremental(self: TUI, options: {
3
+ computeLineDiff: (targetRow: number) => number;
4
+ cursorPos: {
5
+ row: number;
6
+ col: number;
7
+ } | null;
8
+ fullRender: (clear: boolean) => void;
9
+ hardwareCursorRow: number;
10
+ height: number;
11
+ logRedraw: (reason: string) => void;
12
+ newLines: string[];
13
+ prevViewportTop: number;
14
+ viewportTop: number;
15
+ width: number;
16
+ }): void;
17
+ //# sourceMappingURL=incremental-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incremental-render.d.ts","sourceRoot":"","sources":["../../../src/tui/tui-methods/incremental-render.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,GAAG,EACT,OAAO,EAAE;IACP,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/C,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/C,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf,GACA,IAAI,CAyQN","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { isImageLine } from \"../../terminal-image.ts\";\nimport { visibleWidth } from \"../../utils.ts\";\nimport type { TUI } from \"../tui.ts\";\nimport { throwRenderWidthError } from \"./render-width-error.ts\";\n\nexport function renderIncremental(\n self: TUI,\n options: {\n computeLineDiff: (targetRow: number) => number;\n cursorPos: { row: number; col: number } | null;\n fullRender: (clear: boolean) => void;\n hardwareCursorRow: number;\n height: number;\n logRedraw: (reason: string) => void;\n newLines: string[];\n prevViewportTop: number;\n viewportTop: number;\n width: number;\n },\n): void {\n const { computeLineDiff, cursorPos, fullRender, height, logRedraw, newLines, width } = options;\n let { hardwareCursorRow, prevViewportTop, viewportTop } = options;\n // Find first and last changed lines\n let firstChanged = -1;\n let lastChanged = -1;\n const maxLines = Math.max(newLines.length, self.previousLines.length);\n for (let i = 0; i < maxLines; i++) {\n const oldLine = i < self.previousLines.length ? self.previousLines[i] : \"\";\n const newLine = i < newLines.length ? newLines[i] : \"\";\n\n if (oldLine !== newLine) {\n if (firstChanged === -1) {\n firstChanged = i;\n }\n lastChanged = i;\n }\n }\n const appendedLines = newLines.length > self.previousLines.length;\n if (appendedLines) {\n if (firstChanged === -1) {\n firstChanged = self.previousLines.length;\n }\n lastChanged = newLines.length - 1;\n }\n if (firstChanged !== -1) {\n const expandedRange = self.expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines);\n firstChanged = expandedRange.firstChanged;\n lastChanged = expandedRange.lastChanged;\n }\n const appendStart = appendedLines && firstChanged === self.previousLines.length && firstChanged > 0;\n\n // No changes - but still need to update hardware cursor position if it moved\n if (firstChanged === -1) {\n self.positionHardwareCursor(cursorPos, newLines.length);\n self.previousViewportTop = prevViewportTop;\n self.previousHeight = height;\n return;\n }\n\n // All changes are in deleted lines (nothing to render, just clear)\n if (firstChanged >= newLines.length) {\n if (self.previousLines.length > newLines.length) {\n let buffer = \"\\x1b[?2026h\";\n buffer += self.deleteChangedKittyImages(firstChanged, lastChanged);\n // Move to end of new content (clamp to 0 for empty content)\n const targetRow = Math.max(0, newLines.length - 1);\n if (targetRow < prevViewportTop) {\n logRedraw(`deleted lines moved viewport up (${targetRow} < ${prevViewportTop})`);\n fullRender(true);\n return;\n }\n const lineDiff = computeLineDiff(targetRow);\n if (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n else if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n buffer += \"\\r\";\n // Clear extra lines without scrolling\n const extraLines = self.previousLines.length - newLines.length;\n if (extraLines > height) {\n logRedraw(`extraLines > height (${extraLines} > ${height})`);\n fullRender(true);\n return;\n }\n const clearStartOffset = newLines.length === 0 ? 0 : 1;\n if (extraLines > 0 && clearStartOffset > 0) {\n buffer += `\\x1b[${clearStartOffset}B`;\n }\n for (let i = 0; i < extraLines; i++) {\n buffer += \"\\r\\x1b[2K\";\n if (i < extraLines - 1) buffer += \"\\x1b[1B\";\n }\n const moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n if (moveBack > 0) {\n buffer += `\\x1b[${moveBack}A`;\n }\n buffer += \"\\x1b[?2026l\";\n self.terminal.write(buffer);\n self.cursorRow = targetRow;\n self.hardwareCursorRow = targetRow;\n }\n self.positionHardwareCursor(cursorPos, newLines.length);\n self.previousLines = newLines;\n self.previousKittyImageIds = self.collectKittyImageIds(newLines);\n self.previousWidth = width;\n self.previousHeight = height;\n self.previousViewportTop = prevViewportTop;\n return;\n }\n\n // Differential rendering can only touch what was actually visible.\n // If the first changed line is above the previous viewport, redraw only the visible screen rows\n // without clearing scrollback (\\x1b[3J) or replaying the full history into stdout / dumping visible screen (\\x1b[2J).\n if (firstChanged < prevViewportTop) {\n logRedraw(`firstChanged < viewportTop (${firstChanged} < ${prevViewportTop})`);\n self.fullRedrawCount += 1;\n // Preserve the user's scroll position by adjusting for lines added/removed above the viewport.\n // Do NOT scroll to bottom just because content above changed (e.g., tool output expansion).\n const lineDelta = newLines.length - self.previousLines.length;\n const newViewportTop = Math.max(0, Math.min(prevViewportTop + lineDelta, Math.max(0, newLines.length - height)));\n let buffer = \"\\x1b[?2026h\\x1b[H\";\n buffer += self.deleteChangedKittyImages(0, newLines.length - 1);\n const visibleEnd = Math.min(newLines.length, newViewportTop + height);\n for (let i = newViewportTop; i < visibleEnd; i++) {\n buffer += \"\\x1b[2K\";\n buffer += newLines[i];\n if (i < visibleEnd - 1) {\n buffer += \"\\r\\n\";\n }\n }\n const renderedCount = visibleEnd - newViewportTop;\n if (renderedCount < height) {\n for (let i = renderedCount; i < height; i++) {\n buffer += \"\\r\\n\\x1b[2K\";\n }\n const moveBack = height - renderedCount;\n if (moveBack > 0) {\n buffer += `\\x1b[${moveBack}A`;\n }\n }\n buffer += \"\\x1b[?2026l\";\n self.terminal.write(buffer);\n self.previousLines = newLines;\n self.previousKittyImageIds = self.collectKittyImageIds(newLines);\n self.previousWidth = width;\n self.previousHeight = height;\n self.previousViewportTop = newViewportTop;\n self.cursorRow = Math.max(0, visibleEnd - 1);\n self.hardwareCursorRow = self.cursorRow;\n self.maxLinesRendered = Math.max(self.maxLinesRendered, newLines.length);\n self.positionHardwareCursor(cursorPos, newLines.length);\n return;\n }\n\n // Render from first changed line to end\n // Build buffer with all updates wrapped in synchronized output\n let buffer = \"\\x1b[?2026h\"; // Begin synchronized output\n buffer += self.deleteChangedKittyImages(firstChanged, lastChanged);\n const prevViewportBottom = prevViewportTop + height - 1;\n const moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;\n if (moveTargetRow > prevViewportBottom) {\n const currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));\n const moveToBottom = height - 1 - currentScreenRow;\n if (moveToBottom > 0) {\n buffer += `\\x1b[${moveToBottom}B`;\n }\n const scroll = moveTargetRow - prevViewportBottom;\n buffer += \"\\r\\n\".repeat(scroll);\n prevViewportTop += scroll;\n viewportTop += scroll;\n hardwareCursorRow = moveTargetRow;\n }\n\n // Move cursor to first changed line (use hardwareCursorRow for actual position)\n const lineDiff = computeLineDiff(moveTargetRow);\n if (lineDiff > 0) {\n buffer += `\\x1b[${lineDiff}B`; // Move down\n } else if (lineDiff < 0) {\n buffer += `\\x1b[${-lineDiff}A`; // Move up\n }\n\n buffer += appendStart ? \"\\r\\n\" : \"\\r\"; // Move to column 0\n\n // Only render changed lines (firstChanged to lastChanged), not all lines to end\n // This reduces flicker when only a single line changes (e.g., spinner animation)\n const renderEnd = Math.min(lastChanged, newLines.length - 1);\n for (let i = firstChanged; i <= renderEnd; i++) {\n if (i > firstChanged) buffer += \"\\r\\n\";\n const line = newLines[i];\n const isImage = isImageLine(line);\n const imageReservedRows = isImage ? self.getKittyImageReservedRows(newLines, i, renderEnd) : 1;\n if (imageReservedRows > 1) {\n const imageStartScreenRow = i - viewportTop;\n if (imageStartScreenRow < 0 || imageStartScreenRow + imageReservedRows > height) {\n logRedraw(`kitty image pre-clear would scroll (${imageStartScreenRow} + ${imageReservedRows} > ${height})`);\n fullRender(true);\n return;\n }\n\n buffer += \"\\x1b[2K\";\n for (let row = 1; row < imageReservedRows; row++) {\n buffer += \"\\r\\n\\x1b[2K\";\n }\n buffer += `\\x1b[${imageReservedRows - 1}A`;\n buffer += line;\n buffer += `\\x1b[${imageReservedRows - 1}B`;\n i += imageReservedRows - 1;\n continue;\n }\n\n buffer += \"\\x1b[2K\"; // Clear current line\n if (!isImage && visibleWidth(line) > width) {\n throwRenderWidthError(self, newLines, line, i, width);\n }\n buffer += line;\n }\n\n // Track where cursor ended up after rendering\n let finalCursorRow = renderEnd;\n\n // If we had more lines before, clear them and move cursor back\n if (self.previousLines.length > newLines.length) {\n // Move to end of new content first if we stopped before it\n if (renderEnd < newLines.length - 1) {\n const moveDown = newLines.length - 1 - renderEnd;\n buffer += `\\x1b[${moveDown}B`;\n finalCursorRow = newLines.length - 1;\n }\n const extraLines = self.previousLines.length - newLines.length;\n for (let i = newLines.length; i < self.previousLines.length; i++) {\n buffer += \"\\r\\n\\x1b[2K\";\n }\n // Move cursor back to end of new content\n buffer += `\\x1b[${extraLines}A`;\n }\n\n buffer += \"\\x1b[?2026l\"; // End synchronized output\n\n if (process.env.PI_TUI_DEBUG === \"1\") {\n const debugDir = \"/tmp/tui\";\n fs.mkdirSync(debugDir, { recursive: true });\n const debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n const debugData = [\n `firstChanged: ${firstChanged}`,\n `viewportTop: ${viewportTop}`,\n `cursorRow: ${self.cursorRow}`,\n `height: ${height}`,\n `lineDiff: ${lineDiff}`,\n `hardwareCursorRow: ${hardwareCursorRow}`,\n `renderEnd: ${renderEnd}`,\n `finalCursorRow: ${finalCursorRow}`,\n `cursorPos: ${JSON.stringify(cursorPos)}`,\n `newLines.length: ${newLines.length}`,\n `previousLines.length: ${self.previousLines.length}`,\n \"\",\n \"=== newLines ===\",\n JSON.stringify(newLines, null, 2),\n \"\",\n \"=== previousLines ===\",\n JSON.stringify(self.previousLines, null, 2),\n \"\",\n \"=== buffer ===\",\n JSON.stringify(buffer),\n ].join(\"\\n\");\n fs.writeFileSync(debugPath, debugData);\n }\n\n // Write entire buffer at once\n self.terminal.write(buffer);\n\n // Track cursor position for next render\n // cursorRow tracks end of content (for viewport calculation)\n // hardwareCursorRow tracks actual terminal cursor position (for movement)\n self.cursorRow = Math.max(0, newLines.length - 1);\n self.hardwareCursorRow = finalCursorRow;\n // Track terminal's working area (grows but doesn't shrink unless cleared)\n self.maxLinesRendered = Math.max(self.maxLinesRendered, newLines.length);\n self.previousViewportTop = Math.max(prevViewportTop, finalCursorRow - height + 1);\n\n // Position hardware cursor for IME\n self.positionHardwareCursor(cursorPos, newLines.length);\n\n self.previousLines = newLines;\n self.previousKittyImageIds = self.collectKittyImageIds(newLines);\n self.previousWidth = width;\n self.previousHeight = height;\n}\n"]}
@@ -0,0 +1,259 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { isImageLine } from "../../terminal-image.js";
4
+ import { visibleWidth } from "../../utils.js";
5
+ import { throwRenderWidthError } from "./render-width-error.js";
6
+ export function renderIncremental(self, options) {
7
+ const { computeLineDiff, cursorPos, fullRender, height, logRedraw, newLines, width } = options;
8
+ let { hardwareCursorRow, prevViewportTop, viewportTop } = options;
9
+ // Find first and last changed lines
10
+ let firstChanged = -1;
11
+ let lastChanged = -1;
12
+ const maxLines = Math.max(newLines.length, self.previousLines.length);
13
+ for (let i = 0; i < maxLines; i++) {
14
+ const oldLine = i < self.previousLines.length ? self.previousLines[i] : "";
15
+ const newLine = i < newLines.length ? newLines[i] : "";
16
+ if (oldLine !== newLine) {
17
+ if (firstChanged === -1) {
18
+ firstChanged = i;
19
+ }
20
+ lastChanged = i;
21
+ }
22
+ }
23
+ const appendedLines = newLines.length > self.previousLines.length;
24
+ if (appendedLines) {
25
+ if (firstChanged === -1) {
26
+ firstChanged = self.previousLines.length;
27
+ }
28
+ lastChanged = newLines.length - 1;
29
+ }
30
+ if (firstChanged !== -1) {
31
+ const expandedRange = self.expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines);
32
+ firstChanged = expandedRange.firstChanged;
33
+ lastChanged = expandedRange.lastChanged;
34
+ }
35
+ const appendStart = appendedLines && firstChanged === self.previousLines.length && firstChanged > 0;
36
+ // No changes - but still need to update hardware cursor position if it moved
37
+ if (firstChanged === -1) {
38
+ self.positionHardwareCursor(cursorPos, newLines.length);
39
+ self.previousViewportTop = prevViewportTop;
40
+ self.previousHeight = height;
41
+ return;
42
+ }
43
+ // All changes are in deleted lines (nothing to render, just clear)
44
+ if (firstChanged >= newLines.length) {
45
+ if (self.previousLines.length > newLines.length) {
46
+ let buffer = "\x1b[?2026h";
47
+ buffer += self.deleteChangedKittyImages(firstChanged, lastChanged);
48
+ // Move to end of new content (clamp to 0 for empty content)
49
+ const targetRow = Math.max(0, newLines.length - 1);
50
+ if (targetRow < prevViewportTop) {
51
+ logRedraw(`deleted lines moved viewport up (${targetRow} < ${prevViewportTop})`);
52
+ fullRender(true);
53
+ return;
54
+ }
55
+ const lineDiff = computeLineDiff(targetRow);
56
+ if (lineDiff > 0)
57
+ buffer += `\x1b[${lineDiff}B`;
58
+ else if (lineDiff < 0)
59
+ buffer += `\x1b[${-lineDiff}A`;
60
+ buffer += "\r";
61
+ // Clear extra lines without scrolling
62
+ const extraLines = self.previousLines.length - newLines.length;
63
+ if (extraLines > height) {
64
+ logRedraw(`extraLines > height (${extraLines} > ${height})`);
65
+ fullRender(true);
66
+ return;
67
+ }
68
+ const clearStartOffset = newLines.length === 0 ? 0 : 1;
69
+ if (extraLines > 0 && clearStartOffset > 0) {
70
+ buffer += `\x1b[${clearStartOffset}B`;
71
+ }
72
+ for (let i = 0; i < extraLines; i++) {
73
+ buffer += "\r\x1b[2K";
74
+ if (i < extraLines - 1)
75
+ buffer += "\x1b[1B";
76
+ }
77
+ const moveBack = Math.max(0, extraLines - 1 + clearStartOffset);
78
+ if (moveBack > 0) {
79
+ buffer += `\x1b[${moveBack}A`;
80
+ }
81
+ buffer += "\x1b[?2026l";
82
+ self.terminal.write(buffer);
83
+ self.cursorRow = targetRow;
84
+ self.hardwareCursorRow = targetRow;
85
+ }
86
+ self.positionHardwareCursor(cursorPos, newLines.length);
87
+ self.previousLines = newLines;
88
+ self.previousKittyImageIds = self.collectKittyImageIds(newLines);
89
+ self.previousWidth = width;
90
+ self.previousHeight = height;
91
+ self.previousViewportTop = prevViewportTop;
92
+ return;
93
+ }
94
+ // Differential rendering can only touch what was actually visible.
95
+ // If the first changed line is above the previous viewport, redraw only the visible screen rows
96
+ // without clearing scrollback (\x1b[3J) or replaying the full history into stdout / dumping visible screen (\x1b[2J).
97
+ if (firstChanged < prevViewportTop) {
98
+ logRedraw(`firstChanged < viewportTop (${firstChanged} < ${prevViewportTop})`);
99
+ self.fullRedrawCount += 1;
100
+ // Preserve the user's scroll position by adjusting for lines added/removed above the viewport.
101
+ // Do NOT scroll to bottom just because content above changed (e.g., tool output expansion).
102
+ const lineDelta = newLines.length - self.previousLines.length;
103
+ const newViewportTop = Math.max(0, Math.min(prevViewportTop + lineDelta, Math.max(0, newLines.length - height)));
104
+ let buffer = "\x1b[?2026h\x1b[H";
105
+ buffer += self.deleteChangedKittyImages(0, newLines.length - 1);
106
+ const visibleEnd = Math.min(newLines.length, newViewportTop + height);
107
+ for (let i = newViewportTop; i < visibleEnd; i++) {
108
+ buffer += "\x1b[2K";
109
+ buffer += newLines[i];
110
+ if (i < visibleEnd - 1) {
111
+ buffer += "\r\n";
112
+ }
113
+ }
114
+ const renderedCount = visibleEnd - newViewportTop;
115
+ if (renderedCount < height) {
116
+ for (let i = renderedCount; i < height; i++) {
117
+ buffer += "\r\n\x1b[2K";
118
+ }
119
+ const moveBack = height - renderedCount;
120
+ if (moveBack > 0) {
121
+ buffer += `\x1b[${moveBack}A`;
122
+ }
123
+ }
124
+ buffer += "\x1b[?2026l";
125
+ self.terminal.write(buffer);
126
+ self.previousLines = newLines;
127
+ self.previousKittyImageIds = self.collectKittyImageIds(newLines);
128
+ self.previousWidth = width;
129
+ self.previousHeight = height;
130
+ self.previousViewportTop = newViewportTop;
131
+ self.cursorRow = Math.max(0, visibleEnd - 1);
132
+ self.hardwareCursorRow = self.cursorRow;
133
+ self.maxLinesRendered = Math.max(self.maxLinesRendered, newLines.length);
134
+ self.positionHardwareCursor(cursorPos, newLines.length);
135
+ return;
136
+ }
137
+ // Render from first changed line to end
138
+ // Build buffer with all updates wrapped in synchronized output
139
+ let buffer = "\x1b[?2026h"; // Begin synchronized output
140
+ buffer += self.deleteChangedKittyImages(firstChanged, lastChanged);
141
+ const prevViewportBottom = prevViewportTop + height - 1;
142
+ const moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;
143
+ if (moveTargetRow > prevViewportBottom) {
144
+ const currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));
145
+ const moveToBottom = height - 1 - currentScreenRow;
146
+ if (moveToBottom > 0) {
147
+ buffer += `\x1b[${moveToBottom}B`;
148
+ }
149
+ const scroll = moveTargetRow - prevViewportBottom;
150
+ buffer += "\r\n".repeat(scroll);
151
+ prevViewportTop += scroll;
152
+ viewportTop += scroll;
153
+ hardwareCursorRow = moveTargetRow;
154
+ }
155
+ // Move cursor to first changed line (use hardwareCursorRow for actual position)
156
+ const lineDiff = computeLineDiff(moveTargetRow);
157
+ if (lineDiff > 0) {
158
+ buffer += `\x1b[${lineDiff}B`; // Move down
159
+ }
160
+ else if (lineDiff < 0) {
161
+ buffer += `\x1b[${-lineDiff}A`; // Move up
162
+ }
163
+ buffer += appendStart ? "\r\n" : "\r"; // Move to column 0
164
+ // Only render changed lines (firstChanged to lastChanged), not all lines to end
165
+ // This reduces flicker when only a single line changes (e.g., spinner animation)
166
+ const renderEnd = Math.min(lastChanged, newLines.length - 1);
167
+ for (let i = firstChanged; i <= renderEnd; i++) {
168
+ if (i > firstChanged)
169
+ buffer += "\r\n";
170
+ const line = newLines[i];
171
+ const isImage = isImageLine(line);
172
+ const imageReservedRows = isImage ? self.getKittyImageReservedRows(newLines, i, renderEnd) : 1;
173
+ if (imageReservedRows > 1) {
174
+ const imageStartScreenRow = i - viewportTop;
175
+ if (imageStartScreenRow < 0 || imageStartScreenRow + imageReservedRows > height) {
176
+ logRedraw(`kitty image pre-clear would scroll (${imageStartScreenRow} + ${imageReservedRows} > ${height})`);
177
+ fullRender(true);
178
+ return;
179
+ }
180
+ buffer += "\x1b[2K";
181
+ for (let row = 1; row < imageReservedRows; row++) {
182
+ buffer += "\r\n\x1b[2K";
183
+ }
184
+ buffer += `\x1b[${imageReservedRows - 1}A`;
185
+ buffer += line;
186
+ buffer += `\x1b[${imageReservedRows - 1}B`;
187
+ i += imageReservedRows - 1;
188
+ continue;
189
+ }
190
+ buffer += "\x1b[2K"; // Clear current line
191
+ if (!isImage && visibleWidth(line) > width) {
192
+ throwRenderWidthError(self, newLines, line, i, width);
193
+ }
194
+ buffer += line;
195
+ }
196
+ // Track where cursor ended up after rendering
197
+ let finalCursorRow = renderEnd;
198
+ // If we had more lines before, clear them and move cursor back
199
+ if (self.previousLines.length > newLines.length) {
200
+ // Move to end of new content first if we stopped before it
201
+ if (renderEnd < newLines.length - 1) {
202
+ const moveDown = newLines.length - 1 - renderEnd;
203
+ buffer += `\x1b[${moveDown}B`;
204
+ finalCursorRow = newLines.length - 1;
205
+ }
206
+ const extraLines = self.previousLines.length - newLines.length;
207
+ for (let i = newLines.length; i < self.previousLines.length; i++) {
208
+ buffer += "\r\n\x1b[2K";
209
+ }
210
+ // Move cursor back to end of new content
211
+ buffer += `\x1b[${extraLines}A`;
212
+ }
213
+ buffer += "\x1b[?2026l"; // End synchronized output
214
+ if (process.env.PI_TUI_DEBUG === "1") {
215
+ const debugDir = "/tmp/tui";
216
+ fs.mkdirSync(debugDir, { recursive: true });
217
+ const debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);
218
+ const debugData = [
219
+ `firstChanged: ${firstChanged}`,
220
+ `viewportTop: ${viewportTop}`,
221
+ `cursorRow: ${self.cursorRow}`,
222
+ `height: ${height}`,
223
+ `lineDiff: ${lineDiff}`,
224
+ `hardwareCursorRow: ${hardwareCursorRow}`,
225
+ `renderEnd: ${renderEnd}`,
226
+ `finalCursorRow: ${finalCursorRow}`,
227
+ `cursorPos: ${JSON.stringify(cursorPos)}`,
228
+ `newLines.length: ${newLines.length}`,
229
+ `previousLines.length: ${self.previousLines.length}`,
230
+ "",
231
+ "=== newLines ===",
232
+ JSON.stringify(newLines, null, 2),
233
+ "",
234
+ "=== previousLines ===",
235
+ JSON.stringify(self.previousLines, null, 2),
236
+ "",
237
+ "=== buffer ===",
238
+ JSON.stringify(buffer),
239
+ ].join("\n");
240
+ fs.writeFileSync(debugPath, debugData);
241
+ }
242
+ // Write entire buffer at once
243
+ self.terminal.write(buffer);
244
+ // Track cursor position for next render
245
+ // cursorRow tracks end of content (for viewport calculation)
246
+ // hardwareCursorRow tracks actual terminal cursor position (for movement)
247
+ self.cursorRow = Math.max(0, newLines.length - 1);
248
+ self.hardwareCursorRow = finalCursorRow;
249
+ // Track terminal's working area (grows but doesn't shrink unless cleared)
250
+ self.maxLinesRendered = Math.max(self.maxLinesRendered, newLines.length);
251
+ self.previousViewportTop = Math.max(prevViewportTop, finalCursorRow - height + 1);
252
+ // Position hardware cursor for IME
253
+ self.positionHardwareCursor(cursorPos, newLines.length);
254
+ self.previousLines = newLines;
255
+ self.previousKittyImageIds = self.collectKittyImageIds(newLines);
256
+ self.previousWidth = width;
257
+ self.previousHeight = height;
258
+ }
259
+ //# sourceMappingURL=incremental-render.js.map