@vybestack/llxprt-code 0.1.12

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 (575) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +256 -0
  3. package/dist/.last_build +0 -0
  4. package/dist/index.d.ts +7 -0
  5. package/dist/index.js +21 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/package.json +95 -0
  8. package/dist/src/config/auth.d.ts +6 -0
  9. package/dist/src/config/auth.js +42 -0
  10. package/dist/src/config/auth.js.map +1 -0
  11. package/dist/src/config/config.d.ts +41 -0
  12. package/dist/src/config/config.js +345 -0
  13. package/dist/src/config/config.js.map +1 -0
  14. package/dist/src/config/extension.d.ts +21 -0
  15. package/dist/src/config/extension.js +109 -0
  16. package/dist/src/config/extension.js.map +1 -0
  17. package/dist/src/config/sandboxConfig.d.ts +13 -0
  18. package/dist/src/config/sandboxConfig.js +75 -0
  19. package/dist/src/config/sandboxConfig.js.map +1 -0
  20. package/dist/src/config/settings.d.ts +88 -0
  21. package/dist/src/config/settings.js +263 -0
  22. package/dist/src/config/settings.js.map +1 -0
  23. package/dist/src/gemini.d.ts +6 -0
  24. package/dist/src/gemini.js +420 -0
  25. package/dist/src/gemini.js.map +1 -0
  26. package/dist/src/generated/git-commit.d.ts +6 -0
  27. package/dist/src/generated/git-commit.js +9 -0
  28. package/dist/src/generated/git-commit.js.map +1 -0
  29. package/dist/src/nonInteractiveCli.d.ts +7 -0
  30. package/dist/src/nonInteractiveCli.js +131 -0
  31. package/dist/src/nonInteractiveCli.js.map +1 -0
  32. package/dist/src/providers/IMessage.d.ts +38 -0
  33. package/dist/src/providers/IMessage.js +17 -0
  34. package/dist/src/providers/IMessage.js.map +1 -0
  35. package/dist/src/providers/IModel.d.ts +23 -0
  36. package/dist/src/providers/IModel.js +17 -0
  37. package/dist/src/providers/IModel.js.map +1 -0
  38. package/dist/src/providers/IProvider.d.ts +32 -0
  39. package/dist/src/providers/IProvider.js +17 -0
  40. package/dist/src/providers/IProvider.js.map +1 -0
  41. package/dist/src/providers/ITool.d.ts +23 -0
  42. package/dist/src/providers/ITool.js +17 -0
  43. package/dist/src/providers/ITool.js.map +1 -0
  44. package/dist/src/providers/ProviderAwareContentGenerator.d.ts +6 -0
  45. package/dist/src/providers/ProviderAwareContentGenerator.js +9 -0
  46. package/dist/src/providers/ProviderAwareContentGenerator.js.map +1 -0
  47. package/dist/src/providers/ProviderManager.d.ts +19 -0
  48. package/dist/src/providers/ProviderManager.js +63 -0
  49. package/dist/src/providers/ProviderManager.js.map +1 -0
  50. package/dist/src/providers/ProviderManagerAdapter.d.ts +17 -0
  51. package/dist/src/providers/ProviderManagerAdapter.js +113 -0
  52. package/dist/src/providers/ProviderManagerAdapter.js.map +1 -0
  53. package/dist/src/providers/README-qwen3.md +60 -0
  54. package/dist/src/providers/README.md +203 -0
  55. package/dist/src/providers/adapters/IStreamAdapter.d.ts +18 -0
  56. package/dist/src/providers/adapters/IStreamAdapter.js +7 -0
  57. package/dist/src/providers/adapters/IStreamAdapter.js.map +1 -0
  58. package/dist/src/providers/anthropic/AnthropicProvider.d.ts +46 -0
  59. package/dist/src/providers/anthropic/AnthropicProvider.js +478 -0
  60. package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -0
  61. package/dist/src/providers/contentGeneratorProvider.d.ts +13 -0
  62. package/dist/src/providers/contentGeneratorProvider.js +17 -0
  63. package/dist/src/providers/contentGeneratorProvider.js.map +1 -0
  64. package/dist/src/providers/enhanceConfigWithProviders.d.ts +12 -0
  65. package/dist/src/providers/enhanceConfigWithProviders.js +16 -0
  66. package/dist/src/providers/enhanceConfigWithProviders.js.map +1 -0
  67. package/dist/src/providers/gemini/GeminiProvider.d.ts +72 -0
  68. package/dist/src/providers/gemini/GeminiProvider.js +454 -0
  69. package/dist/src/providers/gemini/GeminiProvider.js.map +1 -0
  70. package/dist/src/providers/index.d.ts +13 -0
  71. package/dist/src/providers/index.js +18 -0
  72. package/dist/src/providers/index.js.map +1 -0
  73. package/dist/src/providers/integration/TEST_INSTRUCTIONS.md +197 -0
  74. package/dist/src/providers/openai/ConversationCache.d.ts +20 -0
  75. package/dist/src/providers/openai/ConversationCache.js +109 -0
  76. package/dist/src/providers/openai/ConversationCache.js.map +1 -0
  77. package/dist/src/providers/openai/IChatGenerateParams.d.ts +11 -0
  78. package/dist/src/providers/openai/IChatGenerateParams.js +2 -0
  79. package/dist/src/providers/openai/IChatGenerateParams.js.map +1 -0
  80. package/dist/src/providers/openai/OpenAIProvider.d.ts +71 -0
  81. package/dist/src/providers/openai/OpenAIProvider.js +486 -0
  82. package/dist/src/providers/openai/OpenAIProvider.js.map +1 -0
  83. package/dist/src/providers/openai/Qwen3FireworksProvider.d.ts +39 -0
  84. package/dist/src/providers/openai/Qwen3FireworksProvider.js +209 -0
  85. package/dist/src/providers/openai/Qwen3FireworksProvider.js.map +1 -0
  86. package/dist/src/providers/openai/RESPONSES_API_MODELS.d.ts +2 -0
  87. package/dist/src/providers/openai/RESPONSES_API_MODELS.js +14 -0
  88. package/dist/src/providers/openai/RESPONSES_API_MODELS.js.map +1 -0
  89. package/dist/src/providers/openai/buildResponsesRequest.d.ts +67 -0
  90. package/dist/src/providers/openai/buildResponsesRequest.js +144 -0
  91. package/dist/src/providers/openai/buildResponsesRequest.js.map +1 -0
  92. package/dist/src/providers/openai/docs/accessing-provider-info.md +172 -0
  93. package/dist/src/providers/openai/docs/params-mapping.md +91 -0
  94. package/dist/src/providers/openai/docs/qwen3-fireworks.md +47 -0
  95. package/dist/src/providers/openai/docs/responses-api-tool-calls.md +96 -0
  96. package/dist/src/providers/openai/estimateRemoteTokens.d.ts +26 -0
  97. package/dist/src/providers/openai/estimateRemoteTokens.js +75 -0
  98. package/dist/src/providers/openai/estimateRemoteTokens.js.map +1 -0
  99. package/dist/src/providers/openai/getOpenAIProviderInfo.d.ts +46 -0
  100. package/dist/src/providers/openai/getOpenAIProviderInfo.js +74 -0
  101. package/dist/src/providers/openai/getOpenAIProviderInfo.js.map +1 -0
  102. package/dist/src/providers/openai/parseResponsesStream.d.ts +3 -0
  103. package/dist/src/providers/openai/parseResponsesStream.js +444 -0
  104. package/dist/src/providers/openai/parseResponsesStream.js.map +1 -0
  105. package/dist/src/providers/parsers/TextToolCallParser.d.ts +35 -0
  106. package/dist/src/providers/parsers/TextToolCallParser.js +248 -0
  107. package/dist/src/providers/parsers/TextToolCallParser.js.map +1 -0
  108. package/dist/src/providers/providerConfigUtils.d.ts +26 -0
  109. package/dist/src/providers/providerConfigUtils.js +173 -0
  110. package/dist/src/providers/providerConfigUtils.js.map +1 -0
  111. package/dist/src/providers/providerManagerInstance.d.ts +9 -0
  112. package/dist/src/providers/providerManagerInstance.js +109 -0
  113. package/dist/src/providers/providerManagerInstance.js.map +1 -0
  114. package/dist/src/providers/tokenizers/AnthropicTokenizer.d.ts +19 -0
  115. package/dist/src/providers/tokenizers/AnthropicTokenizer.js +37 -0
  116. package/dist/src/providers/tokenizers/AnthropicTokenizer.js.map +1 -0
  117. package/dist/src/providers/tokenizers/ITokenizer.d.ts +18 -0
  118. package/dist/src/providers/tokenizers/ITokenizer.js +17 -0
  119. package/dist/src/providers/tokenizers/ITokenizer.js.map +1 -0
  120. package/dist/src/providers/tokenizers/OpenAITokenizer.d.ts +24 -0
  121. package/dist/src/providers/tokenizers/OpenAITokenizer.js +56 -0
  122. package/dist/src/providers/tokenizers/OpenAITokenizer.js.map +1 -0
  123. package/dist/src/providers/types.d.ts +14 -0
  124. package/dist/src/providers/types.js +16 -0
  125. package/dist/src/providers/types.js.map +1 -0
  126. package/dist/src/services/CommandService.d.ts +13 -0
  127. package/dist/src/services/CommandService.js +38 -0
  128. package/dist/src/services/CommandService.js.map +1 -0
  129. package/dist/src/tools/IToolFormatter.d.ts +40 -0
  130. package/dist/src/tools/IToolFormatter.js +17 -0
  131. package/dist/src/tools/IToolFormatter.js.map +1 -0
  132. package/dist/src/tools/ToolFormatter.d.ts +45 -0
  133. package/dist/src/tools/ToolFormatter.js +216 -0
  134. package/dist/src/tools/ToolFormatter.js.map +1 -0
  135. package/dist/src/ui/App.d.ts +15 -0
  136. package/dist/src/ui/App.js +468 -0
  137. package/dist/src/ui/App.js.map +1 -0
  138. package/dist/src/ui/colors.d.ts +25 -0
  139. package/dist/src/ui/colors.js +126 -0
  140. package/dist/src/ui/colors.js.map +1 -0
  141. package/dist/src/ui/commands/aboutCommand.d.ts +7 -0
  142. package/dist/src/ui/commands/aboutCommand.js +61 -0
  143. package/dist/src/ui/commands/aboutCommand.js.map +1 -0
  144. package/dist/src/ui/commands/authCommand.d.ts +7 -0
  145. package/dist/src/ui/commands/authCommand.js +14 -0
  146. package/dist/src/ui/commands/authCommand.js.map +1 -0
  147. package/dist/src/ui/commands/clearCommand.d.ts +7 -0
  148. package/dist/src/ui/commands/clearCommand.js +15 -0
  149. package/dist/src/ui/commands/clearCommand.js.map +1 -0
  150. package/dist/src/ui/commands/helpCommand.d.ts +7 -0
  151. package/dist/src/ui/commands/helpCommand.js +18 -0
  152. package/dist/src/ui/commands/helpCommand.js.map +1 -0
  153. package/dist/src/ui/commands/memoryCommand.d.ts +7 -0
  154. package/dist/src/ui/commands/memoryCommand.js +81 -0
  155. package/dist/src/ui/commands/memoryCommand.js.map +1 -0
  156. package/dist/src/ui/commands/privacyCommand.d.ts +7 -0
  157. package/dist/src/ui/commands/privacyCommand.js +14 -0
  158. package/dist/src/ui/commands/privacyCommand.js.map +1 -0
  159. package/dist/src/ui/commands/themeCommand.d.ts +7 -0
  160. package/dist/src/ui/commands/themeCommand.js +14 -0
  161. package/dist/src/ui/commands/themeCommand.js.map +1 -0
  162. package/dist/src/ui/commands/types.d.ts +63 -0
  163. package/dist/src/ui/commands/types.js +7 -0
  164. package/dist/src/ui/commands/types.js.map +1 -0
  165. package/dist/src/ui/components/AboutBox.d.ts +16 -0
  166. package/dist/src/ui/components/AboutBox.js +6 -0
  167. package/dist/src/ui/components/AboutBox.js.map +1 -0
  168. package/dist/src/ui/components/AsciiArt.d.ts +7 -0
  169. package/dist/src/ui/components/AsciiArt.js +24 -0
  170. package/dist/src/ui/components/AsciiArt.js.map +1 -0
  171. package/dist/src/ui/components/AuthDialog.d.ts +15 -0
  172. package/dist/src/ui/components/AuthDialog.js +102 -0
  173. package/dist/src/ui/components/AuthDialog.js.map +1 -0
  174. package/dist/src/ui/components/AuthInProgress.d.ts +11 -0
  175. package/dist/src/ui/components/AuthInProgress.js +27 -0
  176. package/dist/src/ui/components/AuthInProgress.js.map +1 -0
  177. package/dist/src/ui/components/AutoAcceptIndicator.d.ts +12 -0
  178. package/dist/src/ui/components/AutoAcceptIndicator.js +26 -0
  179. package/dist/src/ui/components/AutoAcceptIndicator.js.map +1 -0
  180. package/dist/src/ui/components/ConsoleSummaryDisplay.d.ts +11 -0
  181. package/dist/src/ui/components/ConsoleSummaryDisplay.js +11 -0
  182. package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -0
  183. package/dist/src/ui/components/ContextSummaryDisplay.d.ts +15 -0
  184. package/dist/src/ui/components/ContextSummaryDisplay.js +41 -0
  185. package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -0
  186. package/dist/src/ui/components/DetailedMessagesDisplay.d.ts +14 -0
  187. package/dist/src/ui/components/DetailedMessagesDisplay.js +34 -0
  188. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -0
  189. package/dist/src/ui/components/EditorSettingsDialog.d.ts +15 -0
  190. package/dist/src/ui/components/EditorSettingsDialog.js +73 -0
  191. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -0
  192. package/dist/src/ui/components/ErrorBoundary.d.ts +46 -0
  193. package/dist/src/ui/components/ErrorBoundary.js +115 -0
  194. package/dist/src/ui/components/ErrorBoundary.js.map +1 -0
  195. package/dist/src/ui/components/Footer.d.ts +22 -0
  196. package/dist/src/ui/components/Footer.js +32 -0
  197. package/dist/src/ui/components/Footer.js.map +1 -0
  198. package/dist/src/ui/components/GeminiRespondingSpinner.d.ts +17 -0
  199. package/dist/src/ui/components/GeminiRespondingSpinner.js +16 -0
  200. package/dist/src/ui/components/GeminiRespondingSpinner.js.map +1 -0
  201. package/dist/src/ui/components/Header.d.ts +14 -0
  202. package/dist/src/ui/components/Header.js +20 -0
  203. package/dist/src/ui/components/Header.js.map +1 -0
  204. package/dist/src/ui/components/Help.d.ts +12 -0
  205. package/dist/src/ui/components/Help.js +10 -0
  206. package/dist/src/ui/components/Help.js.map +1 -0
  207. package/dist/src/ui/components/HistoryItemDisplay.d.ts +18 -0
  208. package/dist/src/ui/components/HistoryItemDisplay.js +17 -0
  209. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -0
  210. package/dist/src/ui/components/InputPrompt.d.ts +25 -0
  211. package/dist/src/ui/components/InputPrompt.js +350 -0
  212. package/dist/src/ui/components/InputPrompt.js.map +1 -0
  213. package/dist/src/ui/components/LayoutManager.d.ts +24 -0
  214. package/dist/src/ui/components/LayoutManager.js +58 -0
  215. package/dist/src/ui/components/LayoutManager.js.map +1 -0
  216. package/dist/src/ui/components/LoadingIndicator.d.ts +15 -0
  217. package/dist/src/ui/components/LoadingIndicator.js +20 -0
  218. package/dist/src/ui/components/LoadingIndicator.js.map +1 -0
  219. package/dist/src/ui/components/MemoryUsageDisplay.d.ts +7 -0
  220. package/dist/src/ui/components/MemoryUsageDisplay.js +27 -0
  221. package/dist/src/ui/components/MemoryUsageDisplay.js.map +1 -0
  222. package/dist/src/ui/components/ModelStatsDisplay.d.ts +7 -0
  223. package/dist/src/ui/components/ModelStatsDisplay.js +33 -0
  224. package/dist/src/ui/components/ModelStatsDisplay.js.map +1 -0
  225. package/dist/src/ui/components/ProviderDialog.d.ts +9 -0
  226. package/dist/src/ui/components/ProviderDialog.js +54 -0
  227. package/dist/src/ui/components/ProviderDialog.js.map +1 -0
  228. package/dist/src/ui/components/ProviderModelDialog.d.ts +15 -0
  229. package/dist/src/ui/components/ProviderModelDialog.js +54 -0
  230. package/dist/src/ui/components/ProviderModelDialog.js.map +1 -0
  231. package/dist/src/ui/components/SessionSummaryDisplay.d.ts +11 -0
  232. package/dist/src/ui/components/SessionSummaryDisplay.js +4 -0
  233. package/dist/src/ui/components/SessionSummaryDisplay.js.map +1 -0
  234. package/dist/src/ui/components/ShellModeIndicator.d.ts +7 -0
  235. package/dist/src/ui/components/ShellModeIndicator.js +5 -0
  236. package/dist/src/ui/components/ShellModeIndicator.js.map +1 -0
  237. package/dist/src/ui/components/ShowMoreLines.d.ts +10 -0
  238. package/dist/src/ui/components/ShowMoreLines.js +24 -0
  239. package/dist/src/ui/components/ShowMoreLines.js.map +1 -0
  240. package/dist/src/ui/components/StatsDisplay.d.ts +12 -0
  241. package/dist/src/ui/components/StatsDisplay.js +42 -0
  242. package/dist/src/ui/components/StatsDisplay.js.map +1 -0
  243. package/dist/src/ui/components/SuggestionsDisplay.d.ts +21 -0
  244. package/dist/src/ui/components/SuggestionsDisplay.js +32 -0
  245. package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -0
  246. package/dist/src/ui/components/ThemeDialog.d.ts +19 -0
  247. package/dist/src/ui/components/ThemeDialog.js +127 -0
  248. package/dist/src/ui/components/ThemeDialog.js.map +1 -0
  249. package/dist/src/ui/components/Tips.d.ts +12 -0
  250. package/dist/src/ui/components/Tips.js +8 -0
  251. package/dist/src/ui/components/Tips.js.map +1 -0
  252. package/dist/src/ui/components/ToolStatsDisplay.d.ts +7 -0
  253. package/dist/src/ui/components/ToolStatsDisplay.js +41 -0
  254. package/dist/src/ui/components/ToolStatsDisplay.js.map +1 -0
  255. package/dist/src/ui/components/UpdateNotification.d.ts +10 -0
  256. package/dist/src/ui/components/UpdateNotification.js +10 -0
  257. package/dist/src/ui/components/UpdateNotification.js.map +1 -0
  258. package/dist/src/ui/components/messages/CompressionMessage.d.ts +11 -0
  259. package/dist/src/ui/components/messages/CompressionMessage.js +16 -0
  260. package/dist/src/ui/components/messages/CompressionMessage.js.map +1 -0
  261. package/dist/src/ui/components/messages/DiffRenderer.d.ts +15 -0
  262. package/dist/src/ui/components/messages/DiffRenderer.js +212 -0
  263. package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -0
  264. package/dist/src/ui/components/messages/ErrorMessage.d.ts +11 -0
  265. package/dist/src/ui/components/messages/ErrorMessage.js +9 -0
  266. package/dist/src/ui/components/messages/ErrorMessage.js.map +1 -0
  267. package/dist/src/ui/components/messages/GeminiMessage.d.ts +15 -0
  268. package/dist/src/ui/components/messages/GeminiMessage.js +10 -0
  269. package/dist/src/ui/components/messages/GeminiMessage.js.map +1 -0
  270. package/dist/src/ui/components/messages/GeminiMessageContent.d.ts +14 -0
  271. package/dist/src/ui/components/messages/GeminiMessageContent.js +15 -0
  272. package/dist/src/ui/components/messages/GeminiMessageContent.js.map +1 -0
  273. package/dist/src/ui/components/messages/InfoMessage.d.ts +11 -0
  274. package/dist/src/ui/components/messages/InfoMessage.js +9 -0
  275. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -0
  276. package/dist/src/ui/components/messages/ToolConfirmationMessage.d.ts +15 -0
  277. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +117 -0
  278. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -0
  279. package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +18 -0
  280. package/dist/src/ui/components/messages/ToolGroupMessage.js +53 -0
  281. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -0
  282. package/dist/src/ui/components/messages/ToolMessage.d.ts +15 -0
  283. package/dist/src/ui/components/messages/ToolMessage.js +61 -0
  284. package/dist/src/ui/components/messages/ToolMessage.js.map +1 -0
  285. package/dist/src/ui/components/messages/UserMessage.d.ts +11 -0
  286. package/dist/src/ui/components/messages/UserMessage.js +9 -0
  287. package/dist/src/ui/components/messages/UserMessage.js.map +1 -0
  288. package/dist/src/ui/components/messages/UserShellMessage.d.ts +11 -0
  289. package/dist/src/ui/components/messages/UserShellMessage.js +9 -0
  290. package/dist/src/ui/components/messages/UserShellMessage.js.map +1 -0
  291. package/dist/src/ui/components/shared/MaxSizedBox.d.ts +61 -0
  292. package/dist/src/ui/components/shared/MaxSizedBox.js +384 -0
  293. package/dist/src/ui/components/shared/MaxSizedBox.js.map +1 -0
  294. package/dist/src/ui/components/shared/RadioButtonSelect.d.ts +44 -0
  295. package/dist/src/ui/components/shared/RadioButtonSelect.js +77 -0
  296. package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -0
  297. package/dist/src/ui/components/shared/text-buffer.d.ts +184 -0
  298. package/dist/src/ui/components/shared/text-buffer.js +1021 -0
  299. package/dist/src/ui/components/shared/text-buffer.js.map +1 -0
  300. package/dist/src/ui/constants.d.ts +8 -0
  301. package/dist/src/ui/constants.js +12 -0
  302. package/dist/src/ui/constants.js.map +1 -0
  303. package/dist/src/ui/containers/SessionController.d.ts +26 -0
  304. package/dist/src/ui/containers/SessionController.js +314 -0
  305. package/dist/src/ui/containers/SessionController.js.map +1 -0
  306. package/dist/src/ui/containers/UIStateShell.d.ts +6 -0
  307. package/dist/src/ui/containers/UIStateShell.js +4 -0
  308. package/dist/src/ui/containers/UIStateShell.js.map +1 -0
  309. package/dist/src/ui/contexts/AppDispatchContext.d.ts +12 -0
  310. package/dist/src/ui/contexts/AppDispatchContext.js +17 -0
  311. package/dist/src/ui/contexts/AppDispatchContext.js.map +1 -0
  312. package/dist/src/ui/contexts/OpenAIProviderContext.d.ts +29 -0
  313. package/dist/src/ui/contexts/OpenAIProviderContext.js +63 -0
  314. package/dist/src/ui/contexts/OpenAIProviderContext.js.map +1 -0
  315. package/dist/src/ui/contexts/OverflowContext.d.ts +19 -0
  316. package/dist/src/ui/contexts/OverflowContext.js +43 -0
  317. package/dist/src/ui/contexts/OverflowContext.js.map +1 -0
  318. package/dist/src/ui/contexts/SessionContext.d.ts +36 -0
  319. package/dist/src/ui/contexts/SessionContext.js +66 -0
  320. package/dist/src/ui/contexts/SessionContext.js.map +1 -0
  321. package/dist/src/ui/contexts/SessionStateContext.d.ts +15 -0
  322. package/dist/src/ui/contexts/SessionStateContext.js +26 -0
  323. package/dist/src/ui/contexts/SessionStateContext.js.map +1 -0
  324. package/dist/src/ui/contexts/StreamingContext.d.ts +9 -0
  325. package/dist/src/ui/contexts/StreamingContext.js +15 -0
  326. package/dist/src/ui/contexts/StreamingContext.js.map +1 -0
  327. package/dist/src/ui/editors/editorSettingsManager.d.ts +19 -0
  328. package/dist/src/ui/editors/editorSettingsManager.js +54 -0
  329. package/dist/src/ui/editors/editorSettingsManager.js.map +1 -0
  330. package/dist/src/ui/hooks/atCommandProcessor.d.ts +31 -0
  331. package/dist/src/ui/hooks/atCommandProcessor.js +310 -0
  332. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -0
  333. package/dist/src/ui/hooks/index.d.ts +2 -0
  334. package/dist/src/ui/hooks/index.js +3 -0
  335. package/dist/src/ui/hooks/index.js.map +1 -0
  336. package/dist/src/ui/hooks/shellCommandProcessor.d.ts +16 -0
  337. package/dist/src/ui/hooks/shellCommandProcessor.js +263 -0
  338. package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -0
  339. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +27 -0
  340. package/dist/src/ui/hooks/slashCommandProcessor.js +1413 -0
  341. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -0
  342. package/dist/src/ui/hooks/useAuthCommand.d.ts +15 -0
  343. package/dist/src/ui/hooks/useAuthCommand.js +76 -0
  344. package/dist/src/ui/hooks/useAuthCommand.js.map +1 -0
  345. package/dist/src/ui/hooks/useAutoAcceptIndicator.d.ts +10 -0
  346. package/dist/src/ui/hooks/useAutoAcceptIndicator.js +37 -0
  347. package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -0
  348. package/dist/src/ui/hooks/useBracketedPaste.d.ts +12 -0
  349. package/dist/src/ui/hooks/useBracketedPaste.js +32 -0
  350. package/dist/src/ui/hooks/useBracketedPaste.js.map +1 -0
  351. package/dist/src/ui/hooks/useCompletion.d.ts +21 -0
  352. package/dist/src/ui/hooks/useCompletion.js +375 -0
  353. package/dist/src/ui/hooks/useCompletion.js.map +1 -0
  354. package/dist/src/ui/hooks/useConsoleMessages.d.ts +12 -0
  355. package/dist/src/ui/hooks/useConsoleMessages.js +60 -0
  356. package/dist/src/ui/hooks/useConsoleMessages.js.map +1 -0
  357. package/dist/src/ui/hooks/useEditorSettings.d.ts +17 -0
  358. package/dist/src/ui/hooks/useEditorSettings.js +48 -0
  359. package/dist/src/ui/hooks/useEditorSettings.js.map +1 -0
  360. package/dist/src/ui/hooks/useGeminiStream.d.ts +23 -0
  361. package/dist/src/ui/hooks/useGeminiStream.js +607 -0
  362. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -0
  363. package/dist/src/ui/hooks/useGitBranchName.d.ts +6 -0
  364. package/dist/src/ui/hooks/useGitBranchName.js +61 -0
  365. package/dist/src/ui/hooks/useGitBranchName.js.map +1 -0
  366. package/dist/src/ui/hooks/useHistoryManager.d.ts +22 -0
  367. package/dist/src/ui/hooks/useHistoryManager.js +74 -0
  368. package/dist/src/ui/hooks/useHistoryManager.js.map +1 -0
  369. package/dist/src/ui/hooks/useInputHistory.d.ts +19 -0
  370. package/dist/src/ui/hooks/useInputHistory.js +84 -0
  371. package/dist/src/ui/hooks/useInputHistory.js.map +1 -0
  372. package/dist/src/ui/hooks/useKeypress.d.ts +29 -0
  373. package/dist/src/ui/hooks/useKeypress.js +162 -0
  374. package/dist/src/ui/hooks/useKeypress.js.map +1 -0
  375. package/dist/src/ui/hooks/useLoadingIndicator.d.ts +10 -0
  376. package/dist/src/ui/hooks/useLoadingIndicator.js +44 -0
  377. package/dist/src/ui/hooks/useLoadingIndicator.js.map +1 -0
  378. package/dist/src/ui/hooks/useLogger.d.ts +10 -0
  379. package/dist/src/ui/hooks/useLogger.js +29 -0
  380. package/dist/src/ui/hooks/useLogger.js.map +1 -0
  381. package/dist/src/ui/hooks/useOpenAIProviderInfo.d.ts +17 -0
  382. package/dist/src/ui/hooks/useOpenAIProviderInfo.js +43 -0
  383. package/dist/src/ui/hooks/useOpenAIProviderInfo.js.map +1 -0
  384. package/dist/src/ui/hooks/usePhraseCycler.d.ts +14 -0
  385. package/dist/src/ui/hooks/usePhraseCycler.js +197 -0
  386. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -0
  387. package/dist/src/ui/hooks/usePrivacySettings.d.ts +16 -0
  388. package/dist/src/ui/hooks/usePrivacySettings.js +115 -0
  389. package/dist/src/ui/hooks/usePrivacySettings.js.map +1 -0
  390. package/dist/src/ui/hooks/useProviderDialog.d.ts +25 -0
  391. package/dist/src/ui/hooks/useProviderDialog.js +61 -0
  392. package/dist/src/ui/hooks/useProviderDialog.js.map +1 -0
  393. package/dist/src/ui/hooks/useProviderModelDialog.d.ts +26 -0
  394. package/dist/src/ui/hooks/useProviderModelDialog.js +62 -0
  395. package/dist/src/ui/hooks/useProviderModelDialog.js.map +1 -0
  396. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +33 -0
  397. package/dist/src/ui/hooks/useReactToolScheduler.js +186 -0
  398. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -0
  399. package/dist/src/ui/hooks/useRefreshMemoryCommand.d.ts +6 -0
  400. package/dist/src/ui/hooks/useRefreshMemoryCommand.js +7 -0
  401. package/dist/src/ui/hooks/useRefreshMemoryCommand.js.map +1 -0
  402. package/dist/src/ui/hooks/useSession.d.ts +11 -0
  403. package/dist/src/ui/hooks/useSession.js +19 -0
  404. package/dist/src/ui/hooks/useSession.js.map +1 -0
  405. package/dist/src/ui/hooks/useShellHistory.d.ts +11 -0
  406. package/dist/src/ui/hooks/useShellHistory.js +89 -0
  407. package/dist/src/ui/hooks/useShellHistory.js.map +1 -0
  408. package/dist/src/ui/hooks/useShowMemoryCommand.d.ts +9 -0
  409. package/dist/src/ui/hooks/useShowMemoryCommand.js +50 -0
  410. package/dist/src/ui/hooks/useShowMemoryCommand.js.map +1 -0
  411. package/dist/src/ui/hooks/useStableCallback.d.ts +40 -0
  412. package/dist/src/ui/hooks/useStableCallback.js +58 -0
  413. package/dist/src/ui/hooks/useStableCallback.js.map +1 -0
  414. package/dist/src/ui/hooks/useStateAndRef.d.ts +7 -0
  415. package/dist/src/ui/hooks/useStateAndRef.js +26 -0
  416. package/dist/src/ui/hooks/useStateAndRef.js.map +1 -0
  417. package/dist/src/ui/hooks/useTerminalSize.d.ts +9 -0
  418. package/dist/src/ui/hooks/useTerminalSize.js +27 -0
  419. package/dist/src/ui/hooks/useTerminalSize.js.map +1 -0
  420. package/dist/src/ui/hooks/useThemeCommand.d.ts +16 -0
  421. package/dist/src/ui/hooks/useThemeCommand.js +94 -0
  422. package/dist/src/ui/hooks/useThemeCommand.js.map +1 -0
  423. package/dist/src/ui/hooks/useTimer.d.ts +12 -0
  424. package/dist/src/ui/hooks/useTimer.js +58 -0
  425. package/dist/src/ui/hooks/useTimer.js.map +1 -0
  426. package/dist/src/ui/privacy/CloudFreePrivacyNotice.d.ts +12 -0
  427. package/dist/src/ui/privacy/CloudFreePrivacyNotice.js +42 -0
  428. package/dist/src/ui/privacy/CloudFreePrivacyNotice.js.map +1 -0
  429. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.d.ts +10 -0
  430. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js +17 -0
  431. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js.map +1 -0
  432. package/dist/src/ui/privacy/GeminiPrivacyNotice.d.ts +10 -0
  433. package/dist/src/ui/privacy/GeminiPrivacyNotice.js +17 -0
  434. package/dist/src/ui/privacy/GeminiPrivacyNotice.js.map +1 -0
  435. package/dist/src/ui/privacy/PrivacyNotice.d.ts +12 -0
  436. package/dist/src/ui/privacy/PrivacyNotice.js +25 -0
  437. package/dist/src/ui/privacy/PrivacyNotice.js.map +1 -0
  438. package/dist/src/ui/reducers/appReducer.d.ts +59 -0
  439. package/dist/src/ui/reducers/appReducer.js +91 -0
  440. package/dist/src/ui/reducers/appReducer.js.map +1 -0
  441. package/dist/src/ui/reducers/sessionReducer.d.ts +36 -0
  442. package/dist/src/ui/reducers/sessionReducer.js +30 -0
  443. package/dist/src/ui/reducers/sessionReducer.js.map +1 -0
  444. package/dist/src/ui/themes/ansi-light.d.ts +7 -0
  445. package/dist/src/ui/themes/ansi-light.js +139 -0
  446. package/dist/src/ui/themes/ansi-light.js.map +1 -0
  447. package/dist/src/ui/themes/ansi.d.ts +7 -0
  448. package/dist/src/ui/themes/ansi.js +149 -0
  449. package/dist/src/ui/themes/ansi.js.map +1 -0
  450. package/dist/src/ui/themes/atom-one-dark.d.ts +7 -0
  451. package/dist/src/ui/themes/atom-one-dark.js +136 -0
  452. package/dist/src/ui/themes/atom-one-dark.js.map +1 -0
  453. package/dist/src/ui/themes/ayu-light.d.ts +7 -0
  454. package/dist/src/ui/themes/ayu-light.js +128 -0
  455. package/dist/src/ui/themes/ayu-light.js.map +1 -0
  456. package/dist/src/ui/themes/ayu.d.ts +7 -0
  457. package/dist/src/ui/themes/ayu.js +102 -0
  458. package/dist/src/ui/themes/ayu.js.map +1 -0
  459. package/dist/src/ui/themes/default-light.d.ts +7 -0
  460. package/dist/src/ui/themes/default-light.js +100 -0
  461. package/dist/src/ui/themes/default-light.js.map +1 -0
  462. package/dist/src/ui/themes/default.d.ts +7 -0
  463. package/dist/src/ui/themes/default.js +143 -0
  464. package/dist/src/ui/themes/default.js.map +1 -0
  465. package/dist/src/ui/themes/dracula.d.ts +7 -0
  466. package/dist/src/ui/themes/dracula.js +113 -0
  467. package/dist/src/ui/themes/dracula.js.map +1 -0
  468. package/dist/src/ui/themes/github-dark.d.ts +7 -0
  469. package/dist/src/ui/themes/github-dark.js +136 -0
  470. package/dist/src/ui/themes/github-dark.js.map +1 -0
  471. package/dist/src/ui/themes/github-light.d.ts +7 -0
  472. package/dist/src/ui/themes/github-light.js +138 -0
  473. package/dist/src/ui/themes/github-light.js.map +1 -0
  474. package/dist/src/ui/themes/googlecode.d.ts +7 -0
  475. package/dist/src/ui/themes/googlecode.js +135 -0
  476. package/dist/src/ui/themes/googlecode.js.map +1 -0
  477. package/dist/src/ui/themes/green-screen.d.ts +7 -0
  478. package/dist/src/ui/themes/green-screen.js +113 -0
  479. package/dist/src/ui/themes/green-screen.js.map +1 -0
  480. package/dist/src/ui/themes/no-color.d.ts +7 -0
  481. package/dist/src/ui/themes/no-color.js +84 -0
  482. package/dist/src/ui/themes/no-color.js.map +1 -0
  483. package/dist/src/ui/themes/shades-of-purple.d.ts +11 -0
  484. package/dist/src/ui/themes/shades-of-purple.js +302 -0
  485. package/dist/src/ui/themes/shades-of-purple.js.map +1 -0
  486. package/dist/src/ui/themes/theme-manager.d.ts +33 -0
  487. package/dist/src/ui/themes/theme-manager.js +111 -0
  488. package/dist/src/ui/themes/theme-manager.js.map +1 -0
  489. package/dist/src/ui/themes/theme.d.ts +83 -0
  490. package/dist/src/ui/themes/theme.js +304 -0
  491. package/dist/src/ui/themes/theme.js.map +1 -0
  492. package/dist/src/ui/themes/xcode.d.ts +7 -0
  493. package/dist/src/ui/themes/xcode.js +143 -0
  494. package/dist/src/ui/themes/xcode.js.map +1 -0
  495. package/dist/src/ui/types.d.ts +174 -0
  496. package/dist/src/ui/types.js +43 -0
  497. package/dist/src/ui/types.js.map +1 -0
  498. package/dist/src/ui/utils/CodeColorizer.d.ts +14 -0
  499. package/dist/src/ui/utils/CodeColorizer.js +97 -0
  500. package/dist/src/ui/utils/CodeColorizer.js.map +1 -0
  501. package/dist/src/ui/utils/ConsolePatcher.d.ts +23 -0
  502. package/dist/src/ui/utils/ConsolePatcher.js +42 -0
  503. package/dist/src/ui/utils/ConsolePatcher.js.map +1 -0
  504. package/dist/src/ui/utils/InlineMarkdownRenderer.d.ts +16 -0
  505. package/dist/src/ui/utils/InlineMarkdownRenderer.js +104 -0
  506. package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -0
  507. package/dist/src/ui/utils/MarkdownDisplay.d.ts +14 -0
  508. package/dist/src/ui/utils/MarkdownDisplay.js +205 -0
  509. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -0
  510. package/dist/src/ui/utils/TableRenderer.d.ts +17 -0
  511. package/dist/src/ui/utils/TableRenderer.js +84 -0
  512. package/dist/src/ui/utils/TableRenderer.js.map +1 -0
  513. package/dist/src/ui/utils/clipboardUtils.d.ts +22 -0
  514. package/dist/src/ui/utils/clipboardUtils.js +127 -0
  515. package/dist/src/ui/utils/clipboardUtils.js.map +1 -0
  516. package/dist/src/ui/utils/commandUtils.d.ts +22 -0
  517. package/dist/src/ui/utils/commandUtils.js +25 -0
  518. package/dist/src/ui/utils/commandUtils.js.map +1 -0
  519. package/dist/src/ui/utils/computeStats.d.ts +10 -0
  520. package/dist/src/ui/utils/computeStats.js +55 -0
  521. package/dist/src/ui/utils/computeStats.js.map +1 -0
  522. package/dist/src/ui/utils/displayUtils.d.ts +17 -0
  523. package/dist/src/ui/utils/displayUtils.js +24 -0
  524. package/dist/src/ui/utils/displayUtils.js.map +1 -0
  525. package/dist/src/ui/utils/errorParsing.d.ts +7 -0
  526. package/dist/src/ui/utils/errorParsing.js +106 -0
  527. package/dist/src/ui/utils/errorParsing.js.map +1 -0
  528. package/dist/src/ui/utils/formatters.d.ts +13 -0
  529. package/dist/src/ui/utils/formatters.js +56 -0
  530. package/dist/src/ui/utils/formatters.js.map +1 -0
  531. package/dist/src/ui/utils/markdownUtilities.d.ts +6 -0
  532. package/dist/src/ui/utils/markdownUtilities.js +110 -0
  533. package/dist/src/ui/utils/markdownUtilities.js.map +1 -0
  534. package/dist/src/ui/utils/renderLoopDetector.d.ts +52 -0
  535. package/dist/src/ui/utils/renderLoopDetector.js +146 -0
  536. package/dist/src/ui/utils/renderLoopDetector.js.map +1 -0
  537. package/dist/src/ui/utils/textUtils.d.ts +22 -0
  538. package/dist/src/ui/utils/textUtils.js +58 -0
  539. package/dist/src/ui/utils/textUtils.js.map +1 -0
  540. package/dist/src/ui/utils/updateCheck.d.ts +6 -0
  541. package/dist/src/ui/utils/updateCheck.js +50 -0
  542. package/dist/src/ui/utils/updateCheck.js.map +1 -0
  543. package/dist/src/utils/ConversationContext.d.ts +55 -0
  544. package/dist/src/utils/ConversationContext.js +85 -0
  545. package/dist/src/utils/ConversationContext.js.map +1 -0
  546. package/dist/src/utils/cleanup.d.ts +8 -0
  547. package/dist/src/utils/cleanup.js +34 -0
  548. package/dist/src/utils/cleanup.js.map +1 -0
  549. package/dist/src/utils/package.d.ts +12 -0
  550. package/dist/src/utils/package.js +24 -0
  551. package/dist/src/utils/package.js.map +1 -0
  552. package/dist/src/utils/readStdin.d.ts +6 -0
  553. package/dist/src/utils/readStdin.js +34 -0
  554. package/dist/src/utils/readStdin.js.map +1 -0
  555. package/dist/src/utils/sandbox-macos-permissive-closed.sb +26 -0
  556. package/dist/src/utils/sandbox-macos-permissive-open.sb +19 -0
  557. package/dist/src/utils/sandbox-macos-permissive-proxied.sb +31 -0
  558. package/dist/src/utils/sandbox-macos-restrictive-closed.sb +87 -0
  559. package/dist/src/utils/sandbox-macos-restrictive-open.sb +90 -0
  560. package/dist/src/utils/sandbox-macos-restrictive-proxied.sb +92 -0
  561. package/dist/src/utils/sandbox.d.ts +7 -0
  562. package/dist/src/utils/sandbox.js +680 -0
  563. package/dist/src/utils/sandbox.js.map +1 -0
  564. package/dist/src/utils/startupWarnings.d.ts +6 -0
  565. package/dist/src/utils/startupWarnings.js +40 -0
  566. package/dist/src/utils/startupWarnings.js.map +1 -0
  567. package/dist/src/utils/userStartupWarnings.d.ts +6 -0
  568. package/dist/src/utils/userStartupWarnings.js +48 -0
  569. package/dist/src/utils/userStartupWarnings.js.map +1 -0
  570. package/dist/src/utils/version.d.ts +6 -0
  571. package/dist/src/utils/version.js +11 -0
  572. package/dist/src/utils/version.js.map +1 -0
  573. package/dist/tsconfig.tsbuildinfo +1 -0
  574. package/dist/vybestack-llxprt-code-0.1.12.tgz +0 -0
  575. package/package.json +95 -0
@@ -0,0 +1,1021 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import stripAnsi from 'strip-ansi';
7
+ import { spawnSync } from 'child_process';
8
+ import fs from 'fs';
9
+ import os from 'os';
10
+ import pathMod from 'path';
11
+ import { useState, useCallback, useEffect, useMemo, useReducer } from 'react';
12
+ import stringWidth from 'string-width';
13
+ import { unescapePath } from '@vybestack/llxprt-code-core';
14
+ import { toCodePoints, cpLen, cpSlice } from '../../utils/textUtils.js';
15
+ // Simple helper for word‑wise ops.
16
+ function isWordChar(ch) {
17
+ if (ch === undefined) {
18
+ return false;
19
+ }
20
+ return !/[\s,.;!?]/.test(ch);
21
+ }
22
+ /**
23
+ * Strip characters that can break terminal rendering.
24
+ *
25
+ * Strip ANSI escape codes and control characters except for line breaks.
26
+ * Control characters such as delete break terminal UI rendering.
27
+ */
28
+ function stripUnsafeCharacters(str) {
29
+ const stripped = stripAnsi(str);
30
+ return toCodePoints(stripAnsi(stripped))
31
+ .filter((char) => {
32
+ if (char.length > 1)
33
+ return false;
34
+ const code = char.codePointAt(0);
35
+ if (code === undefined) {
36
+ return false;
37
+ }
38
+ const isUnsafe = code === 127 || (code <= 31 && code !== 13 && code !== 10);
39
+ return !isUnsafe;
40
+ })
41
+ .join('');
42
+ }
43
+ function clamp(v, min, max) {
44
+ return v < min ? min : v > max ? max : v;
45
+ }
46
+ function calculateInitialCursorPosition(initialLines, offset) {
47
+ let remainingChars = offset;
48
+ let row = 0;
49
+ while (row < initialLines.length) {
50
+ const lineLength = cpLen(initialLines[row]);
51
+ // Add 1 for the newline character (except for the last line)
52
+ const totalCharsInLineAndNewline = lineLength + (row < initialLines.length - 1 ? 1 : 0);
53
+ if (remainingChars <= lineLength) {
54
+ // Cursor is on this line
55
+ return [row, remainingChars];
56
+ }
57
+ remainingChars -= totalCharsInLineAndNewline;
58
+ row++;
59
+ }
60
+ // Offset is beyond the text, place cursor at the end of the last line
61
+ if (initialLines.length > 0) {
62
+ const lastRow = initialLines.length - 1;
63
+ return [lastRow, cpLen(initialLines[lastRow])];
64
+ }
65
+ return [0, 0]; // Default for empty text
66
+ }
67
+ export function offsetToLogicalPos(text, offset) {
68
+ let row = 0;
69
+ let col = 0;
70
+ let currentOffset = 0;
71
+ if (offset === 0)
72
+ return [0, 0];
73
+ const lines = text.split('\n');
74
+ for (let i = 0; i < lines.length; i++) {
75
+ const line = lines[i];
76
+ const lineLength = cpLen(line);
77
+ const lineLengthWithNewline = lineLength + (i < lines.length - 1 ? 1 : 0);
78
+ if (offset <= currentOffset + lineLength) {
79
+ // Check against lineLength first
80
+ row = i;
81
+ col = offset - currentOffset;
82
+ return [row, col];
83
+ }
84
+ else if (offset <= currentOffset + lineLengthWithNewline) {
85
+ // Check if offset is the newline itself
86
+ row = i;
87
+ col = lineLength; // Position cursor at the end of the current line content
88
+ // If the offset IS the newline, and it's not the last line, advance to next line, col 0
89
+ if (offset === currentOffset + lineLengthWithNewline &&
90
+ i < lines.length - 1) {
91
+ return [i + 1, 0];
92
+ }
93
+ return [row, col]; // Otherwise, it's at the end of the current line content
94
+ }
95
+ currentOffset += lineLengthWithNewline;
96
+ }
97
+ // If offset is beyond the text length, place cursor at the end of the last line
98
+ // or [0,0] if text is empty
99
+ if (lines.length > 0) {
100
+ row = lines.length - 1;
101
+ col = cpLen(lines[row]);
102
+ }
103
+ else {
104
+ row = 0;
105
+ col = 0;
106
+ }
107
+ return [row, col];
108
+ }
109
+ // Helper to calculate visual lines and map cursor positions
110
+ function calculateVisualLayout(logicalLines, logicalCursor, viewportWidth) {
111
+ const visualLines = [];
112
+ const logicalToVisualMap = [];
113
+ const visualToLogicalMap = [];
114
+ let currentVisualCursor = [0, 0];
115
+ logicalLines.forEach((logLine, logIndex) => {
116
+ logicalToVisualMap[logIndex] = [];
117
+ if (logLine.length === 0) {
118
+ // Handle empty logical line
119
+ logicalToVisualMap[logIndex].push([visualLines.length, 0]);
120
+ visualToLogicalMap.push([logIndex, 0]);
121
+ visualLines.push('');
122
+ if (logIndex === logicalCursor[0] && logicalCursor[1] === 0) {
123
+ currentVisualCursor = [visualLines.length - 1, 0];
124
+ }
125
+ }
126
+ else {
127
+ // Non-empty logical line
128
+ let currentPosInLogLine = 0; // Tracks position within the current logical line (code point index)
129
+ const codePointsInLogLine = toCodePoints(logLine);
130
+ while (currentPosInLogLine < codePointsInLogLine.length) {
131
+ let currentChunk = '';
132
+ let currentChunkVisualWidth = 0;
133
+ let numCodePointsInChunk = 0;
134
+ let lastWordBreakPoint = -1; // Index in codePointsInLogLine for word break
135
+ let numCodePointsAtLastWordBreak = 0;
136
+ // Iterate through code points to build the current visual line (chunk)
137
+ for (let i = currentPosInLogLine; i < codePointsInLogLine.length; i++) {
138
+ const char = codePointsInLogLine[i];
139
+ const charVisualWidth = stringWidth(char);
140
+ if (currentChunkVisualWidth + charVisualWidth > viewportWidth) {
141
+ // Character would exceed viewport width
142
+ if (lastWordBreakPoint !== -1 &&
143
+ numCodePointsAtLastWordBreak > 0 &&
144
+ currentPosInLogLine + numCodePointsAtLastWordBreak < i) {
145
+ // We have a valid word break point to use, and it's not the start of the current segment
146
+ currentChunk = codePointsInLogLine
147
+ .slice(currentPosInLogLine, currentPosInLogLine + numCodePointsAtLastWordBreak)
148
+ .join('');
149
+ numCodePointsInChunk = numCodePointsAtLastWordBreak;
150
+ }
151
+ else {
152
+ // No word break, or word break is at the start of this potential chunk, or word break leads to empty chunk.
153
+ // Hard break: take characters up to viewportWidth, or just the current char if it alone is too wide.
154
+ if (numCodePointsInChunk === 0 &&
155
+ charVisualWidth > viewportWidth) {
156
+ // Single character is wider than viewport, take it anyway
157
+ currentChunk = char;
158
+ numCodePointsInChunk = 1;
159
+ }
160
+ else if (numCodePointsInChunk === 0 &&
161
+ charVisualWidth <= viewportWidth) {
162
+ // This case should ideally be caught by the next iteration if the char fits.
163
+ // If it doesn't fit (because currentChunkVisualWidth was already > 0 from a previous char that filled the line),
164
+ // then numCodePointsInChunk would not be 0.
165
+ // This branch means the current char *itself* doesn't fit an empty line, which is handled by the above.
166
+ // If we are here, it means the loop should break and the current chunk (which is empty) is finalized.
167
+ }
168
+ }
169
+ break; // Break from inner loop to finalize this chunk
170
+ }
171
+ currentChunk += char;
172
+ currentChunkVisualWidth += charVisualWidth;
173
+ numCodePointsInChunk++;
174
+ // Check for word break opportunity (space)
175
+ if (char === ' ') {
176
+ lastWordBreakPoint = i; // Store code point index of the space
177
+ // Store the state *before* adding the space, if we decide to break here.
178
+ numCodePointsAtLastWordBreak = numCodePointsInChunk - 1; // Chars *before* the space
179
+ }
180
+ }
181
+ // If the inner loop completed without breaking (i.e., remaining text fits)
182
+ // or if the loop broke but numCodePointsInChunk is still 0 (e.g. first char too wide for empty line)
183
+ if (numCodePointsInChunk === 0 &&
184
+ currentPosInLogLine < codePointsInLogLine.length) {
185
+ // This can happen if the very first character considered for a new visual line is wider than the viewport.
186
+ // In this case, we take that single character.
187
+ const firstChar = codePointsInLogLine[currentPosInLogLine];
188
+ currentChunk = firstChar;
189
+ numCodePointsInChunk = 1; // Ensure we advance
190
+ }
191
+ // If after everything, numCodePointsInChunk is still 0 but we haven't processed the whole logical line,
192
+ // it implies an issue, like viewportWidth being 0 or less. Avoid infinite loop.
193
+ if (numCodePointsInChunk === 0 &&
194
+ currentPosInLogLine < codePointsInLogLine.length) {
195
+ // Force advance by one character to prevent infinite loop if something went wrong
196
+ currentChunk = codePointsInLogLine[currentPosInLogLine];
197
+ numCodePointsInChunk = 1;
198
+ }
199
+ logicalToVisualMap[logIndex].push([
200
+ visualLines.length,
201
+ currentPosInLogLine,
202
+ ]);
203
+ visualToLogicalMap.push([logIndex, currentPosInLogLine]);
204
+ visualLines.push(currentChunk);
205
+ // Cursor mapping logic
206
+ // Note: currentPosInLogLine here is the start of the currentChunk within the logical line.
207
+ if (logIndex === logicalCursor[0]) {
208
+ const cursorLogCol = logicalCursor[1]; // This is a code point index
209
+ if (cursorLogCol >= currentPosInLogLine &&
210
+ cursorLogCol < currentPosInLogLine + numCodePointsInChunk // Cursor is within this chunk
211
+ ) {
212
+ currentVisualCursor = [
213
+ visualLines.length - 1,
214
+ cursorLogCol - currentPosInLogLine, // Visual col is also code point index within visual line
215
+ ];
216
+ }
217
+ else if (cursorLogCol === currentPosInLogLine + numCodePointsInChunk &&
218
+ numCodePointsInChunk > 0) {
219
+ // Cursor is exactly at the end of this non-empty chunk
220
+ currentVisualCursor = [
221
+ visualLines.length - 1,
222
+ numCodePointsInChunk,
223
+ ];
224
+ }
225
+ }
226
+ const logicalStartOfThisChunk = currentPosInLogLine;
227
+ currentPosInLogLine += numCodePointsInChunk;
228
+ // If the chunk processed did not consume the entire logical line,
229
+ // and the character immediately following the chunk is a space,
230
+ // advance past this space as it acted as a delimiter for word wrapping.
231
+ if (logicalStartOfThisChunk + numCodePointsInChunk <
232
+ codePointsInLogLine.length &&
233
+ currentPosInLogLine < codePointsInLogLine.length && // Redundant if previous is true, but safe
234
+ codePointsInLogLine[currentPosInLogLine] === ' ') {
235
+ currentPosInLogLine++;
236
+ }
237
+ }
238
+ // After all chunks of a non-empty logical line are processed,
239
+ // if the cursor is at the very end of this logical line, update visual cursor.
240
+ if (logIndex === logicalCursor[0] &&
241
+ logicalCursor[1] === codePointsInLogLine.length // Cursor at end of logical line
242
+ ) {
243
+ const lastVisualLineIdx = visualLines.length - 1;
244
+ if (lastVisualLineIdx >= 0 &&
245
+ visualLines[lastVisualLineIdx] !== undefined) {
246
+ currentVisualCursor = [
247
+ lastVisualLineIdx,
248
+ cpLen(visualLines[lastVisualLineIdx]), // Cursor at end of last visual line for this logical line
249
+ ];
250
+ }
251
+ }
252
+ }
253
+ });
254
+ // If the entire logical text was empty, ensure there's one empty visual line.
255
+ if (logicalLines.length === 0 ||
256
+ (logicalLines.length === 1 && logicalLines[0] === '')) {
257
+ if (visualLines.length === 0) {
258
+ visualLines.push('');
259
+ if (!logicalToVisualMap[0])
260
+ logicalToVisualMap[0] = [];
261
+ logicalToVisualMap[0].push([0, 0]);
262
+ visualToLogicalMap.push([0, 0]);
263
+ }
264
+ currentVisualCursor = [0, 0];
265
+ }
266
+ // Handle cursor at the very end of the text (after all processing)
267
+ // This case might be covered by the loop end condition now, but kept for safety.
268
+ else if (logicalCursor[0] === logicalLines.length - 1 &&
269
+ logicalCursor[1] === cpLen(logicalLines[logicalLines.length - 1]) &&
270
+ visualLines.length > 0) {
271
+ const lastVisLineIdx = visualLines.length - 1;
272
+ currentVisualCursor = [lastVisLineIdx, cpLen(visualLines[lastVisLineIdx])];
273
+ }
274
+ return {
275
+ visualLines,
276
+ visualCursor: currentVisualCursor,
277
+ logicalToVisualMap,
278
+ visualToLogicalMap,
279
+ };
280
+ }
281
+ const historyLimit = 100;
282
+ export function textBufferReducer(state, action) {
283
+ const pushUndo = (currentState) => {
284
+ const snapshot = {
285
+ lines: [...currentState.lines],
286
+ cursorRow: currentState.cursorRow,
287
+ cursorCol: currentState.cursorCol,
288
+ };
289
+ const newStack = [...currentState.undoStack, snapshot];
290
+ if (newStack.length > historyLimit) {
291
+ newStack.shift();
292
+ }
293
+ return { ...currentState, undoStack: newStack, redoStack: [] };
294
+ };
295
+ const currentLine = (r) => state.lines[r] ?? '';
296
+ const currentLineLen = (r) => cpLen(currentLine(r));
297
+ switch (action.type) {
298
+ case 'set_text': {
299
+ let nextState = state;
300
+ if (action.pushToUndo !== false) {
301
+ nextState = pushUndo(state);
302
+ }
303
+ const newContentLines = action.payload
304
+ .replace(/\r\n?/g, '\n')
305
+ .split('\n');
306
+ const lines = newContentLines.length === 0 ? [''] : newContentLines;
307
+ const lastNewLineIndex = lines.length - 1;
308
+ return {
309
+ ...nextState,
310
+ lines,
311
+ cursorRow: lastNewLineIndex,
312
+ cursorCol: cpLen(lines[lastNewLineIndex] ?? ''),
313
+ preferredCol: null,
314
+ };
315
+ }
316
+ case 'insert': {
317
+ const nextState = pushUndo(state);
318
+ const newLines = [...nextState.lines];
319
+ let newCursorRow = nextState.cursorRow;
320
+ let newCursorCol = nextState.cursorCol;
321
+ const currentLine = (r) => newLines[r] ?? '';
322
+ const str = stripUnsafeCharacters(action.payload.replace(/\r\n/g, '\n').replace(/\r/g, '\n'));
323
+ const parts = str.split('\n');
324
+ const lineContent = currentLine(newCursorRow);
325
+ const before = cpSlice(lineContent, 0, newCursorCol);
326
+ const after = cpSlice(lineContent, newCursorCol);
327
+ if (parts.length > 1) {
328
+ // First line: existing content before cursor + first part of paste
329
+ newLines[newCursorRow] = before + parts[0];
330
+ // Middle lines (if any) – everything except first & last part
331
+ const middleParts = parts.slice(1, -1);
332
+ if (middleParts.length > 0) {
333
+ newLines.splice(newCursorRow + 1, 0, ...middleParts);
334
+ }
335
+ // Last line: last part of paste + existing content after cursor
336
+ const lastPart = parts[parts.length - 1];
337
+ newLines.splice(newCursorRow + middleParts.length + 1, 0, lastPart + after);
338
+ newCursorRow = newCursorRow + parts.length - 1;
339
+ newCursorCol = cpLen(lastPart);
340
+ }
341
+ else {
342
+ newLines[newCursorRow] = before + parts[0] + after;
343
+ newCursorCol = cpLen(before) + cpLen(parts[0]);
344
+ }
345
+ return {
346
+ ...nextState,
347
+ lines: newLines,
348
+ cursorRow: newCursorRow,
349
+ cursorCol: newCursorCol,
350
+ preferredCol: null,
351
+ };
352
+ }
353
+ case 'backspace': {
354
+ const nextState = pushUndo(state);
355
+ const newLines = [...nextState.lines];
356
+ let newCursorRow = nextState.cursorRow;
357
+ let newCursorCol = nextState.cursorCol;
358
+ const currentLine = (r) => newLines[r] ?? '';
359
+ if (newCursorCol === 0 && newCursorRow === 0)
360
+ return state;
361
+ if (newCursorCol > 0) {
362
+ const lineContent = currentLine(newCursorRow);
363
+ newLines[newCursorRow] =
364
+ cpSlice(lineContent, 0, newCursorCol - 1) +
365
+ cpSlice(lineContent, newCursorCol);
366
+ newCursorCol--;
367
+ }
368
+ else if (newCursorRow > 0) {
369
+ const prevLineContent = currentLine(newCursorRow - 1);
370
+ const currentLineContentVal = currentLine(newCursorRow);
371
+ const newCol = cpLen(prevLineContent);
372
+ newLines[newCursorRow - 1] = prevLineContent + currentLineContentVal;
373
+ newLines.splice(newCursorRow, 1);
374
+ newCursorRow--;
375
+ newCursorCol = newCol;
376
+ }
377
+ return {
378
+ ...nextState,
379
+ lines: newLines,
380
+ cursorRow: newCursorRow,
381
+ cursorCol: newCursorCol,
382
+ preferredCol: null,
383
+ };
384
+ }
385
+ case 'set_viewport_width': {
386
+ if (action.payload === state.viewportWidth) {
387
+ return state;
388
+ }
389
+ return { ...state, viewportWidth: action.payload };
390
+ }
391
+ case 'move': {
392
+ const { dir } = action.payload;
393
+ const { lines, cursorRow, cursorCol, viewportWidth } = state;
394
+ const visualLayout = calculateVisualLayout(lines, [cursorRow, cursorCol], viewportWidth);
395
+ const { visualLines, visualCursor, visualToLogicalMap } = visualLayout;
396
+ let newVisualRow = visualCursor[0];
397
+ let newVisualCol = visualCursor[1];
398
+ let newPreferredCol = state.preferredCol;
399
+ const currentVisLineLen = cpLen(visualLines[newVisualRow] ?? '');
400
+ switch (dir) {
401
+ case 'left':
402
+ newPreferredCol = null;
403
+ if (newVisualCol > 0) {
404
+ newVisualCol--;
405
+ }
406
+ else if (newVisualRow > 0) {
407
+ newVisualRow--;
408
+ newVisualCol = cpLen(visualLines[newVisualRow] ?? '');
409
+ }
410
+ break;
411
+ case 'right':
412
+ newPreferredCol = null;
413
+ if (newVisualCol < currentVisLineLen) {
414
+ newVisualCol++;
415
+ }
416
+ else if (newVisualRow < visualLines.length - 1) {
417
+ newVisualRow++;
418
+ newVisualCol = 0;
419
+ }
420
+ break;
421
+ case 'up':
422
+ if (newVisualRow > 0) {
423
+ if (newPreferredCol === null)
424
+ newPreferredCol = newVisualCol;
425
+ newVisualRow--;
426
+ newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow] ?? ''));
427
+ }
428
+ break;
429
+ case 'down':
430
+ if (newVisualRow < visualLines.length - 1) {
431
+ if (newPreferredCol === null)
432
+ newPreferredCol = newVisualCol;
433
+ newVisualRow++;
434
+ newVisualCol = clamp(newPreferredCol, 0, cpLen(visualLines[newVisualRow] ?? ''));
435
+ }
436
+ break;
437
+ case 'home':
438
+ newPreferredCol = null;
439
+ newVisualCol = 0;
440
+ break;
441
+ case 'end':
442
+ newPreferredCol = null;
443
+ newVisualCol = currentVisLineLen;
444
+ break;
445
+ case 'wordLeft': {
446
+ const { cursorRow, cursorCol, lines } = state;
447
+ if (cursorCol === 0 && cursorRow === 0)
448
+ return state;
449
+ let newCursorRow = cursorRow;
450
+ let newCursorCol = cursorCol;
451
+ if (cursorCol === 0) {
452
+ newCursorRow--;
453
+ newCursorCol = cpLen(lines[newCursorRow] ?? '');
454
+ }
455
+ else {
456
+ const lineContent = lines[cursorRow];
457
+ const arr = toCodePoints(lineContent);
458
+ let start = cursorCol;
459
+ let onlySpaces = true;
460
+ for (let i = 0; i < start; i++) {
461
+ if (isWordChar(arr[i])) {
462
+ onlySpaces = false;
463
+ break;
464
+ }
465
+ }
466
+ if (onlySpaces && start > 0) {
467
+ start--;
468
+ }
469
+ else {
470
+ while (start > 0 && !isWordChar(arr[start - 1]))
471
+ start--;
472
+ while (start > 0 && isWordChar(arr[start - 1]))
473
+ start--;
474
+ }
475
+ newCursorCol = start;
476
+ }
477
+ return {
478
+ ...state,
479
+ cursorRow: newCursorRow,
480
+ cursorCol: newCursorCol,
481
+ preferredCol: null,
482
+ };
483
+ }
484
+ case 'wordRight': {
485
+ const { cursorRow, cursorCol, lines } = state;
486
+ if (cursorRow === lines.length - 1 &&
487
+ cursorCol === cpLen(lines[cursorRow] ?? '')) {
488
+ return state;
489
+ }
490
+ let newCursorRow = cursorRow;
491
+ let newCursorCol = cursorCol;
492
+ const lineContent = lines[cursorRow] ?? '';
493
+ const arr = toCodePoints(lineContent);
494
+ if (cursorCol >= arr.length) {
495
+ newCursorRow++;
496
+ newCursorCol = 0;
497
+ }
498
+ else {
499
+ let end = cursorCol;
500
+ while (end < arr.length && !isWordChar(arr[end]))
501
+ end++;
502
+ while (end < arr.length && isWordChar(arr[end]))
503
+ end++;
504
+ newCursorCol = end;
505
+ }
506
+ return {
507
+ ...state,
508
+ cursorRow: newCursorRow,
509
+ cursorCol: newCursorCol,
510
+ preferredCol: null,
511
+ };
512
+ }
513
+ default:
514
+ break;
515
+ }
516
+ if (visualToLogicalMap[newVisualRow]) {
517
+ const [logRow, logStartCol] = visualToLogicalMap[newVisualRow];
518
+ return {
519
+ ...state,
520
+ cursorRow: logRow,
521
+ cursorCol: clamp(logStartCol + newVisualCol, 0, cpLen(state.lines[logRow] ?? '')),
522
+ preferredCol: newPreferredCol,
523
+ };
524
+ }
525
+ return state;
526
+ }
527
+ case 'delete': {
528
+ const { cursorRow, cursorCol, lines } = state;
529
+ const lineContent = currentLine(cursorRow);
530
+ if (cursorCol < currentLineLen(cursorRow)) {
531
+ const nextState = pushUndo(state);
532
+ const newLines = [...nextState.lines];
533
+ newLines[cursorRow] =
534
+ cpSlice(lineContent, 0, cursorCol) +
535
+ cpSlice(lineContent, cursorCol + 1);
536
+ return { ...nextState, lines: newLines, preferredCol: null };
537
+ }
538
+ else if (cursorRow < lines.length - 1) {
539
+ const nextState = pushUndo(state);
540
+ const nextLineContent = currentLine(cursorRow + 1);
541
+ const newLines = [...nextState.lines];
542
+ newLines[cursorRow] = lineContent + nextLineContent;
543
+ newLines.splice(cursorRow + 1, 1);
544
+ return { ...nextState, lines: newLines, preferredCol: null };
545
+ }
546
+ return state;
547
+ }
548
+ case 'delete_word_left': {
549
+ const { cursorRow, cursorCol } = state;
550
+ if (cursorCol === 0 && cursorRow === 0)
551
+ return state;
552
+ if (cursorCol === 0) {
553
+ // Act as a backspace
554
+ const nextState = pushUndo(state);
555
+ const prevLineContent = currentLine(cursorRow - 1);
556
+ const currentLineContentVal = currentLine(cursorRow);
557
+ const newCol = cpLen(prevLineContent);
558
+ const newLines = [...nextState.lines];
559
+ newLines[cursorRow - 1] = prevLineContent + currentLineContentVal;
560
+ newLines.splice(cursorRow, 1);
561
+ return {
562
+ ...nextState,
563
+ lines: newLines,
564
+ cursorRow: cursorRow - 1,
565
+ cursorCol: newCol,
566
+ preferredCol: null,
567
+ };
568
+ }
569
+ const nextState = pushUndo(state);
570
+ const lineContent = currentLine(cursorRow);
571
+ const arr = toCodePoints(lineContent);
572
+ let start = cursorCol;
573
+ let onlySpaces = true;
574
+ for (let i = 0; i < start; i++) {
575
+ if (isWordChar(arr[i])) {
576
+ onlySpaces = false;
577
+ break;
578
+ }
579
+ }
580
+ if (onlySpaces && start > 0) {
581
+ start--;
582
+ }
583
+ else {
584
+ while (start > 0 && !isWordChar(arr[start - 1]))
585
+ start--;
586
+ while (start > 0 && isWordChar(arr[start - 1]))
587
+ start--;
588
+ }
589
+ const newLines = [...nextState.lines];
590
+ newLines[cursorRow] =
591
+ cpSlice(lineContent, 0, start) + cpSlice(lineContent, cursorCol);
592
+ return {
593
+ ...nextState,
594
+ lines: newLines,
595
+ cursorCol: start,
596
+ preferredCol: null,
597
+ };
598
+ }
599
+ case 'delete_word_right': {
600
+ const { cursorRow, cursorCol, lines } = state;
601
+ const lineContent = currentLine(cursorRow);
602
+ const arr = toCodePoints(lineContent);
603
+ if (cursorCol >= arr.length && cursorRow === lines.length - 1)
604
+ return state;
605
+ if (cursorCol >= arr.length) {
606
+ // Act as a delete
607
+ const nextState = pushUndo(state);
608
+ const nextLineContent = currentLine(cursorRow + 1);
609
+ const newLines = [...nextState.lines];
610
+ newLines[cursorRow] = lineContent + nextLineContent;
611
+ newLines.splice(cursorRow + 1, 1);
612
+ return { ...nextState, lines: newLines, preferredCol: null };
613
+ }
614
+ const nextState = pushUndo(state);
615
+ let end = cursorCol;
616
+ while (end < arr.length && !isWordChar(arr[end]))
617
+ end++;
618
+ while (end < arr.length && isWordChar(arr[end]))
619
+ end++;
620
+ const newLines = [...nextState.lines];
621
+ newLines[cursorRow] =
622
+ cpSlice(lineContent, 0, cursorCol) + cpSlice(lineContent, end);
623
+ return { ...nextState, lines: newLines, preferredCol: null };
624
+ }
625
+ case 'kill_line_right': {
626
+ const { cursorRow, cursorCol, lines } = state;
627
+ const lineContent = currentLine(cursorRow);
628
+ if (cursorCol < currentLineLen(cursorRow)) {
629
+ const nextState = pushUndo(state);
630
+ const newLines = [...nextState.lines];
631
+ newLines[cursorRow] = cpSlice(lineContent, 0, cursorCol);
632
+ return { ...nextState, lines: newLines };
633
+ }
634
+ else if (cursorRow < lines.length - 1) {
635
+ // Act as a delete
636
+ const nextState = pushUndo(state);
637
+ const nextLineContent = currentLine(cursorRow + 1);
638
+ const newLines = [...nextState.lines];
639
+ newLines[cursorRow] = lineContent + nextLineContent;
640
+ newLines.splice(cursorRow + 1, 1);
641
+ return { ...nextState, lines: newLines, preferredCol: null };
642
+ }
643
+ return state;
644
+ }
645
+ case 'kill_line_left': {
646
+ const { cursorRow, cursorCol } = state;
647
+ if (cursorCol > 0) {
648
+ const nextState = pushUndo(state);
649
+ const lineContent = currentLine(cursorRow);
650
+ const newLines = [...nextState.lines];
651
+ newLines[cursorRow] = cpSlice(lineContent, cursorCol);
652
+ return {
653
+ ...nextState,
654
+ lines: newLines,
655
+ cursorCol: 0,
656
+ preferredCol: null,
657
+ };
658
+ }
659
+ return state;
660
+ }
661
+ case 'undo': {
662
+ const stateToRestore = state.undoStack[state.undoStack.length - 1];
663
+ if (!stateToRestore)
664
+ return state;
665
+ const currentSnapshot = {
666
+ lines: [...state.lines],
667
+ cursorRow: state.cursorRow,
668
+ cursorCol: state.cursorCol,
669
+ };
670
+ return {
671
+ ...state,
672
+ ...stateToRestore,
673
+ undoStack: state.undoStack.slice(0, -1),
674
+ redoStack: [...state.redoStack, currentSnapshot],
675
+ };
676
+ }
677
+ case 'redo': {
678
+ const stateToRestore = state.redoStack[state.redoStack.length - 1];
679
+ if (!stateToRestore)
680
+ return state;
681
+ const currentSnapshot = {
682
+ lines: [...state.lines],
683
+ cursorRow: state.cursorRow,
684
+ cursorCol: state.cursorCol,
685
+ };
686
+ return {
687
+ ...state,
688
+ ...stateToRestore,
689
+ redoStack: state.redoStack.slice(0, -1),
690
+ undoStack: [...state.undoStack, currentSnapshot],
691
+ };
692
+ }
693
+ case 'replace_range': {
694
+ const { startRow, startCol, endRow, endCol, text } = action.payload;
695
+ if (startRow > endRow ||
696
+ (startRow === endRow && startCol > endCol) ||
697
+ startRow < 0 ||
698
+ startCol < 0 ||
699
+ endRow >= state.lines.length ||
700
+ (endRow < state.lines.length && endCol > currentLineLen(endRow))) {
701
+ return state; // Invalid range
702
+ }
703
+ const nextState = pushUndo(state);
704
+ const newLines = [...nextState.lines];
705
+ const sCol = clamp(startCol, 0, currentLineLen(startRow));
706
+ const eCol = clamp(endCol, 0, currentLineLen(endRow));
707
+ const prefix = cpSlice(currentLine(startRow), 0, sCol);
708
+ const suffix = cpSlice(currentLine(endRow), eCol);
709
+ const normalisedReplacement = text
710
+ .replace(/\r\n/g, '\n')
711
+ .replace(/\r/g, '\n');
712
+ const replacementParts = normalisedReplacement.split('\n');
713
+ // Replace the content
714
+ if (startRow === endRow) {
715
+ newLines[startRow] = prefix + normalisedReplacement + suffix;
716
+ }
717
+ else {
718
+ const firstLine = prefix + replacementParts[0];
719
+ if (replacementParts.length === 1) {
720
+ // Single line of replacement text, but spanning multiple original lines
721
+ newLines.splice(startRow, endRow - startRow + 1, firstLine + suffix);
722
+ }
723
+ else {
724
+ // Multi-line replacement text
725
+ const lastLine = replacementParts[replacementParts.length - 1] + suffix;
726
+ const middleLines = replacementParts.slice(1, -1);
727
+ newLines.splice(startRow, endRow - startRow + 1, firstLine, ...middleLines, lastLine);
728
+ }
729
+ }
730
+ const finalCursorRow = startRow + replacementParts.length - 1;
731
+ const finalCursorCol = (replacementParts.length > 1 ? 0 : sCol) +
732
+ cpLen(replacementParts[replacementParts.length - 1]);
733
+ return {
734
+ ...nextState,
735
+ lines: newLines,
736
+ cursorRow: finalCursorRow,
737
+ cursorCol: finalCursorCol,
738
+ preferredCol: null,
739
+ };
740
+ }
741
+ case 'move_to_offset': {
742
+ const { offset } = action.payload;
743
+ const [newRow, newCol] = offsetToLogicalPos(state.lines.join('\n'), offset);
744
+ return {
745
+ ...state,
746
+ cursorRow: newRow,
747
+ cursorCol: newCol,
748
+ preferredCol: null,
749
+ };
750
+ }
751
+ case 'create_undo_snapshot': {
752
+ return pushUndo(state);
753
+ }
754
+ default: {
755
+ const exhaustiveCheck = action;
756
+ console.error(`Unknown action encountered: ${exhaustiveCheck}`);
757
+ return state;
758
+ }
759
+ }
760
+ }
761
+ // --- End of reducer logic ---
762
+ export function useTextBuffer({ initialText = '', initialCursorOffset = 0, viewport, stdin, setRawMode, onChange, isValidPath, shellModeActive = false, }) {
763
+ const initialState = useMemo(() => {
764
+ const lines = initialText.split('\n');
765
+ const [initialCursorRow, initialCursorCol] = calculateInitialCursorPosition(lines.length === 0 ? [''] : lines, initialCursorOffset);
766
+ return {
767
+ lines: lines.length === 0 ? [''] : lines,
768
+ cursorRow: initialCursorRow,
769
+ cursorCol: initialCursorCol,
770
+ preferredCol: null,
771
+ undoStack: [],
772
+ redoStack: [],
773
+ clipboard: null,
774
+ selectionAnchor: null,
775
+ viewportWidth: viewport.width,
776
+ };
777
+ }, [initialText, initialCursorOffset, viewport.width]);
778
+ const [state, dispatch] = useReducer(textBufferReducer, initialState);
779
+ const { lines, cursorRow, cursorCol, preferredCol, selectionAnchor } = state;
780
+ const text = useMemo(() => lines.join('\n'), [lines]);
781
+ const visualLayout = useMemo(() => calculateVisualLayout(lines, [cursorRow, cursorCol], state.viewportWidth), [lines, cursorRow, cursorCol, state.viewportWidth]);
782
+ const { visualLines, visualCursor } = visualLayout;
783
+ const [visualScrollRow, setVisualScrollRow] = useState(0);
784
+ useEffect(() => {
785
+ if (onChange) {
786
+ onChange(text);
787
+ }
788
+ }, [text, onChange]);
789
+ useEffect(() => {
790
+ dispatch({ type: 'set_viewport_width', payload: viewport.width });
791
+ }, [viewport.width]);
792
+ // Update visual scroll (vertical)
793
+ useEffect(() => {
794
+ const { height } = viewport;
795
+ let newVisualScrollRow = visualScrollRow;
796
+ if (visualCursor[0] < visualScrollRow) {
797
+ newVisualScrollRow = visualCursor[0];
798
+ }
799
+ else if (visualCursor[0] >= visualScrollRow + height) {
800
+ newVisualScrollRow = visualCursor[0] - height + 1;
801
+ }
802
+ if (newVisualScrollRow !== visualScrollRow) {
803
+ setVisualScrollRow(newVisualScrollRow);
804
+ }
805
+ }, [visualCursor, visualScrollRow, viewport]);
806
+ const insert = useCallback((ch) => {
807
+ if (/[\n\r]/.test(ch)) {
808
+ dispatch({ type: 'insert', payload: ch });
809
+ return;
810
+ }
811
+ const minLengthToInferAsDragDrop = 3;
812
+ if (ch.length >= minLengthToInferAsDragDrop && !shellModeActive) {
813
+ let potentialPath = ch;
814
+ if (potentialPath.length > 2 &&
815
+ potentialPath.startsWith("'") &&
816
+ potentialPath.endsWith("'")) {
817
+ potentialPath = ch.slice(1, -1);
818
+ }
819
+ potentialPath = potentialPath.trim();
820
+ if (isValidPath(unescapePath(potentialPath))) {
821
+ ch = `@${potentialPath}`;
822
+ }
823
+ }
824
+ let currentText = '';
825
+ for (const char of toCodePoints(ch)) {
826
+ if (char.codePointAt(0) === 127) {
827
+ if (currentText.length > 0) {
828
+ dispatch({ type: 'insert', payload: currentText });
829
+ currentText = '';
830
+ }
831
+ dispatch({ type: 'backspace' });
832
+ }
833
+ else {
834
+ currentText += char;
835
+ }
836
+ }
837
+ if (currentText.length > 0) {
838
+ dispatch({ type: 'insert', payload: currentText });
839
+ }
840
+ }, [isValidPath, shellModeActive]);
841
+ const newline = useCallback(() => {
842
+ dispatch({ type: 'insert', payload: '\n' });
843
+ }, []);
844
+ const backspace = useCallback(() => {
845
+ dispatch({ type: 'backspace' });
846
+ }, []);
847
+ const del = useCallback(() => {
848
+ dispatch({ type: 'delete' });
849
+ }, []);
850
+ const move = useCallback((dir) => {
851
+ dispatch({ type: 'move', payload: { dir } });
852
+ }, []);
853
+ const undo = useCallback(() => {
854
+ dispatch({ type: 'undo' });
855
+ }, []);
856
+ const redo = useCallback(() => {
857
+ dispatch({ type: 'redo' });
858
+ }, []);
859
+ const setText = useCallback((newText) => {
860
+ dispatch({ type: 'set_text', payload: newText });
861
+ }, []);
862
+ const deleteWordLeft = useCallback(() => {
863
+ dispatch({ type: 'delete_word_left' });
864
+ }, []);
865
+ const deleteWordRight = useCallback(() => {
866
+ dispatch({ type: 'delete_word_right' });
867
+ }, []);
868
+ const killLineRight = useCallback(() => {
869
+ dispatch({ type: 'kill_line_right' });
870
+ }, []);
871
+ const killLineLeft = useCallback(() => {
872
+ dispatch({ type: 'kill_line_left' });
873
+ }, []);
874
+ const openInExternalEditor = useCallback(async (opts = {}) => {
875
+ const editor = opts.editor ??
876
+ process.env['VISUAL'] ??
877
+ process.env['EDITOR'] ??
878
+ (process.platform === 'win32' ? 'notepad' : 'vi');
879
+ const tmpDir = fs.mkdtempSync(pathMod.join(os.tmpdir(), 'gemini-edit-'));
880
+ const filePath = pathMod.join(tmpDir, 'buffer.txt');
881
+ fs.writeFileSync(filePath, text, 'utf8');
882
+ dispatch({ type: 'create_undo_snapshot' });
883
+ const wasRaw = stdin?.isRaw ?? false;
884
+ try {
885
+ setRawMode?.(false);
886
+ const { status, error } = spawnSync(editor, [filePath], {
887
+ stdio: 'inherit',
888
+ });
889
+ if (error)
890
+ throw error;
891
+ if (typeof status === 'number' && status !== 0)
892
+ throw new Error(`External editor exited with status ${status}`);
893
+ let newText = fs.readFileSync(filePath, 'utf8');
894
+ newText = newText.replace(/\r\n?/g, '\n');
895
+ dispatch({ type: 'set_text', payload: newText, pushToUndo: false });
896
+ }
897
+ catch (err) {
898
+ console.error('[useTextBuffer] external editor error', err);
899
+ }
900
+ finally {
901
+ if (wasRaw)
902
+ setRawMode?.(true);
903
+ try {
904
+ fs.unlinkSync(filePath);
905
+ }
906
+ catch {
907
+ /* ignore */
908
+ }
909
+ try {
910
+ fs.rmdirSync(tmpDir);
911
+ }
912
+ catch {
913
+ /* ignore */
914
+ }
915
+ }
916
+ }, [text, stdin, setRawMode]);
917
+ const handleInput = useCallback((key) => {
918
+ const { sequence: input } = key;
919
+ // Handle paste content atomically
920
+ if (key.paste && input) {
921
+ // For paste, insert the entire content at once, preserving newlines
922
+ insert(input);
923
+ return;
924
+ }
925
+ if (key.name === 'return' ||
926
+ input === '\r' ||
927
+ input === '\n' ||
928
+ input === '\\\r' // VSCode terminal represents shift + enter this way
929
+ )
930
+ newline();
931
+ else if (key.name === 'left' && !key.meta && !key.ctrl)
932
+ move('left');
933
+ else if (key.ctrl && key.name === 'b')
934
+ move('left');
935
+ else if (key.name === 'right' && !key.meta && !key.ctrl)
936
+ move('right');
937
+ else if (key.ctrl && key.name === 'f')
938
+ move('right');
939
+ else if (key.name === 'up')
940
+ move('up');
941
+ else if (key.name === 'down')
942
+ move('down');
943
+ else if ((key.ctrl || key.meta) && key.name === 'left')
944
+ move('wordLeft');
945
+ else if (key.meta && key.name === 'b')
946
+ move('wordLeft');
947
+ else if ((key.ctrl || key.meta) && key.name === 'right')
948
+ move('wordRight');
949
+ else if (key.meta && key.name === 'f')
950
+ move('wordRight');
951
+ else if (key.name === 'home')
952
+ move('home');
953
+ else if (key.ctrl && key.name === 'a')
954
+ move('home');
955
+ else if (key.name === 'end')
956
+ move('end');
957
+ else if (key.ctrl && key.name === 'e')
958
+ move('end');
959
+ else if (key.ctrl && key.name === 'w')
960
+ deleteWordLeft();
961
+ else if ((key.meta || key.ctrl) &&
962
+ (key.name === 'backspace' || input === '\x7f'))
963
+ deleteWordLeft();
964
+ else if ((key.meta || key.ctrl) && key.name === 'delete')
965
+ deleteWordRight();
966
+ else if (key.name === 'backspace' ||
967
+ input === '\x7f' ||
968
+ (key.ctrl && key.name === 'h'))
969
+ backspace();
970
+ else if (key.name === 'delete' || (key.ctrl && key.name === 'd'))
971
+ del();
972
+ else if (input && !key.ctrl && !key.meta) {
973
+ insert(input);
974
+ }
975
+ }, [newline, move, deleteWordLeft, deleteWordRight, backspace, del, insert]);
976
+ const renderedVisualLines = useMemo(() => visualLines.slice(visualScrollRow, visualScrollRow + viewport.height), [visualLines, visualScrollRow, viewport.height]);
977
+ const replaceRange = useCallback((startRow, startCol, endRow, endCol, text) => {
978
+ dispatch({
979
+ type: 'replace_range',
980
+ payload: { startRow, startCol, endRow, endCol, text },
981
+ });
982
+ }, []);
983
+ const replaceRangeByOffset = useCallback((startOffset, endOffset, replacementText) => {
984
+ const [startRow, startCol] = offsetToLogicalPos(text, startOffset);
985
+ const [endRow, endCol] = offsetToLogicalPos(text, endOffset);
986
+ replaceRange(startRow, startCol, endRow, endCol, replacementText);
987
+ }, [text, replaceRange]);
988
+ const moveToOffset = useCallback((offset) => {
989
+ dispatch({ type: 'move_to_offset', payload: { offset } });
990
+ }, []);
991
+ const returnValue = {
992
+ lines,
993
+ text,
994
+ cursor: [cursorRow, cursorCol],
995
+ preferredCol,
996
+ selectionAnchor,
997
+ allVisualLines: visualLines,
998
+ viewportVisualLines: renderedVisualLines,
999
+ visualCursor,
1000
+ visualScrollRow,
1001
+ setText,
1002
+ insert,
1003
+ newline,
1004
+ backspace,
1005
+ del,
1006
+ move,
1007
+ undo,
1008
+ redo,
1009
+ replaceRange,
1010
+ replaceRangeByOffset,
1011
+ moveToOffset,
1012
+ deleteWordLeft,
1013
+ deleteWordRight,
1014
+ killLineRight,
1015
+ killLineLeft,
1016
+ handleInput,
1017
+ openInExternalEditor,
1018
+ };
1019
+ return returnValue;
1020
+ }
1021
+ //# sourceMappingURL=text-buffer.js.map