@fairyhunter13/opentui-core 0.1.91 → 0.1.94

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 (570) hide show
  1. package/3d/SpriteResourceManager.d.ts +74 -0
  2. package/3d/SpriteUtils.d.ts +13 -0
  3. package/3d/TextureUtils.d.ts +24 -0
  4. package/3d/ThreeRenderable.d.ts +40 -0
  5. package/3d/WGPURenderer.d.ts +61 -0
  6. package/3d/animation/ExplodingSpriteEffect.d.ts +71 -0
  7. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +76 -0
  8. package/3d/animation/SpriteAnimator.d.ts +124 -0
  9. package/3d/animation/SpriteParticleGenerator.d.ts +62 -0
  10. package/3d/canvas.d.ts +44 -0
  11. package/3d/index.d.ts +12 -0
  12. package/3d/physics/PlanckPhysicsAdapter.d.ts +19 -0
  13. package/3d/physics/RapierPhysicsAdapter.d.ts +19 -0
  14. package/3d/physics/physics-interface.d.ts +27 -0
  15. package/3d.d.ts +2 -0
  16. package/3d.js +34042 -0
  17. package/3d.js.map +155 -0
  18. package/LICENSE +21 -0
  19. package/NativeSpanFeed.d.ts +41 -0
  20. package/Renderable.d.ts +334 -0
  21. package/animation/Timeline.d.ts +126 -0
  22. package/ansi.d.ts +13 -0
  23. package/buffer.d.ts +107 -0
  24. package/console.d.ts +143 -0
  25. package/edit-buffer.d.ts +98 -0
  26. package/editor-view.d.ts +73 -0
  27. package/index-e6ec7apq.js +18415 -0
  28. package/index-e6ec7apq.js.map +64 -0
  29. package/index-h066zmrb.js +12619 -0
  30. package/index-h066zmrb.js.map +43 -0
  31. package/index-ynzawt3n.js +113 -0
  32. package/index-ynzawt3n.js.map +10 -0
  33. package/index.d.ts +21 -0
  34. package/index.js +430 -0
  35. package/index.js.map +9 -0
  36. package/lib/KeyHandler.d.ts +61 -0
  37. package/lib/RGBA.d.ts +25 -0
  38. package/lib/ascii.font.d.ts +508 -0
  39. package/lib/border.d.ts +49 -0
  40. package/lib/bunfs.d.ts +7 -0
  41. package/lib/clipboard.d.ts +17 -0
  42. package/lib/clock.d.ts +15 -0
  43. package/lib/data-paths.d.ts +26 -0
  44. package/lib/debounce.d.ts +42 -0
  45. package/lib/detect-links.d.ts +6 -0
  46. package/lib/env.d.ts +42 -0
  47. package/lib/extmarks-history.d.ts +17 -0
  48. package/lib/extmarks.d.ts +89 -0
  49. package/lib/hast-styled-text.d.ts +17 -0
  50. package/lib/index.d.ts +21 -0
  51. package/lib/keymapping.d.ts +25 -0
  52. package/lib/objects-in-viewport.d.ts +24 -0
  53. package/lib/output.capture.d.ts +24 -0
  54. package/lib/parse.keypress-kitty.d.ts +2 -0
  55. package/lib/parse.keypress.d.ts +26 -0
  56. package/lib/parse.mouse.d.ts +30 -0
  57. package/lib/paste.d.ts +7 -0
  58. package/lib/queue.d.ts +15 -0
  59. package/lib/renderable.validations.d.ts +12 -0
  60. package/lib/scroll-acceleration.d.ts +43 -0
  61. package/lib/selection.d.ts +63 -0
  62. package/lib/singleton.d.ts +7 -0
  63. package/lib/stdin-parser.d.ts +76 -0
  64. package/lib/styled-text.d.ts +63 -0
  65. package/lib/terminal-capability-detection.d.ts +30 -0
  66. package/lib/terminal-palette.d.ts +50 -0
  67. package/lib/tree-sitter/assets/update.d.ts +11 -0
  68. package/lib/tree-sitter/client.d.ts +47 -0
  69. package/lib/tree-sitter/default-parsers.d.ts +2 -0
  70. package/lib/tree-sitter/download-utils.d.ts +21 -0
  71. package/lib/tree-sitter/index.d.ts +8 -0
  72. package/lib/tree-sitter/parser.worker.d.ts +1 -0
  73. package/lib/tree-sitter/parsers-config.d.ts +38 -0
  74. package/lib/tree-sitter/resolve-ft.d.ts +2 -0
  75. package/lib/tree-sitter/types.d.ts +81 -0
  76. package/lib/tree-sitter-styled-text.d.ts +14 -0
  77. package/lib/validate-dir-name.d.ts +1 -0
  78. package/lib/yoga.options.d.ts +32 -0
  79. package/package.json +51 -63
  80. package/parser.worker.js +869 -0
  81. package/parser.worker.js.map +12 -0
  82. package/plugins/core-slot.d.ts +72 -0
  83. package/plugins/registry.d.ts +38 -0
  84. package/plugins/types.d.ts +34 -0
  85. package/post/filters.d.ts +105 -0
  86. package/renderables/ASCIIFont.d.ts +52 -0
  87. package/renderables/Box.d.ts +72 -0
  88. package/renderables/Code.d.ts +78 -0
  89. package/renderables/Diff.d.ts +142 -0
  90. package/renderables/EditBufferRenderable.d.ts +162 -0
  91. package/renderables/FrameBuffer.d.ts +16 -0
  92. package/renderables/Input.d.ts +67 -0
  93. package/renderables/LineNumberRenderable.d.ts +74 -0
  94. package/renderables/Markdown.d.ts +173 -0
  95. package/renderables/ScrollBar.d.ts +77 -0
  96. package/renderables/ScrollBox.d.ts +124 -0
  97. package/renderables/Select.d.ts +115 -0
  98. package/renderables/Slider.d.ts +44 -0
  99. package/renderables/TabSelect.d.ts +96 -0
  100. package/renderables/Text.d.ts +36 -0
  101. package/renderables/TextBufferRenderable.d.ts +105 -0
  102. package/renderables/TextNode.d.ts +91 -0
  103. package/renderables/TextTable.d.ts +140 -0
  104. package/renderables/Textarea.d.ts +114 -0
  105. package/renderables/TimeToFirstDraw.d.ts +24 -0
  106. package/renderables/__tests__/renderable-test-utils.d.ts +12 -0
  107. package/renderables/composition/VRenderable.d.ts +16 -0
  108. package/renderables/composition/constructs.d.ts +35 -0
  109. package/renderables/composition/vnode.d.ts +46 -0
  110. package/renderables/index.d.ts +22 -0
  111. package/renderables/markdown-parser.d.ts +10 -0
  112. package/renderer.d.ts +388 -0
  113. package/runtime-plugin-support.d.ts +3 -0
  114. package/runtime-plugin-support.js +29 -0
  115. package/runtime-plugin-support.js.map +10 -0
  116. package/runtime-plugin.d.ts +11 -0
  117. package/runtime-plugin.js +16 -0
  118. package/runtime-plugin.js.map +9 -0
  119. package/syntax-style.d.ts +54 -0
  120. package/testing/manual-clock.d.ts +16 -0
  121. package/testing/mock-keys.d.ts +81 -0
  122. package/testing/mock-mouse.d.ts +38 -0
  123. package/testing/mock-tree-sitter-client.d.ts +23 -0
  124. package/testing/spy.d.ts +7 -0
  125. package/testing/test-recorder.d.ts +61 -0
  126. package/testing/test-renderer.d.ts +23 -0
  127. package/testing.d.ts +6 -0
  128. package/testing.js +675 -0
  129. package/testing.js.map +15 -0
  130. package/text-buffer-view.d.ts +42 -0
  131. package/text-buffer.d.ts +67 -0
  132. package/types.d.ts +131 -0
  133. package/utils.d.ts +14 -0
  134. package/zig-structs.d.ts +155 -0
  135. package/zig.d.ts +351 -0
  136. package/dev/keypress-debug-renderer.ts +0 -148
  137. package/dev/keypress-debug.ts +0 -43
  138. package/dev/print-env-vars.ts +0 -32
  139. package/dev/test-tmux-graphics-334.sh +0 -68
  140. package/dev/thai-debug-test.ts +0 -68
  141. package/docs/development.md +0 -141
  142. package/docs/env-vars.md +0 -140
  143. package/docs/getting-started.md +0 -353
  144. package/docs/renderables-vs-constructs.md +0 -159
  145. package/docs/tree-sitter.md +0 -311
  146. package/scripts/build.ts +0 -400
  147. package/scripts/publish.ts +0 -60
  148. package/src/3d/SpriteResourceManager.ts +0 -286
  149. package/src/3d/SpriteUtils.ts +0 -71
  150. package/src/3d/TextureUtils.ts +0 -196
  151. package/src/3d/ThreeRenderable.ts +0 -197
  152. package/src/3d/WGPURenderer.ts +0 -294
  153. package/src/3d/animation/ExplodingSpriteEffect.ts +0 -513
  154. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +0 -429
  155. package/src/3d/animation/SpriteAnimator.ts +0 -633
  156. package/src/3d/animation/SpriteParticleGenerator.ts +0 -435
  157. package/src/3d/canvas.ts +0 -464
  158. package/src/3d/index.ts +0 -12
  159. package/src/3d/physics/PlanckPhysicsAdapter.ts +0 -72
  160. package/src/3d/physics/RapierPhysicsAdapter.ts +0 -66
  161. package/src/3d/physics/physics-interface.ts +0 -31
  162. package/src/3d/shaders/supersampling.wgsl +0 -201
  163. package/src/3d.ts +0 -3
  164. package/src/NativeSpanFeed.ts +0 -300
  165. package/src/Renderable.ts +0 -1698
  166. package/src/__snapshots__/buffer.test.ts.snap +0 -28
  167. package/src/animation/Timeline.test.ts +0 -2709
  168. package/src/animation/Timeline.ts +0 -598
  169. package/src/ansi.ts +0 -18
  170. package/src/benchmark/latest-all-bench-run.json +0 -707
  171. package/src/benchmark/latest-async-bench-run.json +0 -336
  172. package/src/benchmark/latest-default-bench-run.json +0 -657
  173. package/src/benchmark/latest-large-bench-run.json +0 -707
  174. package/src/benchmark/latest-quick-bench-run.json +0 -207
  175. package/src/benchmark/markdown-benchmark.ts +0 -1804
  176. package/src/benchmark/native-span-feed-async-benchmark.ts +0 -355
  177. package/src/benchmark/native-span-feed-benchmark.md +0 -56
  178. package/src/benchmark/native-span-feed-benchmark.ts +0 -596
  179. package/src/benchmark/native-span-feed-compare.ts +0 -280
  180. package/src/benchmark/renderer-benchmark.ts +0 -754
  181. package/src/benchmark/text-table-benchmark.ts +0 -947
  182. package/src/buffer.test.ts +0 -291
  183. package/src/buffer.ts +0 -519
  184. package/src/console.test.ts +0 -612
  185. package/src/console.ts +0 -1255
  186. package/src/edit-buffer.test.ts +0 -1769
  187. package/src/edit-buffer.ts +0 -411
  188. package/src/editor-view.test.ts +0 -1032
  189. package/src/editor-view.ts +0 -284
  190. package/src/examples/ascii-font-selection-demo.ts +0 -245
  191. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  192. package/src/examples/assets/concrete.png +0 -0
  193. package/src/examples/assets/crate.png +0 -0
  194. package/src/examples/assets/crate_emissive.png +0 -0
  195. package/src/examples/assets/forrest_background.png +0 -0
  196. package/src/examples/assets/hast-example.json +0 -1018
  197. package/src/examples/assets/heart.png +0 -0
  198. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  199. package/src/examples/assets/main_char_idle.png +0 -0
  200. package/src/examples/assets/main_char_jump_end.png +0 -0
  201. package/src/examples/assets/main_char_jump_landing.png +0 -0
  202. package/src/examples/assets/main_char_jump_start.png +0 -0
  203. package/src/examples/assets/main_char_run_loop.png +0 -0
  204. package/src/examples/assets/roughness_map.jpg +0 -0
  205. package/src/examples/build.ts +0 -115
  206. package/src/examples/code-demo.ts +0 -584
  207. package/src/examples/console-demo.ts +0 -358
  208. package/src/examples/core-plugin-slots-demo.ts +0 -759
  209. package/src/examples/diff-demo.ts +0 -699
  210. package/src/examples/draggable-three-demo.ts +0 -259
  211. package/src/examples/editor-demo.ts +0 -322
  212. package/src/examples/extmarks-demo.ts +0 -204
  213. package/src/examples/focus-restore-demo.ts +0 -310
  214. package/src/examples/fonts.ts +0 -245
  215. package/src/examples/fractal-shader-demo.ts +0 -268
  216. package/src/examples/framebuffer-demo.ts +0 -674
  217. package/src/examples/full-unicode-demo.ts +0 -181
  218. package/src/examples/golden-star-demo.ts +0 -933
  219. package/src/examples/grayscale-buffer-demo.ts +0 -249
  220. package/src/examples/hast-syntax-highlighting-demo.ts +0 -129
  221. package/src/examples/index.ts +0 -925
  222. package/src/examples/input-demo.ts +0 -377
  223. package/src/examples/input-select-layout-demo.ts +0 -425
  224. package/src/examples/install.sh +0 -143
  225. package/src/examples/keypress-debug-demo.ts +0 -452
  226. package/src/examples/lib/HexList.ts +0 -122
  227. package/src/examples/lib/PaletteGrid.ts +0 -125
  228. package/src/examples/lib/standalone-keys.ts +0 -25
  229. package/src/examples/lib/tab-controller.ts +0 -243
  230. package/src/examples/lights-phong-demo.ts +0 -290
  231. package/src/examples/link-demo.ts +0 -220
  232. package/src/examples/live-state-demo.ts +0 -480
  233. package/src/examples/markdown-demo.ts +0 -620
  234. package/src/examples/mouse-interaction-demo.ts +0 -428
  235. package/src/examples/nested-zindex-demo.ts +0 -357
  236. package/src/examples/opacity-example.ts +0 -235
  237. package/src/examples/opentui-demo.ts +0 -1057
  238. package/src/examples/physx-planck-2d-demo.ts +0 -507
  239. package/src/examples/physx-rapier-2d-demo.ts +0 -526
  240. package/src/examples/relative-positioning-demo.ts +0 -323
  241. package/src/examples/scroll-example.ts +0 -214
  242. package/src/examples/scrollbox-mouse-test.ts +0 -112
  243. package/src/examples/scrollbox-overlay-hit-test.ts +0 -206
  244. package/src/examples/select-demo.ts +0 -237
  245. package/src/examples/shader-cube-demo.ts +0 -772
  246. package/src/examples/simple-layout-example.ts +0 -591
  247. package/src/examples/slider-demo.ts +0 -617
  248. package/src/examples/split-mode-demo.ts +0 -445
  249. package/src/examples/sprite-animation-demo.ts +0 -443
  250. package/src/examples/sprite-particle-generator-demo.ts +0 -486
  251. package/src/examples/static-sprite-demo.ts +0 -193
  252. package/src/examples/sticky-scroll-example.ts +0 -308
  253. package/src/examples/styled-text-demo.ts +0 -282
  254. package/src/examples/tab-select-demo.ts +0 -219
  255. package/src/examples/terminal-title.ts +0 -29
  256. package/src/examples/terminal.ts +0 -305
  257. package/src/examples/text-node-demo.ts +0 -416
  258. package/src/examples/text-selection-demo.ts +0 -377
  259. package/src/examples/text-table-demo.ts +0 -503
  260. package/src/examples/text-truncation-demo.ts +0 -481
  261. package/src/examples/text-wrap.ts +0 -757
  262. package/src/examples/texture-loading-demo.ts +0 -259
  263. package/src/examples/timeline-example.ts +0 -670
  264. package/src/examples/transparency-demo.ts +0 -241
  265. package/src/examples/vnode-composition-demo.ts +0 -404
  266. package/src/index.ts +0 -22
  267. package/src/lib/KeyHandler.integration.test.ts +0 -292
  268. package/src/lib/KeyHandler.stopPropagation.test.ts +0 -289
  269. package/src/lib/KeyHandler.test.ts +0 -662
  270. package/src/lib/KeyHandler.ts +0 -222
  271. package/src/lib/RGBA.test.ts +0 -984
  272. package/src/lib/RGBA.ts +0 -204
  273. package/src/lib/ascii.font.ts +0 -330
  274. package/src/lib/border.test.ts +0 -83
  275. package/src/lib/border.ts +0 -168
  276. package/src/lib/bunfs.test.ts +0 -27
  277. package/src/lib/bunfs.ts +0 -18
  278. package/src/lib/clipboard.test.ts +0 -41
  279. package/src/lib/clipboard.ts +0 -47
  280. package/src/lib/clock.ts +0 -31
  281. package/src/lib/data-paths.test.ts +0 -133
  282. package/src/lib/data-paths.ts +0 -109
  283. package/src/lib/debounce.ts +0 -106
  284. package/src/lib/detect-links.test.ts +0 -98
  285. package/src/lib/detect-links.ts +0 -56
  286. package/src/lib/env.test.ts +0 -228
  287. package/src/lib/env.ts +0 -209
  288. package/src/lib/extmarks-history.ts +0 -51
  289. package/src/lib/extmarks-multiwidth.test.ts +0 -322
  290. package/src/lib/extmarks.test.ts +0 -3457
  291. package/src/lib/extmarks.ts +0 -843
  292. package/src/lib/fonts/block.json +0 -405
  293. package/src/lib/fonts/grid.json +0 -265
  294. package/src/lib/fonts/huge.json +0 -741
  295. package/src/lib/fonts/pallet.json +0 -314
  296. package/src/lib/fonts/shade.json +0 -591
  297. package/src/lib/fonts/slick.json +0 -321
  298. package/src/lib/fonts/tiny.json +0 -69
  299. package/src/lib/hast-styled-text.ts +0 -59
  300. package/src/lib/index.ts +0 -21
  301. package/src/lib/keymapping.test.ts +0 -280
  302. package/src/lib/keymapping.ts +0 -87
  303. package/src/lib/objects-in-viewport.test.ts +0 -787
  304. package/src/lib/objects-in-viewport.ts +0 -153
  305. package/src/lib/output.capture.ts +0 -58
  306. package/src/lib/parse.keypress-kitty.protocol.test.ts +0 -340
  307. package/src/lib/parse.keypress-kitty.test.ts +0 -663
  308. package/src/lib/parse.keypress-kitty.ts +0 -439
  309. package/src/lib/parse.keypress.test.ts +0 -1849
  310. package/src/lib/parse.keypress.ts +0 -397
  311. package/src/lib/parse.mouse.test.ts +0 -552
  312. package/src/lib/parse.mouse.ts +0 -232
  313. package/src/lib/paste.ts +0 -16
  314. package/src/lib/queue.ts +0 -65
  315. package/src/lib/renderable.validations.test.ts +0 -87
  316. package/src/lib/renderable.validations.ts +0 -83
  317. package/src/lib/scroll-acceleration.ts +0 -98
  318. package/src/lib/selection.ts +0 -240
  319. package/src/lib/singleton.ts +0 -28
  320. package/src/lib/stdin-parser.test.ts +0 -1676
  321. package/src/lib/stdin-parser.ts +0 -1248
  322. package/src/lib/styled-text.ts +0 -178
  323. package/src/lib/terminal-capability-detection.test.ts +0 -202
  324. package/src/lib/terminal-capability-detection.ts +0 -79
  325. package/src/lib/terminal-palette.test.ts +0 -878
  326. package/src/lib/terminal-palette.ts +0 -383
  327. package/src/lib/tree-sitter/assets/README.md +0 -118
  328. package/src/lib/tree-sitter/assets/update.ts +0 -331
  329. package/src/lib/tree-sitter/assets.d.ts +0 -9
  330. package/src/lib/tree-sitter/cache.test.ts +0 -270
  331. package/src/lib/tree-sitter/client.test.ts +0 -1061
  332. package/src/lib/tree-sitter/client.ts +0 -615
  333. package/src/lib/tree-sitter/default-parsers.ts +0 -80
  334. package/src/lib/tree-sitter/download-utils.ts +0 -148
  335. package/src/lib/tree-sitter/index.ts +0 -28
  336. package/src/lib/tree-sitter/parser.worker.ts +0 -1001
  337. package/src/lib/tree-sitter/parsers-config.ts +0 -75
  338. package/src/lib/tree-sitter/resolve-ft.ts +0 -62
  339. package/src/lib/tree-sitter/types.ts +0 -81
  340. package/src/lib/tree-sitter-styled-text.test.ts +0 -1253
  341. package/src/lib/tree-sitter-styled-text.ts +0 -306
  342. package/src/lib/validate-dir-name.ts +0 -55
  343. package/src/lib/yoga.options.test.ts +0 -628
  344. package/src/lib/yoga.options.ts +0 -346
  345. package/src/plugins/core-slot.ts +0 -579
  346. package/src/plugins/registry.ts +0 -377
  347. package/src/plugins/types.ts +0 -46
  348. package/src/post/filters.ts +0 -888
  349. package/src/renderables/ASCIIFont.ts +0 -219
  350. package/src/renderables/Box.test.ts +0 -160
  351. package/src/renderables/Box.ts +0 -295
  352. package/src/renderables/Code.test.ts +0 -2062
  353. package/src/renderables/Code.ts +0 -357
  354. package/src/renderables/Diff.regression.test.ts +0 -226
  355. package/src/renderables/Diff.test.ts +0 -3027
  356. package/src/renderables/Diff.ts +0 -1209
  357. package/src/renderables/EditBufferRenderable.ts +0 -764
  358. package/src/renderables/FrameBuffer.ts +0 -47
  359. package/src/renderables/Input.test.ts +0 -1228
  360. package/src/renderables/Input.ts +0 -245
  361. package/src/renderables/LineNumberRenderable.ts +0 -675
  362. package/src/renderables/Markdown.ts +0 -1106
  363. package/src/renderables/ScrollBar.ts +0 -422
  364. package/src/renderables/ScrollBox.ts +0 -883
  365. package/src/renderables/Select.test.ts +0 -1010
  366. package/src/renderables/Select.ts +0 -523
  367. package/src/renderables/Slider.test.ts +0 -456
  368. package/src/renderables/Slider.ts +0 -347
  369. package/src/renderables/TabSelect.test.ts +0 -197
  370. package/src/renderables/TabSelect.ts +0 -455
  371. package/src/renderables/Text.selection-buffer.test.ts +0 -123
  372. package/src/renderables/Text.test.ts +0 -2660
  373. package/src/renderables/Text.ts +0 -147
  374. package/src/renderables/TextBufferRenderable.ts +0 -518
  375. package/src/renderables/TextNode.test.ts +0 -1058
  376. package/src/renderables/TextNode.ts +0 -325
  377. package/src/renderables/TextTable.test.ts +0 -1421
  378. package/src/renderables/TextTable.ts +0 -1344
  379. package/src/renderables/Textarea.ts +0 -732
  380. package/src/renderables/TimeToFirstDraw.ts +0 -89
  381. package/src/renderables/__snapshots__/Code.test.ts.snap +0 -13
  382. package/src/renderables/__snapshots__/Diff.test.ts.snap +0 -785
  383. package/src/renderables/__snapshots__/Text.test.ts.snap +0 -421
  384. package/src/renderables/__snapshots__/TextTable.test.ts.snap +0 -215
  385. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +0 -144
  386. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +0 -816
  387. package/src/renderables/__tests__/LineNumberRenderable.test.ts +0 -1787
  388. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +0 -85
  389. package/src/renderables/__tests__/Markdown.test.ts +0 -2287
  390. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +0 -87
  391. package/src/renderables/__tests__/Textarea.buffer.test.ts +0 -682
  392. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +0 -675
  393. package/src/renderables/__tests__/Textarea.editing.test.ts +0 -2041
  394. package/src/renderables/__tests__/Textarea.error-handling.test.ts +0 -35
  395. package/src/renderables/__tests__/Textarea.events.test.ts +0 -738
  396. package/src/renderables/__tests__/Textarea.highlights.test.ts +0 -590
  397. package/src/renderables/__tests__/Textarea.keybinding.test.ts +0 -3149
  398. package/src/renderables/__tests__/Textarea.paste.test.ts +0 -357
  399. package/src/renderables/__tests__/Textarea.rendering.test.ts +0 -1864
  400. package/src/renderables/__tests__/Textarea.scroll.test.ts +0 -733
  401. package/src/renderables/__tests__/Textarea.selection.test.ts +0 -1590
  402. package/src/renderables/__tests__/Textarea.stress.test.ts +0 -670
  403. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +0 -383
  404. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +0 -310
  405. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +0 -221
  406. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +0 -89
  407. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +0 -457
  408. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +0 -158
  409. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +0 -387
  410. package/src/renderables/__tests__/markdown-parser.test.ts +0 -217
  411. package/src/renderables/__tests__/renderable-test-utils.ts +0 -60
  412. package/src/renderables/composition/README.md +0 -8
  413. package/src/renderables/composition/VRenderable.ts +0 -32
  414. package/src/renderables/composition/constructs.ts +0 -127
  415. package/src/renderables/composition/vnode.ts +0 -289
  416. package/src/renderables/index.ts +0 -22
  417. package/src/renderables/markdown-parser.ts +0 -66
  418. package/src/renderer.ts +0 -2363
  419. package/src/runtime-plugin-support.ts +0 -39
  420. package/src/runtime-plugin.ts +0 -144
  421. package/src/syntax-style.test.ts +0 -841
  422. package/src/syntax-style.ts +0 -264
  423. package/src/testing/README.md +0 -210
  424. package/src/testing/capture-spans.test.ts +0 -194
  425. package/src/testing/integration.test.ts +0 -276
  426. package/src/testing/manual-clock.ts +0 -106
  427. package/src/testing/mock-keys.test.ts +0 -1356
  428. package/src/testing/mock-keys.ts +0 -449
  429. package/src/testing/mock-mouse.test.ts +0 -218
  430. package/src/testing/mock-mouse.ts +0 -247
  431. package/src/testing/mock-tree-sitter-client.ts +0 -73
  432. package/src/testing/spy.ts +0 -13
  433. package/src/testing/test-recorder.test.ts +0 -415
  434. package/src/testing/test-recorder.ts +0 -145
  435. package/src/testing/test-renderer.ts +0 -116
  436. package/src/testing.ts +0 -7
  437. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +0 -481
  438. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +0 -19
  439. package/src/tests/__snapshots__/scrollbox.test.ts.snap +0 -29
  440. package/src/tests/absolute-positioning.snapshot.test.ts +0 -638
  441. package/src/tests/allocator-stats.test.ts +0 -38
  442. package/src/tests/destroy-during-render.test.ts +0 -200
  443. package/src/tests/hover-cursor.test.ts +0 -98
  444. package/src/tests/native-span-feed-async.test.ts +0 -173
  445. package/src/tests/native-span-feed-close.test.ts +0 -120
  446. package/src/tests/native-span-feed-coverage.test.ts +0 -227
  447. package/src/tests/native-span-feed-edge-cases.test.ts +0 -352
  448. package/src/tests/native-span-feed-use-after-free.test.ts +0 -45
  449. package/src/tests/opacity.test.ts +0 -123
  450. package/src/tests/renderable.snapshot.test.ts +0 -524
  451. package/src/tests/renderable.test.ts +0 -1281
  452. package/src/tests/renderer.console-startup.test.ts +0 -65
  453. package/src/tests/renderer.control.test.ts +0 -364
  454. package/src/tests/renderer.core-slot-binding.test.ts +0 -952
  455. package/src/tests/renderer.cursor.test.ts +0 -26
  456. package/src/tests/renderer.destroy-during-render.test.ts +0 -110
  457. package/src/tests/renderer.focus-restore.test.ts +0 -228
  458. package/src/tests/renderer.focus.test.ts +0 -251
  459. package/src/tests/renderer.idle.test.ts +0 -219
  460. package/src/tests/renderer.input.test.ts +0 -2145
  461. package/src/tests/renderer.kitty-flags.test.ts +0 -195
  462. package/src/tests/renderer.mouse.test.ts +0 -1269
  463. package/src/tests/renderer.palette.test.ts +0 -629
  464. package/src/tests/renderer.selection.test.ts +0 -49
  465. package/src/tests/renderer.slot-registry.test.ts +0 -649
  466. package/src/tests/renderer.useMouse.test.ts +0 -50
  467. package/src/tests/runtime-plugin-support.fixture.ts +0 -11
  468. package/src/tests/runtime-plugin-support.test.ts +0 -28
  469. package/src/tests/runtime-plugin.fixture.ts +0 -40
  470. package/src/tests/runtime-plugin.test.ts +0 -190
  471. package/src/tests/scrollbox-culling-bug.test.ts +0 -114
  472. package/src/tests/scrollbox-hitgrid-resize.test.ts +0 -136
  473. package/src/tests/scrollbox-hitgrid.test.ts +0 -909
  474. package/src/tests/scrollbox.test.ts +0 -1530
  475. package/src/tests/wrap-resize-perf.test.ts +0 -229
  476. package/src/tests/yoga-setters.test.ts +0 -921
  477. package/src/text-buffer-view.test.ts +0 -705
  478. package/src/text-buffer-view.ts +0 -189
  479. package/src/text-buffer.test.ts +0 -347
  480. package/src/text-buffer.ts +0 -250
  481. package/src/types.ts +0 -152
  482. package/src/utils.ts +0 -88
  483. package/src/zig/ansi.zig +0 -268
  484. package/src/zig/bench/README.md +0 -50
  485. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +0 -887
  486. package/src/zig/bench/edit-buffer_bench.zig +0 -476
  487. package/src/zig/bench/native-span-feed_bench.zig +0 -100
  488. package/src/zig/bench/rope-markers_bench.zig +0 -713
  489. package/src/zig/bench/rope_bench.zig +0 -514
  490. package/src/zig/bench/styled-text_bench.zig +0 -470
  491. package/src/zig/bench/text-buffer-coords_bench.zig +0 -362
  492. package/src/zig/bench/text-buffer-view_bench.zig +0 -459
  493. package/src/zig/bench/text-chunk-graphemes_bench.zig +0 -273
  494. package/src/zig/bench/utf8_bench.zig +0 -799
  495. package/src/zig/bench-utils.zig +0 -431
  496. package/src/zig/bench.zig +0 -217
  497. package/src/zig/buffer.zig +0 -2223
  498. package/src/zig/build.zig +0 -289
  499. package/src/zig/build.zig.zon +0 -16
  500. package/src/zig/edit-buffer.zig +0 -825
  501. package/src/zig/editor-view.zig +0 -802
  502. package/src/zig/event-bus.zig +0 -13
  503. package/src/zig/event-emitter.zig +0 -65
  504. package/src/zig/file-logger.zig +0 -92
  505. package/src/zig/grapheme.zig +0 -599
  506. package/src/zig/lib.zig +0 -1834
  507. package/src/zig/link.zig +0 -333
  508. package/src/zig/logger.zig +0 -43
  509. package/src/zig/mem-registry.zig +0 -125
  510. package/src/zig/native-span-feed-bench-lib.zig +0 -7
  511. package/src/zig/native-span-feed.zig +0 -708
  512. package/src/zig/renderer.zig +0 -1386
  513. package/src/zig/rope.zig +0 -1220
  514. package/src/zig/syntax-style.zig +0 -161
  515. package/src/zig/terminal.zig +0 -975
  516. package/src/zig/test.zig +0 -70
  517. package/src/zig/tests/README.md +0 -18
  518. package/src/zig/tests/buffer_test.zig +0 -2526
  519. package/src/zig/tests/edit-buffer-history_test.zig +0 -271
  520. package/src/zig/tests/edit-buffer_test.zig +0 -1689
  521. package/src/zig/tests/editor-view_test.zig +0 -3299
  522. package/src/zig/tests/event-emitter_test.zig +0 -249
  523. package/src/zig/tests/grapheme_test.zig +0 -1304
  524. package/src/zig/tests/link_test.zig +0 -190
  525. package/src/zig/tests/mem-registry_test.zig +0 -473
  526. package/src/zig/tests/memory_leak_regression_test.zig +0 -159
  527. package/src/zig/tests/native-span-feed_test.zig +0 -1264
  528. package/src/zig/tests/renderer_test.zig +0 -1010
  529. package/src/zig/tests/rope-nested_test.zig +0 -712
  530. package/src/zig/tests/rope_fuzz_test.zig +0 -238
  531. package/src/zig/tests/rope_test.zig +0 -2362
  532. package/src/zig/tests/segment-merge.test.zig +0 -148
  533. package/src/zig/tests/syntax-style_test.zig +0 -557
  534. package/src/zig/tests/terminal_test.zig +0 -719
  535. package/src/zig/tests/text-buffer-drawing_test.zig +0 -3237
  536. package/src/zig/tests/text-buffer-highlights_test.zig +0 -666
  537. package/src/zig/tests/text-buffer-iterators_test.zig +0 -776
  538. package/src/zig/tests/text-buffer-segment_test.zig +0 -320
  539. package/src/zig/tests/text-buffer-selection_test.zig +0 -1035
  540. package/src/zig/tests/text-buffer-selection_viewport_test.zig +0 -358
  541. package/src/zig/tests/text-buffer-view_test.zig +0 -3649
  542. package/src/zig/tests/text-buffer_test.zig +0 -2191
  543. package/src/zig/tests/unicode-width-map.zon +0 -3909
  544. package/src/zig/tests/utf8_no_zwj_test.zig +0 -260
  545. package/src/zig/tests/utf8_test.zig +0 -4057
  546. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +0 -267
  547. package/src/zig/tests/utf8_wcwidth_test.zig +0 -357
  548. package/src/zig/tests/word-wrap-editing_test.zig +0 -498
  549. package/src/zig/tests/wrap-cache-perf_test.zig +0 -113
  550. package/src/zig/text-buffer-iterators.zig +0 -499
  551. package/src/zig/text-buffer-segment.zig +0 -404
  552. package/src/zig/text-buffer-view.zig +0 -1371
  553. package/src/zig/text-buffer.zig +0 -1180
  554. package/src/zig/utf8.zig +0 -1948
  555. package/src/zig/utils.zig +0 -9
  556. package/src/zig-structs.ts +0 -261
  557. package/src/zig.ts +0 -3843
  558. package/tsconfig.build.json +0 -22
  559. package/tsconfig.json +0 -28
  560. /package/{src/lib/tree-sitter/assets → assets}/javascript/highlights.scm +0 -0
  561. /package/{src/lib/tree-sitter/assets → assets}/javascript/tree-sitter-javascript.wasm +0 -0
  562. /package/{src/lib/tree-sitter/assets → assets}/markdown/highlights.scm +0 -0
  563. /package/{src/lib/tree-sitter/assets → assets}/markdown/injections.scm +0 -0
  564. /package/{src/lib/tree-sitter/assets → assets}/markdown/tree-sitter-markdown.wasm +0 -0
  565. /package/{src/lib/tree-sitter/assets → assets}/markdown_inline/highlights.scm +0 -0
  566. /package/{src/lib/tree-sitter/assets → assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  567. /package/{src/lib/tree-sitter/assets → assets}/typescript/highlights.scm +0 -0
  568. /package/{src/lib/tree-sitter/assets → assets}/typescript/tree-sitter-typescript.wasm +0 -0
  569. /package/{src/lib/tree-sitter/assets → assets}/zig/highlights.scm +0 -0
  570. /package/{src/lib/tree-sitter/assets → assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -1,2041 +0,0 @@
1
- import { describe, expect, it, beforeEach, afterEach } from "bun:test"
2
- import { createTestRenderer, type TestRenderer, type MockInput } from "../../testing/test-renderer.js"
3
- import { createTextareaRenderable } from "./renderable-test-utils.js"
4
- import { TextareaRenderable } from "../Textarea.js"
5
-
6
- let currentRenderer: TestRenderer
7
- let renderOnce: () => Promise<void>
8
- let currentMockInput: MockInput
9
-
10
- describe("Textarea - Editing Tests", () => {
11
- beforeEach(async () => {
12
- ;({
13
- renderer: currentRenderer,
14
- renderOnce,
15
- mockInput: currentMockInput,
16
- } = await createTestRenderer({
17
- width: 80,
18
- height: 24,
19
- }))
20
- })
21
-
22
- afterEach(() => {
23
- currentRenderer.destroy()
24
- })
25
-
26
- describe("Initialization", () => {
27
- it("should initialize with default options", async () => {
28
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
29
- width: 40,
30
- height: 10,
31
- })
32
-
33
- expect(editor.x).toBeDefined()
34
- expect(editor.y).toBeDefined()
35
- expect(editor.width).toBeGreaterThan(0)
36
- expect(editor.height).toBeGreaterThan(0)
37
- expect(editor.focusable).toBe(true)
38
- })
39
-
40
- it("should initialize with content", async () => {
41
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
42
- initialValue: "Hello World",
43
- width: 40,
44
- height: 10,
45
- })
46
-
47
- expect(editor.plainText).toBe("Hello World")
48
- })
49
-
50
- it("should initialize with empty content", async () => {
51
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
52
- initialValue: "",
53
- width: 40,
54
- height: 10,
55
- })
56
-
57
- expect(editor.plainText).toBe("")
58
- })
59
-
60
- it("should initialize with multi-line content", async () => {
61
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
62
- initialValue: "Line 1\nLine 2\nLine 3",
63
- width: 40,
64
- height: 10,
65
- })
66
-
67
- expect(editor.plainText).toBe("Line 1\nLine 2\nLine 3")
68
- })
69
- })
70
-
71
- describe("Focus Management", () => {
72
- it("should handle focus and blur", async () => {
73
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
74
- initialValue: "test",
75
- width: 40,
76
- height: 10,
77
- })
78
-
79
- expect(editor.focused).toBe(false)
80
-
81
- editor.focus()
82
- expect(editor.focused).toBe(true)
83
-
84
- editor.blur()
85
- expect(editor.focused).toBe(false)
86
- })
87
- })
88
-
89
- describe("Text Insertion via Methods", () => {
90
- it("should insert single character", async () => {
91
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
92
- initialValue: "Hello",
93
- width: 40,
94
- height: 10,
95
- })
96
-
97
- editor.gotoLine(9999) // Move to end
98
- editor.insertChar("!")
99
-
100
- expect(editor.plainText).toBe("Hello!")
101
- })
102
-
103
- it("should insert text", async () => {
104
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
105
- initialValue: "Hello",
106
- width: 40,
107
- height: 10,
108
- })
109
-
110
- editor.gotoLine(9999) // Move to end
111
- editor.insertText(" World")
112
-
113
- expect(editor.plainText).toBe("Hello World")
114
- })
115
-
116
- it("should insert text in middle", async () => {
117
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
118
- initialValue: "HelloWorld",
119
- width: 40,
120
- height: 10,
121
- })
122
-
123
- editor.moveCursorRight()
124
- editor.moveCursorRight()
125
- editor.moveCursorRight()
126
- editor.moveCursorRight()
127
- editor.moveCursorRight()
128
- editor.insertText(" ")
129
-
130
- expect(editor.plainText).toBe("Hello World")
131
- })
132
- })
133
-
134
- describe("Text Deletion via Methods", () => {
135
- it("should delete character at cursor", async () => {
136
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
137
- initialValue: "Hello World",
138
- width: 40,
139
- height: 10,
140
- })
141
-
142
- // Move to 'W' and delete it
143
- for (let i = 0; i < 6; i++) {
144
- editor.moveCursorRight()
145
- }
146
- editor.deleteChar()
147
-
148
- expect(editor.plainText).toBe("Hello orld")
149
- })
150
-
151
- it("should delete character backward", async () => {
152
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
153
- initialValue: "Hello",
154
- width: 40,
155
- height: 10,
156
- })
157
-
158
- editor.gotoLine(9999) // Move to end
159
- editor.deleteCharBackward()
160
-
161
- expect(editor.plainText).toBe("Hell")
162
- })
163
-
164
- it("should delete entire line", async () => {
165
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
166
- initialValue: "Line 1\nLine 2\nLine 3",
167
- width: 40,
168
- height: 10,
169
- })
170
-
171
- editor.gotoLine(1)
172
- editor.deleteLine()
173
-
174
- expect(editor.plainText).toBe("Line 1\nLine 3")
175
- })
176
-
177
- it("should delete to line end", async () => {
178
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
179
- initialValue: "Hello World",
180
- width: 40,
181
- height: 10,
182
- })
183
-
184
- for (let i = 0; i < 6; i++) {
185
- editor.moveCursorRight()
186
- }
187
- editor.deleteToLineEnd()
188
-
189
- expect(editor.plainText).toBe("Hello ")
190
- })
191
- })
192
-
193
- describe("Cursor Movement via Methods", () => {
194
- it("should move cursor left and right", async () => {
195
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
196
- initialValue: "ABCDE",
197
- width: 40,
198
- height: 10,
199
- })
200
-
201
- const initialCursor = editor.logicalCursor
202
- expect(initialCursor.col).toBe(0)
203
-
204
- editor.moveCursorRight()
205
- expect(editor.logicalCursor.col).toBe(1)
206
-
207
- editor.moveCursorRight()
208
- expect(editor.logicalCursor.col).toBe(2)
209
-
210
- editor.moveCursorLeft()
211
- expect(editor.logicalCursor.col).toBe(1)
212
- })
213
-
214
- it("should move cursor up and down", async () => {
215
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
216
- initialValue: "Line 1\nLine 2\nLine 3",
217
- width: 40,
218
- height: 10,
219
- })
220
-
221
- expect(editor.logicalCursor.row).toBe(0)
222
-
223
- editor.moveCursorDown()
224
- expect(editor.logicalCursor.row).toBe(1)
225
-
226
- editor.moveCursorDown()
227
- expect(editor.logicalCursor.row).toBe(2)
228
-
229
- editor.moveCursorUp()
230
- expect(editor.logicalCursor.row).toBe(1)
231
- })
232
-
233
- it("should move to line start and end", async () => {
234
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
235
- initialValue: "Hello World",
236
- width: 40,
237
- height: 10,
238
- })
239
-
240
- const cursor = editor.logicalCursor
241
- editor.editBuffer.setCursorToLineCol(cursor.row, 9999) // Move to end of line
242
- expect(editor.logicalCursor.col).toBe(11)
243
-
244
- editor.editBuffer.setCursor(editor.logicalCursor.row, 0)
245
- expect(editor.logicalCursor.col).toBe(0)
246
- })
247
-
248
- it("should move to buffer start and end", async () => {
249
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
250
- initialValue: "Line 1\nLine 2\nLine 3",
251
- width: 40,
252
- height: 10,
253
- })
254
-
255
- editor.gotoLine(9999) // Move to end
256
- let cursor = editor.logicalCursor
257
- expect(cursor.row).toBe(2)
258
-
259
- editor.gotoLine(0) // Move to start
260
- cursor = editor.logicalCursor
261
- expect(cursor.row).toBe(0)
262
- expect(cursor.col).toBe(0)
263
- })
264
-
265
- it("should goto specific line", async () => {
266
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
267
- initialValue: "Line 0\nLine 1\nLine 2",
268
- width: 40,
269
- height: 10,
270
- })
271
-
272
- editor.gotoLine(1)
273
- expect(editor.logicalCursor.row).toBe(1)
274
-
275
- editor.gotoLine(2)
276
- expect(editor.logicalCursor.row).toBe(2)
277
- })
278
- })
279
-
280
- describe("Keyboard Input - Character Insertion", () => {
281
- it("should insert character when key is pressed", async () => {
282
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
283
- initialValue: "",
284
- width: 40,
285
- height: 10,
286
- })
287
-
288
- editor.focus()
289
-
290
- currentMockInput.pressKey("h")
291
- expect(editor.plainText).toBe("h")
292
-
293
- currentMockInput.pressKey("i")
294
- expect(editor.plainText).toBe("hi")
295
- })
296
-
297
- it("should insert multiple characters in sequence", async () => {
298
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
299
- initialValue: "",
300
- width: 40,
301
- height: 10,
302
- })
303
-
304
- editor.focus()
305
-
306
- currentMockInput.pressKey("h")
307
- currentMockInput.pressKey("e")
308
- currentMockInput.pressKey("l")
309
- currentMockInput.pressKey("l")
310
- currentMockInput.pressKey("o")
311
-
312
- expect(editor.plainText).toBe("hello")
313
- })
314
-
315
- it("should insert space character", async () => {
316
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
317
- initialValue: "Hello",
318
- width: 40,
319
- height: 10,
320
- })
321
-
322
- editor.focus()
323
- editor.gotoLine(9999) // Move to end
324
-
325
- currentMockInput.pressKey(" ")
326
- currentMockInput.pressKey("W")
327
- currentMockInput.pressKey("o")
328
- currentMockInput.pressKey("r")
329
- currentMockInput.pressKey("l")
330
- currentMockInput.pressKey("d")
331
-
332
- expect(editor.plainText).toBe("Hello World")
333
- })
334
-
335
- it("should not insert when not focused", async () => {
336
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
337
- initialValue: "",
338
- width: 40,
339
- height: 10,
340
- })
341
-
342
- // Don't focus
343
- expect(editor.focused).toBe(false)
344
-
345
- currentMockInput.pressKey("a")
346
- expect(editor.plainText).toBe("")
347
- })
348
- })
349
-
350
- describe("Keyboard Input - Arrow Keys", () => {
351
- it("should move cursor left with arrow key", async () => {
352
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
353
- initialValue: "ABC",
354
- width: 40,
355
- height: 10,
356
- })
357
-
358
- editor.focus()
359
- editor.gotoLine(9999) // Move to end
360
- expect(editor.logicalCursor.col).toBe(3)
361
-
362
- currentMockInput.pressArrow("left")
363
- expect(editor.logicalCursor.col).toBe(2)
364
-
365
- currentMockInput.pressArrow("left")
366
- expect(editor.logicalCursor.col).toBe(1)
367
- })
368
-
369
- it("should move cursor right with arrow key", async () => {
370
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
371
- initialValue: "ABC",
372
- width: 40,
373
- height: 10,
374
- })
375
-
376
- editor.focus()
377
- expect(editor.logicalCursor.col).toBe(0)
378
-
379
- currentMockInput.pressArrow("right")
380
- expect(editor.logicalCursor.col).toBe(1)
381
-
382
- currentMockInput.pressArrow("right")
383
- expect(editor.logicalCursor.col).toBe(2)
384
- })
385
-
386
- it("should move cursor up and down with arrow keys", async () => {
387
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
388
- initialValue: "Line 1\nLine 2\nLine 3",
389
- width: 40,
390
- height: 10,
391
- })
392
-
393
- editor.focus()
394
- expect(editor.logicalCursor.row).toBe(0)
395
-
396
- currentMockInput.pressArrow("down")
397
- expect(editor.logicalCursor.row).toBe(1)
398
-
399
- currentMockInput.pressArrow("down")
400
- expect(editor.logicalCursor.row).toBe(2)
401
-
402
- currentMockInput.pressArrow("up")
403
- expect(editor.logicalCursor.row).toBe(1)
404
- })
405
-
406
- it("should move cursor smoothly from end of one line to start of next", async () => {
407
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
408
- initialValue: "ABC\nDEF",
409
- width: 40,
410
- height: 10,
411
- })
412
-
413
- editor.focus()
414
- const cursor = editor.logicalCursor
415
- editor.editBuffer.setCursorToLineCol(cursor.row, 9999) // Move to end of line // End of "ABC"
416
- expect(editor.logicalCursor.col).toBe(3)
417
-
418
- // Move right should go to start of next line
419
- currentMockInput.pressArrow("right")
420
- expect(editor.logicalCursor.row).toBe(1)
421
- expect(editor.logicalCursor.col).toBe(0)
422
-
423
- // Move left should go back to end of previous line
424
- currentMockInput.pressArrow("left")
425
- expect(editor.logicalCursor.row).toBe(0)
426
- expect(editor.logicalCursor.col).toBe(3)
427
- })
428
- })
429
-
430
- describe("Keyboard Input - Backspace and Delete", () => {
431
- it("should handle backspace key", async () => {
432
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
433
- initialValue: "Hello",
434
- width: 40,
435
- height: 10,
436
- })
437
-
438
- editor.focus()
439
- editor.gotoLine(9999) // Move to end
440
-
441
- currentMockInput.pressBackspace()
442
- expect(editor.plainText).toBe("Hell")
443
-
444
- currentMockInput.pressBackspace()
445
- expect(editor.plainText).toBe("Hel")
446
- })
447
-
448
- it("should handle delete key", async () => {
449
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
450
- initialValue: "Hello",
451
- width: 40,
452
- height: 10,
453
- })
454
-
455
- editor.focus()
456
- // Cursor at start
457
-
458
- currentMockInput.pressKey("DELETE")
459
- expect(editor.plainText).toBe("ello")
460
- })
461
-
462
- it("should join lines when backspace at start of line", async () => {
463
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
464
- initialValue: "Hello\nWorld",
465
- width: 40,
466
- height: 10,
467
- })
468
-
469
- editor.focus()
470
- editor.gotoLine(1) // Move to line 2 (0-indexed line 1)
471
- expect(editor.logicalCursor.row).toBe(1)
472
- expect(editor.logicalCursor.col).toBe(0)
473
-
474
- currentMockInput.pressBackspace()
475
- expect(editor.plainText).toBe("HelloWorld")
476
- expect(editor.logicalCursor.row).toBe(0)
477
- expect(editor.logicalCursor.col).toBe(5) // Should be at end of "Hello"
478
- })
479
-
480
- it("should remove empty line when backspace at start", async () => {
481
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
482
- initialValue: "Hello\n\nWorld",
483
- width: 40,
484
- height: 10,
485
- })
486
-
487
- editor.focus()
488
- editor.gotoLine(1) // Move to empty line
489
- expect(editor.logicalCursor.row).toBe(1)
490
-
491
- currentMockInput.pressBackspace()
492
- expect(editor.plainText).toBe("Hello\nWorld")
493
- expect(editor.logicalCursor.row).toBe(0)
494
- })
495
-
496
- it("should join lines with content when backspace at start", async () => {
497
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
498
- initialValue: "Line1\nLine2\nLine3",
499
- width: 40,
500
- height: 10,
501
- })
502
-
503
- editor.focus()
504
- editor.gotoLine(2) // Move to "Line3"
505
- expect(editor.logicalCursor.row).toBe(2)
506
- expect(editor.logicalCursor.col).toBe(0)
507
-
508
- currentMockInput.pressBackspace()
509
- expect(editor.plainText).toBe("Line1\nLine2Line3")
510
- expect(editor.logicalCursor.row).toBe(1)
511
- expect(editor.logicalCursor.col).toBe(5) // After "Line2"
512
- })
513
-
514
- it("should not do anything when backspace at start of first line", async () => {
515
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
516
- initialValue: "Hello\nWorld",
517
- width: 40,
518
- height: 10,
519
- })
520
-
521
- editor.focus()
522
- expect(editor.logicalCursor.row).toBe(0)
523
- expect(editor.logicalCursor.col).toBe(0)
524
-
525
- currentMockInput.pressBackspace()
526
- expect(editor.plainText).toBe("Hello\nWorld")
527
- expect(editor.logicalCursor.row).toBe(0)
528
- expect(editor.logicalCursor.col).toBe(0)
529
- })
530
-
531
- it("should handle multiple backspaces joining multiple lines", async () => {
532
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
533
- initialValue: "A\nB\nC\nD",
534
- width: 40,
535
- height: 10,
536
- })
537
-
538
- editor.focus()
539
- editor.gotoLine(3) // Line "D"
540
- expect(editor.logicalCursor.row).toBe(3)
541
- expect(editor.logicalCursor.col).toBe(0)
542
-
543
- currentMockInput.pressBackspace()
544
- expect(editor.plainText).toBe("A\nB\nCD")
545
- expect(editor.logicalCursor.row).toBe(2)
546
- // Cursor should be at the join point (after "C")
547
- expect(editor.logicalCursor.col).toBe(1)
548
-
549
- // Now delete "C" by pressing backspace
550
- currentMockInput.pressBackspace()
551
- expect(editor.plainText).toBe("A\nB\nD")
552
- expect(editor.logicalCursor.row).toBe(2)
553
- expect(editor.logicalCursor.col).toBe(0)
554
-
555
- // Now join line 2 with line 1
556
- currentMockInput.pressBackspace()
557
- expect(editor.plainText).toBe("A\nBD")
558
- expect(editor.logicalCursor.row).toBe(1)
559
- expect(editor.logicalCursor.col).toBe(1) // After "B"
560
-
561
- // Delete "B"
562
- currentMockInput.pressBackspace()
563
- expect(editor.plainText).toBe("A\nD")
564
- expect(editor.logicalCursor.row).toBe(1)
565
- expect(editor.logicalCursor.col).toBe(0)
566
-
567
- // Now join line 1 with line 0
568
- currentMockInput.pressBackspace()
569
- expect(editor.plainText).toBe("AD")
570
- expect(editor.logicalCursor.row).toBe(0)
571
- expect(editor.logicalCursor.col).toBe(1)
572
- })
573
-
574
- it("should handle backspace after typing on new line", async () => {
575
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
576
- initialValue: "Hello",
577
- width: 40,
578
- height: 10,
579
- })
580
-
581
- editor.focus()
582
- editor.gotoLine(9999) // Move to end
583
-
584
- currentMockInput.pressEnter()
585
- expect(editor.plainText).toBe("Hello\n")
586
-
587
- currentMockInput.pressKey("W")
588
- currentMockInput.pressKey("o")
589
- currentMockInput.pressKey("r")
590
- expect(editor.plainText).toBe("Hello\nWor")
591
-
592
- // Now backspace to delete "r"
593
- currentMockInput.pressBackspace()
594
- expect(editor.plainText).toBe("Hello\nWo")
595
-
596
- // Move to start of line and backspace to join
597
- editor.editBuffer.setCursor(editor.logicalCursor.row, 0)
598
- currentMockInput.pressBackspace()
599
- expect(editor.plainText).toBe("HelloWo")
600
- })
601
-
602
- it("should move cursor right after joining lines with backspace", async () => {
603
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
604
- initialValue: "Hello\nWorld",
605
- width: 40,
606
- height: 10,
607
- })
608
-
609
- editor.focus()
610
- editor.gotoLine(1) // Move to "World"
611
- expect(editor.logicalCursor.row).toBe(1)
612
- expect(editor.logicalCursor.col).toBe(0)
613
-
614
- // Join lines with backspace
615
- currentMockInput.pressBackspace()
616
- expect(editor.plainText).toBe("HelloWorld")
617
- expect(editor.logicalCursor.row).toBe(0)
618
- expect(editor.logicalCursor.col).toBe(5) // After "Hello"
619
-
620
- // Press right repeatedly - should advance one at a time
621
- const positions: number[] = [editor.logicalCursor.col]
622
- for (let i = 0; i < 5; i++) {
623
- currentMockInput.pressArrow("right")
624
- positions.push(editor.logicalCursor.col)
625
- }
626
-
627
- // Should advance one position each time: [5, 6, 7, 8, 9, 10]
628
- expect(positions).toEqual([5, 6, 7, 8, 9, 10])
629
- })
630
-
631
- it("should move right one position after join", async () => {
632
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
633
- initialValue: "AB\nCD",
634
- width: 40,
635
- height: 10,
636
- })
637
-
638
- editor.focus()
639
- editor.gotoLine(1)
640
-
641
- // Backspace to join
642
- currentMockInput.pressBackspace()
643
- expect(editor.plainText).toBe("ABCD")
644
- expect(editor.logicalCursor.col).toBe(2)
645
-
646
- // Press right - should advance by 1
647
- currentMockInput.pressArrow("right")
648
- expect(editor.logicalCursor.col).toBe(3)
649
- })
650
-
651
- it("should advance cursor by 1 at every position after join", async () => {
652
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
653
- initialValue: "ABCDE\nFGHIJ",
654
- width: 40,
655
- height: 10,
656
- })
657
-
658
- editor.focus()
659
- editor.gotoLine(1)
660
-
661
- // Join lines
662
- currentMockInput.pressBackspace()
663
- expect(editor.plainText).toBe("ABCDEFGHIJ")
664
- expect(editor.logicalCursor.col).toBe(5)
665
-
666
- // Each right press should advance by exactly 1
667
- const expectedPositions = [5, 6, 7, 8, 9, 10]
668
-
669
- for (let i = 0; i < expectedPositions.length; i++) {
670
- expect(editor.logicalCursor.col).toBe(expectedPositions[i])
671
- if (i < expectedPositions.length - 1) {
672
- currentMockInput.pressArrow("right")
673
- }
674
- }
675
- })
676
-
677
- it("should move right after backspace join - setText content", async () => {
678
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
679
- initialValue: "ABC\nDEF",
680
- width: 40,
681
- height: 10,
682
- })
683
-
684
- editor.focus()
685
- editor.gotoLine(1)
686
- currentMockInput.pressBackspace()
687
- expect(editor.plainText).toBe("ABCDEF")
688
- expect(editor.logicalCursor.col).toBe(3)
689
-
690
- currentMockInput.pressArrow("right")
691
- expect(editor.logicalCursor.col).toBe(4)
692
- })
693
-
694
- it("should move right after backspace join - typed content", async () => {
695
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
696
- initialValue: "",
697
- width: 40,
698
- height: 10,
699
- })
700
-
701
- editor.focus()
702
-
703
- // Type "ABC", Enter, "DEF"
704
- currentMockInput.pressKey("A")
705
- currentMockInput.pressKey("B")
706
- currentMockInput.pressKey("C")
707
- currentMockInput.pressEnter()
708
- currentMockInput.pressKey("D")
709
- currentMockInput.pressKey("E")
710
- currentMockInput.pressKey("F")
711
-
712
- // Join and verify cursor advances
713
- editor.editBuffer.setCursor(editor.logicalCursor.row, 0)
714
- currentMockInput.pressBackspace()
715
- expect(editor.plainText).toBe("ABCDEF")
716
- expect(editor.logicalCursor.col).toBe(3)
717
-
718
- currentMockInput.pressArrow("right")
719
- expect(editor.logicalCursor.col).toBe(4)
720
-
721
- currentMockInput.pressArrow("right")
722
- expect(editor.logicalCursor.col).toBe(5)
723
- })
724
-
725
- it("should move cursor left after joining lines with backspace", async () => {
726
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
727
- initialValue: "ABC\nDEF",
728
- width: 40,
729
- height: 10,
730
- })
731
-
732
- editor.focus()
733
- editor.gotoLine(1) // Move to "DEF"
734
-
735
- // Join lines
736
- currentMockInput.pressBackspace()
737
- expect(editor.plainText).toBe("ABCDEF")
738
- expect(editor.logicalCursor.col).toBe(3) // After "ABC"
739
-
740
- // Move right past the boundary
741
- currentMockInput.pressArrow("right")
742
- currentMockInput.pressArrow("right")
743
- expect(editor.logicalCursor.col).toBe(5)
744
-
745
- // Now move left - should move smoothly back one at a time
746
- const positions: number[] = [editor.logicalCursor.col]
747
- for (let i = 0; i < 5; i++) {
748
- currentMockInput.pressArrow("left")
749
- positions.push(editor.logicalCursor.col)
750
- }
751
-
752
- // Should go back one at a time: [5, 4, 3, 2, 1, 0]
753
- expect(positions).toEqual([5, 4, 3, 2, 1, 0])
754
- })
755
-
756
- it("should move cursor left across chunk boundaries after joining lines", async () => {
757
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
758
- initialValue: "ABC\nDEF",
759
- width: 40,
760
- height: 10,
761
- })
762
-
763
- editor.focus()
764
- editor.gotoLine(1) // Move to "DEF"
765
-
766
- // Join lines
767
- currentMockInput.pressBackspace()
768
- expect(editor.plainText).toBe("ABCDEF")
769
- expect(editor.logicalCursor.col).toBe(3) // After "ABC"
770
-
771
- // Move right to "D"
772
- currentMockInput.pressArrow("right")
773
- expect(editor.logicalCursor.col).toBe(4)
774
-
775
- // Move right to "E"
776
- currentMockInput.pressArrow("right")
777
- expect(editor.logicalCursor.col).toBe(5)
778
-
779
- // Now move left back across the chunk boundary
780
- currentMockInput.pressArrow("left")
781
- expect(editor.logicalCursor.col).toBe(4)
782
-
783
- currentMockInput.pressArrow("left")
784
- expect(editor.logicalCursor.col).toBe(3)
785
-
786
- currentMockInput.pressArrow("left")
787
- expect(editor.logicalCursor.col).toBe(2)
788
- })
789
-
790
- it("should handle shift+backspace same as backspace", async () => {
791
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
792
- initialValue: "Hello World",
793
- width: 40,
794
- height: 10,
795
- })
796
-
797
- editor.focus()
798
- editor.gotoLine(9999) // Move to end
799
-
800
- currentMockInput.pressKey("BACKSPACE", { shift: true })
801
- expect(editor.plainText).toBe("Hello Worl")
802
-
803
- currentMockInput.pressKey("BACKSPACE", { shift: true })
804
- expect(editor.plainText).toBe("Hello Wor")
805
-
806
- currentMockInput.pressBackspace()
807
- expect(editor.plainText).toBe("Hello Wo")
808
- })
809
-
810
- it("should join lines with shift+backspace at start of line", async () => {
811
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
812
- initialValue: "First\nSecond",
813
- width: 40,
814
- height: 10,
815
- })
816
-
817
- editor.focus()
818
- editor.gotoLine(1)
819
- expect(editor.logicalCursor.row).toBe(1)
820
- expect(editor.logicalCursor.col).toBe(0)
821
-
822
- currentMockInput.pressKey("BACKSPACE", { shift: true })
823
- expect(editor.plainText).toBe("FirstSecond")
824
- expect(editor.logicalCursor.row).toBe(0)
825
- expect(editor.logicalCursor.col).toBe(5)
826
- })
827
-
828
- it("should handle shift+backspace with selection", async () => {
829
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
830
- initialValue: "Hello World",
831
- width: 40,
832
- height: 10,
833
- })
834
-
835
- editor.focus()
836
-
837
- for (let i = 0; i < 5; i++) {
838
- currentMockInput.pressArrow("right", { shift: true })
839
- }
840
- expect(editor.hasSelection()).toBe(true)
841
- expect(editor.getSelectedText()).toBe("Hello")
842
-
843
- currentMockInput.pressKey("BACKSPACE", { shift: true })
844
- expect(editor.plainText).toBe(" World")
845
- expect(editor.hasSelection()).toBe(false)
846
- })
847
-
848
- it("should delete characters consistently with shift+backspace after typing", async () => {
849
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
850
- initialValue: "",
851
- width: 40,
852
- height: 10,
853
- })
854
-
855
- editor.focus()
856
-
857
- currentMockInput.pressKey("T")
858
- currentMockInput.pressKey("e")
859
- currentMockInput.pressKey("s")
860
- currentMockInput.pressKey("t")
861
- expect(editor.plainText).toBe("Test")
862
-
863
- currentMockInput.pressKey("BACKSPACE", { shift: true })
864
- expect(editor.plainText).toBe("Tes")
865
-
866
- currentMockInput.pressKey("BACKSPACE", { shift: true })
867
- expect(editor.plainText).toBe("Te")
868
-
869
- currentMockInput.pressBackspace()
870
- expect(editor.plainText).toBe("T")
871
-
872
- currentMockInput.pressKey("BACKSPACE", { shift: true })
873
- expect(editor.plainText).toBe("")
874
- })
875
-
876
- it("should not differentiate between backspace and shift+backspace behavior", async () => {
877
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
878
- initialValue: "ABCDEF",
879
- width: 40,
880
- height: 10,
881
- })
882
-
883
- editor.focus()
884
- editor.gotoLine(9999)
885
-
886
- currentMockInput.pressBackspace()
887
- expect(editor.plainText).toBe("ABCDE")
888
-
889
- currentMockInput.pressKey("BACKSPACE", { shift: true })
890
- expect(editor.plainText).toBe("ABCD")
891
-
892
- currentMockInput.pressBackspace()
893
- expect(editor.plainText).toBe("ABC")
894
-
895
- currentMockInput.pressKey("BACKSPACE", { shift: true })
896
- expect(editor.plainText).toBe("AB")
897
- })
898
-
899
- it("should handle shift+backspace at start of buffer", async () => {
900
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
901
- initialValue: "Test",
902
- width: 40,
903
- height: 10,
904
- })
905
-
906
- editor.focus()
907
- expect(editor.logicalCursor.col).toBe(0)
908
-
909
- currentMockInput.pressKey("BACKSPACE", { shift: true })
910
- expect(editor.plainText).toBe("Test")
911
- expect(editor.logicalCursor.col).toBe(0)
912
- })
913
-
914
- it("should handle alternating backspace and shift+backspace", async () => {
915
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
916
- initialValue: "123456",
917
- width: 40,
918
- height: 10,
919
- })
920
-
921
- editor.focus()
922
- editor.gotoLine(9999)
923
- expect(editor.plainText).toBe("123456")
924
-
925
- currentMockInput.pressBackspace()
926
- expect(editor.plainText).toBe("12345")
927
-
928
- currentMockInput.pressKey("BACKSPACE", { shift: true })
929
- expect(editor.plainText).toBe("1234")
930
-
931
- currentMockInput.pressBackspace()
932
- expect(editor.plainText).toBe("123")
933
-
934
- currentMockInput.pressKey("BACKSPACE", { shift: true })
935
- expect(editor.plainText).toBe("12")
936
-
937
- currentMockInput.pressBackspace()
938
- expect(editor.plainText).toBe("1")
939
-
940
- currentMockInput.pressKey("BACKSPACE", { shift: true })
941
- expect(editor.plainText).toBe("")
942
- })
943
- })
944
-
945
- describe("Keyboard Input - Kitty Keyboard Protocol", () => {
946
- let kittyRenderer: TestRenderer
947
- let kittyRenderOnce: () => Promise<void>
948
- let kittyMockInput: MockInput
949
-
950
- beforeEach(async () => {
951
- ;({
952
- renderer: kittyRenderer,
953
- renderOnce: kittyRenderOnce,
954
- mockInput: kittyMockInput,
955
- } = await createTestRenderer({
956
- width: 80,
957
- height: 24,
958
- kittyKeyboard: true,
959
- }))
960
- })
961
-
962
- afterEach(() => {
963
- kittyRenderer.destroy()
964
- })
965
-
966
- it("should handle shift+backspace in kitty mode", async () => {
967
- const textarea = new TextareaRenderable(kittyRenderer, {
968
- left: 0,
969
- top: 0,
970
- width: 40,
971
- height: 10,
972
- initialValue: "Hello World",
973
- })
974
- kittyRenderer.root.add(textarea)
975
- await kittyRenderOnce()
976
-
977
- textarea.focus()
978
- textarea.gotoLine(9999)
979
-
980
- kittyMockInput.pressKey("BACKSPACE", { shift: true })
981
- expect(textarea.plainText).toBe("Hello Worl")
982
-
983
- kittyMockInput.pressKey("BACKSPACE", { shift: true })
984
- expect(textarea.plainText).toBe("Hello Wor")
985
- })
986
-
987
- it("should handle shift+backspace joining lines in kitty mode", async () => {
988
- const textarea = new TextareaRenderable(kittyRenderer, {
989
- left: 0,
990
- top: 0,
991
- width: 40,
992
- height: 10,
993
- initialValue: "Line1\nLine2",
994
- })
995
- kittyRenderer.root.add(textarea)
996
- await kittyRenderOnce()
997
-
998
- textarea.focus()
999
- textarea.gotoLine(1)
1000
-
1001
- kittyMockInput.pressKey("BACKSPACE", { shift: true })
1002
- expect(textarea.plainText).toBe("Line1Line2")
1003
- expect(textarea.logicalCursor.row).toBe(0)
1004
- expect(textarea.logicalCursor.col).toBe(5)
1005
- })
1006
-
1007
- it("should handle shift+backspace with selection in kitty mode", async () => {
1008
- const textarea = new TextareaRenderable(kittyRenderer, {
1009
- left: 0,
1010
- top: 0,
1011
- width: 40,
1012
- height: 10,
1013
- initialValue: "Hello World",
1014
- })
1015
- kittyRenderer.root.add(textarea)
1016
- await kittyRenderOnce()
1017
-
1018
- textarea.focus()
1019
-
1020
- for (let i = 0; i < 5; i++) {
1021
- kittyMockInput.pressArrow("right", { shift: true })
1022
- }
1023
- expect(textarea.hasSelection()).toBe(true)
1024
- expect(textarea.getSelectedText()).toBe("Hello")
1025
-
1026
- kittyMockInput.pressKey("BACKSPACE", { shift: true })
1027
- expect(textarea.plainText).toBe(" World")
1028
- expect(textarea.hasSelection()).toBe(false)
1029
- })
1030
-
1031
- it("should distinguish backspace vs shift+backspace keybindings in kitty mode", async () => {
1032
- const textarea = new TextareaRenderable(kittyRenderer, {
1033
- left: 0,
1034
- top: 0,
1035
- width: 40,
1036
- height: 10,
1037
- initialValue: "ABC",
1038
- })
1039
- kittyRenderer.root.add(textarea)
1040
- await kittyRenderOnce()
1041
-
1042
- textarea.focus()
1043
- textarea.gotoLine(9999)
1044
-
1045
- kittyMockInput.pressBackspace()
1046
- expect(textarea.plainText).toBe("AB")
1047
-
1048
- kittyMockInput.pressKey("BACKSPACE", { shift: true })
1049
- expect(textarea.plainText).toBe("A")
1050
- })
1051
-
1052
- it("should handle mixed backspace and shift+backspace in kitty mode", async () => {
1053
- const textarea = new TextareaRenderable(kittyRenderer, {
1054
- left: 0,
1055
- top: 0,
1056
- width: 40,
1057
- height: 10,
1058
- initialValue: "123456",
1059
- })
1060
- kittyRenderer.root.add(textarea)
1061
- await kittyRenderOnce()
1062
-
1063
- textarea.focus()
1064
- textarea.gotoLine(9999)
1065
-
1066
- kittyMockInput.pressBackspace()
1067
- kittyMockInput.pressKey("BACKSPACE", { shift: true })
1068
- kittyMockInput.pressBackspace()
1069
- kittyMockInput.pressKey("BACKSPACE", { shift: true })
1070
-
1071
- expect(textarea.plainText).toBe("12")
1072
- })
1073
-
1074
- it("should handle shift+delete in kitty mode", async () => {
1075
- const textarea = new TextareaRenderable(kittyRenderer, {
1076
- left: 0,
1077
- top: 0,
1078
- width: 40,
1079
- height: 10,
1080
- initialValue: "Hello",
1081
- })
1082
- kittyRenderer.root.add(textarea)
1083
- await kittyRenderOnce()
1084
-
1085
- textarea.focus()
1086
-
1087
- kittyMockInput.pressKey("DELETE", { shift: true })
1088
- expect(textarea.plainText).toBe("ello")
1089
- })
1090
-
1091
- it("should handle ctrl+backspace for word deletion in kitty mode", async () => {
1092
- const textarea = new TextareaRenderable(kittyRenderer, {
1093
- left: 0,
1094
- top: 0,
1095
- width: 40,
1096
- height: 10,
1097
- initialValue: "hello world test",
1098
- })
1099
- kittyRenderer.root.add(textarea)
1100
- await kittyRenderOnce()
1101
-
1102
- textarea.focus()
1103
- textarea.gotoLine(9999)
1104
-
1105
- kittyMockInput.pressKey("w", { ctrl: true })
1106
- expect(textarea.plainText).toBe("hello world ")
1107
- })
1108
-
1109
- it("should handle meta+backspace for word deletion in kitty mode", async () => {
1110
- const textarea = new TextareaRenderable(kittyRenderer, {
1111
- left: 0,
1112
- top: 0,
1113
- width: 40,
1114
- height: 10,
1115
- initialValue: "hello world test",
1116
- })
1117
- kittyRenderer.root.add(textarea)
1118
- await kittyRenderOnce()
1119
-
1120
- textarea.focus()
1121
- textarea.gotoLine(9999)
1122
-
1123
- kittyMockInput.pressBackspace({ meta: true })
1124
- const text = textarea.plainText
1125
- expect(text.startsWith("hello world")).toBe(true)
1126
- expect(text.length).toBeLessThan(16)
1127
- })
1128
- })
1129
-
1130
- describe("Keyboard Input - Enter/Return", () => {
1131
- it("should insert newline with Enter key", async () => {
1132
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1133
- initialValue: "HelloWorld",
1134
- width: 40,
1135
- height: 10,
1136
- })
1137
-
1138
- editor.focus()
1139
-
1140
- // Move to middle
1141
- for (let i = 0; i < 5; i++) {
1142
- editor.moveCursorRight()
1143
- }
1144
-
1145
- currentMockInput.pressEnter()
1146
- expect(editor.plainText).toBe("Hello\nWorld")
1147
- })
1148
-
1149
- it("should insert newline at end", async () => {
1150
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1151
- initialValue: "Hello",
1152
- width: 40,
1153
- height: 10,
1154
- })
1155
-
1156
- editor.focus()
1157
- editor.gotoLine(9999) // Move to end
1158
-
1159
- currentMockInput.pressEnter()
1160
- expect(editor.plainText).toBe("Hello\n")
1161
- })
1162
-
1163
- it("should handle multiple newlines", async () => {
1164
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1165
- initialValue: "Line1",
1166
- width: 40,
1167
- height: 10,
1168
- })
1169
-
1170
- editor.focus()
1171
- editor.gotoLine(9999) // Move to end
1172
-
1173
- currentMockInput.pressEnter()
1174
- currentMockInput.pressKey("L")
1175
- currentMockInput.pressKey("i")
1176
- currentMockInput.pressKey("n")
1177
- currentMockInput.pressKey("e")
1178
- currentMockInput.pressKey("2")
1179
-
1180
- expect(editor.plainText).toBe("Line1\nLine2")
1181
- })
1182
- })
1183
-
1184
- describe("Keyboard Input - Home and End", () => {
1185
- it("should move to line start with Home", async () => {
1186
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1187
- initialValue: "Hello World",
1188
- width: 40,
1189
- height: 10,
1190
- })
1191
-
1192
- editor.focus()
1193
- editor.gotoLine(9999) // Move to end
1194
- expect(editor.logicalCursor.col).toBe(11)
1195
-
1196
- currentMockInput.pressKey("HOME")
1197
- expect(editor.logicalCursor.col).toBe(0)
1198
- })
1199
-
1200
- it("should move to line end with End", async () => {
1201
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1202
- initialValue: "Hello World",
1203
- width: 40,
1204
- height: 10,
1205
- })
1206
-
1207
- editor.focus()
1208
- expect(editor.logicalCursor.col).toBe(0)
1209
-
1210
- currentMockInput.pressKey("END")
1211
- expect(editor.logicalCursor.col).toBe(11)
1212
- })
1213
- })
1214
-
1215
- describe("Keyboard Input - Control Commands", () => {
1216
- it("should move to line start with Ctrl+A", async () => {
1217
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1218
- initialValue: "Line 1\nLine 2\nLine 3",
1219
- width: 40,
1220
- height: 10,
1221
- })
1222
-
1223
- editor.focus()
1224
- editor.gotoLine(1) // Move to line 2
1225
- for (let i = 0; i < 3; i++) {
1226
- editor.moveCursorRight() // Move to middle of line
1227
- }
1228
- expect(editor.logicalCursor.row).toBe(1)
1229
- expect(editor.logicalCursor.col).toBe(3)
1230
-
1231
- currentMockInput.pressKey("a", { ctrl: true })
1232
- const cursor = editor.logicalCursor
1233
- expect(cursor.row).toBe(1) // Should stay on same line
1234
- expect(cursor.col).toBe(0) // Should move to start of line
1235
- })
1236
-
1237
- it("should move to line end with Ctrl+E", async () => {
1238
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1239
- initialValue: "Line 1\nLine 2\nLine 3",
1240
- width: 40,
1241
- height: 10,
1242
- })
1243
-
1244
- editor.focus()
1245
- editor.gotoLine(1) // Move to line 2
1246
-
1247
- currentMockInput.pressKey("e", { ctrl: true })
1248
- const cursor = editor.logicalCursor
1249
- expect(cursor.row).toBe(1) // Should stay on same line
1250
- expect(cursor.col).toBe(6) // "Line 2" is 6 chars
1251
- })
1252
-
1253
- it("should delete character forward with Ctrl+D", async () => {
1254
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1255
- initialValue: "Line 1\nLine 2\nLine 3",
1256
- width: 40,
1257
- height: 10,
1258
- })
1259
-
1260
- editor.focus()
1261
- editor.gotoLine(1)
1262
-
1263
- currentMockInput.pressKey("d", { ctrl: true })
1264
- expect(editor.plainText).toBe("Line 1\nine 2\nLine 3")
1265
- })
1266
-
1267
- it("should delete to line end with Ctrl+K", async () => {
1268
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1269
- initialValue: "Hello World",
1270
- width: 40,
1271
- height: 10,
1272
- })
1273
-
1274
- editor.focus()
1275
- for (let i = 0; i < 6; i++) {
1276
- editor.moveCursorRight()
1277
- }
1278
-
1279
- currentMockInput.pressKey("k", { ctrl: true })
1280
- expect(editor.plainText).toBe("Hello ")
1281
- })
1282
-
1283
- it("should move to buffer start with Home key", async () => {
1284
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1285
- initialValue: "Line 1\nLine 2\nLine 3",
1286
- width: 40,
1287
- height: 10,
1288
- })
1289
-
1290
- editor.focus()
1291
- editor.gotoLine(2) // Move to line 3
1292
- for (let i = 0; i < 3; i++) {
1293
- editor.moveCursorRight() // Move to middle of line
1294
- }
1295
- expect(editor.logicalCursor.row).toBe(2)
1296
- expect(editor.logicalCursor.col).toBe(3)
1297
-
1298
- currentMockInput.pressKey("HOME")
1299
- expect(editor.logicalCursor.row).toBe(0)
1300
- expect(editor.logicalCursor.col).toBe(0)
1301
- })
1302
-
1303
- it("should move to buffer end with End key", async () => {
1304
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1305
- initialValue: "Line 1\nLine 2\nLine 3",
1306
- width: 40,
1307
- height: 10,
1308
- })
1309
-
1310
- editor.focus()
1311
- expect(editor.logicalCursor.row).toBe(0)
1312
- expect(editor.logicalCursor.col).toBe(0)
1313
-
1314
- currentMockInput.pressKey("END")
1315
- expect(editor.logicalCursor.row).toBe(2)
1316
- expect(editor.logicalCursor.col).toBe(6) // "Line 3" is 6 chars
1317
- })
1318
-
1319
- it("should select from cursor to buffer start with Home+Shift", async () => {
1320
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1321
- initialValue: "Line 1\nLine 2\nLine 3",
1322
- width: 40,
1323
- height: 10,
1324
- })
1325
-
1326
- editor.focus()
1327
- editor.gotoLine(1) // Move to line 2
1328
- for (let i = 0; i < 3; i++) {
1329
- editor.moveCursorRight() // Move to "Lin|e 2"
1330
- }
1331
- expect(editor.logicalCursor.row).toBe(1)
1332
- expect(editor.logicalCursor.col).toBe(3)
1333
-
1334
- currentMockInput.pressKey("HOME", { shift: true })
1335
- expect(editor.logicalCursor.row).toBe(0)
1336
- expect(editor.logicalCursor.col).toBe(0)
1337
-
1338
- const selection = editor.getSelection()
1339
- expect(selection).not.toBeNull()
1340
- expect(selection!.start).toBe(0) // Selection starts at buffer start
1341
- // Selection should include everything from buffer start to original cursor position
1342
- // gotoLine(1) positions at end of line, moveCursorRight 3 times goes to col 3 of next line
1343
- // Selection from buffer start to cursor includes "Line 1\nLine" (one more than "Lin" due to cursor position)
1344
- expect(editor.getSelectedText()).toBe("Line 1\nLine")
1345
- })
1346
-
1347
- it("should select from cursor to buffer end with End+Shift", async () => {
1348
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1349
- initialValue: "Line 1\nLine 2\nLine 3",
1350
- width: 40,
1351
- height: 10,
1352
- })
1353
-
1354
- editor.focus()
1355
- editor.gotoLine(1) // Move to line 2
1356
- for (let i = 0; i < 3; i++) {
1357
- editor.moveCursorRight() // Move to "Lin|e 2"
1358
- }
1359
- expect(editor.logicalCursor.row).toBe(1)
1360
- expect(editor.logicalCursor.col).toBe(3)
1361
-
1362
- currentMockInput.pressKey("END", { shift: true })
1363
- expect(editor.logicalCursor.row).toBe(2)
1364
- expect(editor.logicalCursor.col).toBe(6)
1365
-
1366
- const selection = editor.getSelection()
1367
- expect(selection).not.toBeNull()
1368
- // Selection should include everything from original cursor position to buffer end
1369
- expect(editor.getSelectedText()).toBe("e 2\nLine 3")
1370
- })
1371
- })
1372
-
1373
- describe("Word Movement and Deletion", () => {
1374
- it("should move forward by word with Alt+F", async () => {
1375
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1376
- initialValue: "hello world foo bar",
1377
- width: 40,
1378
- height: 10,
1379
- })
1380
-
1381
- editor.focus()
1382
- expect(editor.logicalCursor.col).toBe(0)
1383
-
1384
- currentMockInput.pressKey("f", { meta: true })
1385
- expect(editor.logicalCursor.col).toBe(6)
1386
-
1387
- currentMockInput.pressKey("f", { meta: true })
1388
- expect(editor.logicalCursor.col).toBe(12)
1389
-
1390
- currentMockInput.pressKey("f", { meta: true })
1391
- expect(editor.logicalCursor.col).toBe(16)
1392
- })
1393
-
1394
- it("should move backward by word with Alt+B", async () => {
1395
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1396
- initialValue: "hello world foo bar",
1397
- width: 40,
1398
- height: 10,
1399
- })
1400
-
1401
- editor.focus()
1402
- editor.gotoLine(9999)
1403
- expect(editor.logicalCursor.col).toBe(19)
1404
-
1405
- currentMockInput.pressKey("b", { meta: true })
1406
- expect(editor.logicalCursor.col).toBe(16)
1407
-
1408
- currentMockInput.pressKey("b", { meta: true })
1409
- expect(editor.logicalCursor.col).toBe(12)
1410
-
1411
- currentMockInput.pressKey("b", { meta: true })
1412
- expect(editor.logicalCursor.col).toBe(6)
1413
- })
1414
-
1415
- it("should move forward by word with Meta+Right", async () => {
1416
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1417
- initialValue: "one two three",
1418
- width: 40,
1419
- height: 10,
1420
- })
1421
-
1422
- editor.focus()
1423
-
1424
- currentMockInput.pressArrow("right", { meta: true })
1425
- expect(editor.logicalCursor.col).toBe(4)
1426
-
1427
- currentMockInput.pressArrow("right", { meta: true })
1428
- expect(editor.logicalCursor.col).toBe(8)
1429
- })
1430
-
1431
- it("should move backward by word with Meta+Left", async () => {
1432
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1433
- initialValue: "one two three",
1434
- width: 40,
1435
- height: 10,
1436
- })
1437
-
1438
- editor.focus()
1439
- editor.gotoLine(9999)
1440
-
1441
- currentMockInput.pressArrow("left", { meta: true })
1442
- expect(editor.logicalCursor.col).toBe(8)
1443
-
1444
- currentMockInput.pressArrow("left", { meta: true })
1445
- expect(editor.logicalCursor.col).toBe(4)
1446
- })
1447
-
1448
- it("should delete word forward with Alt+D", async () => {
1449
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1450
- initialValue: "hello world foo",
1451
- width: 40,
1452
- height: 10,
1453
- })
1454
-
1455
- editor.focus()
1456
- expect(editor.plainText).toBe("hello world foo")
1457
-
1458
- currentMockInput.pressKey("d", { meta: true })
1459
- expect(editor.plainText).toBe("world foo")
1460
- })
1461
-
1462
- it("should delete word backward with Alt+Backspace", async () => {
1463
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1464
- initialValue: "hello world foo",
1465
- width: 40,
1466
- height: 10,
1467
- })
1468
-
1469
- editor.focus()
1470
- editor.gotoLine(9999)
1471
-
1472
- currentMockInput.pressBackspace({ meta: true })
1473
- const text = editor.plainText
1474
- expect(text.startsWith("hello world")).toBe(true)
1475
- expect(text.length).toBeLessThan(15)
1476
- })
1477
-
1478
- it("should delete word backward with Ctrl+W", async () => {
1479
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1480
- initialValue: "test string here",
1481
- width: 40,
1482
- height: 10,
1483
- })
1484
-
1485
- editor.focus()
1486
- editor.gotoLine(9999)
1487
-
1488
- currentMockInput.pressKey("w", { ctrl: true })
1489
- expect(editor.plainText).toBe("test string ")
1490
-
1491
- currentMockInput.pressKey("w", { ctrl: true })
1492
- expect(editor.plainText).toBe("test ")
1493
- })
1494
-
1495
- it("should delete line with Ctrl+Shift+D (requires Kitty keyboard protocol)", async () => {
1496
- const {
1497
- renderer: kittyRenderer,
1498
- renderOnce: kittyRenderOnce,
1499
- mockInput: kittyMockInput,
1500
- } = await createTestRenderer({
1501
- width: 80,
1502
- height: 24,
1503
- kittyKeyboard: true,
1504
- })
1505
-
1506
- const { textarea: editor } = await createTextareaRenderable(kittyRenderer, kittyRenderOnce, {
1507
- initialValue: "Line 1\nLine 2\nLine 3",
1508
- width: 40,
1509
- height: 10,
1510
- })
1511
-
1512
- editor.focus()
1513
- editor.gotoLine(1)
1514
-
1515
- kittyMockInput.pressKey("d", { ctrl: true, shift: true })
1516
- expect(editor.plainText).toBe("Line 1\nLine 3")
1517
-
1518
- kittyRenderer.destroy()
1519
- })
1520
-
1521
- it("should handle word movement across multiple lines", async () => {
1522
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1523
- initialValue: "first line\nsecond line",
1524
- width: 40,
1525
- height: 10,
1526
- })
1527
-
1528
- editor.focus()
1529
-
1530
- currentMockInput.pressKey("f", { meta: true })
1531
- expect(editor.logicalCursor.col).toBe(6)
1532
-
1533
- currentMockInput.pressKey("f", { meta: true })
1534
- expect(editor.logicalCursor.row).toBe(1)
1535
- })
1536
-
1537
- it("should delete word forward from line start", async () => {
1538
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1539
- initialValue: "hello\nworld test",
1540
- width: 40,
1541
- height: 10,
1542
- })
1543
-
1544
- editor.focus()
1545
- editor.gotoLine(1)
1546
- const initialLength = editor.plainText.length
1547
-
1548
- currentMockInput.pressKey("d", { meta: true })
1549
- expect(editor.plainText.length).toBeLessThan(initialLength)
1550
- expect(editor.plainText).toContain("hello")
1551
- })
1552
-
1553
- it("should handle word deletion operations with Alt+D", async () => {
1554
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1555
- initialValue: "hello world test",
1556
- width: 40,
1557
- height: 10,
1558
- })
1559
-
1560
- editor.focus()
1561
-
1562
- currentMockInput.pressKey("d", { meta: true })
1563
- expect(editor.plainText).toBe("world test")
1564
- })
1565
-
1566
- it("should navigate by words and characters", async () => {
1567
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1568
- initialValue: "abc def ghi",
1569
- width: 40,
1570
- height: 10,
1571
- })
1572
-
1573
- editor.focus()
1574
-
1575
- currentMockInput.pressKey("f", { meta: true })
1576
- const col1 = editor.logicalCursor.col
1577
- expect(col1).toBeGreaterThan(0)
1578
-
1579
- currentMockInput.pressArrow("right")
1580
- const col2 = editor.logicalCursor.col
1581
- expect(col2).toBe(col1 + 1)
1582
-
1583
- currentMockInput.pressKey("f", { meta: true })
1584
- const col3 = editor.logicalCursor.col
1585
- expect(col3).toBeGreaterThan(col2)
1586
- })
1587
-
1588
- it("should delete word forward even with selection when using meta+d", async () => {
1589
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1590
- initialValue: "hello world foo",
1591
- width: 40,
1592
- height: 10,
1593
- selectable: true,
1594
- })
1595
-
1596
- editor.focus()
1597
-
1598
- currentMockInput.pressArrow("right", { shift: true })
1599
- currentMockInput.pressArrow("right", { shift: true })
1600
- currentMockInput.pressArrow("right", { shift: true })
1601
- expect(editor.hasSelection()).toBe(true)
1602
-
1603
- currentMockInput.pressKey("d", { meta: true })
1604
- expect(editor.plainText).toBe("lo world foo")
1605
- })
1606
- })
1607
-
1608
- describe("Chunk Boundary Navigation", () => {
1609
- it("should move cursor across chunks created by insertions", async () => {
1610
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1611
- initialValue: "",
1612
- width: 40,
1613
- height: 10,
1614
- })
1615
-
1616
- editor.focus()
1617
-
1618
- // Insert "Hello"
1619
- currentMockInput.pressKey("H")
1620
- currentMockInput.pressKey("e")
1621
- currentMockInput.pressKey("l")
1622
- currentMockInput.pressKey("l")
1623
- currentMockInput.pressKey("o")
1624
- expect(editor.plainText).toBe("Hello")
1625
- expect(editor.logicalCursor.col).toBe(5)
1626
-
1627
- // Move cursor back to position 2
1628
- for (let i = 0; i < 3; i++) {
1629
- currentMockInput.pressArrow("left")
1630
- }
1631
- expect(editor.logicalCursor.col).toBe(2)
1632
-
1633
- // Insert "XXX" - this creates a new chunk in the middle
1634
- currentMockInput.pressKey("X")
1635
- currentMockInput.pressKey("X")
1636
- currentMockInput.pressKey("X")
1637
- expect(editor.plainText).toBe("HeXXXllo")
1638
- expect(editor.logicalCursor.col).toBe(5)
1639
-
1640
- // Now move right - should move smoothly across chunk boundaries
1641
- currentMockInput.pressArrow("right")
1642
- expect(editor.logicalCursor.col).toBe(6) // "l"
1643
-
1644
- currentMockInput.pressArrow("right")
1645
- expect(editor.logicalCursor.col).toBe(7) // "l"
1646
-
1647
- currentMockInput.pressArrow("right")
1648
- expect(editor.logicalCursor.col).toBe(8) // "o"
1649
- })
1650
-
1651
- it("should move cursor left across multiple chunks", async () => {
1652
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1653
- initialValue: "Test",
1654
- width: 40,
1655
- height: 10,
1656
- })
1657
-
1658
- editor.focus()
1659
- editor.gotoLine(9999) // Move to end
1660
-
1661
- // Insert at end
1662
- currentMockInput.pressKey("1")
1663
- currentMockInput.pressKey("2")
1664
- currentMockInput.pressKey("3")
1665
- expect(editor.plainText).toBe("Test123")
1666
-
1667
- // Move to middle and insert again
1668
- editor.gotoLine(0) // Move to start
1669
- for (let i = 0; i < 4; i++) {
1670
- currentMockInput.pressArrow("right")
1671
- }
1672
- currentMockInput.pressKey("A")
1673
- currentMockInput.pressKey("B")
1674
- expect(editor.plainText).toBe("TestAB123")
1675
- expect(editor.logicalCursor.col).toBe(6)
1676
-
1677
- // Now move left across all chunk boundaries
1678
- for (let i = 6; i > 0; i--) {
1679
- currentMockInput.pressArrow("left")
1680
- expect(editor.logicalCursor.col).toBe(i - 1)
1681
- }
1682
- expect(editor.logicalCursor.col).toBe(0)
1683
- })
1684
-
1685
- it("should move cursor right across all chunks to end", async () => {
1686
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1687
- initialValue: "AB",
1688
- width: 40,
1689
- height: 10,
1690
- })
1691
-
1692
- editor.focus()
1693
- const cursor = editor.logicalCursor
1694
- editor.editBuffer.setCursorToLineCol(cursor.row, 9999) // Move to end of line
1695
- expect(editor.logicalCursor.col).toBe(2)
1696
-
1697
- // Insert at end
1698
- currentMockInput.pressKey("C")
1699
- currentMockInput.pressKey("D")
1700
- expect(editor.plainText).toBe("ABCD")
1701
-
1702
- // Move to start
1703
- editor.gotoLine(0) // Move to start
1704
- expect(editor.logicalCursor.col).toBe(0)
1705
-
1706
- // Move right through all characters
1707
- for (let i = 0; i < 4; i++) {
1708
- currentMockInput.pressArrow("right")
1709
- expect(editor.logicalCursor.col).toBe(i + 1)
1710
- }
1711
- })
1712
-
1713
- it("should handle cursor movement after multiple insertions and deletions", async () => {
1714
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1715
- initialValue: "Start",
1716
- width: 40,
1717
- height: 10,
1718
- })
1719
-
1720
- editor.focus()
1721
- editor.gotoLine(9999) // Move to end
1722
- expect(editor.logicalCursor.col).toBe(5)
1723
-
1724
- // Insert text
1725
- currentMockInput.pressKey("1")
1726
- currentMockInput.pressKey("2")
1727
-
1728
- // Delete one
1729
- currentMockInput.pressBackspace()
1730
- expect(editor.plainText).toBe("Start1")
1731
-
1732
- // Insert more
1733
- currentMockInput.pressKey("X")
1734
- currentMockInput.pressKey("Y")
1735
- expect(editor.plainText).toBe("Start1XY")
1736
-
1737
- // Move back to start
1738
- editor.gotoLine(0) // Move to start
1739
-
1740
- // Move right through all characters one by one
1741
- for (let i = 0; i < 8; i++) {
1742
- expect(editor.logicalCursor.col).toBe(i)
1743
- currentMockInput.pressArrow("right")
1744
- }
1745
- expect(editor.logicalCursor.col).toBe(8)
1746
- })
1747
- })
1748
-
1749
- describe("Complex Editing Scenarios", () => {
1750
- it("should handle typing, navigation, and deletion", async () => {
1751
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1752
- initialValue: "",
1753
- width: 40,
1754
- height: 10,
1755
- })
1756
-
1757
- editor.focus()
1758
-
1759
- // Type "Hello"
1760
- currentMockInput.pressKey("H")
1761
- currentMockInput.pressKey("e")
1762
- currentMockInput.pressKey("l")
1763
- currentMockInput.pressKey("l")
1764
- currentMockInput.pressKey("o")
1765
- expect(editor.plainText).toBe("Hello")
1766
-
1767
- // Add space and "World"
1768
- currentMockInput.pressKey(" ")
1769
- currentMockInput.pressKey("W")
1770
- currentMockInput.pressKey("o")
1771
- currentMockInput.pressKey("r")
1772
- currentMockInput.pressKey("l")
1773
- currentMockInput.pressKey("d")
1774
- expect(editor.plainText).toBe("Hello World")
1775
-
1776
- // Backspace a few times
1777
- currentMockInput.pressBackspace()
1778
- currentMockInput.pressBackspace()
1779
- currentMockInput.pressBackspace()
1780
- expect(editor.plainText).toBe("Hello Wo")
1781
- })
1782
-
1783
- it("should handle newlines and multi-line editing", async () => {
1784
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1785
- initialValue: "",
1786
- width: 40,
1787
- height: 10,
1788
- })
1789
-
1790
- editor.focus()
1791
-
1792
- currentMockInput.pressKey("L")
1793
- currentMockInput.pressKey("i")
1794
- currentMockInput.pressKey("n")
1795
- currentMockInput.pressKey("e")
1796
- currentMockInput.pressKey("1")
1797
- currentMockInput.pressEnter()
1798
- currentMockInput.pressKey("L")
1799
- currentMockInput.pressKey("i")
1800
- currentMockInput.pressKey("n")
1801
- currentMockInput.pressKey("e")
1802
- currentMockInput.pressKey("2")
1803
-
1804
- expect(editor.plainText).toBe("Line1\nLine2")
1805
- })
1806
-
1807
- it("should handle insert and delete in sequence", async () => {
1808
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1809
- initialValue: "Test",
1810
- width: 40,
1811
- height: 10,
1812
- })
1813
-
1814
- editor.focus()
1815
- editor.gotoLine(9999) // Move to end
1816
-
1817
- currentMockInput.pressKey("i")
1818
- currentMockInput.pressKey("n")
1819
- currentMockInput.pressKey("g")
1820
- expect(editor.plainText).toBe("Testing")
1821
-
1822
- currentMockInput.pressBackspace()
1823
- currentMockInput.pressBackspace()
1824
- expect(editor.plainText).toBe("Testi")
1825
- })
1826
- })
1827
-
1828
- describe("Edit Operations", () => {
1829
- it("should maintain correct cursor position after join, insert, backspace", async () => {
1830
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1831
- initialValue: "ABC\nDEF",
1832
- width: 40,
1833
- height: 10,
1834
- })
1835
-
1836
- editor.focus()
1837
-
1838
- editor.gotoLine(1)
1839
- expect(editor.logicalCursor.row).toBe(1)
1840
- expect(editor.logicalCursor.col).toBe(0)
1841
- expect(editor.plainText).toBe("ABC\nDEF")
1842
-
1843
- currentMockInput.pressBackspace()
1844
- expect(editor.plainText).toBe("ABCDEF")
1845
- expect(editor.logicalCursor.row).toBe(0)
1846
- expect(editor.logicalCursor.col).toBe(3)
1847
-
1848
- currentMockInput.pressKey("X")
1849
- expect(editor.plainText).toBe("ABCXDEF")
1850
- expect(editor.logicalCursor.col).toBe(4)
1851
-
1852
- currentMockInput.pressBackspace()
1853
- expect(editor.plainText).toBe("ABCDEF")
1854
- expect(editor.logicalCursor.col).toBe(3)
1855
- })
1856
-
1857
- it("should type correctly after backspace", async () => {
1858
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1859
- initialValue: "",
1860
- width: 40,
1861
- height: 10,
1862
- })
1863
-
1864
- editor.focus()
1865
-
1866
- currentMockInput.pressKey("h")
1867
- currentMockInput.pressKey("e")
1868
- currentMockInput.pressKey("l")
1869
- currentMockInput.pressKey("l")
1870
- currentMockInput.pressKey("o")
1871
-
1872
- expect(editor.plainText).toBe("hello")
1873
-
1874
- currentMockInput.pressBackspace()
1875
- expect(editor.plainText).toBe("hell")
1876
-
1877
- currentMockInput.pressKey("p")
1878
- expect(editor.plainText).toBe("hellp")
1879
-
1880
- currentMockInput.pressKey("!")
1881
- expect(editor.plainText).toBe("hellp!")
1882
- })
1883
-
1884
- it("should type correctly after multiple backspaces", async () => {
1885
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1886
- initialValue: "",
1887
- width: 40,
1888
- height: 10,
1889
- })
1890
-
1891
- editor.focus()
1892
-
1893
- currentMockInput.pressKey("t")
1894
- currentMockInput.pressKey("e")
1895
- currentMockInput.pressKey("s")
1896
- currentMockInput.pressKey("t")
1897
- currentMockInput.pressKey("i")
1898
- currentMockInput.pressKey("n")
1899
- currentMockInput.pressKey("g")
1900
-
1901
- expect(editor.plainText).toBe("testing")
1902
-
1903
- currentMockInput.pressBackspace()
1904
- currentMockInput.pressBackspace()
1905
- currentMockInput.pressBackspace()
1906
-
1907
- expect(editor.plainText).toBe("test")
1908
-
1909
- currentMockInput.pressKey("e")
1910
- currentMockInput.pressKey("d")
1911
-
1912
- expect(editor.plainText).toBe("tested")
1913
- })
1914
-
1915
- it("should type correctly after backspacing all text", async () => {
1916
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1917
- initialValue: "",
1918
- width: 40,
1919
- height: 10,
1920
- })
1921
-
1922
- editor.focus()
1923
-
1924
- currentMockInput.pressKey("w")
1925
- currentMockInput.pressKey("r")
1926
- currentMockInput.pressKey("o")
1927
- currentMockInput.pressKey("n")
1928
- currentMockInput.pressKey("g")
1929
-
1930
- expect(editor.plainText).toBe("wrong")
1931
-
1932
- for (let i = 0; i < 5; i++) {
1933
- currentMockInput.pressBackspace()
1934
- }
1935
-
1936
- expect(editor.plainText).toBe("")
1937
-
1938
- currentMockInput.pressKey("r")
1939
- currentMockInput.pressKey("i")
1940
- currentMockInput.pressKey("g")
1941
- currentMockInput.pressKey("h")
1942
- currentMockInput.pressKey("t")
1943
-
1944
- expect(editor.plainText).toBe("right")
1945
- })
1946
- })
1947
-
1948
- describe("Deletion with empty lines", () => {
1949
- it("should delete selection on line after empty lines correctly", async () => {
1950
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1951
- initialValue: "AAAA\n\nBBBB\n\nCCCC",
1952
- width: 40,
1953
- height: 10,
1954
- selectable: true,
1955
- wrapMode: "word",
1956
- })
1957
-
1958
- editor.focus()
1959
- editor.gotoLine(2) // Line with "BBBB"
1960
-
1961
- expect(editor.logicalCursor.row).toBe(2)
1962
- expect(editor.plainText).toBe("AAAA\n\nBBBB\n\nCCCC")
1963
-
1964
- // Select "BBBB" by pressing shift+right 4 times
1965
- for (let i = 0; i < 4; i++) {
1966
- currentMockInput.pressArrow("right", { shift: true })
1967
- }
1968
-
1969
- expect(editor.hasSelection()).toBe(true)
1970
- expect(editor.getSelectedText()).toBe("BBBB")
1971
-
1972
- // Delete the selection
1973
- currentMockInput.pressKey("DELETE")
1974
-
1975
- expect(editor.hasSelection()).toBe(false)
1976
- expect(editor.plainText).toBe("AAAA\n\n\n\nCCCC")
1977
- expect(editor.logicalCursor.row).toBe(2)
1978
- expect(editor.logicalCursor.col).toBe(0)
1979
- })
1980
-
1981
- it("should delete selection on first line correctly (baseline test)", async () => {
1982
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
1983
- initialValue: "AAAA\n\nBBBB\n\nCCCC",
1984
- width: 40,
1985
- height: 10,
1986
- selectable: true,
1987
- wrapMode: "word",
1988
- })
1989
-
1990
- editor.focus()
1991
- editor.gotoLine(0) // First line with "AAAA"
1992
-
1993
- expect(editor.logicalCursor.row).toBe(0)
1994
-
1995
- // Select "AAAA"
1996
- for (let i = 0; i < 4; i++) {
1997
- currentMockInput.pressArrow("right", { shift: true })
1998
- }
1999
-
2000
- expect(editor.getSelectedText()).toBe("AAAA")
2001
-
2002
- // Delete the selection
2003
- currentMockInput.pressKey("DELETE")
2004
-
2005
- expect(editor.hasSelection()).toBe(false)
2006
- expect(editor.plainText).toBe("\n\nBBBB\n\nCCCC")
2007
- })
2008
-
2009
- it("should delete selection on last line after empty lines correctly", async () => {
2010
- const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
2011
- initialValue: "AAAA\n\nBBBB\n\nCCCC",
2012
- width: 40,
2013
- height: 10,
2014
- selectable: true,
2015
- wrapMode: "word",
2016
- })
2017
-
2018
- editor.focus()
2019
- editor.gotoLine(4) // Last line with "CCCC"
2020
-
2021
- expect(editor.logicalCursor.row).toBe(4)
2022
-
2023
- // Select "CCCC"
2024
- for (let i = 0; i < 4; i++) {
2025
- currentMockInput.pressArrow("right", { shift: true })
2026
- }
2027
-
2028
- const selectedText = editor.getSelectedText()
2029
- expect(selectedText).toBe("CCCC")
2030
-
2031
- // Delete the selection
2032
- currentMockInput.pressKey("DELETE")
2033
-
2034
- expect(editor.hasSelection()).toBe(false)
2035
- // After deleting CCCC, we should still have AAAA and BBBB
2036
- expect(editor.plainText).toContain("AAAA")
2037
- expect(editor.plainText).toContain("BBBB")
2038
- expect(editor.plainText).not.toContain("CCCC")
2039
- })
2040
- })
2041
- })