@alchemy.run/sigil 0.0.0-alpha.3 → 0.0.0-alpha.5

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 (207) hide show
  1. package/README.md +23 -13
  2. package/THIRD_PARTY_NOTICES.md +70 -23
  3. package/dist/Text-D5HUf3Fj.d.ts +452 -0
  4. package/dist/ansi.d.ts +137 -143
  5. package/dist/ansi.js +87 -2
  6. package/dist/capabilities.d.ts +5 -0
  7. package/dist/capabilities.js +3 -0
  8. package/dist/cell-_ZVhbfl0.js +44 -0
  9. package/dist/color-CkbalRqK.js +2 -0
  10. package/dist/color-policy-BMzMwV7Q.d.ts +22 -0
  11. package/dist/color-policy-SVj1pYTA.js +560 -0
  12. package/dist/color-profile-DHhQHY55.js +36 -0
  13. package/dist/color-profile-u0Nhe9Nv.d.ts +97 -0
  14. package/dist/color.d.ts +21 -0
  15. package/dist/color.js +3 -0
  16. package/dist/cursor-position-D2LAkRG0.d.ts +7 -0
  17. package/dist/detect-Bh4yGP6w.d.ts +186 -0
  18. package/dist/detect-BuTXtY6e.js +373 -0
  19. package/dist/{devtools-BhYGjb7h.js → devtools-DbthxoD1.js} +22 -23
  20. package/dist/env-YVw64yZS.js +9 -0
  21. package/dist/escapes-CB_6CWOE.d.ts +72 -0
  22. package/dist/geometry-BxXOzJgo.d.ts +11 -0
  23. package/dist/index-Bmc2tRPk.d.ts +21 -0
  24. package/dist/index.d.ts +235 -754
  25. package/dist/index.js +1362 -3001
  26. package/dist/osc-CCH7xDoS.js +71 -0
  27. package/dist/osc-Cn0fw77g.d.ts +23 -0
  28. package/dist/paint-C19minOS.d.ts +81 -0
  29. package/dist/query-vaIeGOkH.d.ts +152 -0
  30. package/dist/router.d.ts +392 -0
  31. package/dist/router.js +709 -0
  32. package/dist/sample-Cqw1bjUL.js +445 -0
  33. package/dist/screen-BOh__-65.js +324 -0
  34. package/dist/screen-BReKIheE.d.ts +40 -0
  35. package/dist/screen.d.ts +5 -0
  36. package/dist/screen.js +5 -0
  37. package/dist/semantic-text-style-DIMzC7xt.js +91 -0
  38. package/dist/serialize-BTkAZgw1.js +79 -0
  39. package/dist/session-BJmzX2NJ.js +664 -0
  40. package/dist/sgr-BhwaWAJB.js +246 -0
  41. package/dist/store-CgrG9K4y.d.ts +72 -0
  42. package/dist/string-width-CijQwpIk.js +69 -0
  43. package/dist/strip-BvU4toXG.js +6 -0
  44. package/dist/terminal.d.ts +118 -0
  45. package/dist/terminal.js +2 -0
  46. package/dist/tokenize-AjqbvtiT.js +1242 -0
  47. package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
  48. package/dist/truncate-D31fhU6i.js +562 -0
  49. package/dist/use-focus-C2sciZOo.js +1335 -0
  50. package/package.json +43 -17
  51. package/src/ansi/chalk.ts +12 -53
  52. package/src/ansi/cursor.ts +2 -4
  53. package/src/ansi/east-asian-width.ts +44 -0
  54. package/src/ansi/escapes.ts +18 -26
  55. package/src/ansi/graphemes.ts +8 -0
  56. package/src/ansi/hyperlink.ts +44 -0
  57. package/src/ansi/index.ts +14 -14
  58. package/src/ansi/osc.ts +77 -0
  59. package/src/ansi/sgr.ts +2 -5
  60. package/src/ansi/slice.ts +1 -1
  61. package/src/ansi/string-width.ts +91 -206
  62. package/src/ansi/strip.ts +13 -33
  63. package/src/ansi/tokenize.ts +96 -169
  64. package/src/ansi/truncate.ts +5 -3
  65. package/src/ansi/wrap.ts +13 -14
  66. package/src/ansi-tokenizer.ts +1 -1
  67. package/src/capabilities/color-policy.ts +34 -0
  68. package/src/capabilities/detect.ts +594 -0
  69. package/src/capabilities/index.ts +37 -0
  70. package/src/capabilities/query.ts +657 -0
  71. package/src/capabilities/store.ts +379 -0
  72. package/src/color/index.ts +3 -0
  73. package/src/color/paint.ts +169 -0
  74. package/src/color/palette.ts +48 -0
  75. package/src/color/sample.ts +323 -0
  76. package/src/color.ts +1 -0
  77. package/src/components/AnsiText.tsx +42 -0
  78. package/src/components/App.tsx +109 -22
  79. package/src/components/BackgroundContext.ts +2 -3
  80. package/src/components/Box.tsx +43 -60
  81. package/src/components/CursorContext.ts +1 -1
  82. package/src/components/ErrorBoundary.tsx +1 -1
  83. package/src/components/ErrorOverview.tsx +8 -7
  84. package/src/components/Hyperlink.tsx +56 -0
  85. package/src/components/Spacer.tsx +1 -1
  86. package/src/components/Static.tsx +1 -1
  87. package/src/components/StderrContext.ts +0 -2
  88. package/src/components/StdinContext.ts +0 -1
  89. package/src/components/StdoutContext.ts +1 -3
  90. package/src/components/TerminalOscContext.ts +25 -0
  91. package/src/components/Text.tsx +23 -46
  92. package/src/components/Transform.tsx +2 -2
  93. package/src/cursor-position.ts +1 -1
  94. package/src/devtools.ts +84 -24
  95. package/src/dom.ts +11 -8
  96. package/src/env.ts +12 -0
  97. package/src/get-max-width.ts +1 -1
  98. package/src/global.d.ts +6 -4
  99. package/src/{boxes.ts → glyphs.ts} +17 -18
  100. package/src/hooks/use-animation.ts +1 -1
  101. package/src/hooks/use-app.ts +1 -1
  102. package/src/hooks/use-box-metrics.ts +1 -1
  103. package/src/hooks/use-capabilities.ts +73 -0
  104. package/src/hooks/use-cursor.ts +3 -3
  105. package/src/hooks/use-focus-manager.ts +1 -1
  106. package/src/hooks/use-focus.ts +5 -6
  107. package/src/hooks/use-input.ts +4 -4
  108. package/src/hooks/use-is-screen-reader-enabled.ts +1 -1
  109. package/src/hooks/use-paste.ts +2 -2
  110. package/src/hooks/use-stderr.ts +1 -1
  111. package/src/hooks/use-stdin.ts +1 -1
  112. package/src/hooks/use-stdout.ts +1 -1
  113. package/src/hooks/use-terminal-osc.ts +59 -0
  114. package/src/hooks/use-window-size.ts +2 -2
  115. package/src/index.ts +88 -44
  116. package/src/ink.tsx +620 -745
  117. package/src/input-parser.ts +1 -1
  118. package/src/instances.ts +1 -1
  119. package/src/kitty-keyboard.ts +128 -0
  120. package/src/measure-element.ts +1 -1
  121. package/src/measure-text.ts +2 -2
  122. package/src/{render-node-to-output.ts → paint-tree.ts} +78 -53
  123. package/src/parse-keypress.ts +4 -5
  124. package/src/parse-stack-line.ts +0 -1
  125. package/src/patch-console.ts +44 -0
  126. package/src/reconciler.ts +36 -62
  127. package/src/render-background.ts +37 -16
  128. package/src/render-border.ts +97 -64
  129. package/src/render-frame.ts +83 -0
  130. package/src/render-to-string.ts +24 -9
  131. package/src/render.ts +24 -16
  132. package/src/router/components.tsx +343 -0
  133. package/src/router/context.ts +41 -0
  134. package/src/router/history.ts +194 -0
  135. package/src/router/hooks.tsx +391 -0
  136. package/src/router/index.ts +34 -0
  137. package/src/router/matcher.ts +571 -0
  138. package/src/sanitize-ansi.ts +1 -1
  139. package/src/screen/ansi.ts +184 -0
  140. package/src/screen/canvas.ts +137 -0
  141. package/src/screen/cell.ts +138 -0
  142. package/src/screen/color-profile.ts +47 -0
  143. package/src/screen/geometry.ts +9 -0
  144. package/src/screen/index.ts +6 -0
  145. package/src/screen/screen.ts +272 -0
  146. package/src/screen/serialize.ts +129 -0
  147. package/src/screen.ts +1 -0
  148. package/src/semantic-text-style.ts +118 -0
  149. package/src/signal-exit.ts +4 -5
  150. package/src/squash-text-nodes.ts +4 -7
  151. package/src/stream.ts +2 -4
  152. package/src/structured-text.ts +321 -0
  153. package/src/styles.ts +16 -17
  154. package/src/terminal/index.ts +2 -0
  155. package/src/terminal/inline-presenter.ts +120 -0
  156. package/src/terminal/input.ts +86 -0
  157. package/src/terminal/render-scheduler.ts +37 -0
  158. package/src/terminal/screen-presenter.ts +188 -0
  159. package/src/terminal/session.ts +407 -0
  160. package/src/terminal-size.ts +9 -8
  161. package/src/terminal.ts +1 -0
  162. package/src/testing/browser.ts +588 -0
  163. package/src/testing/emulators.ts +205 -0
  164. package/src/testing/explorer-app/index.html +12 -0
  165. package/src/testing/explorer-app/main.ts +381 -0
  166. package/src/testing/explorer-app/style.css +194 -0
  167. package/src/testing/explorer-app/tsconfig.json +15 -0
  168. package/src/testing/explorer-app/vite-env.d.ts +1 -0
  169. package/src/testing/index.ts +26 -0
  170. package/src/testing/keys.ts +56 -0
  171. package/src/testing/live.ts +85 -0
  172. package/src/testing/matchers.ts +70 -0
  173. package/src/testing/public.ts +94 -0
  174. package/src/testing/terminal.ts +349 -0
  175. package/src/testing/vitest.ts +157 -0
  176. package/src/transform-adapter.ts +14 -0
  177. package/src/types.ts +1 -6
  178. package/src/utils.ts +2 -2
  179. package/src/wrap-text.ts +4 -4
  180. package/src/yoga/config.ts +2 -2
  181. package/src/yoga/core/absoluteLayout.ts +15 -15
  182. package/src/yoga/core/baseline.ts +3 -3
  183. package/src/yoga/core/cache.ts +4 -4
  184. package/src/yoga/core/calculateLayout.ts +33 -27
  185. package/src/yoga/core/config.ts +1 -1
  186. package/src/yoga/core/flexLine.ts +3 -3
  187. package/src/yoga/core/helpers.ts +3 -3
  188. package/src/yoga/core/layoutResults.ts +4 -4
  189. package/src/yoga/core/node.ts +16 -16
  190. package/src/yoga/core/pixelGrid.ts +4 -4
  191. package/src/yoga/core/style.ts +11 -11
  192. package/src/yoga/core/types.ts +2 -2
  193. package/src/yoga/index.ts +6 -6
  194. package/src/yoga/node.ts +8 -8
  195. package/dist/sgr-CMfEpjSk.d.ts +0 -91
  196. package/dist/truncate-CBiyyZzw.js +0 -2156
  197. package/src/ansi/supports-color.ts +0 -213
  198. package/src/ansi/widest-line.ts +0 -12
  199. package/src/auto-bind.ts +0 -41
  200. package/src/colorize.ts +0 -60
  201. package/src/devtools-window-polyfill.ts +0 -73
  202. package/src/indent-string.ts +0 -16
  203. package/src/is-in-ci.ts +0 -7
  204. package/src/log-update.ts +0 -370
  205. package/src/output.ts +0 -308
  206. package/src/renderer.ts +0 -73
  207. package/src/write-synchronized.ts +0 -9
@@ -0,0 +1,324 @@
1
+ import { d as tokenize, l as styledCharsFromTokens } from "./tokenize-AjqbvtiT.js";
2
+ import { t as stringWidth } from "./string-width-CijQwpIk.js";
3
+ import { i as emptyCell, r as createCell, t as cellAttributes } from "./cell-_ZVhbfl0.js";
4
+ import { t as blend } from "./sample-Cqw1bjUL.js";
5
+ import "./color-profile-DHhQHY55.js";
6
+ import "./serialize-BTkAZgw1.js";
7
+ //#region src/screen/ansi.ts
8
+ const ESC = "\x1B";
9
+ const BEL = "\x07";
10
+ const C1_ST = "œ";
11
+ const LINK_PREFIX = `${ESC}]8;`;
12
+ /** Converts the renderer's canonical ANSI state into backend-neutral cells. */
13
+ function cellsFromAnsi(text) {
14
+ return styledCharsFromTokens(tokenize(text)).map((character) => cellFromStyledChar(character));
15
+ }
16
+ function cellFromStyledChar(character, width = stringWidth(character.value)) {
17
+ const parsed = parseStyles(character.styles);
18
+ const style = {
19
+ ...parsed.foreground ? { foreground: parsed.foreground } : {},
20
+ ...parsed.background ? { background: parsed.background } : {},
21
+ ...parsed.underlineColor ? { underlineColor: parsed.underlineColor } : {},
22
+ underline: parsed.underline,
23
+ attributes: parsed.attributes
24
+ };
25
+ return createCell(character.value, Math.max(1, width), style, parsed.hyperlink);
26
+ }
27
+ function parseStyles(codes) {
28
+ let foreground;
29
+ let background;
30
+ let underlineColor;
31
+ let underline = "none";
32
+ let attributes = cellAttributes.none;
33
+ let hyperlink;
34
+ for (const { code } of codes) {
35
+ if (code.startsWith(LINK_PREFIX)) {
36
+ hyperlink = parseHyperlink(code);
37
+ continue;
38
+ }
39
+ if (!code.startsWith(`${ESC}[`) || !code.endsWith("m")) continue;
40
+ const parameters = code.slice(2, -1);
41
+ const primary = Number.parseInt(parameters, 10);
42
+ if (primary >= 30 && primary <= 37) foreground = {
43
+ model: "indexed",
44
+ index: primary - 30,
45
+ encoding: "ansi16"
46
+ };
47
+ else if (primary >= 90 && primary <= 97) foreground = {
48
+ model: "indexed",
49
+ index: primary - 90 + 8,
50
+ encoding: "ansi16"
51
+ };
52
+ else if (primary >= 40 && primary <= 47) background = {
53
+ model: "indexed",
54
+ index: primary - 40,
55
+ encoding: "ansi16"
56
+ };
57
+ else if (primary >= 100 && primary <= 107) background = {
58
+ model: "indexed",
59
+ index: primary - 100 + 8,
60
+ encoding: "ansi16"
61
+ };
62
+ else if (primary === 38) foreground = parseExtendedColor(parameters);
63
+ else if (primary === 48) background = parseExtendedColor(parameters);
64
+ else if (primary === 58) underlineColor = parseExtendedColor(parameters);
65
+ else if (primary === 1) attributes += cellAttributes.bold;
66
+ else if (primary === 2) attributes += cellAttributes.faint;
67
+ else if (primary === 3) attributes += cellAttributes.italic;
68
+ else if (primary === 5) attributes += cellAttributes.blink;
69
+ else if (primary === 6) attributes += cellAttributes.rapidBlink;
70
+ else if (primary === 7) attributes += cellAttributes.inverse;
71
+ else if (primary === 8) attributes += cellAttributes.hidden;
72
+ else if (primary === 9) attributes += cellAttributes.strikethrough;
73
+ else if (primary === 4) underline = parseUnderline(parameters);
74
+ }
75
+ return {
76
+ ...foreground ? { foreground } : {},
77
+ ...background ? { background } : {},
78
+ ...underlineColor ? { underlineColor } : {},
79
+ underline,
80
+ attributes,
81
+ ...hyperlink ? { hyperlink } : {}
82
+ };
83
+ }
84
+ function parseExtendedColor(parameters) {
85
+ const parts = parameters.split(parameters.includes(":") ? ":" : ";");
86
+ const model = parts[1];
87
+ if (model === "5") {
88
+ const index = Number(parts[2]);
89
+ return Number.isInteger(index) && index >= 0 && index <= 255 ? {
90
+ model: "indexed",
91
+ index,
92
+ encoding: "ansi256"
93
+ } : void 0;
94
+ }
95
+ if (model !== "2") return;
96
+ const channels = parts.slice(-3).map(Number);
97
+ if (channels.length !== 3 || channels.some((channel) => !isByte(channel))) return;
98
+ return {
99
+ model: "rgb",
100
+ red: channels[0],
101
+ green: channels[1],
102
+ blue: channels[2],
103
+ alpha: 255
104
+ };
105
+ }
106
+ function parseUnderline(parameters) {
107
+ return {
108
+ 0: "none",
109
+ 1: "single",
110
+ 2: "double",
111
+ 3: "curly",
112
+ 4: "dotted",
113
+ 5: "dashed"
114
+ }[parameters.includes(":") ? Number(parameters.split(":").at(-1)) : 1] ?? "single";
115
+ }
116
+ function parseHyperlink(code) {
117
+ let body = code.slice(LINK_PREFIX.length);
118
+ if (body.endsWith(`${ESC}\\`)) body = body.slice(0, -2);
119
+ else if (body.endsWith(BEL) || body.endsWith(C1_ST)) body = body.slice(0, -1);
120
+ const separator = body.indexOf(";");
121
+ if (separator < 0) return;
122
+ const parameters = body.slice(0, separator);
123
+ const url = body.slice(separator + 1);
124
+ return parameters ? {
125
+ url,
126
+ parameters
127
+ } : { url };
128
+ }
129
+ function isByte(value) {
130
+ return Number.isInteger(value) && value >= 0 && value <= 255;
131
+ }
132
+ //#endregion
133
+ //#region src/screen/screen.ts
134
+ /**
135
+ A mutable two-dimensional terminal cell buffer. Cells themselves are immutable,
136
+ so current and next screens can compare them by value or safely share constants.
137
+ */
138
+ var Screen = class {
139
+ #width;
140
+ #height;
141
+ #rows;
142
+ #painted;
143
+ #dirty;
144
+ constructor(width, height) {
145
+ validateDimensions(width, height);
146
+ this.#width = width;
147
+ this.#height = height;
148
+ this.#rows = Array.from({ length: height }, () => Array(width).fill(emptyCell));
149
+ this.#painted = Array.from({ length: height }, () => Array(width).fill(false));
150
+ this.#dirty = Array.from({ length: height }, () => width > 0 ? {
151
+ start: 0,
152
+ end: width
153
+ } : void 0);
154
+ }
155
+ get width() {
156
+ return this.#width;
157
+ }
158
+ get height() {
159
+ return this.#height;
160
+ }
161
+ bounds() {
162
+ return {
163
+ x: 0,
164
+ y: 0,
165
+ width: this.width,
166
+ height: this.height
167
+ };
168
+ }
169
+ cellAt(x, y) {
170
+ return this.#rows[y]?.[x];
171
+ }
172
+ /** Whether a drawable explicitly touched this position. */
173
+ isPainted(x, y) {
174
+ return this.#painted[y]?.[x] ?? false;
175
+ }
176
+ setCell(x, y, cell) {
177
+ const row = this.#rows[y];
178
+ if (!row || x < 0 || x >= this.width) return;
179
+ if (!Number.isInteger(cell.width) || cell.width < 1) throw new Error("Only leading cells with a positive width may be written");
180
+ const finalColumn = x + cell.width;
181
+ const clipped = finalColumn > this.width;
182
+ const overwriteEnd = Math.min(finalColumn, this.width);
183
+ for (let column = x; column < overwriteEnd; column++) this.#clearGraphemeAt(row, y, column);
184
+ if (clipped) {
185
+ for (let column = x; column < this.width; column++) row[column] = emptyCell;
186
+ this.#markDirty(y, x, this.width);
187
+ return;
188
+ }
189
+ row[x] = cell;
190
+ this.#painted[y][x] = true;
191
+ for (let column = x + 1; column < finalColumn; column++) {
192
+ row[column] = {
193
+ grapheme: "",
194
+ width: 0,
195
+ style: cell.style,
196
+ ...cell.hyperlink ? { hyperlink: cell.hyperlink } : {}
197
+ };
198
+ this.#painted[y][column] = true;
199
+ }
200
+ this.#markDirty(y, x, finalColumn);
201
+ }
202
+ /**
203
+ Composes independent cell channels over the existing cell. An undefined
204
+ patch is transparent; an explicit space in `content` paints a blank.
205
+ */
206
+ composeCell(x, y, patch) {
207
+ if (!patch) return;
208
+ const row = this.#rows[y];
209
+ if (!row || x < 0 || x >= this.width) return;
210
+ let leadingColumn = x;
211
+ while (leadingColumn > 0 && row[leadingColumn]?.width === 0) leadingColumn--;
212
+ const destination = row[leadingColumn] ?? emptyCell;
213
+ const writeColumn = patch.content ? x : leadingColumn;
214
+ const style = {
215
+ ...this.#composeColor(destination.style, patch, "foreground"),
216
+ ...this.#composeColor(destination.style, patch, "background"),
217
+ ...this.#composeColor(destination.style, patch, "underlineColor"),
218
+ underline: patch.underline ?? destination.style.underline,
219
+ attributes: patch.attributes ?? destination.style.attributes
220
+ };
221
+ const content = patch.content ?? destination;
222
+ const hyperlink = patch.hyperlink === void 0 ? destination.hyperlink : patch.hyperlink ?? void 0;
223
+ this.setCell(writeColumn, y, createCell(content.grapheme, content.width, style, hyperlink));
224
+ }
225
+ /** Composes a patch throughout a rectangle, clipped to this screen. */
226
+ fill(bounds, patch) {
227
+ if (!patch) return;
228
+ const startX = Math.max(0, bounds.x);
229
+ const startY = Math.max(0, bounds.y);
230
+ const endX = Math.min(this.width, bounds.x + bounds.width);
231
+ const endY = Math.min(this.height, bounds.y + bounds.height);
232
+ const step = Math.max(1, patch.content?.width ?? 1);
233
+ for (let y = startY; y < endY; y++) for (let x = startX; x < endX; x += step) this.composeCell(x, y, patch);
234
+ }
235
+ /** Resizes while preserving complete graphemes in the shared top-left area. */
236
+ resize(width, height) {
237
+ validateDimensions(width, height);
238
+ const rows = Array.from({ length: height }, () => Array(width).fill(emptyCell));
239
+ const painted = Array.from({ length: height }, () => Array(width).fill(false));
240
+ const sharedHeight = Math.min(height, this.height);
241
+ for (let y = 0; y < sharedHeight; y++) {
242
+ const source = this.#rows[y];
243
+ const destination = rows[y];
244
+ for (let x = 0; x < Math.min(width, this.width); x++) {
245
+ const cell = source[x];
246
+ if (cell.width === 0 || x + cell.width > width) continue;
247
+ destination[x] = cell;
248
+ painted[y][x] = this.#painted[y][x];
249
+ for (let column = x + 1; column < x + cell.width; column++) {
250
+ destination[column] = source[column];
251
+ painted[y][column] = this.#painted[y][column];
252
+ }
253
+ }
254
+ }
255
+ this.#width = width;
256
+ this.#height = height;
257
+ this.#rows = rows;
258
+ this.#painted = painted;
259
+ this.#dirty = Array.from({ length: height }, () => width > 0 ? {
260
+ start: 0,
261
+ end: width
262
+ } : void 0);
263
+ }
264
+ clear() {
265
+ for (const [y, row] of this.#rows.entries()) {
266
+ row.fill(emptyCell);
267
+ this.#painted[y].fill(true);
268
+ this.#markDirty(y, 0, this.width);
269
+ }
270
+ }
271
+ toRows() {
272
+ return this.#rows;
273
+ }
274
+ dirtySpans() {
275
+ return this.#dirty.flatMap((span, y) => span ? [{
276
+ y,
277
+ ...span
278
+ }] : []);
279
+ }
280
+ takeDirtySpans() {
281
+ const spans = this.dirtySpans();
282
+ this.#dirty.fill(void 0);
283
+ return spans;
284
+ }
285
+ #clearGraphemeAt(row, y, x) {
286
+ const existing = row[x];
287
+ if (!existing || existing === emptyCell) return;
288
+ let leadingColumn = x;
289
+ while (leadingColumn > 0 && row[leadingColumn]?.width === 0) leadingColumn--;
290
+ const leadingCell = row[leadingColumn];
291
+ const width = Math.max(1, leadingCell?.width ?? 1);
292
+ for (let column = leadingColumn; column < Math.min(leadingColumn + width, this.width); column++) {
293
+ row[column] = emptyCell;
294
+ this.#painted[y][column] = true;
295
+ }
296
+ this.#markDirty(y, leadingColumn, leadingColumn + width);
297
+ }
298
+ #composeColor(destination, patch, channel) {
299
+ const value = patch[channel];
300
+ if (value === void 0) return destination[channel] ? { [channel]: destination[channel] } : {};
301
+ if (value === null) return {};
302
+ const destinationColor = destination[channel];
303
+ if (value.model === "rgb" && value.alpha < 255 && destinationColor) return { [channel]: blend(value, destinationColor) };
304
+ return { [channel]: value };
305
+ }
306
+ #markDirty(y, start, end) {
307
+ if (y < 0 || y >= this.height || start >= end) return;
308
+ const clippedStart = Math.max(0, start);
309
+ const clippedEnd = Math.min(this.width, end);
310
+ const current = this.#dirty[y];
311
+ this.#dirty[y] = current ? {
312
+ start: Math.min(current.start, clippedStart),
313
+ end: Math.max(current.end, clippedEnd)
314
+ } : {
315
+ start: clippedStart,
316
+ end: clippedEnd
317
+ };
318
+ }
319
+ };
320
+ function validateDimensions(width, height) {
321
+ if (!Number.isInteger(width) || width < 0 || !Number.isInteger(height) || height < 0) throw new Error("Screen dimensions must be non-negative integers");
322
+ }
323
+ //#endregion
324
+ export { cellFromStyledChar as n, cellsFromAnsi as r, Screen as t };
@@ -0,0 +1,40 @@
1
+ import { i as Cell, o as CellPatch } from "./color-profile-u0Nhe9Nv.js";
2
+ import { n as Rect } from "./geometry-BxXOzJgo.js";
3
+ //#region src/screen/screen.d.ts
4
+ type Line = readonly Cell[];
5
+ /** A half-open range of changed columns in one row. */
6
+ type DirtySpan = {
7
+ readonly y: number;
8
+ readonly start: number;
9
+ readonly end: number;
10
+ };
11
+ /**
12
+ A mutable two-dimensional terminal cell buffer. Cells themselves are immutable,
13
+ so current and next screens can compare them by value or safely share constants.
14
+ */
15
+ declare class Screen {
16
+ #private;
17
+ constructor(width: number, height: number);
18
+ get width(): number;
19
+ get height(): number;
20
+ bounds(): Rect;
21
+ cellAt(x: number, y: number): Cell | undefined;
22
+ /** Whether a drawable explicitly touched this position. */
23
+ isPainted(x: number, y: number): boolean;
24
+ setCell(x: number, y: number, cell: Cell): void;
25
+ /**
26
+ Composes independent cell channels over the existing cell. An undefined
27
+ patch is transparent; an explicit space in `content` paints a blank.
28
+ */
29
+ composeCell(x: number, y: number, patch: CellPatch | undefined): void;
30
+ /** Composes a patch throughout a rectangle, clipped to this screen. */
31
+ fill(bounds: Rect, patch: CellPatch | undefined): void;
32
+ /** Resizes while preserving complete graphemes in the shared top-left area. */
33
+ resize(width: number, height: number): void;
34
+ clear(): void;
35
+ toRows(): readonly Line[];
36
+ dirtySpans(): readonly DirtySpan[];
37
+ takeDirtySpans(): readonly DirtySpan[];
38
+ }
39
+ //#endregion
40
+ export { Screen as n, Line as t };
@@ -0,0 +1,5 @@
1
+ import { _ as emptyCellStyle, a as CellContent, c as Color, d as RgbColor, f as UnderlineStyle, g as emptyCell, h as createCell, i as Cell, l as Hyperlink, m as cellsEqual, n as colorProfileFromLevel, o as CellPatch, p as cellAttributes, r as quantizeColor, s as CellStyle, t as ColorProfile, u as IndexedColor } from "./color-profile-u0Nhe9Nv.js";
2
+ import { n as Rect, t as Point } from "./geometry-BxXOzJgo.js";
3
+ import { a as cellFromStyledChar, i as styledCharFromCell, n as serializeLine, o as cellsFromAnsi, r as serializeScreen, t as SerializeOptions } from "./index-Bmc2tRPk.js";
4
+ import { n as Screen, t as Line } from "./screen-BReKIheE.js";
5
+ export { Cell, CellContent, CellPatch, CellStyle, Color, ColorProfile, Hyperlink, IndexedColor, type Line, Point, Rect, RgbColor, Screen, SerializeOptions, UnderlineStyle, cellAttributes, cellFromStyledChar, cellsEqual, cellsFromAnsi, colorProfileFromLevel, createCell, emptyCell, emptyCellStyle, quantizeColor, serializeLine, serializeScreen, styledCharFromCell };
package/dist/screen.js ADDED
@@ -0,0 +1,5 @@
1
+ import { a as emptyCellStyle, i as emptyCell, n as cellsEqual, r as createCell, t as cellAttributes } from "./cell-_ZVhbfl0.js";
2
+ import { n as cellFromStyledChar, r as cellsFromAnsi, t as Screen } from "./screen-BOh__-65.js";
3
+ import { n as quantizeColor, t as colorProfileFromLevel } from "./color-profile-DHhQHY55.js";
4
+ import { n as serializeScreen, r as styledCharFromCell, t as serializeLine } from "./serialize-BTkAZgw1.js";
5
+ export { Screen, cellAttributes, cellFromStyledChar, cellsEqual, cellsFromAnsi, colorProfileFromLevel, createCell, emptyCell, emptyCellStyle, quantizeColor, serializeLine, serializeScreen, styledCharFromCell };
@@ -0,0 +1,91 @@
1
+ import { l as hexToRgb } from "./sgr-BhwaWAJB.js";
2
+ import { t as cellAttributes } from "./cell-_ZVhbfl0.js";
3
+ //#region src/semantic-text-style.ts
4
+ const emptySemanticTextStyle = { attributes: cellAttributes.none };
5
+ const namedColors = {
6
+ black: 0,
7
+ red: 1,
8
+ green: 2,
9
+ yellow: 3,
10
+ blue: 4,
11
+ magenta: 5,
12
+ cyan: 6,
13
+ white: 7,
14
+ blackBright: 8,
15
+ gray: 8,
16
+ grey: 8,
17
+ redBright: 9,
18
+ greenBright: 10,
19
+ yellowBright: 11,
20
+ blueBright: 12,
21
+ magentaBright: 13,
22
+ cyanBright: 14,
23
+ whiteBright: 15
24
+ };
25
+ const rgbPattern = /^rgb\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)$/;
26
+ const ansi256Pattern = /^ansi256\(\s?(\d+)\s?\)$/;
27
+ function parseSemanticColor(value) {
28
+ if (!value) return;
29
+ if (typeof value !== "string") return value;
30
+ const named = namedColors[value];
31
+ if (named !== void 0) return {
32
+ model: "indexed",
33
+ index: named,
34
+ encoding: "ansi16"
35
+ };
36
+ if (value.startsWith("#")) {
37
+ const [red, green, blue] = hexToRgb(value);
38
+ return {
39
+ model: "rgb",
40
+ red,
41
+ green,
42
+ blue,
43
+ alpha: 255
44
+ };
45
+ }
46
+ const rgb = rgbPattern.exec(value);
47
+ if (rgb) return {
48
+ model: "rgb",
49
+ red: Number(rgb[1]),
50
+ green: Number(rgb[2]),
51
+ blue: Number(rgb[3]),
52
+ alpha: 255
53
+ };
54
+ const ansi256 = ansi256Pattern.exec(value);
55
+ if (ansi256) return {
56
+ model: "indexed",
57
+ index: Number(ansi256[1]),
58
+ encoding: "ansi256"
59
+ };
60
+ }
61
+ function mergeSemanticTextStyles(parent, child) {
62
+ if (!child) return parent;
63
+ const attributes = parent.attributes | child.attributes;
64
+ const foreground = child.resetForeground ? void 0 : child.foreground ?? parent.foreground;
65
+ const background = child.resetBackground ? void 0 : child.background ?? parent.background;
66
+ return {
67
+ ...foreground ? { foreground } : {},
68
+ ...background ? { background } : {},
69
+ ...child.resetForeground ? { resetForeground: true } : {},
70
+ ...child.resetBackground ? { resetBackground: true } : {},
71
+ ...child.underline ?? parent.underline ? { underline: child.underline ?? parent.underline } : {},
72
+ attributes
73
+ };
74
+ }
75
+ function semanticTextStyleToCellStyle(style) {
76
+ const foreground = solidColor(style.foreground);
77
+ const background = solidColor(style.background);
78
+ return {
79
+ ...foreground ? { foreground } : {},
80
+ ...background ? { background } : {},
81
+ underline: style.underline ?? "none",
82
+ attributes: style.attributes
83
+ };
84
+ }
85
+ function solidColor(paint) {
86
+ if (!paint) return void 0;
87
+ if (typeof paint === "string") return parseSemanticColor(paint);
88
+ return "model" in paint ? paint : void 0;
89
+ }
90
+ //#endregion
91
+ export { semanticTextStyleToCellStyle as i, mergeSemanticTextStyles as n, parseSemanticColor as r, emptySemanticTextStyle as t };
@@ -0,0 +1,79 @@
1
+ import { i as getEndCode, u as styledCharsToString } from "./tokenize-AjqbvtiT.js";
2
+ import { t as cellAttributes } from "./cell-_ZVhbfl0.js";
3
+ import { n as quantizeColor } from "./color-profile-DHhQHY55.js";
4
+ //#region src/screen/serialize.ts
5
+ const ESC = "\x1B";
6
+ const BEL = "\x07";
7
+ /** Serializes one structured cell run with minimal style transitions. */
8
+ function serializeLine(line, options) {
9
+ const characters = line.map((cell) => styledCharFromCell(cell, options.colorProfile, options.styles ?? true));
10
+ const output = styledCharsToString(characters);
11
+ return options.trimEnd === false ? output : output.trimEnd();
12
+ }
13
+ function serializeScreen(screen, options) {
14
+ return screen.toRows().map((line) => serializeLine(line, options)).join("\n");
15
+ }
16
+ /** Converts a semantic cell to the canonical ANSI compatibility style state. */
17
+ function styledCharFromCell(cell, profile, styles = true) {
18
+ return {
19
+ type: "char",
20
+ value: cell.grapheme,
21
+ fullWidth: cell.width > 1,
22
+ styles: styles ? ansiCodesFromCell(cell, profile) : []
23
+ };
24
+ }
25
+ function ansiCodesFromCell(cell, profile) {
26
+ const result = [];
27
+ const { style } = cell;
28
+ if (cell.hyperlink) result.push(codePair(hyperlinkStart(cell.hyperlink)));
29
+ addAttribute(result, style.attributes, cellAttributes.inverse, 7);
30
+ addAttribute(result, style.attributes, cellAttributes.hidden, 8);
31
+ addAttribute(result, style.attributes, cellAttributes.strikethrough, 9);
32
+ if (style.underline !== "none") {
33
+ const variant = {
34
+ single: "4",
35
+ double: "4:2",
36
+ curly: "4:3",
37
+ dotted: "4:4",
38
+ dashed: "4:5"
39
+ }[style.underline];
40
+ result.push(codePair(`${ESC}[${variant}m`));
41
+ }
42
+ addAttribute(result, style.attributes, cellAttributes.italic, 3);
43
+ addAttribute(result, style.attributes, cellAttributes.bold, 1);
44
+ addAttribute(result, style.attributes, cellAttributes.rapidBlink, 6);
45
+ addAttribute(result, style.attributes, cellAttributes.blink, 5);
46
+ const background = quantizeColor(style.background, profile);
47
+ if (background) result.push(codePair(colorCode(background, "background")));
48
+ const foreground = quantizeColor(style.foreground, profile);
49
+ if (foreground) result.push(codePair(colorCode(foreground, "foreground")));
50
+ addAttribute(result, style.attributes, cellAttributes.faint, 2);
51
+ const underlineColor = quantizeColor(style.underlineColor, profile);
52
+ if (underlineColor) result.push(codePair(colorCode(underlineColor, "underline")));
53
+ return result;
54
+ }
55
+ function addAttribute(result, attributes, attribute, sgr) {
56
+ if (Math.floor(attributes / attribute) % 2 === 1) result.push(codePair(`${ESC}[${sgr}m`));
57
+ }
58
+ function colorCode(color, channel) {
59
+ const prefix = {
60
+ foreground: 38,
61
+ background: 48,
62
+ underline: 58
63
+ }[channel];
64
+ if (color.model === "rgb") return `${ESC}[${prefix};2;${color.red};${color.green};${color.blue}m`;
65
+ if (channel === "underline" || color.index >= 16 || color.encoding === "ansi256") return `${ESC}[${prefix};5;${color.index}m`;
66
+ const basic = color.index < 8 ? color.index : color.index - 8 + 60;
67
+ return `${ESC}[${(channel === "background" ? 40 : 30) + basic}m`;
68
+ }
69
+ function hyperlinkStart(hyperlink) {
70
+ return `${ESC}]8;${hyperlink.parameters ?? ""};${hyperlink.url}${BEL}`;
71
+ }
72
+ function codePair(code) {
73
+ return {
74
+ code,
75
+ endCode: getEndCode(code)
76
+ };
77
+ }
78
+ //#endregion
79
+ export { serializeScreen as n, styledCharFromCell as r, serializeLine as t };