@react-x11/components 0.3.0 → 0.5.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 (314) hide show
  1. package/README.md +131 -4
  2. package/dist/charts/components.d.ts +3 -1
  3. package/dist/charts/components.d.ts.map +1 -1
  4. package/dist/charts/components.js +8 -4
  5. package/dist/charts/components.js.map +1 -1
  6. package/dist/charts/node.d.ts +13 -6
  7. package/dist/charts/node.d.ts.map +1 -1
  8. package/dist/charts/node.js +75 -24
  9. package/dist/charts/node.js.map +1 -1
  10. package/dist/charts/render.d.ts +4 -0
  11. package/dist/charts/render.d.ts.map +1 -1
  12. package/dist/charts/render.js +11 -6
  13. package/dist/charts/render.js.map +1 -1
  14. package/dist/code-editor/node.d.ts +47 -16
  15. package/dist/code-editor/node.d.ts.map +1 -1
  16. package/dist/code-editor/node.js +121 -51
  17. package/dist/code-editor/node.js.map +1 -1
  18. package/dist/flow/draw.d.ts +19 -1
  19. package/dist/flow/draw.d.ts.map +1 -1
  20. package/dist/flow/draw.js +64 -35
  21. package/dist/flow/draw.js.map +1 -1
  22. package/dist/flow/index.d.ts.map +1 -1
  23. package/dist/flow/index.js +24 -8
  24. package/dist/flow/index.js.map +1 -1
  25. package/dist/flow/model.d.ts +4 -2
  26. package/dist/flow/model.d.ts.map +1 -1
  27. package/dist/flow/model.js +4 -2
  28. package/dist/flow/model.js.map +1 -1
  29. package/dist/flow/node.d.ts +40 -9
  30. package/dist/flow/node.d.ts.map +1 -1
  31. package/dist/flow/node.js +142 -53
  32. package/dist/flow/node.js.map +1 -1
  33. package/dist/flow/types.d.ts +46 -21
  34. package/dist/flow/types.d.ts.map +1 -1
  35. package/dist/formula/index.d.ts +4 -2
  36. package/dist/formula/index.d.ts.map +1 -1
  37. package/dist/formula/index.js.map +1 -1
  38. package/dist/formula/node.d.ts +5 -1
  39. package/dist/formula/node.d.ts.map +1 -1
  40. package/dist/formula/node.js +19 -3
  41. package/dist/formula/node.js.map +1 -1
  42. package/dist/html/controls.d.ts +4 -1
  43. package/dist/html/controls.d.ts.map +1 -1
  44. package/dist/html/controls.js.map +1 -1
  45. package/dist/html/css/cascade.d.ts +11 -5
  46. package/dist/html/css/cascade.d.ts.map +1 -1
  47. package/dist/html/css/cascade.js +18 -8
  48. package/dist/html/css/cascade.js.map +1 -1
  49. package/dist/html/css/parse.d.ts +15 -10
  50. package/dist/html/css/parse.d.ts.map +1 -1
  51. package/dist/html/css/parse.js +41 -16
  52. package/dist/html/css/parse.js.map +1 -1
  53. package/dist/html/css/style.d.ts +3 -0
  54. package/dist/html/css/style.d.ts.map +1 -1
  55. package/dist/html/css/style.js +3 -1
  56. package/dist/html/css/style.js.map +1 -1
  57. package/dist/html/css/values.d.ts +14 -1
  58. package/dist/html/css/values.d.ts.map +1 -1
  59. package/dist/html/css/values.js +11 -8
  60. package/dist/html/css/values.js.map +1 -1
  61. package/dist/html/index.d.ts.map +1 -1
  62. package/dist/html/index.js +1 -0
  63. package/dist/html/index.js.map +1 -1
  64. package/dist/html/layout/boxes.d.ts +12 -5
  65. package/dist/html/layout/boxes.d.ts.map +1 -1
  66. package/dist/html/layout/boxes.js +7 -4
  67. package/dist/html/layout/boxes.js.map +1 -1
  68. package/dist/html/layout/inline.d.ts.map +1 -1
  69. package/dist/html/layout/inline.js +22 -1
  70. package/dist/html/layout/inline.js.map +1 -1
  71. package/dist/html/node.d.ts +22 -8
  72. package/dist/html/node.d.ts.map +1 -1
  73. package/dist/html/node.js +97 -15
  74. package/dist/html/node.js.map +1 -1
  75. package/dist/html/paint.d.ts +3 -0
  76. package/dist/html/paint.d.ts.map +1 -1
  77. package/dist/html/paint.js +2 -2
  78. package/dist/html/paint.js.map +1 -1
  79. package/dist/index.d.ts +11 -1
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +26 -0
  82. package/dist/index.js.map +1 -1
  83. package/dist/maps/clip.d.ts +43 -0
  84. package/dist/maps/clip.d.ts.map +1 -0
  85. package/dist/maps/clip.js +171 -0
  86. package/dist/maps/clip.js.map +1 -0
  87. package/dist/maps/gzip.d.ts +15 -0
  88. package/dist/maps/gzip.d.ts.map +1 -0
  89. package/dist/maps/gzip.js +56 -0
  90. package/dist/maps/gzip.js.map +1 -0
  91. package/dist/maps/index.d.ts +55 -0
  92. package/dist/maps/index.d.ts.map +1 -0
  93. package/dist/maps/index.js +141 -0
  94. package/dist/maps/index.js.map +1 -0
  95. package/dist/maps/labels.d.ts +123 -0
  96. package/dist/maps/labels.d.ts.map +1 -0
  97. package/dist/maps/labels.js +323 -0
  98. package/dist/maps/labels.js.map +1 -0
  99. package/dist/maps/mvt.d.ts +244 -0
  100. package/dist/maps/mvt.d.ts.map +1 -0
  101. package/dist/maps/mvt.js +820 -0
  102. package/dist/maps/mvt.js.map +1 -0
  103. package/dist/maps/node.d.ts +278 -0
  104. package/dist/maps/node.d.ts.map +1 -0
  105. package/dist/maps/node.js +1459 -0
  106. package/dist/maps/node.js.map +1 -0
  107. package/dist/maps/overlay.d.ts +157 -0
  108. package/dist/maps/overlay.d.ts.map +1 -0
  109. package/dist/maps/overlay.js +472 -0
  110. package/dist/maps/overlay.js.map +1 -0
  111. package/dist/maps/paint.d.ts +226 -0
  112. package/dist/maps/paint.d.ts.map +1 -0
  113. package/dist/maps/paint.js +705 -0
  114. package/dist/maps/paint.js.map +1 -0
  115. package/dist/maps/proj.d.ts +281 -0
  116. package/dist/maps/proj.d.ts.map +1 -0
  117. package/dist/maps/proj.js +451 -0
  118. package/dist/maps/proj.js.map +1 -0
  119. package/dist/maps/sources.d.ts +256 -0
  120. package/dist/maps/sources.d.ts.map +1 -0
  121. package/dist/maps/sources.js +210 -0
  122. package/dist/maps/sources.js.map +1 -0
  123. package/dist/maps/style.d.ts +141 -0
  124. package/dist/maps/style.d.ts.map +1 -0
  125. package/dist/maps/style.js +147 -0
  126. package/dist/maps/style.js.map +1 -0
  127. package/dist/maps/styles.d.ts +82 -0
  128. package/dist/maps/styles.d.ts.map +1 -0
  129. package/dist/maps/styles.js +898 -0
  130. package/dist/maps/styles.js.map +1 -0
  131. package/dist/maps/tiles.d.ts +283 -0
  132. package/dist/maps/tiles.d.ts.map +1 -0
  133. package/dist/maps/tiles.js +469 -0
  134. package/dist/maps/tiles.js.map +1 -0
  135. package/dist/maps/types.d.ts +244 -0
  136. package/dist/maps/types.d.ts.map +1 -0
  137. package/dist/maps/types.js +2 -0
  138. package/dist/maps/types.js.map +1 -0
  139. package/dist/qml/containers.d.ts +3 -0
  140. package/dist/qml/containers.d.ts.map +1 -0
  141. package/dist/qml/containers.js +331 -0
  142. package/dist/qml/containers.js.map +1 -0
  143. package/dist/qml/controls.d.ts +12 -0
  144. package/dist/qml/controls.d.ts.map +1 -0
  145. package/dist/qml/controls.js +21 -0
  146. package/dist/qml/controls.js.map +1 -0
  147. package/dist/qml/globals.d.ts +6 -0
  148. package/dist/qml/globals.d.ts.map +1 -0
  149. package/dist/qml/globals.js +25 -0
  150. package/dist/qml/globals.js.map +1 -0
  151. package/dist/qml/index.d.ts +15 -0
  152. package/dist/qml/index.d.ts.map +1 -0
  153. package/dist/qml/index.js +25 -0
  154. package/dist/qml/index.js.map +1 -0
  155. package/dist/qml/interaction.d.ts +12 -0
  156. package/dist/qml/interaction.d.ts.map +1 -0
  157. package/dist/qml/interaction.js +246 -0
  158. package/dist/qml/interaction.js.map +1 -0
  159. package/dist/qml/ir.d.ts +106 -0
  160. package/dist/qml/ir.d.ts.map +1 -0
  161. package/dist/qml/ir.js +7 -0
  162. package/dist/qml/ir.js.map +1 -0
  163. package/dist/qml/layouts.d.ts +3 -0
  164. package/dist/qml/layouts.d.ts.map +1 -0
  165. package/dist/qml/layouts.js +122 -0
  166. package/dist/qml/layouts.js.map +1 -0
  167. package/dist/qml/models.d.ts +14 -0
  168. package/dist/qml/models.d.ts.map +1 -0
  169. package/dist/qml/models.js +80 -0
  170. package/dist/qml/models.js.map +1 -0
  171. package/dist/qml/objects.d.ts +228 -0
  172. package/dist/qml/objects.d.ts.map +1 -0
  173. package/dist/qml/objects.js +1103 -0
  174. package/dist/qml/objects.js.map +1 -0
  175. package/dist/qml/parse.d.ts +10 -0
  176. package/dist/qml/parse.d.ts.map +1 -0
  177. package/dist/qml/parse.js +607 -0
  178. package/dist/qml/parse.js.map +1 -0
  179. package/dist/qml/qtquick.d.ts +7 -0
  180. package/dist/qml/qtquick.d.ts.map +1 -0
  181. package/dist/qml/qtquick.js +347 -0
  182. package/dist/qml/qtquick.js.map +1 -0
  183. package/dist/qml/react.d.ts +83 -0
  184. package/dist/qml/react.d.ts.map +1 -0
  185. package/dist/qml/react.js +323 -0
  186. package/dist/qml/react.js.map +1 -0
  187. package/dist/qml/resolver.d.ts +38 -0
  188. package/dist/qml/resolver.d.ts.map +1 -0
  189. package/dist/qml/resolver.js +64 -0
  190. package/dist/qml/resolver.js.map +1 -0
  191. package/dist/qml/slots.d.ts +65 -0
  192. package/dist/qml/slots.d.ts.map +1 -0
  193. package/dist/qml/slots.js +230 -0
  194. package/dist/qml/slots.js.map +1 -0
  195. package/dist/qml/states.d.ts +5 -0
  196. package/dist/qml/states.d.ts.map +1 -0
  197. package/dist/qml/states.js +276 -0
  198. package/dist/qml/states.js.map +1 -0
  199. package/dist/qml/view-utils.d.ts +42 -0
  200. package/dist/qml/view-utils.d.ts.map +1 -0
  201. package/dist/qml/view-utils.js +121 -0
  202. package/dist/qml/view-utils.js.map +1 -0
  203. package/dist/reorder/hx.d.ts +18 -0
  204. package/dist/reorder/hx.d.ts.map +1 -0
  205. package/dist/reorder/hx.js +10 -0
  206. package/dist/reorder/hx.js.map +1 -0
  207. package/dist/reorder/index.d.ts +314 -0
  208. package/dist/reorder/index.d.ts.map +1 -0
  209. package/dist/reorder/index.js +1539 -0
  210. package/dist/reorder/index.js.map +1 -0
  211. package/dist/reorder/model.d.ts +107 -0
  212. package/dist/reorder/model.d.ts.map +1 -0
  213. package/dist/reorder/model.js +162 -0
  214. package/dist/reorder/model.js.map +1 -0
  215. package/dist/richtext/node.d.ts +15 -5
  216. package/dist/richtext/node.d.ts.map +1 -1
  217. package/dist/richtext/node.js +40 -11
  218. package/dist/richtext/node.js.map +1 -1
  219. package/dist/richtext/runs.d.ts +35 -13
  220. package/dist/richtext/runs.d.ts.map +1 -1
  221. package/dist/richtext/runs.js +83 -27
  222. package/dist/richtext/runs.js.map +1 -1
  223. package/dist/tabs/hx.d.ts +18 -0
  224. package/dist/tabs/hx.d.ts.map +1 -0
  225. package/dist/tabs/hx.js +10 -0
  226. package/dist/tabs/hx.js.map +1 -0
  227. package/dist/tabs/index.d.ts +160 -0
  228. package/dist/tabs/index.d.ts.map +1 -0
  229. package/dist/tabs/index.js +1265 -0
  230. package/dist/tabs/index.js.map +1 -0
  231. package/dist/terminal/vt/fonts.d.ts +45 -15
  232. package/dist/terminal/vt/fonts.d.ts.map +1 -1
  233. package/dist/terminal/vt/fonts.js +89 -19
  234. package/dist/terminal/vt/fonts.js.map +1 -1
  235. package/dist/terminal/vt/index.d.ts +1 -1
  236. package/dist/terminal/vt/index.d.ts.map +1 -1
  237. package/dist/terminal/vt/index.js +3 -3
  238. package/dist/terminal/vt/index.js.map +1 -1
  239. package/dist/terminal/vt/node.d.ts +42 -0
  240. package/dist/terminal/vt/node.d.ts.map +1 -1
  241. package/dist/terminal/vt/node.js +95 -11
  242. package/dist/terminal/vt/node.js.map +1 -1
  243. package/dist/terminal/vt/pty.d.ts +16 -0
  244. package/dist/terminal/vt/pty.d.ts.map +1 -1
  245. package/dist/terminal/vt/pty.js +186 -0
  246. package/dist/terminal/vt/pty.js.map +1 -1
  247. package/dist/terminal/vt/renderer.d.ts.map +1 -1
  248. package/dist/terminal/vt/renderer.js +13 -3
  249. package/dist/terminal/vt/renderer.js.map +1 -1
  250. package/package.json +23 -3
  251. package/src/charts/components.ts +14 -7
  252. package/src/charts/node.ts +81 -26
  253. package/src/charts/render.ts +16 -6
  254. package/src/code-editor/node.ts +147 -53
  255. package/src/flow/draw.ts +104 -35
  256. package/src/flow/index.ts +33 -13
  257. package/src/flow/model.ts +4 -2
  258. package/src/flow/node.ts +158 -59
  259. package/src/flow/types.ts +46 -21
  260. package/src/formula/index.ts +4 -2
  261. package/src/formula/node.ts +24 -5
  262. package/src/html/controls.ts +4 -1
  263. package/src/html/css/cascade.ts +18 -7
  264. package/src/html/css/parse.ts +46 -21
  265. package/src/html/css/style.ts +6 -1
  266. package/src/html/css/values.ts +25 -9
  267. package/src/html/index.ts +1 -0
  268. package/src/html/layout/boxes.ts +19 -9
  269. package/src/html/layout/inline.ts +23 -1
  270. package/src/html/node.ts +110 -17
  271. package/src/html/paint.ts +17 -2
  272. package/src/index.ts +142 -0
  273. package/src/maps/clip.ts +184 -0
  274. package/src/maps/gzip.ts +66 -0
  275. package/src/maps/index.ts +316 -0
  276. package/src/maps/labels.ts +442 -0
  277. package/src/maps/mvt.ts +857 -0
  278. package/src/maps/node.ts +1819 -0
  279. package/src/maps/overlay.ts +639 -0
  280. package/src/maps/paint.ts +978 -0
  281. package/src/maps/proj.ts +641 -0
  282. package/src/maps/sources.ts +425 -0
  283. package/src/maps/style.ts +309 -0
  284. package/src/maps/styles.ts +1040 -0
  285. package/src/maps/tiles.ts +676 -0
  286. package/src/maps/types.ts +260 -0
  287. package/src/qml/containers.tsx +380 -0
  288. package/src/qml/controls.tsx +47 -0
  289. package/src/qml/globals.ts +33 -0
  290. package/src/qml/index.ts +67 -0
  291. package/src/qml/interaction.tsx +317 -0
  292. package/src/qml/ir.ts +80 -0
  293. package/src/qml/layouts.tsx +141 -0
  294. package/src/qml/models.ts +101 -0
  295. package/src/qml/objects.ts +1431 -0
  296. package/src/qml/parse.ts +624 -0
  297. package/src/qml/qtquick.tsx +413 -0
  298. package/src/qml/react.tsx +454 -0
  299. package/src/qml/resolver.ts +99 -0
  300. package/src/qml/slots.ts +249 -0
  301. package/src/qml/states.ts +318 -0
  302. package/src/qml/view-utils.ts +140 -0
  303. package/src/reorder/hx.ts +31 -0
  304. package/src/reorder/index.ts +2223 -0
  305. package/src/reorder/model.ts +232 -0
  306. package/src/richtext/node.ts +49 -14
  307. package/src/richtext/runs.ts +115 -30
  308. package/src/tabs/hx.ts +31 -0
  309. package/src/tabs/index.ts +1686 -0
  310. package/src/terminal/vt/fonts.ts +128 -36
  311. package/src/terminal/vt/index.ts +4 -2
  312. package/src/terminal/vt/node.ts +105 -12
  313. package/src/terminal/vt/pty.ts +243 -0
  314. package/src/terminal/vt/renderer.ts +13 -3
@@ -332,3 +332,246 @@ export function nodePtyHost(): PtyHost {
332
332
  sharedHost = host;
333
333
  return host;
334
334
  }
335
+
336
+ // --- the Bun implementation ------------------------------------------------
337
+
338
+ /**
339
+ * Bun's built-in pty, as of Bun 1.4: `Bun.spawn(argv, { terminal })` hands
340
+ * back a `Terminal` on the subprocess.
341
+ *
342
+ * This exists for the reason the whole file exists in the first place — a pty
343
+ * should not cost 64 MB and a native build. Under Bun it costs nothing: the
344
+ * pty is the runtime's, so `node-pty` is not installed, not probed, and not
345
+ * loaded, and the vt backend works out of the box on a machine with no C
346
+ * toolchain. Same argument as `@xterm/headless` being lazy: an app should not
347
+ * pay for what its runtime already provides.
348
+ *
349
+ * Written structurally, like `NodePty` above and for the same two reasons:
350
+ * `src/` may not name another runtime's types, and `@types/bun` is not
351
+ * installed here (nor in a Node app that merely imports this package).
352
+ */
353
+ interface BunTerminalHandle {
354
+ write(data: string | Uint8Array): void;
355
+ resize(cols: number, rows: number): void;
356
+ close(): void;
357
+ }
358
+
359
+ interface BunSubprocess {
360
+ readonly pid: number;
361
+ readonly exitCode: number | null;
362
+ readonly signalCode: string | null;
363
+ readonly exited: Promise<number>;
364
+ readonly terminal?: BunTerminalHandle | null;
365
+ kill(signal?: string | number): void;
366
+ }
367
+
368
+ interface BunRuntime {
369
+ /** The pty class. Present from 1.4 — this is the feature detector. */
370
+ Terminal?: unknown;
371
+ spawn(
372
+ argv: readonly string[],
373
+ options: {
374
+ cwd?: string;
375
+ env?: Record<string, string | undefined>;
376
+ terminal?: {
377
+ cols?: number;
378
+ rows?: number;
379
+ data?(terminal: BunTerminalHandle, chunk: Uint8Array): void;
380
+ };
381
+ },
382
+ ): BunSubprocess;
383
+ }
384
+
385
+ /**
386
+ * The Bun runtime, if this is Bun *and* its Bun is new enough to have a pty.
387
+ *
388
+ * `Bun.Terminal` rather than a parse of `Bun.version`: the `terminal` option
389
+ * is ignored rather than rejected by a Bun that predates it, so a version
390
+ * comparison is the difference between falling through to node-pty and
391
+ * spawning a child whose output goes nowhere.
392
+ */
393
+ function bunRuntime(): BunRuntime | null {
394
+ const bun = (globalThis as { Bun?: BunRuntime }).Bun;
395
+ if (!bun || typeof bun.spawn !== 'function') return null;
396
+ return typeof bun.Terminal === 'function' ? bun : null;
397
+ }
398
+
399
+ class BunPtySession implements PtySession {
400
+ #proc: BunSubprocess;
401
+ #term: BunTerminalHandle;
402
+ #alive = true;
403
+ // Bun takes the output callback as a *spawn option*, so bytes can land
404
+ // before `openPty` has even returned — let alone before the caller has
405
+ // called `onData`. Anything that arrives in that window is held here and
406
+ // flushed on attach; without it the shell's first prompt is a coin flip.
407
+ #backlog: Uint8Array[] = [];
408
+ #data: ((chunk: Uint8Array) => void) | null = null;
409
+ // Same race, one step later: a program that exits immediately settles
410
+ // `exited` before `onExit` is attached.
411
+ #exit: ExitInfo | null = null;
412
+ #onExit: ((info: ExitInfo) => void) | null = null;
413
+
414
+ constructor(proc: BunSubprocess, term: BunTerminalHandle) {
415
+ this.#proc = proc;
416
+ this.#term = term;
417
+ void proc.exited.then(() => {
418
+ this.#alive = false;
419
+ // Bun reports the signal by *name* (`'SIGTERM'`) and nulls `exitCode`
420
+ // when one ended the child — which is `ExitInfo` exactly, so unlike the
421
+ // node-pty path there is no number to stringify and no name table to
422
+ // get wrong per platform.
423
+ const info: ExitInfo = {
424
+ code: proc.signalCode ? null : (proc.exitCode ?? 0),
425
+ signal: proc.signalCode ?? null,
426
+ };
427
+ if (this.#onExit) this.#onExit(info);
428
+ else this.#exit = info;
429
+ });
430
+ }
431
+
432
+ /** Called from the spawn-time `data` callback. */
433
+ receive(chunk: Uint8Array): void {
434
+ if (this.#data) this.#data(chunk);
435
+ else this.#backlog.push(chunk);
436
+ }
437
+
438
+ get pid(): number | null {
439
+ return this.#alive ? this.#proc.pid : null;
440
+ }
441
+
442
+ write(data: string): void {
443
+ if (!this.#alive) return;
444
+ try {
445
+ this.#term.write(data);
446
+ } catch {
447
+ // the child exited between the keystroke and this write
448
+ }
449
+ }
450
+
451
+ resize(cols: number, rows: number): void {
452
+ if (!this.#alive || cols <= 0 || rows <= 0) return;
453
+ try {
454
+ this.#term.resize(cols, rows);
455
+ } catch {
456
+ // same race as write
457
+ }
458
+ }
459
+
460
+ kill(signal = 'SIGTERM'): boolean {
461
+ if (!this.#alive) return false;
462
+ try {
463
+ this.#proc.kill(signal);
464
+ return true;
465
+ } catch {
466
+ return false;
467
+ }
468
+ }
469
+
470
+ onData(listener: (chunk: Uint8Array) => void): void {
471
+ this.#data = listener;
472
+ // Bytes, not a string: Bun hands over a `Buffer`, and the emulator's
473
+ // decoder is stateful across chunks. Decoding here would split a
474
+ // multi-byte character on whatever boundary the pty read returned.
475
+ const held = this.#backlog;
476
+ this.#backlog = [];
477
+ for (const chunk of held) listener(chunk);
478
+ }
479
+
480
+ onExit(listener: (info: ExitInfo) => void): void {
481
+ this.#onExit = listener;
482
+ if (this.#exit) {
483
+ const info = this.#exit;
484
+ this.#exit = null;
485
+ listener(info);
486
+ }
487
+ }
488
+
489
+ // No `pause`/`resume`: Bun's terminal has no flow control to expose, and
490
+ // the interface makes them optional for exactly this case. The emulator's
491
+ // own write queue still bounds parse work per tick; only the pipe's
492
+ // buffered bytes grow.
493
+ }
494
+
495
+ let sharedBunHost: PtyHost | null = null;
496
+
497
+ /**
498
+ * The runtime's own pty. Null-free: callers reach it through
499
+ * `defaultPtyHost()`, and `available()` answers honestly under Node.
500
+ */
501
+ export function bunPtyHost(): PtyHost {
502
+ if (sharedBunHost) return sharedBunHost;
503
+
504
+ const host: PtyHost = {
505
+ environment() {
506
+ return nodeProcess()?.env ?? {};
507
+ },
508
+
509
+ async available() {
510
+ return bunRuntime() !== null;
511
+ },
512
+
513
+ async openPty(argv, options) {
514
+ const bun = bunRuntime();
515
+ if (!bun) throw new PtyUnavailableError();
516
+ const ambient = host.environment?.() ?? {};
517
+ const merged: Record<string, string> = {};
518
+ for (const [key, value] of Object.entries({
519
+ ...ambient,
520
+ ...options.env,
521
+ })) {
522
+ // An explicit `undefined` removes a variable, as `SpawnOptions` says
523
+ if (value !== undefined) merged[key] = String(value);
524
+ }
525
+ // Bun sets no `TERM` of its own — the pty is a device, not a profile —
526
+ // so the honest advertisement is made here, as the node-pty path makes
527
+ // it through node-pty's `name`.
528
+ merged.TERM ??= 'xterm-256color';
529
+ const file = argv[0] ?? defaultShell(ambient);
530
+ let session: BunPtySession | null = null;
531
+ const proc = bun.spawn([file, ...argv.slice(1)], {
532
+ cwd: options.cwd,
533
+ env: merged,
534
+ terminal: {
535
+ cols: options.cols,
536
+ rows: options.rows,
537
+ data(_terminal, chunk) {
538
+ session?.receive(chunk);
539
+ },
540
+ },
541
+ });
542
+ const term = proc.terminal;
543
+ if (!term) {
544
+ // A Bun that has `Terminal` but did not give us one back: kill the
545
+ // child rather than leak it, and report it as a load failure so the
546
+ // caller renders `fallback` instead of an empty terminal.
547
+ try {
548
+ proc.kill();
549
+ } catch {
550
+ // already gone
551
+ }
552
+ throw new PtyUnavailableError(
553
+ new Error('Bun.spawn returned no terminal for a pty request'),
554
+ );
555
+ }
556
+ session = new BunPtySession(proc, term);
557
+ return session;
558
+ },
559
+ };
560
+
561
+ sharedBunHost = host;
562
+ return host;
563
+ }
564
+
565
+ /**
566
+ * The pty the current runtime should use: Bun's own where there is one,
567
+ * `node-pty` otherwise.
568
+ *
569
+ * Bun wins on purpose even when node-pty is installed and would load (Bun's
570
+ * N-API support is good enough that it does). The built-in needs no native
571
+ * build, no ABI match and no 64 MB, and "use what the runtime provides" is
572
+ * the same call this package makes everywhere else. An app that wants the
573
+ * other one back passes `pty={nodePtyHost()}`, which is what the seam is for.
574
+ */
575
+ export function defaultPtyHost(): PtyHost {
576
+ return bunRuntime() ? bunPtyHost() : nodePtyHost();
577
+ }
@@ -425,15 +425,25 @@ export class RetainedRenderer extends BatchingRenderer {
425
425
  const metrics = this._metrics;
426
426
  if (!surface || !metrics || count <= 0 || srcRow === dstRow) return false;
427
427
  const h = metrics.cellHeight;
428
+ const delta = dstRow - srcRow;
429
+ // `copyWithin(rect, dx, dy)` is `scrollRegion` for a surface: it shifts
430
+ // the pixels *within* `rect` and writes nothing outside it — the band
431
+ // that survives is `rect ∩ (rect + delta)`. So the rect is the union of
432
+ // the source rows and the destination rows, not the source alone. Handed
433
+ // only the source, a scroll up by one moved rows 2… into rows 1… and
434
+ // never wrote row 0, while the mirror — shifted as a block — believed
435
+ // the old row 1 had landed there, so the top line stayed stale after
436
+ // every scroll (issue #60). With the union, the surviving band is exactly
437
+ // `dstRow…dstRow+count`, sourced from exactly `srcRow…srcRow+count`.
428
438
  const ok = surface.copyWithin(
429
439
  {
430
440
  x: 0,
431
- y: srcRow * h,
441
+ y: Math.min(srcRow, dstRow) * h,
432
442
  width: this._cols * metrics.cellWidth,
433
- height: count * h,
443
+ height: (count + Math.abs(delta)) * h,
434
444
  },
435
445
  0,
436
- (dstRow - srcRow) * h,
446
+ delta * h,
437
447
  );
438
448
  if (ok) this.count('copies');
439
449
  return ok;