@textui/core 0.1.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 (323) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/adapters/index.d.ts +12 -0
  4. package/dist/adapters/index.d.ts.map +1 -0
  5. package/dist/adapters/index.js +11 -0
  6. package/dist/app/app.d.ts +200 -0
  7. package/dist/app/app.d.ts.map +1 -0
  8. package/dist/app/app.js +980 -0
  9. package/dist/core/animation.d.ts +34 -0
  10. package/dist/core/animation.d.ts.map +1 -0
  11. package/dist/core/animation.js +125 -0
  12. package/dist/core/clipboard.d.ts +29 -0
  13. package/dist/core/clipboard.d.ts.map +1 -0
  14. package/dist/core/clipboard.js +30 -0
  15. package/dist/core/commands.d.ts +42 -0
  16. package/dist/core/commands.d.ts.map +1 -0
  17. package/dist/core/commands.js +146 -0
  18. package/dist/core/components.d.ts +27 -0
  19. package/dist/core/components.d.ts.map +1 -0
  20. package/dist/core/components.js +78 -0
  21. package/dist/core/events.d.ts +23 -0
  22. package/dist/core/events.d.ts.map +1 -0
  23. package/dist/core/events.js +77 -0
  24. package/dist/core/focus.d.ts +69 -0
  25. package/dist/core/focus.d.ts.map +1 -0
  26. package/dist/core/focus.js +336 -0
  27. package/dist/core/i18n.d.ts +27 -0
  28. package/dist/core/i18n.d.ts.map +1 -0
  29. package/dist/core/i18n.js +88 -0
  30. package/dist/core/keybindings.d.ts +53 -0
  31. package/dist/core/keybindings.d.ts.map +1 -0
  32. package/dist/core/keybindings.js +163 -0
  33. package/dist/core/layers.d.ts +28 -0
  34. package/dist/core/layers.d.ts.map +1 -0
  35. package/dist/core/layers.js +84 -0
  36. package/dist/core/manifest.d.ts +22 -0
  37. package/dist/core/manifest.d.ts.map +1 -0
  38. package/dist/core/manifest.js +85 -0
  39. package/dist/core/navigation.d.ts +47 -0
  40. package/dist/core/navigation.d.ts.map +1 -0
  41. package/dist/core/navigation.js +110 -0
  42. package/dist/core/resources.d.ts +115 -0
  43. package/dist/core/resources.d.ts.map +1 -0
  44. package/dist/core/resources.js +321 -0
  45. package/dist/core/services.d.ts +21 -0
  46. package/dist/core/services.d.ts.map +1 -0
  47. package/dist/core/services.js +63 -0
  48. package/dist/core/store.d.ts +60 -0
  49. package/dist/core/store.d.ts.map +1 -0
  50. package/dist/core/store.js +593 -0
  51. package/dist/core/surfaces.d.ts +81 -0
  52. package/dist/core/surfaces.d.ts.map +1 -0
  53. package/dist/core/surfaces.js +237 -0
  54. package/dist/core/syntax.d.ts +49 -0
  55. package/dist/core/syntax.d.ts.map +1 -0
  56. package/dist/core/syntax.js +172 -0
  57. package/dist/core/when.d.ts +15 -0
  58. package/dist/core/when.d.ts.map +1 -0
  59. package/dist/core/when.js +224 -0
  60. package/dist/index.d.ts +49 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +54 -0
  63. package/dist/jsx/factory.d.ts +27 -0
  64. package/dist/jsx/factory.d.ts.map +1 -0
  65. package/dist/jsx/factory.js +102 -0
  66. package/dist/jsx/intrinsics.d.ts +96 -0
  67. package/dist/jsx/intrinsics.d.ts.map +1 -0
  68. package/dist/jsx/intrinsics.js +1 -0
  69. package/dist/jsx/jsx-dev-runtime.d.ts +13 -0
  70. package/dist/jsx/jsx-dev-runtime.d.ts.map +1 -0
  71. package/dist/jsx/jsx-dev-runtime.js +12 -0
  72. package/dist/jsx/jsx-runtime.d.ts +42 -0
  73. package/dist/jsx/jsx-runtime.d.ts.map +1 -0
  74. package/dist/jsx/jsx-runtime.js +16 -0
  75. package/dist/render/buffer.d.ts +77 -0
  76. package/dist/render/buffer.d.ts.map +1 -0
  77. package/dist/render/buffer.js +275 -0
  78. package/dist/render/color.d.ts +35 -0
  79. package/dist/render/color.d.ts.map +1 -0
  80. package/dist/render/color.js +160 -0
  81. package/dist/render/diff.d.ts +37 -0
  82. package/dist/render/diff.d.ts.map +1 -0
  83. package/dist/render/diff.js +66 -0
  84. package/dist/render/layout.d.ts +72 -0
  85. package/dist/render/layout.d.ts.map +1 -0
  86. package/dist/render/layout.js +633 -0
  87. package/dist/render/static.d.ts +63 -0
  88. package/dist/render/static.d.ts.map +1 -0
  89. package/dist/render/static.js +209 -0
  90. package/dist/runtime/bindings.d.ts +46 -0
  91. package/dist/runtime/bindings.d.ts.map +1 -0
  92. package/dist/runtime/bindings.js +116 -0
  93. package/dist/runtime/hooks.d.ts +284 -0
  94. package/dist/runtime/hooks.d.ts.map +1 -0
  95. package/dist/runtime/hooks.js +846 -0
  96. package/dist/runtime/instance.d.ts +106 -0
  97. package/dist/runtime/instance.d.ts.map +1 -0
  98. package/dist/runtime/instance.js +181 -0
  99. package/dist/runtime/paint.d.ts +27 -0
  100. package/dist/runtime/paint.d.ts.map +1 -0
  101. package/dist/runtime/paint.js +567 -0
  102. package/dist/runtime/reconcile.d.ts +23 -0
  103. package/dist/runtime/reconcile.d.ts.map +1 -0
  104. package/dist/runtime/reconcile.js +260 -0
  105. package/dist/runtime/runtime.d.ts +42 -0
  106. package/dist/runtime/runtime.d.ts.map +1 -0
  107. package/dist/runtime/runtime.js +1 -0
  108. package/dist/runtime/style.d.ts +55 -0
  109. package/dist/runtime/style.d.ts.map +1 -0
  110. package/dist/runtime/style.js +143 -0
  111. package/dist/themes/borders.d.ts +10 -0
  112. package/dist/themes/borders.d.ts.map +1 -0
  113. package/dist/themes/borders.js +88 -0
  114. package/dist/themes/builtin.d.ts +31 -0
  115. package/dist/themes/builtin.d.ts.map +1 -0
  116. package/dist/themes/builtin.js +291 -0
  117. package/dist/themes/glyphs.d.ts +15 -0
  118. package/dist/themes/glyphs.d.ts.map +1 -0
  119. package/dist/themes/glyphs.js +97 -0
  120. package/dist/themes/index.d.ts +5 -0
  121. package/dist/themes/index.d.ts.map +1 -0
  122. package/dist/themes/index.js +4 -0
  123. package/dist/themes/registry.d.ts +20 -0
  124. package/dist/themes/registry.d.ts.map +1 -0
  125. package/dist/themes/registry.js +204 -0
  126. package/dist/types/adapter.d.ts +38 -0
  127. package/dist/types/adapter.d.ts.map +1 -0
  128. package/dist/types/adapter.js +1 -0
  129. package/dist/types/animation.d.ts +31 -0
  130. package/dist/types/animation.d.ts.map +1 -0
  131. package/dist/types/animation.js +1 -0
  132. package/dist/types/app.d.ts +148 -0
  133. package/dist/types/app.d.ts.map +1 -0
  134. package/dist/types/app.js +1 -0
  135. package/dist/types/async.d.ts +30 -0
  136. package/dist/types/async.d.ts.map +1 -0
  137. package/dist/types/async.js +1 -0
  138. package/dist/types/capabilities.d.ts +44 -0
  139. package/dist/types/capabilities.d.ts.map +1 -0
  140. package/dist/types/capabilities.js +33 -0
  141. package/dist/types/cells.d.ts +72 -0
  142. package/dist/types/cells.d.ts.map +1 -0
  143. package/dist/types/cells.js +10 -0
  144. package/dist/types/command.d.ts +127 -0
  145. package/dist/types/command.d.ts.map +1 -0
  146. package/dist/types/command.js +1 -0
  147. package/dist/types/component-registry.d.ts +77 -0
  148. package/dist/types/component-registry.d.ts.map +1 -0
  149. package/dist/types/component-registry.js +1 -0
  150. package/dist/types/disposable.d.ts +8 -0
  151. package/dist/types/disposable.d.ts.map +1 -0
  152. package/dist/types/disposable.js +1 -0
  153. package/dist/types/focus.d.ts +72 -0
  154. package/dist/types/focus.d.ts.map +1 -0
  155. package/dist/types/focus.js +1 -0
  156. package/dist/types/geometry.d.ts +28 -0
  157. package/dist/types/geometry.d.ts.map +1 -0
  158. package/dist/types/geometry.js +14 -0
  159. package/dist/types/graph.d.ts +129 -0
  160. package/dist/types/graph.d.ts.map +1 -0
  161. package/dist/types/graph.js +31 -0
  162. package/dist/types/i18n.d.ts +23 -0
  163. package/dist/types/i18n.d.ts.map +1 -0
  164. package/dist/types/i18n.js +1 -0
  165. package/dist/types/index.d.ts +32 -0
  166. package/dist/types/index.d.ts.map +1 -0
  167. package/dist/types/index.js +31 -0
  168. package/dist/types/input.d.ts +65 -0
  169. package/dist/types/input.d.ts.map +1 -0
  170. package/dist/types/input.js +1 -0
  171. package/dist/types/keybinding.d.ts +49 -0
  172. package/dist/types/keybinding.d.ts.map +1 -0
  173. package/dist/types/keybinding.js +1 -0
  174. package/dist/types/layer.d.ts +54 -0
  175. package/dist/types/layer.d.ts.map +1 -0
  176. package/dist/types/layer.js +1 -0
  177. package/dist/types/manifest.d.ts +114 -0
  178. package/dist/types/manifest.d.ts.map +1 -0
  179. package/dist/types/manifest.js +1 -0
  180. package/dist/types/markdown.d.ts +58 -0
  181. package/dist/types/markdown.d.ts.map +1 -0
  182. package/dist/types/markdown.js +1 -0
  183. package/dist/types/navigation.d.ts +40 -0
  184. package/dist/types/navigation.d.ts.map +1 -0
  185. package/dist/types/navigation.js +1 -0
  186. package/dist/types/render.d.ts +72 -0
  187. package/dist/types/render.d.ts.map +1 -0
  188. package/dist/types/render.js +1 -0
  189. package/dist/types/resource.d.ts +170 -0
  190. package/dist/types/resource.d.ts.map +1 -0
  191. package/dist/types/resource.js +1 -0
  192. package/dist/types/services.d.ts +24 -0
  193. package/dist/types/services.d.ts.map +1 -0
  194. package/dist/types/services.js +3 -0
  195. package/dist/types/shell.d.ts +32 -0
  196. package/dist/types/shell.d.ts.map +1 -0
  197. package/dist/types/shell.js +1 -0
  198. package/dist/types/store.d.ts +124 -0
  199. package/dist/types/store.d.ts.map +1 -0
  200. package/dist/types/store.js +1 -0
  201. package/dist/types/stream.d.ts +18 -0
  202. package/dist/types/stream.d.ts.map +1 -0
  203. package/dist/types/stream.js +1 -0
  204. package/dist/types/style.d.ts +166 -0
  205. package/dist/types/style.d.ts.map +1 -0
  206. package/dist/types/style.js +1 -0
  207. package/dist/types/surface.d.ts +97 -0
  208. package/dist/types/surface.d.ts.map +1 -0
  209. package/dist/types/surface.js +1 -0
  210. package/dist/types/syntax.d.ts +68 -0
  211. package/dist/types/syntax.d.ts.map +1 -0
  212. package/dist/types/syntax.js +5 -0
  213. package/dist/types/terminal.d.ts +52 -0
  214. package/dist/types/terminal.d.ts.map +1 -0
  215. package/dist/types/terminal.js +1 -0
  216. package/dist/types/theme.d.ts +117 -0
  217. package/dist/types/theme.d.ts.map +1 -0
  218. package/dist/types/theme.js +1 -0
  219. package/dist/types/when.d.ts +19 -0
  220. package/dist/types/when.d.ts.map +1 -0
  221. package/dist/types/when.js +1 -0
  222. package/dist/ui/primitives.d.ts +56 -0
  223. package/dist/ui/primitives.d.ts.map +1 -0
  224. package/dist/ui/primitives.js +108 -0
  225. package/dist/ui/screen.d.ts +23 -0
  226. package/dist/ui/screen.d.ts.map +1 -0
  227. package/dist/ui/screen.js +18 -0
  228. package/dist/util/disposable.d.ts +6 -0
  229. package/dist/util/disposable.d.ts.map +1 -0
  230. package/dist/util/disposable.js +49 -0
  231. package/dist/util/markdown.d.ts +24 -0
  232. package/dist/util/markdown.d.ts.map +1 -0
  233. package/dist/util/markdown.js +220 -0
  234. package/dist/util/paths.d.ts +47 -0
  235. package/dist/util/paths.d.ts.map +1 -0
  236. package/dist/util/paths.js +134 -0
  237. package/dist/util/stream.d.ts +32 -0
  238. package/dist/util/stream.d.ts.map +1 -0
  239. package/dist/util/stream.js +206 -0
  240. package/dist/util/text.d.ts +65 -0
  241. package/dist/util/text.d.ts.map +1 -0
  242. package/dist/util/text.js +419 -0
  243. package/package.json +70 -0
  244. package/src/adapters/index.ts +11 -0
  245. package/src/app/app.ts +1096 -0
  246. package/src/core/animation.ts +144 -0
  247. package/src/core/clipboard.ts +40 -0
  248. package/src/core/commands.ts +169 -0
  249. package/src/core/components.ts +91 -0
  250. package/src/core/events.ts +95 -0
  251. package/src/core/focus.ts +358 -0
  252. package/src/core/i18n.ts +107 -0
  253. package/src/core/keybindings.ts +184 -0
  254. package/src/core/layers.ts +94 -0
  255. package/src/core/manifest.ts +84 -0
  256. package/src/core/navigation.ts +135 -0
  257. package/src/core/resources.ts +362 -0
  258. package/src/core/services.ts +69 -0
  259. package/src/core/store.ts +640 -0
  260. package/src/core/surfaces.ts +292 -0
  261. package/src/core/syntax.ts +200 -0
  262. package/src/core/when.ts +238 -0
  263. package/src/index.ts +76 -0
  264. package/src/jsx/factory.ts +124 -0
  265. package/src/jsx/intrinsics.ts +99 -0
  266. package/src/jsx/jsx-dev-runtime.ts +23 -0
  267. package/src/jsx/jsx-runtime.ts +76 -0
  268. package/src/render/buffer.ts +318 -0
  269. package/src/render/color.ts +180 -0
  270. package/src/render/diff.ts +99 -0
  271. package/src/render/layout.ts +764 -0
  272. package/src/render/static.ts +290 -0
  273. package/src/runtime/bindings.ts +150 -0
  274. package/src/runtime/hooks.ts +1057 -0
  275. package/src/runtime/instance.ts +284 -0
  276. package/src/runtime/paint.ts +737 -0
  277. package/src/runtime/reconcile.ts +335 -0
  278. package/src/runtime/runtime.ts +47 -0
  279. package/src/runtime/style.ts +205 -0
  280. package/src/themes/borders.ts +95 -0
  281. package/src/themes/builtin.ts +301 -0
  282. package/src/themes/glyphs.ts +101 -0
  283. package/src/themes/index.ts +4 -0
  284. package/src/themes/registry.ts +224 -0
  285. package/src/types/adapter.ts +41 -0
  286. package/src/types/animation.ts +34 -0
  287. package/src/types/app.ts +149 -0
  288. package/src/types/async.ts +35 -0
  289. package/src/types/capabilities.ts +79 -0
  290. package/src/types/cells.ts +79 -0
  291. package/src/types/command.ts +139 -0
  292. package/src/types/component-registry.ts +82 -0
  293. package/src/types/disposable.ts +8 -0
  294. package/src/types/focus.ts +77 -0
  295. package/src/types/geometry.ts +50 -0
  296. package/src/types/graph.ts +174 -0
  297. package/src/types/i18n.ts +25 -0
  298. package/src/types/index.ts +31 -0
  299. package/src/types/input.ts +81 -0
  300. package/src/types/keybinding.ts +51 -0
  301. package/src/types/layer.ts +46 -0
  302. package/src/types/manifest.ts +101 -0
  303. package/src/types/markdown.ts +47 -0
  304. package/src/types/navigation.ts +42 -0
  305. package/src/types/render.ts +86 -0
  306. package/src/types/resource.ts +185 -0
  307. package/src/types/services.ts +28 -0
  308. package/src/types/shell.ts +30 -0
  309. package/src/types/store.ts +148 -0
  310. package/src/types/stream.ts +24 -0
  311. package/src/types/style.ts +205 -0
  312. package/src/types/surface.ts +119 -0
  313. package/src/types/syntax.ts +93 -0
  314. package/src/types/terminal.ts +58 -0
  315. package/src/types/theme.ts +121 -0
  316. package/src/types/when.ts +21 -0
  317. package/src/ui/primitives.ts +118 -0
  318. package/src/ui/screen.ts +41 -0
  319. package/src/util/disposable.ts +49 -0
  320. package/src/util/markdown.ts +225 -0
  321. package/src/util/paths.ts +138 -0
  322. package/src/util/stream.ts +213 -0
  323. package/src/util/text.ts +428 -0
@@ -0,0 +1,16 @@
1
+ import { componentNameOf, Fragment } from './factory.js';
2
+ export { Fragment };
3
+ function build(type, props, key) {
4
+ const node = typeof type === 'string'
5
+ ? { component: type, ...props }
6
+ : { component: componentNameOf(type), ...props, $meta: { fn: type } };
7
+ if (key !== undefined)
8
+ node.key = key;
9
+ return node;
10
+ }
11
+ export function jsx(type, props, key) {
12
+ return build(type, props, key);
13
+ }
14
+ export function jsxs(type, props, key) {
15
+ return build(type, props, key);
16
+ }
@@ -0,0 +1,77 @@
1
+ import type { Rect } from '../types/geometry.js';
2
+ import type { Cell, CellBuffer } from '../types/cells.js';
3
+ import { type PackedColor } from './color.js';
4
+ /** One cell as it is stored: colours packed, nothing allocated to read it. */
5
+ export interface PackedCell {
6
+ char: string;
7
+ fg: PackedColor;
8
+ bg: PackedColor;
9
+ attrs: number;
10
+ link: string | undefined;
11
+ }
12
+ /** Internal cell flags, kept out of the public attrs bitfield. */
13
+ export declare const FLAG_CONTINUATION = 1;
14
+ /**
15
+ * The frame.
16
+ *
17
+ * Cells live in parallel arrays rather than objects because the diff walks
18
+ * every cell of every frame, and one allocation per cell per frame is the
19
+ * difference between a smooth redraw and a visibly stuttering one.
20
+ */
21
+ export declare class Buffer implements CellBuffer {
22
+ width: number;
23
+ height: number;
24
+ chars: string[];
25
+ fg: Int32Array;
26
+ bg: Int32Array;
27
+ attrs: Uint16Array;
28
+ flags: Uint8Array;
29
+ links: (string | undefined)[];
30
+ private prevChars;
31
+ private prevFg;
32
+ private prevBg;
33
+ private prevAttrs;
34
+ private prevLinks;
35
+ private committed;
36
+ constructor(width: number, height: number);
37
+ /** Cell-object access, for the `CellBuffer` contract and the test harness. */
38
+ get(x: number, y: number): Cell | undefined;
39
+ /**
40
+ * The same cell, as the numbers it is actually stored as.
41
+ *
42
+ * `get` is the friendly shape: it unpacks both colours into `Color` values,
43
+ * which is right for a test or a caller reasoning about colour and wrong for
44
+ * a loop over a region - packing them straight back is an allocation and a
45
+ * round trip per cell. This is what the renderer's inner loops use.
46
+ */
47
+ packedAt(x: number, y: number): PackedCell | undefined;
48
+ set(x: number, y: number, cell: Cell): void;
49
+ index(x: number, y: number): number;
50
+ inBounds(x: number, y: number): boolean;
51
+ /**
52
+ * Write one grapheme. A double-width grapheme claims the next cell as a
53
+ * continuation, and writing over either half clears the other - otherwise a
54
+ * half-overwritten wide character shifts every cell after it on that row.
55
+ */
56
+ put(x: number, y: number, char: string, fg?: PackedColor, bg?: PackedColor, attrs?: number, link?: string): void;
57
+ /**
58
+ * Blank a region, or the whole buffer.
59
+ *
60
+ * By span rather than by cell. Clearing everything happens once a frame, and
61
+ * a cell-at-a-time loop over twelve thousand of them - each with two bounds
62
+ * checks and an index multiply - was costing more than painting the content
63
+ * that replaced it. `fill` is one call into the engine per array, and the
64
+ * four that matter are typed.
65
+ */
66
+ clear(rect?: Rect, bg?: PackedColor): void;
67
+ private fillSpan;
68
+ resize(width: number, height: number): void;
69
+ cellChanged(i: number): boolean;
70
+ dirtyRows(): number[];
71
+ commit(): void;
72
+ /** Force the next diff to repaint everything. After a resize or a redraw. */
73
+ invalidate(): void;
74
+ toText(rect?: Rect): string;
75
+ }
76
+ export declare function createBuffer(width: number, height: number): Buffer;
77
+ //# sourceMappingURL=buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../src/render/buffer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAA4B,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAExE,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,WAAW,CAAC;IAChB,EAAE,EAAE,WAAW,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAGD,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC;;;;;;GAMG;AACH,qBAAa,MAAO,YAAW,UAAU;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IAEf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,EAAE,EAAE,UAAU,CAAC;IACf,EAAE,EAAE,UAAU,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAE9B,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,SAAS,CAAS;gBAEd,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAkBzC,8EAA8E;IAC9E,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAa3C;;;;;;;OAOG;IACH,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAYtD,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI;IAO3C,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM;IAInC,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAIvC;;;;OAIG;IACH,GAAG,CACD,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,EACZ,EAAE,GAAE,WAA2B,EAC/B,EAAE,GAAE,WAA2B,EAC/B,KAAK,SAAI,EACT,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI;IAqDP;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,GAAE,WAA2B,GAAG,IAAI;IAmBzD,OAAO,CAAC,QAAQ;IAShB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAoC3C,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO;IAU/B,SAAS,IAAI,MAAM,EAAE;IAiBrB,MAAM,IAAI,IAAI;IASd,6EAA6E;IAC7E,UAAU,IAAI,IAAI;IAIlB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM;CAgB5B;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAElE"}
@@ -0,0 +1,275 @@
1
+ import { COLOR_DEFAULT, packColor } from './color.js';
2
+ import { graphemeWidth } from '../util/text.js';
3
+ /** Internal cell flags, kept out of the public attrs bitfield. */
4
+ export const FLAG_CONTINUATION = 1;
5
+ /**
6
+ * The frame.
7
+ *
8
+ * Cells live in parallel arrays rather than objects because the diff walks
9
+ * every cell of every frame, and one allocation per cell per frame is the
10
+ * difference between a smooth redraw and a visibly stuttering one.
11
+ */
12
+ export class Buffer {
13
+ width;
14
+ height;
15
+ chars;
16
+ fg;
17
+ bg;
18
+ attrs;
19
+ flags;
20
+ links;
21
+ prevChars;
22
+ prevFg;
23
+ prevBg;
24
+ prevAttrs;
25
+ prevLinks;
26
+ committed = false;
27
+ constructor(width, height) {
28
+ this.width = Math.max(0, width);
29
+ this.height = Math.max(0, height);
30
+ const n = this.width * this.height;
31
+ this.chars = new Array(n).fill(' ');
32
+ this.fg = new Int32Array(n).fill(COLOR_DEFAULT);
33
+ this.bg = new Int32Array(n).fill(COLOR_DEFAULT);
34
+ this.attrs = new Uint16Array(n);
35
+ this.flags = new Uint8Array(n);
36
+ this.links = new Array(n).fill(undefined);
37
+ this.prevChars = new Array(n).fill(' ');
38
+ this.prevFg = new Int32Array(n).fill(COLOR_DEFAULT);
39
+ this.prevBg = new Int32Array(n).fill(COLOR_DEFAULT);
40
+ this.prevAttrs = new Uint16Array(n);
41
+ this.prevLinks = new Array(n).fill(undefined);
42
+ }
43
+ /** Cell-object access, for the `CellBuffer` contract and the test harness. */
44
+ get(x, y) {
45
+ if (!this.inBounds(x, y))
46
+ return undefined;
47
+ const i = this.index(x, y);
48
+ return {
49
+ char: this.chars[i],
50
+ fg: packedToColor(this.fg[i]),
51
+ bg: packedToColor(this.bg[i]),
52
+ attrs: this.attrs[i],
53
+ link: this.links[i],
54
+ continuation: (this.flags[i] & FLAG_CONTINUATION) !== 0,
55
+ };
56
+ }
57
+ /**
58
+ * The same cell, as the numbers it is actually stored as.
59
+ *
60
+ * `get` is the friendly shape: it unpacks both colours into `Color` values,
61
+ * which is right for a test or a caller reasoning about colour and wrong for
62
+ * a loop over a region - packing them straight back is an allocation and a
63
+ * round trip per cell. This is what the renderer's inner loops use.
64
+ */
65
+ packedAt(x, y) {
66
+ if (!this.inBounds(x, y))
67
+ return undefined;
68
+ const i = this.index(x, y);
69
+ return {
70
+ char: this.chars[i],
71
+ fg: this.fg[i],
72
+ bg: this.bg[i],
73
+ attrs: this.attrs[i],
74
+ link: this.links[i],
75
+ };
76
+ }
77
+ set(x, y, cell) {
78
+ this.put(x, y, cell.char, packColor(cell.fg), packColor(cell.bg), cell.attrs, cell.link);
79
+ }
80
+ index(x, y) {
81
+ return y * this.width + x;
82
+ }
83
+ inBounds(x, y) {
84
+ return x >= 0 && x < this.width && y >= 0 && y < this.height;
85
+ }
86
+ /**
87
+ * Write one grapheme. A double-width grapheme claims the next cell as a
88
+ * continuation, and writing over either half clears the other - otherwise a
89
+ * half-overwritten wide character shifts every cell after it on that row.
90
+ */
91
+ put(x, y, char, fg = COLOR_DEFAULT, bg = COLOR_DEFAULT, attrs = 0, link) {
92
+ if (!this.inBounds(x, y))
93
+ return;
94
+ const i = this.index(x, y);
95
+ // Overwriting the right half of a wide pair: blank the left half.
96
+ if ((this.flags[i] & FLAG_CONTINUATION) !== 0 && x > 0) {
97
+ this.chars[i - 1] = ' ';
98
+ this.flags[i - 1] = 0;
99
+ }
100
+ // Overwriting a wide left half: blank its continuation.
101
+ if (x + 1 < this.width && (this.flags[i + 1] & FLAG_CONTINUATION) !== 0) {
102
+ this.chars[i + 1] = ' ';
103
+ this.flags[i + 1] = 0;
104
+ }
105
+ /*
106
+ * The width of one printable ASCII character, without asking.
107
+ *
108
+ * `graphemeWidth` is a function call per cell painted - twelve thousand of
109
+ * them a frame on a full screen - to answer "is `a` one cell wide". It is,
110
+ * and the character code says so.
111
+ */
112
+ const only = char.length === 1 ? char.charCodeAt(0) : -1;
113
+ const w = only >= 0x20 && only <= 0x7e ? 1 : graphemeWidth(char);
114
+ if (w === 0)
115
+ return;
116
+ this.chars[i] = char;
117
+ this.fg[i] = fg;
118
+ this.bg[i] = bg;
119
+ this.attrs[i] = attrs;
120
+ this.flags[i] = 0;
121
+ this.links[i] = link;
122
+ if (w === 2) {
123
+ if (x + 1 >= this.width) {
124
+ // A wide grapheme in the last column cannot render; blank it.
125
+ this.chars[i] = ' ';
126
+ return;
127
+ }
128
+ const j = i + 1;
129
+ if (x + 2 < this.width && (this.flags[j + 1] & FLAG_CONTINUATION) !== 0) {
130
+ this.chars[j + 1] = ' ';
131
+ this.flags[j + 1] = 0;
132
+ }
133
+ this.chars[j] = '';
134
+ this.fg[j] = fg;
135
+ this.bg[j] = bg;
136
+ this.attrs[j] = attrs;
137
+ this.flags[j] = FLAG_CONTINUATION;
138
+ this.links[j] = link;
139
+ }
140
+ }
141
+ /**
142
+ * Blank a region, or the whole buffer.
143
+ *
144
+ * By span rather than by cell. Clearing everything happens once a frame, and
145
+ * a cell-at-a-time loop over twelve thousand of them - each with two bounds
146
+ * checks and an index multiply - was costing more than painting the content
147
+ * that replaced it. `fill` is one call into the engine per array, and the
148
+ * four that matter are typed.
149
+ */
150
+ clear(rect, bg = COLOR_DEFAULT) {
151
+ if (rect === undefined) {
152
+ this.fillSpan(0, this.width * this.height, bg);
153
+ return;
154
+ }
155
+ const x0 = Math.max(0, rect.x);
156
+ const x1 = Math.min(this.width, rect.x + rect.width);
157
+ const y0 = Math.max(0, rect.y);
158
+ const y1 = Math.min(this.height, rect.y + rect.height);
159
+ if (x1 <= x0 || y1 <= y0)
160
+ return;
161
+ // A row at a time: rows are contiguous, columns are not.
162
+ for (let y = y0; y < y1; y++) {
163
+ const start = y * this.width;
164
+ this.fillSpan(start + x0, start + x1, bg);
165
+ }
166
+ }
167
+ fillSpan(from, to, bg) {
168
+ this.chars.fill(' ', from, to);
169
+ this.fg.fill(COLOR_DEFAULT, from, to);
170
+ this.bg.fill(bg, from, to);
171
+ this.attrs.fill(0, from, to);
172
+ this.flags.fill(0, from, to);
173
+ this.links.fill(undefined, from, to);
174
+ }
175
+ resize(width, height) {
176
+ if (width === this.width && height === this.height)
177
+ return;
178
+ const next = new Buffer(width, height);
179
+ const w = Math.min(width, this.width);
180
+ const h = Math.min(height, this.height);
181
+ for (let y = 0; y < h; y++) {
182
+ for (let x = 0; x < w; x++) {
183
+ const from = this.index(x, y);
184
+ const to = next.index(x, y);
185
+ next.chars[to] = this.chars[from];
186
+ next.fg[to] = this.fg[from];
187
+ next.bg[to] = this.bg[from];
188
+ next.attrs[to] = this.attrs[from];
189
+ next.flags[to] = this.flags[from];
190
+ next.links[to] = this.links[from];
191
+ }
192
+ }
193
+ this.width = next.width;
194
+ this.height = next.height;
195
+ this.chars = next.chars;
196
+ this.fg = next.fg;
197
+ this.bg = next.bg;
198
+ this.attrs = next.attrs;
199
+ this.flags = next.flags;
200
+ this.links = next.links;
201
+ // A resize invalidates the previous frame entirely.
202
+ const n = width * height;
203
+ this.prevChars = new Array(n).fill(' ');
204
+ this.prevFg = new Int32Array(n).fill(COLOR_DEFAULT);
205
+ this.prevBg = new Int32Array(n).fill(COLOR_DEFAULT);
206
+ this.prevAttrs = new Uint16Array(n);
207
+ this.prevLinks = new Array(n).fill(undefined);
208
+ this.committed = false;
209
+ }
210
+ cellChanged(i) {
211
+ return (this.chars[i] !== this.prevChars[i] ||
212
+ this.fg[i] !== this.prevFg[i] ||
213
+ this.bg[i] !== this.prevBg[i] ||
214
+ this.attrs[i] !== this.prevAttrs[i] ||
215
+ this.links[i] !== this.prevLinks[i]);
216
+ }
217
+ dirtyRows() {
218
+ if (!this.committed) {
219
+ return Array.from({ length: this.height }, (_, y) => y);
220
+ }
221
+ const rows = [];
222
+ for (let y = 0; y < this.height; y++) {
223
+ const start = y * this.width;
224
+ for (let x = 0; x < this.width; x++) {
225
+ if (this.cellChanged(start + x)) {
226
+ rows.push(y);
227
+ break;
228
+ }
229
+ }
230
+ }
231
+ return rows;
232
+ }
233
+ commit() {
234
+ this.prevChars = this.chars.slice();
235
+ this.prevFg = this.fg.slice();
236
+ this.prevBg = this.bg.slice();
237
+ this.prevAttrs = this.attrs.slice();
238
+ this.prevLinks = this.links.slice();
239
+ this.committed = true;
240
+ }
241
+ /** Force the next diff to repaint everything. After a resize or a redraw. */
242
+ invalidate() {
243
+ this.committed = false;
244
+ }
245
+ toText(rect) {
246
+ const r = rect ?? { x: 0, y: 0, width: this.width, height: this.height };
247
+ const lines = [];
248
+ for (let y = r.y; y < r.y + r.height; y++) {
249
+ if (y < 0 || y >= this.height)
250
+ continue;
251
+ let line = '';
252
+ for (let x = r.x; x < r.x + r.width; x++) {
253
+ if (x < 0 || x >= this.width)
254
+ continue;
255
+ const i = this.index(x, y);
256
+ if ((this.flags[i] & FLAG_CONTINUATION) !== 0)
257
+ continue;
258
+ line += this.chars[i];
259
+ }
260
+ lines.push(line.replace(/[ ]+$/, ''));
261
+ }
262
+ return lines.join('\n');
263
+ }
264
+ }
265
+ export function createBuffer(width, height) {
266
+ return new Buffer(width, height);
267
+ }
268
+ function packedToColor(packed) {
269
+ if (packed === COLOR_DEFAULT)
270
+ return 'default';
271
+ if (packed >= 0x1000000) {
272
+ return { rgb: [(packed >> 16) & 0xff, (packed >> 8) & 0xff, packed & 0xff] };
273
+ }
274
+ return { palette: packed };
275
+ }
@@ -0,0 +1,35 @@
1
+ import type { AnsiColorName, Color, ColorDepth } from '../types/index.js';
2
+ /**
3
+ * Colours are packed into one integer so a cell is cheap to store and cheap to
4
+ * compare - the frame diff runs over every cell, every frame.
5
+ *
6
+ * -1 terminal default
7
+ * 0..255 palette index (0..15 are the ANSI names)
8
+ * >= 0x1000000 24-bit rgb, as 0x1000000 | rrggbb
9
+ */
10
+ export type PackedColor = number;
11
+ export declare const COLOR_DEFAULT: PackedColor;
12
+ export declare const ANSI_NAMES: Record<AnsiColorName, number>;
13
+ export declare function packRgb(r: number, g: number, b: number): PackedColor;
14
+ export declare function isRgb(c: PackedColor): boolean;
15
+ export declare function unpackRgb(c: PackedColor): [number, number, number];
16
+ export declare function packColor(color: Color | undefined): PackedColor;
17
+ /**
18
+ * Reduce a colour to what the terminal can show. A component never picks a
19
+ * fallback itself - it names a token, and this decides what that survives as.
20
+ */
21
+ export declare function downsample(c: PackedColor, depth: ColorDepth): PackedColor;
22
+ /** Relative luminance, for picking readable foreground over a background. */
23
+ export declare function luminance(c: PackedColor): number;
24
+ /** Mix two packed colours. `t` of 0 is `a`, 1 is `b`. */
25
+ export declare function mix(a: PackedColor, b: PackedColor, t: number): PackedColor;
26
+ /**
27
+ * A packed colour back as a `Color`, which is the shape a style takes.
28
+ *
29
+ * The inverse of `packColor`, for the places that compute a colour and then
30
+ * have to hand it to a component - blending a tint out of two theme colours,
31
+ * say. Painting goes the other way and should stay packed.
32
+ */
33
+ export declare function unpackColor(packed: PackedColor): Color;
34
+ export declare function toHex(c: PackedColor): string;
35
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/render/color.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE1E;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAEjC,eAAO,MAAM,aAAa,EAAE,WAAgB,CAAC;AAG7C,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAKpD,CAAC;AAEF,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,WAAW,CAEpE;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAE7C;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAElE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,WAAW,CA6B/D;AAyDD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,GAAG,WAAW,CAazE;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAOhD;AAED,yDAAyD;AACzD,wBAAgB,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,GAAG,WAAW,CAQ1E;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAOtD;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAG5C"}
@@ -0,0 +1,160 @@
1
+ export const COLOR_DEFAULT = -1;
2
+ const RGB_FLAG = 0x1000000;
3
+ export const ANSI_NAMES = {
4
+ black: 0, red: 1, green: 2, yellow: 3,
5
+ blue: 4, magenta: 5, cyan: 6, white: 7,
6
+ brightBlack: 8, brightRed: 9, brightGreen: 10, brightYellow: 11,
7
+ brightBlue: 12, brightMagenta: 13, brightCyan: 14, brightWhite: 15,
8
+ };
9
+ export function packRgb(r, g, b) {
10
+ return RGB_FLAG | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);
11
+ }
12
+ export function isRgb(c) {
13
+ return c >= RGB_FLAG;
14
+ }
15
+ export function unpackRgb(c) {
16
+ return [(c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff];
17
+ }
18
+ export function packColor(color) {
19
+ if (color === undefined || color === 'default')
20
+ return COLOR_DEFAULT;
21
+ if (typeof color === 'string') {
22
+ if (color.startsWith('#')) {
23
+ const hex = color.slice(1);
24
+ if (hex.length === 3) {
25
+ const r = parseInt(hex[0], 16);
26
+ const g = parseInt(hex[1], 16);
27
+ const b = parseInt(hex[2], 16);
28
+ return packRgb(r * 17, g * 17, b * 17);
29
+ }
30
+ if (hex.length === 6) {
31
+ return packRgb(parseInt(hex.slice(0, 2), 16), parseInt(hex.slice(2, 4), 16), parseInt(hex.slice(4, 6), 16));
32
+ }
33
+ return COLOR_DEFAULT;
34
+ }
35
+ const idx = ANSI_NAMES[color];
36
+ return idx === undefined ? COLOR_DEFAULT : idx;
37
+ }
38
+ if ('rgb' in color) {
39
+ const [r, g, b] = color.rgb;
40
+ return packRgb(r, g, b);
41
+ }
42
+ if ('palette' in color)
43
+ return color.palette & 0xff;
44
+ return COLOR_DEFAULT;
45
+ }
46
+ /** The xterm 256 palette, so 24-bit can be reduced without a lookup table. */
47
+ const CUBE_STEPS = [0, 95, 135, 175, 215, 255];
48
+ function nearestCube(v) {
49
+ let best = 0;
50
+ let bestDist = Infinity;
51
+ for (let i = 0; i < CUBE_STEPS.length; i++) {
52
+ const d = Math.abs(CUBE_STEPS[i] - v);
53
+ if (d < bestDist) {
54
+ bestDist = d;
55
+ best = i;
56
+ }
57
+ }
58
+ return best;
59
+ }
60
+ function rgbTo256(r, g, b) {
61
+ // Greyscale ramp is a better fit when the channels are close.
62
+ if (Math.abs(r - g) < 8 && Math.abs(g - b) < 8) {
63
+ if (r < 8)
64
+ return 16;
65
+ if (r > 248)
66
+ return 231;
67
+ return 232 + Math.round(((r - 8) / 247) * 23);
68
+ }
69
+ return 16 + 36 * nearestCube(r) + 6 * nearestCube(g) + nearestCube(b);
70
+ }
71
+ const ANSI16_RGB = [
72
+ [0, 0, 0], [205, 49, 49], [13, 188, 121], [229, 229, 16],
73
+ [36, 114, 200], [188, 63, 188], [17, 168, 205], [229, 229, 229],
74
+ [102, 102, 102], [241, 76, 76], [35, 209, 139], [245, 245, 67],
75
+ [59, 142, 234], [214, 112, 214], [41, 184, 219], [255, 255, 255],
76
+ ];
77
+ function rgbTo16(r, g, b) {
78
+ let best = 0;
79
+ let bestDist = Infinity;
80
+ for (let i = 0; i < 16; i++) {
81
+ const [cr, cg, cb] = ANSI16_RGB[i];
82
+ const d = (r - cr) ** 2 + (g - cg) ** 2 + (b - cb) ** 2;
83
+ if (d < bestDist) {
84
+ bestDist = d;
85
+ best = i;
86
+ }
87
+ }
88
+ return best;
89
+ }
90
+ function palette256ToRgb(idx) {
91
+ if (idx < 16)
92
+ return ANSI16_RGB[idx];
93
+ if (idx >= 232) {
94
+ const v = 8 + (idx - 232) * 10;
95
+ return [v, v, v];
96
+ }
97
+ const n = idx - 16;
98
+ return [
99
+ CUBE_STEPS[Math.floor(n / 36) % 6],
100
+ CUBE_STEPS[Math.floor(n / 6) % 6],
101
+ CUBE_STEPS[n % 6],
102
+ ];
103
+ }
104
+ /**
105
+ * Reduce a colour to what the terminal can show. A component never picks a
106
+ * fallback itself - it names a token, and this decides what that survives as.
107
+ */
108
+ export function downsample(c, depth) {
109
+ if (c === COLOR_DEFAULT)
110
+ return c;
111
+ if (depth === 0)
112
+ return COLOR_DEFAULT;
113
+ if (depth === 24)
114
+ return c;
115
+ if (isRgb(c)) {
116
+ const [r, g, b] = unpackRgb(c);
117
+ return depth === 8 ? rgbTo256(r, g, b) : rgbTo16(r, g, b);
118
+ }
119
+ if (depth === 8)
120
+ return c;
121
+ if (c < 16)
122
+ return c;
123
+ const [r, g, b] = palette256ToRgb(c);
124
+ return rgbTo16(r, g, b);
125
+ }
126
+ /** Relative luminance, for picking readable foreground over a background. */
127
+ export function luminance(c) {
128
+ const [r, g, b] = isRgb(c) ? unpackRgb(c) : palette256ToRgb(c < 0 ? 0 : c);
129
+ const f = (v) => {
130
+ const s = v / 255;
131
+ return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
132
+ };
133
+ return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
134
+ }
135
+ /** Mix two packed colours. `t` of 0 is `a`, 1 is `b`. */
136
+ export function mix(a, b, t) {
137
+ const [ar, ag, ab] = isRgb(a) ? unpackRgb(a) : palette256ToRgb(Math.max(0, a));
138
+ const [br, bg, bb] = isRgb(b) ? unpackRgb(b) : palette256ToRgb(Math.max(0, b));
139
+ return packRgb(Math.round(ar + (br - ar) * t), Math.round(ag + (bg - ag) * t), Math.round(ab + (bb - ab) * t));
140
+ }
141
+ /**
142
+ * A packed colour back as a `Color`, which is the shape a style takes.
143
+ *
144
+ * The inverse of `packColor`, for the places that compute a colour and then
145
+ * have to hand it to a component - blending a tint out of two theme colours,
146
+ * say. Painting goes the other way and should stay packed.
147
+ */
148
+ export function unpackColor(packed) {
149
+ if (packed === COLOR_DEFAULT)
150
+ return 'default';
151
+ if (isRgb(packed)) {
152
+ const [r, g, b] = unpackRgb(packed);
153
+ return { rgb: [r, g, b] };
154
+ }
155
+ return { palette: packed };
156
+ }
157
+ export function toHex(c) {
158
+ const [r, g, b] = isRgb(c) ? unpackRgb(c) : palette256ToRgb(Math.max(0, c));
159
+ return `#${[r, g, b].map((v) => v.toString(16).padStart(2, '0')).join('')}`;
160
+ }
@@ -0,0 +1,37 @@
1
+ import type { Buffer } from './buffer.js';
2
+ import type { PackedColor } from './color.js';
3
+ /** One contiguous run of identical-style cells - what the writer emits. */
4
+ export interface Run {
5
+ x: number;
6
+ y: number;
7
+ text: string;
8
+ fg: PackedColor;
9
+ bg: PackedColor;
10
+ attrs: number;
11
+ link: string | undefined;
12
+ }
13
+ export interface Frame {
14
+ runs: Run[];
15
+ cursor: {
16
+ x: number;
17
+ y: number;
18
+ visible: boolean;
19
+ } | null;
20
+ /** True when every row was emitted - first frame, or after invalidate. */
21
+ full: boolean;
22
+ }
23
+ /**
24
+ * Turn changed cells into runs.
25
+ *
26
+ * Two economies matter here and nowhere else: only touched rows are walked,
27
+ * and within a row, adjacent changed cells sharing a style become one run, so
28
+ * a redraw costs one cursor move and one SGR change per run rather than per
29
+ * cell. A run continues through a short stretch of unchanged cells when
30
+ * repainting them is cheaper than moving the cursor around them.
31
+ */
32
+ export declare function diffFrame(buffer: Buffer, cursor?: {
33
+ x: number;
34
+ y: number;
35
+ visible: boolean;
36
+ } | null, gapTolerance?: number): Frame;
37
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/render/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,2EAA2E;AAC3E,MAAM,WAAW,GAAG;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,WAAW,CAAC;IAChB,EAAE,EAAE,WAAW,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,IAAW,EAChE,YAAY,SAAI,GACf,KAAK,CA+DP"}
@@ -0,0 +1,66 @@
1
+ import { FLAG_CONTINUATION } from './buffer.js';
2
+ /**
3
+ * Turn changed cells into runs.
4
+ *
5
+ * Two economies matter here and nowhere else: only touched rows are walked,
6
+ * and within a row, adjacent changed cells sharing a style become one run, so
7
+ * a redraw costs one cursor move and one SGR change per run rather than per
8
+ * cell. A run continues through a short stretch of unchanged cells when
9
+ * repainting them is cheaper than moving the cursor around them.
10
+ */
11
+ export function diffFrame(buffer, cursor = null, gapTolerance = 4) {
12
+ const runs = [];
13
+ const rows = buffer.dirtyRows();
14
+ const full = rows.length === buffer.height && buffer.height > 0;
15
+ for (const y of rows) {
16
+ const base = y * buffer.width;
17
+ let x = 0;
18
+ while (x < buffer.width) {
19
+ const i = base + x;
20
+ if ((buffer.flags[i] & FLAG_CONTINUATION) !== 0 || !buffer.cellChanged(i)) {
21
+ x++;
22
+ continue;
23
+ }
24
+ const fg = buffer.fg[i];
25
+ const bg = buffer.bg[i];
26
+ const attrs = buffer.attrs[i];
27
+ const link = buffer.links[i];
28
+ let text = '';
29
+ let cx = x;
30
+ let gap = 0;
31
+ let pendingGap = '';
32
+ while (cx < buffer.width) {
33
+ const j = base + cx;
34
+ if ((buffer.flags[j] & FLAG_CONTINUATION) !== 0) {
35
+ cx++;
36
+ continue;
37
+ }
38
+ const sameStyle = buffer.fg[j] === fg &&
39
+ buffer.bg[j] === bg &&
40
+ buffer.attrs[j] === attrs &&
41
+ buffer.links[j] === link;
42
+ if (!sameStyle)
43
+ break;
44
+ if (buffer.cellChanged(j)) {
45
+ if (pendingGap !== '') {
46
+ text += pendingGap;
47
+ pendingGap = '';
48
+ gap = 0;
49
+ }
50
+ text += buffer.chars[j];
51
+ cx++;
52
+ continue;
53
+ }
54
+ gap++;
55
+ if (gap > gapTolerance)
56
+ break;
57
+ pendingGap += buffer.chars[j];
58
+ cx++;
59
+ }
60
+ if (text !== '')
61
+ runs.push({ x, y, text, fg, bg, attrs, link });
62
+ x = cx > x ? cx : x + 1;
63
+ }
64
+ }
65
+ return { runs, cursor, full };
66
+ }