linecraft 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +313 -64
  3. package/lib/api/color.d.ts +6 -0
  4. package/lib/api/color.d.ts.map +1 -0
  5. package/lib/api/color.js +9 -0
  6. package/lib/api/color.js.map +1 -0
  7. package/lib/api/color.test.d.ts +2 -0
  8. package/lib/api/color.test.d.ts.map +1 -0
  9. package/lib/api/color.test.js +23 -0
  10. package/lib/api/color.test.js.map +1 -0
  11. package/lib/api/flex.d.ts +55 -0
  12. package/lib/api/flex.d.ts.map +1 -0
  13. package/lib/api/flex.js +86 -0
  14. package/lib/api/flex.js.map +1 -0
  15. package/lib/api/flex.test.d.ts +2 -0
  16. package/lib/api/flex.test.d.ts.map +1 -0
  17. package/lib/api/flex.test.js +82 -0
  18. package/lib/api/flex.test.js.map +1 -0
  19. package/lib/api/grid.d.ts +22 -0
  20. package/lib/api/grid.d.ts.map +1 -0
  21. package/lib/api/grid.js +65 -0
  22. package/lib/api/grid.js.map +1 -0
  23. package/lib/api/grid.test.d.ts +2 -0
  24. package/lib/api/grid.test.d.ts.map +1 -0
  25. package/lib/api/grid.test.js +48 -0
  26. package/lib/api/grid.test.js.map +1 -0
  27. package/lib/components/base.d.ts +53 -0
  28. package/lib/components/base.d.ts.map +1 -0
  29. package/lib/components/base.js +47 -0
  30. package/lib/components/base.js.map +1 -0
  31. package/lib/components/col.d.ts +35 -0
  32. package/lib/components/col.d.ts.map +1 -0
  33. package/lib/components/col.js +168 -0
  34. package/lib/components/col.js.map +1 -0
  35. package/lib/components/col.test.d.ts +2 -0
  36. package/lib/components/col.test.d.ts.map +1 -0
  37. package/lib/components/col.test.js +96 -0
  38. package/lib/components/col.test.js.map +1 -0
  39. package/lib/components/index.d.ts +3 -0
  40. package/lib/components/index.d.ts.map +1 -0
  41. package/lib/components/index.js +5 -0
  42. package/lib/components/index.js.map +1 -0
  43. package/lib/components/progress-bar-grid.d.ts +20 -0
  44. package/lib/components/progress-bar-grid.d.ts.map +1 -0
  45. package/lib/components/progress-bar-grid.js +44 -0
  46. package/lib/components/progress-bar-grid.js.map +1 -0
  47. package/lib/components/progress-bar-grid.test.d.ts +2 -0
  48. package/lib/components/progress-bar-grid.test.d.ts.map +1 -0
  49. package/lib/components/progress-bar-grid.test.js +101 -0
  50. package/lib/components/progress-bar-grid.test.js.map +1 -0
  51. package/lib/components/progress-bar.d.ts +26 -3
  52. package/lib/components/progress-bar.d.ts.map +1 -1
  53. package/lib/components/progress-bar.js +62 -6
  54. package/lib/components/progress-bar.js.map +1 -1
  55. package/lib/components/progress-bar.test.d.ts +2 -0
  56. package/lib/components/progress-bar.test.d.ts.map +1 -0
  57. package/lib/components/progress-bar.test.js +153 -0
  58. package/lib/components/progress-bar.test.js.map +1 -0
  59. package/lib/components/prompt.d.ts +14 -0
  60. package/lib/components/prompt.d.ts.map +1 -0
  61. package/lib/components/prompt.js +77 -0
  62. package/lib/components/prompt.js.map +1 -0
  63. package/lib/components/renderable.d.ts +42 -0
  64. package/lib/components/renderable.d.ts.map +1 -0
  65. package/lib/components/renderable.js +225 -0
  66. package/lib/components/renderable.js.map +1 -0
  67. package/lib/components/spinner.d.ts +2 -2
  68. package/lib/components/spinner.d.ts.map +1 -1
  69. package/lib/components/spinner.js +3 -1
  70. package/lib/components/spinner.js.map +1 -1
  71. package/lib/components/spinner.test.d.ts +2 -0
  72. package/lib/components/spinner.test.d.ts.map +1 -0
  73. package/lib/components/spinner.test.js +168 -0
  74. package/lib/components/spinner.test.js.map +1 -0
  75. package/lib/components/style.d.ts +16 -0
  76. package/lib/components/style.d.ts.map +1 -0
  77. package/lib/components/style.js +72 -0
  78. package/lib/components/style.js.map +1 -0
  79. package/lib/components/style.test.d.ts +2 -0
  80. package/lib/components/style.test.d.ts.map +1 -0
  81. package/lib/components/style.test.js +135 -0
  82. package/lib/components/style.test.js.map +1 -0
  83. package/lib/components/text.d.ts +24 -0
  84. package/lib/components/text.d.ts.map +1 -0
  85. package/lib/components/text.js +65 -0
  86. package/lib/components/text.js.map +1 -0
  87. package/lib/drawing/boxes.d.ts +33 -0
  88. package/lib/drawing/boxes.d.ts.map +1 -0
  89. package/lib/drawing/boxes.js +76 -0
  90. package/lib/drawing/boxes.js.map +1 -0
  91. package/lib/index.d.ts +18 -11
  92. package/lib/index.d.ts.map +1 -1
  93. package/lib/index.js +21 -10
  94. package/lib/index.js.map +1 -1
  95. package/lib/index.test.d.ts +2 -0
  96. package/lib/index.test.d.ts.map +1 -0
  97. package/lib/index.test.js +80 -0
  98. package/lib/index.test.js.map +1 -0
  99. package/lib/layout/flex.d.ts +39 -0
  100. package/lib/layout/flex.d.ts.map +1 -0
  101. package/lib/layout/flex.js +300 -0
  102. package/lib/layout/flex.js.map +1 -0
  103. package/lib/layout/flex.test.d.ts +2 -0
  104. package/lib/layout/flex.test.d.ts.map +1 -0
  105. package/lib/layout/flex.test.js +206 -0
  106. package/lib/layout/flex.test.js.map +1 -0
  107. package/lib/layout/grid.d.ts +53 -0
  108. package/lib/layout/grid.d.ts.map +1 -0
  109. package/lib/layout/grid.js +421 -0
  110. package/lib/layout/grid.js.map +1 -0
  111. package/lib/layout/grid.test.d.ts +2 -0
  112. package/lib/layout/grid.test.d.ts.map +1 -0
  113. package/lib/layout/grid.test.js +139 -0
  114. package/lib/layout/grid.test.js.map +1 -0
  115. package/lib/native/ansi.d.ts +104 -0
  116. package/lib/native/ansi.d.ts.map +1 -0
  117. package/lib/native/ansi.js +120 -0
  118. package/lib/native/ansi.js.map +1 -0
  119. package/lib/native/ansi.test.d.ts +2 -0
  120. package/lib/native/ansi.test.d.ts.map +1 -0
  121. package/lib/native/ansi.test.js +57 -0
  122. package/lib/native/ansi.test.js.map +1 -0
  123. package/lib/native/buffer.d.ts +32 -0
  124. package/lib/native/buffer.d.ts.map +1 -0
  125. package/lib/native/buffer.js +49 -0
  126. package/lib/native/buffer.js.map +1 -0
  127. package/lib/native/buffer.test.d.ts +2 -0
  128. package/lib/native/buffer.test.d.ts.map +1 -0
  129. package/lib/native/buffer.test.js +64 -0
  130. package/lib/native/buffer.test.js.map +1 -0
  131. package/lib/native/diff.d.ts +20 -0
  132. package/lib/native/diff.d.ts.map +1 -0
  133. package/lib/native/diff.js +33 -0
  134. package/lib/native/diff.js.map +1 -0
  135. package/lib/native/diff.test.d.ts +2 -0
  136. package/lib/native/diff.test.d.ts.map +1 -0
  137. package/lib/native/diff.test.js +106 -0
  138. package/lib/native/diff.test.js.map +1 -0
  139. package/lib/native/region-old.d.ts +117 -0
  140. package/lib/native/region-old.d.ts.map +1 -0
  141. package/lib/native/region-old.js +539 -0
  142. package/lib/native/region-old.js.map +1 -0
  143. package/lib/native/region-renderer.d.ts +167 -0
  144. package/lib/native/region-renderer.d.ts.map +1 -0
  145. package/lib/native/region-renderer.js +1238 -0
  146. package/lib/native/region-renderer.js.map +1 -0
  147. package/lib/native/region-simple.d.ts +44 -0
  148. package/lib/native/region-simple.d.ts.map +1 -0
  149. package/lib/native/region-simple.js +290 -0
  150. package/lib/native/region-simple.js.map +1 -0
  151. package/lib/native/region.d.ts +53 -0
  152. package/lib/native/region.d.ts.map +1 -0
  153. package/lib/native/region.js +426 -0
  154. package/lib/native/region.js.map +1 -0
  155. package/lib/native/region.test.d.ts +2 -0
  156. package/lib/native/region.test.d.ts.map +1 -0
  157. package/lib/native/region.test.js +248 -0
  158. package/lib/native/region.test.js.map +1 -0
  159. package/lib/native/throttle.d.ts +29 -0
  160. package/lib/native/throttle.d.ts.map +1 -0
  161. package/lib/native/throttle.js +57 -0
  162. package/lib/native/throttle.js.map +1 -0
  163. package/lib/native/throttle.test.d.ts +2 -0
  164. package/lib/native/throttle.test.d.ts.map +1 -0
  165. package/lib/native/throttle.test.js +86 -0
  166. package/lib/native/throttle.test.js.map +1 -0
  167. package/lib/native.d.ts +5 -11
  168. package/lib/native.d.ts.map +1 -1
  169. package/lib/native.js +8 -64
  170. package/lib/native.js.map +1 -1
  171. package/lib/region.d.ts +48 -5
  172. package/lib/region.d.ts.map +1 -1
  173. package/lib/region.js +474 -36
  174. package/lib/region.js.map +1 -1
  175. package/lib/region.test.d.ts +2 -0
  176. package/lib/region.test.d.ts.map +1 -0
  177. package/lib/region.test.js +227 -0
  178. package/lib/region.test.js.map +1 -0
  179. package/lib/region.visual.test.d.ts +2 -0
  180. package/lib/region.visual.test.d.ts.map +1 -0
  181. package/lib/region.visual.test.js +55 -0
  182. package/lib/region.visual.test.js.map +1 -0
  183. package/lib/test-helpers/capturable-terminal.d.ts +61 -0
  184. package/lib/test-helpers/capturable-terminal.d.ts.map +1 -0
  185. package/lib/test-helpers/capturable-terminal.js +113 -0
  186. package/lib/test-helpers/capturable-terminal.js.map +1 -0
  187. package/lib/test-helpers/capturable-terminal.test.d.ts +2 -0
  188. package/lib/test-helpers/capturable-terminal.test.d.ts.map +1 -0
  189. package/lib/test-helpers/capturable-terminal.test.js +45 -0
  190. package/lib/test-helpers/capturable-terminal.test.js.map +1 -0
  191. package/lib/test-helpers/mock-region.d.ts +21 -0
  192. package/lib/test-helpers/mock-region.d.ts.map +1 -0
  193. package/lib/test-helpers/mock-region.js +37 -0
  194. package/lib/test-helpers/mock-region.js.map +1 -0
  195. package/lib/test-helpers/virtual-terminal-diff-reflow.test.d.ts +2 -0
  196. package/lib/test-helpers/virtual-terminal-diff-reflow.test.d.ts.map +1 -0
  197. package/lib/test-helpers/virtual-terminal-diff-reflow.test.js +256 -0
  198. package/lib/test-helpers/virtual-terminal-diff-reflow.test.js.map +1 -0
  199. package/lib/test-helpers/virtual-terminal-flex-resize.test.d.ts +2 -0
  200. package/lib/test-helpers/virtual-terminal-flex-resize.test.d.ts.map +1 -0
  201. package/lib/test-helpers/virtual-terminal-flex-resize.test.js +438 -0
  202. package/lib/test-helpers/virtual-terminal-flex-resize.test.js.map +1 -0
  203. package/lib/test-helpers/virtual-terminal.d.ts +176 -0
  204. package/lib/test-helpers/virtual-terminal.d.ts.map +1 -0
  205. package/lib/test-helpers/virtual-terminal.js +492 -0
  206. package/lib/test-helpers/virtual-terminal.js.map +1 -0
  207. package/lib/test-helpers/virtual-terminal.test.d.ts +2 -0
  208. package/lib/test-helpers/virtual-terminal.test.d.ts.map +1 -0
  209. package/lib/test-helpers/virtual-terminal.test.js +219 -0
  210. package/lib/test-helpers/virtual-terminal.test.js.map +1 -0
  211. package/lib/ts/components/spinner.test.d.ts +2 -0
  212. package/lib/ts/components/spinner.test.d.ts.map +1 -0
  213. package/lib/ts/components/spinner.test.js +168 -0
  214. package/lib/ts/components/spinner.test.js.map +1 -0
  215. package/lib/ts/utils/colors.test.d.ts +2 -0
  216. package/lib/ts/utils/colors.test.d.ts.map +1 -0
  217. package/lib/ts/utils/colors.test.js +87 -0
  218. package/lib/ts/utils/colors.test.js.map +1 -0
  219. package/lib/types.d.ts +8 -2
  220. package/lib/types.d.ts.map +1 -1
  221. package/lib/types.js.map +1 -1
  222. package/lib/utils/colors-simple.d.ts +51 -0
  223. package/lib/utils/colors-simple.d.ts.map +1 -0
  224. package/lib/utils/colors-simple.js +59 -0
  225. package/lib/utils/colors-simple.js.map +1 -0
  226. package/lib/utils/colors.d.ts +1 -1
  227. package/lib/utils/colors.d.ts.map +1 -1
  228. package/lib/utils/colors.js.map +1 -1
  229. package/lib/utils/colors.test.d.ts +2 -0
  230. package/lib/utils/colors.test.d.ts.map +1 -0
  231. package/lib/utils/colors.test.js +87 -0
  232. package/lib/utils/colors.test.js.map +1 -0
  233. package/lib/utils/cursor-position.d.ts +22 -0
  234. package/lib/utils/cursor-position.d.ts.map +1 -0
  235. package/lib/utils/cursor-position.js +139 -0
  236. package/lib/utils/cursor-position.js.map +1 -0
  237. package/lib/utils/debug-log.d.ts +2 -0
  238. package/lib/utils/debug-log.d.ts.map +1 -0
  239. package/lib/utils/debug-log.js +36 -0
  240. package/lib/utils/debug-log.js.map +1 -0
  241. package/lib/utils/terminal.d.ts +27 -0
  242. package/lib/utils/terminal.d.ts.map +1 -0
  243. package/lib/utils/terminal.js +116 -0
  244. package/lib/utils/terminal.js.map +1 -0
  245. package/lib/utils/text.d.ts +21 -0
  246. package/lib/utils/text.d.ts.map +1 -0
  247. package/lib/utils/text.js +82 -0
  248. package/lib/utils/text.js.map +1 -0
  249. package/lib/utils/wait-for-spacebar.d.ts +10 -0
  250. package/lib/utils/wait-for-spacebar.d.ts.map +1 -0
  251. package/lib/utils/wait-for-spacebar.js +71 -0
  252. package/lib/utils/wait-for-spacebar.js.map +1 -0
  253. package/package.json +31 -28
  254. package/.cursor/plan.md +0 -952
  255. package/TESTING.md +0 -102
  256. package/build.zig +0 -100
  257. package/examples/basic-progress.ts +0 -21
  258. package/examples/multi-lane.ts +0 -29
  259. package/examples/spinner.ts +0 -20
  260. package/examples/test-basic.ts +0 -23
  261. package/src/ts/components/progress-bar.ts +0 -53
  262. package/src/ts/components/spinner.ts +0 -56
  263. package/src/ts/index.ts +0 -37
  264. package/src/ts/native.ts +0 -86
  265. package/src/ts/region.ts +0 -89
  266. package/src/ts/types/ffi-napi.d.ts +0 -11
  267. package/src/ts/types/ref-napi.d.ts +0 -5
  268. package/src/ts/types.ts +0 -53
  269. package/src/ts/utils/colors.ts +0 -72
  270. package/src/zig/ansi.zig +0 -21
  271. package/src/zig/buffer.zig +0 -37
  272. package/src/zig/diff.zig +0 -43
  273. package/src/zig/region.zig +0 -292
  274. package/src/zig/renderer.zig +0 -92
  275. package/src/zig/test_ansi.zig +0 -66
  276. package/src/zig/test_buffer.zig +0 -82
  277. package/src/zig/test_diff.zig +0 -220
  278. package/src/zig/test_integration.zig +0 -76
  279. package/src/zig/test_region.zig +0 -191
  280. package/src/zig/test_runner.zig +0 -27
  281. package/src/zig/test_throttle.zig +0 -59
  282. package/src/zig/throttle.zig +0 -38
  283. package/tsconfig.json +0 -21
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.test.js","sourceRoot":"","sources":["../../src/native/diff.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ export interface RegionOptions {
2
+ width?: number;
3
+ height?: number;
4
+ stdout?: NodeJS.WriteStream;
5
+ disableRendering?: boolean;
6
+ }
7
+ /**
8
+ * TerminalRegion manages a rectangular region of the terminal.
9
+ *
10
+ * The region reserves new lines at the bottom of the terminal and only
11
+ * updates within those reserved lines. This prevents overwriting existing
12
+ * terminal content.
13
+ *
14
+ * Performance optimizations:
15
+ * - Frame diffing to minimize writes
16
+ * - Throttling to limit render frequency
17
+ * - Batched writes to stdout
18
+ * - Efficient string operations
19
+ * - Relative cursor movements (no absolute positioning)
20
+ */
21
+ export declare class TerminalRegion {
22
+ private width;
23
+ private height;
24
+ private pendingFrame;
25
+ private previousFrame;
26
+ private renderScheduled;
27
+ private throttle;
28
+ private renderBuffer;
29
+ private stdout;
30
+ private disableRendering;
31
+ private isInitialized;
32
+ private resizeCleanup?;
33
+ private widthExplicitlySet;
34
+ private savedCursorPosition;
35
+ private autoWrapDisabled;
36
+ private startRow;
37
+ private lastRenderedHeight;
38
+ constructor(options?: RegionOptions);
39
+ /**
40
+ * Set up process exit handler to automatically clean up the region
41
+ */
42
+ private setupExitHandler;
43
+ /**
44
+ * Set up resize event handler to react to terminal size changes
45
+ */
46
+ private setupResizeHandler;
47
+ /**
48
+ * Initialize the region by reserving new lines at the bottom of the terminal.
49
+ * This appends new lines so the region doesn't overwrite existing content.
50
+ *
51
+ * Also disables terminal auto-wrap so we can manage all wrapping ourselves.
52
+ */
53
+ private initializeRegion;
54
+ /**
55
+ * Expand region to accommodate more lines
56
+ */
57
+ private expandTo;
58
+ /**
59
+ * Get a single line (1-based line numbers)
60
+ * Returns empty string if line doesn't exist
61
+ */
62
+ getLine(lineNumber: number): string;
63
+ /**
64
+ * Set a single line (1-based line numbers)
65
+ *
66
+ * Note: With auto-wrap disabled, we manage all wrapping ourselves.
67
+ * This method sets a single line - if content needs to wrap, it should
68
+ * be handled by the component layer (col, flex, etc.) before calling this.
69
+ */
70
+ setLine(lineNumber: number, content: string): void;
71
+ /**
72
+ * Set entire content (multiple lines with \n separators)
73
+ */
74
+ set(content: string): void;
75
+ /**
76
+ * Schedule a render (respects throttle)
77
+ */
78
+ private scheduleRender;
79
+ /**
80
+ * Copy pending frame to previous frame
81
+ */
82
+ private copyPendingToPrevious;
83
+ /**
84
+ * Render immediately (bypasses throttle)
85
+ * Uses relative cursor movements to update only within reserved lines
86
+ */
87
+ renderNow(): void;
88
+ /**
89
+ * Force immediate render of pending updates (bypasses throttle)
90
+ */
91
+ flush(): void;
92
+ /**
93
+ * Set throttle FPS
94
+ */
95
+ setThrottleFps(fps: number): void;
96
+ /**
97
+ * Clear a single line (1-based)
98
+ */
99
+ clearLine(lineNumber: number): void;
100
+ /**
101
+ * Clear entire region
102
+ */
103
+ clear(): void;
104
+ /**
105
+ * Destroy the region (cleanup)
106
+ * Automatically deletes any blank lines from the terminal, but preserves content
107
+ *
108
+ * @param clearFirst - If true, clears the region before destroying (default: false)
109
+ *
110
+ * Note: This is automatically called on process exit, but you can also call it explicitly
111
+ * to clean up resources earlier (e.g., before continuing with other terminal output)
112
+ */
113
+ destroy(clearFirst?: boolean): void;
114
+ getWidth(): number;
115
+ getHeight(): number;
116
+ }
117
+ //# sourceMappingURL=region-old.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"region-old.d.ts","sourceRoot":"","sources":["../../src/native/region-old.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,gBAAgB,CAAU;IAClC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,aAAa,CAAC,CAAa;IACnC,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,kBAAkB,CAAa;gBAE3B,OAAO,GAAE,aAAkB;IAgCvC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoE1B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAuBxB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAuBhB;;;OAGG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAanC;;;;;;OAMG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA6BlD;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IA8B1B;;OAEG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAK7B;;;OAGG;IACH,SAAS,IAAI,IAAI;IA6JjB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIjC;;OAEG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAOnC;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;;;;;;;OAQG;IACH,OAAO,CAAC,UAAU,GAAE,OAAe,GAAG,IAAI;IA+D1C,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,MAAM;CAGpB"}
@@ -0,0 +1,539 @@
1
+ // Region management for terminal rendering - TypeScript implementation
2
+ // Optimized for Node.js stdout performance
3
+ import * as ansi from './ansi';
4
+ import { RenderBuffer } from './buffer';
5
+ import { Throttle } from './throttle';
6
+ import { getTerminalWidth, onResize } from '../utils/terminal';
7
+ /**
8
+ * TerminalRegion manages a rectangular region of the terminal.
9
+ *
10
+ * The region reserves new lines at the bottom of the terminal and only
11
+ * updates within those reserved lines. This prevents overwriting existing
12
+ * terminal content.
13
+ *
14
+ * Performance optimizations:
15
+ * - Frame diffing to minimize writes
16
+ * - Throttling to limit render frequency
17
+ * - Batched writes to stdout
18
+ * - Efficient string operations
19
+ * - Relative cursor movements (no absolute positioning)
20
+ */
21
+ export class TerminalRegion {
22
+ width;
23
+ height;
24
+ pendingFrame = [];
25
+ previousFrame = [];
26
+ renderScheduled = false;
27
+ throttle;
28
+ renderBuffer;
29
+ stdout;
30
+ disableRendering;
31
+ isInitialized = false;
32
+ resizeCleanup;
33
+ widthExplicitlySet;
34
+ savedCursorPosition = false; // Track if we've saved the cursor position
35
+ autoWrapDisabled = false; // Track if we've disabled terminal auto-wrap
36
+ startRow = null; // Absolute terminal row where region starts (1-based)
37
+ lastRenderedHeight = 0; // Track height from last render to detect changes
38
+ constructor(options = {}) {
39
+ this.widthExplicitlySet = options.width !== undefined;
40
+ this.width = options.width ?? getTerminalWidth();
41
+ this.height = options.height ?? 1;
42
+ this.lastRenderedHeight = this.height; // Initialize to current height
43
+ this.stdout = options.stdout ?? process.stdout;
44
+ this.disableRendering = options.disableRendering ?? false;
45
+ // Initialize frames with empty lines
46
+ this.pendingFrame = Array(this.height).fill('');
47
+ this.previousFrame = Array(this.height).fill('');
48
+ this.throttle = new Throttle(60); // Default 60 FPS
49
+ this.renderBuffer = new RenderBuffer(this.stdout);
50
+ // Reserve space for the region by printing newlines
51
+ if (!this.disableRendering) {
52
+ this.initializeRegion();
53
+ }
54
+ // Set up resize handling if width was not explicitly set (auto-resize enabled)
55
+ if (!this.widthExplicitlySet && !this.disableRendering) {
56
+ this.setupResizeHandler();
57
+ }
58
+ // Set up automatic cleanup on process exit
59
+ // This ensures regions are properly cleaned up even if destroy() isn't called
60
+ if (!this.disableRendering) {
61
+ this.setupExitHandler();
62
+ }
63
+ }
64
+ /**
65
+ * Set up process exit handler to automatically clean up the region
66
+ */
67
+ setupExitHandler() {
68
+ // Use a weak reference pattern - store a cleanup function
69
+ // that will be called on process exit
70
+ const cleanup = () => {
71
+ if (this.isInitialized) {
72
+ this.destroy();
73
+ }
74
+ };
75
+ // Register cleanup on various exit events
76
+ process.once('exit', cleanup);
77
+ process.once('SIGINT', cleanup);
78
+ process.once('SIGTERM', cleanup);
79
+ // Also handle uncaught exceptions (but don't prevent default behavior)
80
+ const originalUncaughtException = process.listeners('uncaughtException');
81
+ process.once('uncaughtException', (error, origin) => {
82
+ cleanup();
83
+ // Re-emit if there were other listeners
84
+ if (originalUncaughtException.length > 0) {
85
+ originalUncaughtException.forEach((listener) => {
86
+ listener(error, origin);
87
+ });
88
+ }
89
+ });
90
+ }
91
+ /**
92
+ * Set up resize event handler to react to terminal size changes
93
+ */
94
+ setupResizeHandler() {
95
+ // If a custom stdout is provided (e.g., for testing),
96
+ // listen to its resize events. Otherwise, use the global onResize utility.
97
+ if (this.stdout && this.stdout !== process.stdout) {
98
+ // Custom stdout - listen to its resize events directly
99
+ const resizeHandler = () => {
100
+ // Re-disable auto-wrap on resize (some terminals reset state on resize)
101
+ if (!this.disableRendering && this.autoWrapDisabled) {
102
+ this.stdout.write(ansi.DISABLE_AUTO_WRAP);
103
+ }
104
+ // Only auto-resize if width wasn't explicitly set by the user
105
+ if (!this.widthExplicitlySet) {
106
+ const oldWidth = this.width;
107
+ // Read width directly from the custom stdout
108
+ // CRITICAL: Apply the same margin as getTerminalWidth() - leave last column empty
109
+ const rawWidth = this.stdout.isTTY && this.stdout.columns
110
+ ? this.stdout.columns
111
+ : this.width;
112
+ const actualWidth = Math.max(1, rawWidth - 1);
113
+ // Only update if it actually changed
114
+ if (actualWidth !== oldWidth) {
115
+ this.width = actualWidth;
116
+ // Don't auto-render here - the high-level API (or user code) will handle rebuilding
117
+ // flex layouts and other dynamic content with the new width
118
+ // This prevents rendering broken layouts before they're rebuilt
119
+ }
120
+ }
121
+ };
122
+ this.stdout.on('resize', resizeHandler);
123
+ this.resizeCleanup = () => {
124
+ this.stdout.off('resize', resizeHandler);
125
+ };
126
+ }
127
+ else {
128
+ // Use the global onResize utility (for real process.stdout)
129
+ this.resizeCleanup = onResize((newWidth, newHeight) => {
130
+ // Re-disable auto-wrap on resize (some terminals reset state on resize)
131
+ // This ensures content doesn't reflow automatically
132
+ // Write directly to stdout since this happens outside of render cycle
133
+ if (!this.disableRendering && this.autoWrapDisabled) {
134
+ this.stdout.write(ansi.DISABLE_AUTO_WRAP);
135
+ }
136
+ // Only auto-resize if width wasn't explicitly set by the user
137
+ if (!this.widthExplicitlySet) {
138
+ const oldWidth = this.width;
139
+ // Read width directly from stdout to ensure we get the latest value
140
+ // Node.js updates process.stdout.columns when resize happens
141
+ // CRITICAL: Apply the same margin as getTerminalWidth() - leave last column empty
142
+ const rawWidth = process.stdout.isTTY && process.stdout.columns
143
+ ? process.stdout.columns
144
+ : newWidth;
145
+ const actualWidth = Math.max(1, rawWidth - 1);
146
+ // Only update if it actually changed
147
+ if (actualWidth !== oldWidth) {
148
+ this.width = actualWidth;
149
+ // Don't auto-render here - the high-level API (or user code) will handle rebuilding
150
+ // flex layouts and other dynamic content with the new width
151
+ // This prevents rendering broken layouts before they're rebuilt
152
+ }
153
+ }
154
+ });
155
+ }
156
+ }
157
+ /**
158
+ * Initialize the region by reserving new lines at the bottom of the terminal.
159
+ * This appends new lines so the region doesn't overwrite existing content.
160
+ *
161
+ * Also disables terminal auto-wrap so we can manage all wrapping ourselves.
162
+ */
163
+ initializeRegion() {
164
+ // Disable terminal auto-wrap - we'll manage all wrapping ourselves
165
+ // This makes reflow math much easier because we control it, not the terminal
166
+ // IMPORTANT: Write directly to stdout and flush immediately so it takes effect before any content
167
+ if (!this.disableRendering && !this.autoWrapDisabled) {
168
+ this.stdout.write(ansi.DISABLE_AUTO_WRAP);
169
+ this.autoWrapDisabled = true;
170
+ }
171
+ if (this.isInitialized)
172
+ return;
173
+ // Reserve space by printing newlines (this moves cursor down)
174
+ // Each newline reserves one line for the region
175
+ for (let i = 0; i < this.height; i++) {
176
+ this.stdout.write('\n');
177
+ }
178
+ // After printing newlines, cursor is at the start of the line after the region
179
+ // Save this position - it's our anchor point for relative positioning
180
+ this.stdout.write(ansi.SAVE_CURSOR);
181
+ this.savedCursorPosition = true;
182
+ this.isInitialized = true;
183
+ }
184
+ /**
185
+ * Expand region to accommodate more lines
186
+ */
187
+ expandTo(newHeight) {
188
+ const oldHeight = this.height;
189
+ this.height = newHeight;
190
+ // Expand pending frame
191
+ while (this.pendingFrame.length < newHeight) {
192
+ this.pendingFrame.push('');
193
+ }
194
+ // Expand previous frame
195
+ while (this.previousFrame.length < newHeight) {
196
+ this.previousFrame.push('');
197
+ }
198
+ // If we need more lines and region is initialized, reserve additional space
199
+ if (this.isInitialized && newHeight > oldHeight && !this.disableRendering) {
200
+ const additionalLines = newHeight - oldHeight;
201
+ for (let i = 0; i < additionalLines; i++) {
202
+ this.stdout.write('\n');
203
+ }
204
+ }
205
+ }
206
+ /**
207
+ * Get a single line (1-based line numbers)
208
+ * Returns empty string if line doesn't exist
209
+ */
210
+ getLine(lineNumber) {
211
+ if (lineNumber < 1) {
212
+ throw new Error('Line numbers start at 1');
213
+ }
214
+ const lineIndex = lineNumber - 1;
215
+ if (lineIndex >= this.pendingFrame.length) {
216
+ return '';
217
+ }
218
+ return this.pendingFrame[lineIndex] || '';
219
+ }
220
+ /**
221
+ * Set a single line (1-based line numbers)
222
+ *
223
+ * Note: With auto-wrap disabled, we manage all wrapping ourselves.
224
+ * This method sets a single line - if content needs to wrap, it should
225
+ * be handled by the component layer (col, flex, etc.) before calling this.
226
+ */
227
+ setLine(lineNumber, content) {
228
+ if (lineNumber < 1) {
229
+ throw new Error('Line numbers start at 1');
230
+ }
231
+ const lineIndex = lineNumber - 1;
232
+ // CRITICAL: Don't expand beyond current height if height was explicitly set
233
+ // The region.set() method for components sets the height explicitly,
234
+ // so we should not expand here. Only expand if we're in "auto-expand" mode.
235
+ // For now, we'll allow expansion but the caller (region.set) will truncate after rendering.
236
+ if (lineIndex >= this.height) {
237
+ this.expandTo(lineIndex + 1);
238
+ // Update height to match
239
+ this.height = lineIndex + 1;
240
+ }
241
+ // Ensure pending frame has enough lines
242
+ while (this.pendingFrame.length <= lineIndex) {
243
+ this.pendingFrame.push('');
244
+ }
245
+ // Update the line
246
+ this.pendingFrame[lineIndex] = content;
247
+ // Schedule render
248
+ this.scheduleRender();
249
+ }
250
+ /**
251
+ * Set entire content (multiple lines with \n separators)
252
+ */
253
+ set(content) {
254
+ // Split by newlines
255
+ const lines = content.split('\n');
256
+ // Expand region if needed
257
+ if (lines.length > this.height) {
258
+ this.expandTo(lines.length);
259
+ }
260
+ // Update all lines in pending frame
261
+ // If new content has fewer lines than current height, clear the extra lines
262
+ this.pendingFrame = [...lines];
263
+ // Ensure frame is the right size - pad with empty strings if needed
264
+ while (this.pendingFrame.length < this.height) {
265
+ this.pendingFrame.push('');
266
+ }
267
+ // If we shrunk (fewer lines than before), clear the extra lines in previous frame too
268
+ // This ensures the diff algorithm will detect them as needing to be cleared
269
+ if (lines.length < this.previousFrame.length) {
270
+ for (let i = lines.length; i < this.previousFrame.length; i++) {
271
+ this.previousFrame[i] = this.previousFrame[i] || '';
272
+ }
273
+ }
274
+ // Schedule render
275
+ this.scheduleRender();
276
+ }
277
+ /**
278
+ * Schedule a render (respects throttle)
279
+ */
280
+ scheduleRender() {
281
+ if (this.disableRendering) {
282
+ // For tests - just copy pending to previous
283
+ this.previousFrame = [...this.pendingFrame];
284
+ return;
285
+ }
286
+ if (this.throttle.shouldRender()) {
287
+ this.renderNow();
288
+ }
289
+ else {
290
+ this.renderScheduled = true;
291
+ }
292
+ }
293
+ /**
294
+ * Copy pending frame to previous frame
295
+ */
296
+ copyPendingToPrevious() {
297
+ // Use spread operator for efficient shallow copy
298
+ this.previousFrame = [...this.pendingFrame];
299
+ }
300
+ /**
301
+ * Render immediately (bypasses throttle)
302
+ * Uses relative cursor movements to update only within reserved lines
303
+ */
304
+ renderNow() {
305
+ if (this.disableRendering) {
306
+ this.copyPendingToPrevious();
307
+ return;
308
+ }
309
+ // Ensure region is initialized
310
+ if (!this.isInitialized) {
311
+ this.initializeRegion();
312
+ }
313
+ // CRITICAL: Always disable auto-wrap before every render
314
+ // Some terminals reset this state, or other code might enable it
315
+ // We MUST write it directly to stdout (not to render buffer) so it takes effect immediately
316
+ // Node.js stdout.write() is synchronous and blocks until written, so it's effectively flushed
317
+ if (!this.disableRendering) {
318
+ // Write directly to stdout (bypasses render buffer) to ensure immediate effect
319
+ this.stdout.write(ansi.DISABLE_AUTO_WRAP);
320
+ this.autoWrapDisabled = true;
321
+ }
322
+ // Hide cursor in render buffer too (for consistency)
323
+ this.renderBuffer.write(ansi.HIDE_CURSOR);
324
+ // CRITICAL: OhMyZsh uses absolute positioning, not SAVE/RESTORE cursor
325
+ // SAVE/RESTORE can be unreliable, especially after resize
326
+ // Instead, we'll use a simpler approach: always restore to saved position,
327
+ // but re-save it after every render to keep it accurate
328
+ // Restore to saved position (end of region) - this is our anchor point
329
+ this.renderBuffer.write(ansi.RESTORE_CURSOR);
330
+ // CRITICAL: If height changed, we need to adjust the saved position
331
+ // The saved cursor is at: startRow + oldHeight
332
+ // We need it at: startRow + newHeight
333
+ if (this.lastRenderedHeight !== this.height && this.savedCursorPosition) {
334
+ const heightDiff = this.height - this.lastRenderedHeight;
335
+ if (heightDiff > 0) {
336
+ // Height increased: move down to new end using cursor movement (not newlines)
337
+ this.renderBuffer.write(ansi.moveCursorDown(heightDiff));
338
+ }
339
+ else if (heightDiff < 0) {
340
+ // Height decreased: move up to new end
341
+ this.renderBuffer.write(ansi.moveCursorUp(-heightDiff));
342
+ }
343
+ // Re-save the corrected position
344
+ this.renderBuffer.write(ansi.SAVE_CURSOR);
345
+ }
346
+ // CRITICAL: Don't use SAVE/RESTORE - it's unreliable
347
+ // Instead, move to start of region by going up from saved position
348
+ // Then render each line, clearing before writing to ensure clean slate
349
+ // CRITICAL: Only render up to this.height lines, even if pendingFrame has more
350
+ // This prevents rendering extra lines that were accidentally added by setLine
351
+ // The region.set() method for components should have already truncated pendingFrame,
352
+ // but this is a safety check
353
+ const linesToRender = Math.min(this.pendingFrame.length, this.height);
354
+ // Move to start of region (from saved position at end)
355
+ // Use this.height to position correctly
356
+ if (this.height > 0) {
357
+ this.renderBuffer.write(ansi.moveCursorUp(this.height));
358
+ }
359
+ this.renderBuffer.write(ansi.MOVE_TO_START_OF_LINE);
360
+ // Now render each line, one at a time, clearing before writing
361
+ // This ensures we're always writing to the correct line and prevents duplicates
362
+ for (let i = 0; i < linesToRender; i++) {
363
+ const content = this.pendingFrame[i];
364
+ // If this is not the first line, move down one line
365
+ if (i > 0) {
366
+ this.renderBuffer.write(ansi.moveCursorDown(1));
367
+ }
368
+ // CRITICAL: Always clear the line BEFORE writing
369
+ // This prevents any leftover content from causing duplicates
370
+ this.renderBuffer.write(ansi.MOVE_TO_START_OF_LINE);
371
+ this.renderBuffer.write(ansi.CLEAR_LINE);
372
+ this.renderBuffer.write(ansi.MOVE_TO_START_OF_LINE);
373
+ // Truncate content to terminal width BEFORE writing
374
+ const plainContent = content.replace(/\x1b\[[0-9;]*m/g, '');
375
+ let contentToWrite = content;
376
+ if (plainContent.length > this.width) {
377
+ // Truncate: find where to cut while preserving ANSI codes
378
+ let visualPos = 0;
379
+ let charPos = 0;
380
+ while (charPos < content.length && visualPos < this.width) {
381
+ if (content[charPos] === '\x1b') {
382
+ // Skip ANSI code
383
+ let ansiEnd = charPos + 1;
384
+ while (ansiEnd < content.length) {
385
+ if (content[ansiEnd] === 'm') {
386
+ ansiEnd++;
387
+ break;
388
+ }
389
+ if ((content[ansiEnd] >= '0' && content[ansiEnd] <= '9') ||
390
+ content[ansiEnd] === ';' ||
391
+ content[ansiEnd] === '[') {
392
+ ansiEnd++;
393
+ }
394
+ else {
395
+ break;
396
+ }
397
+ }
398
+ charPos = ansiEnd;
399
+ }
400
+ else {
401
+ charPos++;
402
+ visualPos++;
403
+ }
404
+ }
405
+ contentToWrite = content.substring(0, charPos);
406
+ }
407
+ // Write truncated content
408
+ this.renderBuffer.write(contentToWrite);
409
+ // CRITICAL: After writing, return to start of line
410
+ // This ensures cursor is at a known position for the next iteration
411
+ this.renderBuffer.write(ansi.MOVE_TO_START_OF_LINE);
412
+ }
413
+ // Handle deletions (lines that were in previousFrame but not in pendingFrame)
414
+ // Since we've already cleared and re-rendered all lines, deletions are handled
415
+ // by the fact that those lines are no longer in pendingFrame
416
+ // No additional action needed - the lines are already cleared
417
+ // After rendering all lines, we're at the start of the last line we rendered
418
+ // this.height should already match linesToRender (updated by region.set() before render)
419
+ // But if they don't match for some reason, update it now
420
+ if (linesToRender !== this.height) {
421
+ this.height = linesToRender;
422
+ }
423
+ // We're already at the start of the last rendered line
424
+ // No need to move - we're already at the end of the region
425
+ // CRITICAL: Save cursor position at end of region for next render
426
+ // This is our anchor point - we'll move up from here to get to the start
427
+ this.renderBuffer.write(ansi.SAVE_CURSOR);
428
+ this.savedCursorPosition = true;
429
+ // Show cursor
430
+ this.renderBuffer.write(ansi.SHOW_CURSOR);
431
+ // Flush buffer (single write to stdout)
432
+ this.renderBuffer.flush();
433
+ // Copy pending to previous
434
+ this.copyPendingToPrevious();
435
+ // Update last rendered height for next render
436
+ this.lastRenderedHeight = this.height;
437
+ this.renderScheduled = false;
438
+ }
439
+ /**
440
+ * Force immediate render of pending updates (bypasses throttle)
441
+ */
442
+ flush() {
443
+ this.renderNow();
444
+ }
445
+ /**
446
+ * Set throttle FPS
447
+ */
448
+ setThrottleFps(fps) {
449
+ this.throttle.setFps(fps);
450
+ }
451
+ /**
452
+ * Clear a single line (1-based)
453
+ */
454
+ clearLine(lineNumber) {
455
+ if (lineNumber < 1) {
456
+ throw new Error('Line numbers start at 1');
457
+ }
458
+ this.setLine(lineNumber, '');
459
+ }
460
+ /**
461
+ * Clear entire region
462
+ */
463
+ clear() {
464
+ // Clear all lines in pendingFrame (which may be larger than height if region expanded)
465
+ const maxLines = Math.max(this.height, this.pendingFrame.length);
466
+ for (let i = 1; i <= maxLines; i++) {
467
+ this.setLine(i, '');
468
+ }
469
+ }
470
+ /**
471
+ * Destroy the region (cleanup)
472
+ * Automatically deletes any blank lines from the terminal, but preserves content
473
+ *
474
+ * @param clearFirst - If true, clears the region before destroying (default: false)
475
+ *
476
+ * Note: This is automatically called on process exit, but you can also call it explicitly
477
+ * to clean up resources earlier (e.g., before continuing with other terminal output)
478
+ */
479
+ destroy(clearFirst = false) {
480
+ // Re-enable terminal auto-wrap if we disabled it
481
+ // Write directly to stdout to ensure it takes effect immediately
482
+ if (!this.disableRendering && this.autoWrapDisabled) {
483
+ this.stdout.write(ansi.ENABLE_AUTO_WRAP);
484
+ this.autoWrapDisabled = false;
485
+ }
486
+ // Prevent double-destruction
487
+ if (!this.isInitialized && this.pendingFrame.length === 0) {
488
+ return;
489
+ }
490
+ // Clean up resize handler if it exists
491
+ if (this.resizeCleanup) {
492
+ this.resizeCleanup();
493
+ this.resizeCleanup = undefined;
494
+ }
495
+ // Clear if requested
496
+ if (clearFirst) {
497
+ this.clear();
498
+ // Render the clear immediately so previousFrame is updated
499
+ this.renderNow();
500
+ }
501
+ if (!this.disableRendering && this.isInitialized) {
502
+ // Check if all lines are blank
503
+ // After clearFirst + renderNow(), previousFrame will have empty lines
504
+ // Otherwise, check previousFrame to see if content exists
505
+ const allLinesBlank = this.previousFrame.every(line => line.trim() === '');
506
+ // Only delete lines if they are blank
507
+ // If clearFirst was true, we've already cleared and rendered, so previousFrame will be empty
508
+ // If clearFirst was false, we check previousFrame to see if content exists
509
+ if (allLinesBlank && this.height > 0) {
510
+ // Restore to saved position (end of region)
511
+ this.renderBuffer.write(ansi.RESTORE_CURSOR);
512
+ // Move to start of first line of region
513
+ this.renderBuffer.write(ansi.moveCursorUp(this.height));
514
+ // Use MOVE_TO_START_OF_LINE which is more reliable than \r
515
+ this.renderBuffer.write(ansi.MOVE_TO_START_OF_LINE);
516
+ // Delete the blank lines (shifts content up if supported)
517
+ // This will remove the lines from the terminal display
518
+ this.renderBuffer.write(ansi.deleteLines(this.height));
519
+ // Flush the cleanup
520
+ this.renderBuffer.flush();
521
+ }
522
+ // If lines have content, we leave them as-is - the user can see the output
523
+ }
524
+ // Clear buffers (internal state only, doesn't affect terminal)
525
+ this.pendingFrame = [];
526
+ this.previousFrame = [];
527
+ this.renderBuffer.clear();
528
+ // Mark as destroyed to prevent double-cleanup
529
+ this.isInitialized = false;
530
+ }
531
+ // Getters for width and height
532
+ getWidth() {
533
+ return this.width;
534
+ }
535
+ getHeight() {
536
+ return this.height;
537
+ }
538
+ }
539
+ //# sourceMappingURL=region-old.js.map