@alchemy.run/sigil 0.0.0-alpha.1 → 0.0.0-alpha.11

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 (223) hide show
  1. package/README.md +499 -313
  2. package/THIRD_PARTY_NOTICES.md +98 -23
  3. package/dist/Text-DV9CuzAT.d.ts +452 -0
  4. package/dist/ansi.d.ts +217 -0
  5. package/dist/ansi.js +87 -0
  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-BAC9-TZX.js +592 -0
  11. package/dist/color-policy-CCxuHIdD.d.ts +22 -0
  12. package/dist/color-profile-CyeHnG1T.d.ts +97 -0
  13. package/dist/color-profile-DHhQHY55.js +36 -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-B3dL4Q11.js +374 -0
  18. package/dist/detect-Db6GbKOm.d.ts +195 -0
  19. package/dist/{devtools-QpCMm9JH.mjs → devtools-DbthxoD1.js} +23 -24
  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-D48vQhhe.d.ts +21 -0
  24. package/dist/index-DDVME65c.d.ts +919 -0
  25. package/dist/index.d.ts +1310 -0
  26. package/dist/index.js +3211 -0
  27. package/dist/jsx-dev-runtime.d.ts +2 -0
  28. package/dist/jsx-dev-runtime.js +227 -0
  29. package/dist/jsx-runtime-XtwIVFsg.js +255 -0
  30. package/dist/jsx-runtime.d.ts +2 -0
  31. package/dist/jsx-runtime.js +8 -0
  32. package/dist/osc-BFKKSqpg.js +71 -0
  33. package/dist/osc-Cn0fw77g.d.ts +23 -0
  34. package/dist/paint-Cx-zC_sX.d.ts +81 -0
  35. package/dist/query-BNc2B8GD.d.ts +152 -0
  36. package/dist/react-CTZ_8dwh.js +1197 -0
  37. package/dist/react.d.ts +2 -0
  38. package/dist/react.js +49 -0
  39. package/dist/router.d.ts +392 -0
  40. package/dist/router.js +711 -0
  41. package/dist/sample-Cqw1bjUL.js +445 -0
  42. package/dist/screen-CgC2WlVM.d.ts +49 -0
  43. package/dist/screen-CiPytswf.js +342 -0
  44. package/dist/screen.d.ts +5 -0
  45. package/dist/screen.js +5 -0
  46. package/dist/semantic-text-style-DIMzC7xt.js +91 -0
  47. package/dist/serialize-BTkAZgw1.js +79 -0
  48. package/dist/session-DDQ5V300.js +723 -0
  49. package/dist/sgr-BhwaWAJB.js +246 -0
  50. package/dist/store-C1P5fOUi.d.ts +72 -0
  51. package/dist/string-width-CijQwpIk.js +69 -0
  52. package/dist/strip-BvU4toXG.js +6 -0
  53. package/dist/terminal.d.ts +121 -0
  54. package/dist/terminal.js +2 -0
  55. package/dist/tokenize-AjqbvtiT.js +1242 -0
  56. package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
  57. package/dist/truncate-D31fhU6i.js +562 -0
  58. package/dist/use-focus-B5npZrJU.js +18736 -0
  59. package/dist/yoga-5jKhYCJC.js +3465 -0
  60. package/dist/yoga.d.ts +2 -0
  61. package/dist/yoga.js +2 -0
  62. package/package.json +89 -29
  63. package/src/ansi/chalk.ts +138 -0
  64. package/src/ansi/cursor.ts +46 -0
  65. package/src/ansi/east-asian-width.ts +259 -0
  66. package/src/ansi/escapes.ts +120 -0
  67. package/src/ansi/graphemes.ts +8 -0
  68. package/src/ansi/hyperlink.ts +44 -0
  69. package/src/ansi/index.ts +27 -0
  70. package/src/ansi/osc.ts +77 -0
  71. package/src/ansi/sgr.ts +234 -0
  72. package/src/ansi/slice.ts +43 -0
  73. package/src/ansi/string-width.ts +121 -0
  74. package/src/ansi/strip.ts +13 -0
  75. package/src/ansi/tokenize.ts +380 -0
  76. package/src/ansi/truncate.ts +196 -0
  77. package/src/ansi/wrap.ts +765 -0
  78. package/src/ansi-tokenizer.ts +510 -0
  79. package/src/capabilities/color-policy.ts +34 -0
  80. package/src/capabilities/detect.ts +608 -0
  81. package/src/capabilities/index.ts +37 -0
  82. package/src/capabilities/query.ts +679 -0
  83. package/src/capabilities/store.ts +394 -0
  84. package/src/code-excerpt.ts +39 -0
  85. package/src/color/index.ts +3 -0
  86. package/src/color/paint.ts +169 -0
  87. package/src/color/palette.ts +48 -0
  88. package/src/color/sample.ts +323 -0
  89. package/src/color.ts +1 -0
  90. package/src/components/AccessibilityContext.ts +5 -0
  91. package/src/components/AnimationContext.ts +24 -0
  92. package/src/components/AnsiText.tsx +42 -0
  93. package/src/components/App.tsx +878 -0
  94. package/src/components/AppContext.ts +111 -0
  95. package/src/components/BackgroundContext.ts +7 -0
  96. package/src/components/Box.tsx +100 -0
  97. package/src/components/CursorContext.ts +19 -0
  98. package/src/components/ErrorBoundary.tsx +39 -0
  99. package/src/components/ErrorOverview.tsx +135 -0
  100. package/src/components/FocusContext.ts +30 -0
  101. package/src/components/Hyperlink.tsx +56 -0
  102. package/src/components/Newline.tsx +16 -0
  103. package/src/components/Spacer.tsx +11 -0
  104. package/src/components/Static.tsx +60 -0
  105. package/src/components/StderrContext.ts +24 -0
  106. package/src/components/StdinContext.ts +48 -0
  107. package/src/components/StdoutContext.ts +26 -0
  108. package/src/components/TerminalOscContext.ts +25 -0
  109. package/src/components/Text.tsx +122 -0
  110. package/src/components/Transform.tsx +38 -0
  111. package/src/components/VirtualList.tsx +128 -0
  112. package/src/cursor-position.ts +103 -0
  113. package/src/devtools.ts +103 -0
  114. package/src/dom.ts +301 -0
  115. package/src/env.ts +12 -0
  116. package/src/get-max-width.ts +11 -0
  117. package/src/global.d.ts +38 -0
  118. package/src/glyphs.ts +99 -0
  119. package/src/hooks/use-animation.ts +142 -0
  120. package/src/hooks/use-app.ts +8 -0
  121. package/src/hooks/use-box-metrics.ts +134 -0
  122. package/src/hooks/use-capabilities.ts +73 -0
  123. package/src/hooks/use-cursor.ts +33 -0
  124. package/src/hooks/use-focus-manager.ts +62 -0
  125. package/src/hooks/use-focus.ts +82 -0
  126. package/src/hooks/use-input.ts +267 -0
  127. package/src/hooks/use-is-screen-reader-enabled.ts +12 -0
  128. package/src/hooks/use-paste.ts +78 -0
  129. package/src/hooks/use-stderr.ts +8 -0
  130. package/src/hooks/use-stdin.ts +10 -0
  131. package/src/hooks/use-stdout.ts +8 -0
  132. package/src/hooks/use-terminal-osc.ts +59 -0
  133. package/src/hooks/use-virtual-scroll.ts +84 -0
  134. package/src/hooks/use-window-size.ts +37 -0
  135. package/src/index.ts +96 -0
  136. package/src/ink.tsx +1452 -0
  137. package/src/input-parser.ts +303 -0
  138. package/src/instances.ts +9 -0
  139. package/src/jsx-dev-runtime.ts +3 -0
  140. package/src/jsx-runtime.ts +6 -0
  141. package/src/kitty-keyboard.ts +185 -0
  142. package/src/measure-element.ts +62 -0
  143. package/src/measure-text.ts +31 -0
  144. package/src/paint-tree.ts +220 -0
  145. package/src/parse-keypress.ts +515 -0
  146. package/src/parse-stack-line.ts +138 -0
  147. package/src/patch-console.ts +106 -0
  148. package/src/quick-lru.ts +85 -0
  149. package/src/react.ts +53 -0
  150. package/src/reconciler.ts +476 -0
  151. package/src/render-background.ts +59 -0
  152. package/src/render-border.ts +167 -0
  153. package/src/render-frame.ts +83 -0
  154. package/src/render-to-string.ts +146 -0
  155. package/src/render.ts +284 -0
  156. package/src/router/components.tsx +343 -0
  157. package/src/router/context.ts +41 -0
  158. package/src/router/history.ts +194 -0
  159. package/src/router/hooks.tsx +391 -0
  160. package/src/router/index.ts +34 -0
  161. package/src/router/matcher.ts +571 -0
  162. package/src/sanitize-ansi.ts +33 -0
  163. package/src/screen/ansi.ts +184 -0
  164. package/src/screen/canvas.ts +160 -0
  165. package/src/screen/cell.ts +138 -0
  166. package/src/screen/color-profile.ts +47 -0
  167. package/src/screen/geometry.ts +9 -0
  168. package/src/screen/index.ts +6 -0
  169. package/src/screen/screen.ts +305 -0
  170. package/src/screen/serialize.ts +129 -0
  171. package/src/screen.ts +1 -0
  172. package/src/semantic-text-style.ts +118 -0
  173. package/src/signal-exit.ts +106 -0
  174. package/src/squash-text-nodes.ts +37 -0
  175. package/src/stream.ts +28 -0
  176. package/src/structured-text.ts +325 -0
  177. package/src/styles.ts +753 -0
  178. package/src/terminal/index.ts +2 -0
  179. package/src/terminal/inline-presenter.ts +120 -0
  180. package/src/terminal/input.ts +92 -0
  181. package/src/terminal/render-scheduler.ts +37 -0
  182. package/src/terminal/screen-presenter.ts +242 -0
  183. package/src/terminal/session.ts +408 -0
  184. package/src/terminal-size.ts +58 -0
  185. package/src/terminal.ts +1 -0
  186. package/src/testing/browser.ts +588 -0
  187. package/src/testing/emulators.ts +205 -0
  188. package/src/testing/explorer-app/index.html +12 -0
  189. package/src/testing/explorer-app/main.ts +381 -0
  190. package/src/testing/explorer-app/style.css +194 -0
  191. package/src/testing/explorer-app/tsconfig.json +15 -0
  192. package/src/testing/explorer-app/vite-env.d.ts +1 -0
  193. package/src/testing/index.ts +26 -0
  194. package/src/testing/keys.ts +56 -0
  195. package/src/testing/live.ts +85 -0
  196. package/src/testing/matchers.ts +70 -0
  197. package/src/testing/public.ts +94 -0
  198. package/src/testing/terminal.ts +361 -0
  199. package/src/testing/vitest.ts +157 -0
  200. package/src/throttle.ts +73 -0
  201. package/src/transform-adapter.ts +14 -0
  202. package/src/types.ts +10 -0
  203. package/src/virtual-scroll.ts +133 -0
  204. package/src/wrap-text.ts +54 -0
  205. package/src/yoga/config.ts +57 -0
  206. package/src/yoga/core/absoluteLayout.ts +626 -0
  207. package/src/yoga/core/baseline.ts +66 -0
  208. package/src/yoga/core/cache.ts +136 -0
  209. package/src/yoga/core/calculateLayout.ts +2926 -0
  210. package/src/yoga/core/config.ts +104 -0
  211. package/src/yoga/core/flexLine.ts +177 -0
  212. package/src/yoga/core/helpers.ts +293 -0
  213. package/src/yoga/core/layoutResults.ts +167 -0
  214. package/src/yoga/core/node.ts +611 -0
  215. package/src/yoga/core/numeric.ts +44 -0
  216. package/src/yoga/core/pixelGrid.ts +151 -0
  217. package/src/yoga/core/style.ts +887 -0
  218. package/src/yoga/core/types.ts +224 -0
  219. package/src/yoga/generated/YGEnums.ts +263 -0
  220. package/src/yoga/index.ts +19 -0
  221. package/src/yoga/node.ts +1140 -0
  222. package/dist/index.d.mts +0 -2379
  223. package/dist/index.mjs +0 -10072
package/src/stream.ts ADDED
@@ -0,0 +1,28 @@
1
+ import { isTty } from "#/env.ts";
2
+
3
+ export type OutputStream = NodeJS.WritableStream & {
4
+ isTTY?: boolean;
5
+ columns?: number;
6
+ rows?: number;
7
+ destroyed?: boolean;
8
+ writableEnded?: boolean;
9
+ };
10
+
11
+ type RawModeStream = NodeJS.ReadableStream & {
12
+ isTTY: true;
13
+ setRawMode: (mode: boolean) => void;
14
+ ref?: () => void;
15
+ unref?: () => void;
16
+ };
17
+
18
+ const isRawModeStream = (stdin: NodeJS.ReadableStream): stdin is RawModeStream => {
19
+ return isTty(stdin) && "setRawMode" in stdin && typeof stdin.setRawMode === "function";
20
+ };
21
+
22
+ export const getRawModeStream = (stdin: NodeJS.ReadableStream): RawModeStream | undefined => {
23
+ if (!isRawModeStream(stdin)) {
24
+ return;
25
+ }
26
+
27
+ return stdin;
28
+ };
@@ -0,0 +1,325 @@
1
+ import { tokenizeAnsi } from "#/ansi-tokenizer.ts";
2
+ import { graphemes } from "#/ansi/graphemes.ts";
3
+ import { stringWidth } from "#/ansi/string-width.ts";
4
+ import { stripAnsi } from "#/ansi/strip.ts";
5
+ import { samplePaint, type PaintContext } from "#/color/index.ts";
6
+ import type { Paint } from "#/color/paint.ts";
7
+ import type { DOMElement, DOMNode } from "#/dom.ts";
8
+ import { cellsFromAnsi } from "#/screen/ansi.ts";
9
+ import { createCell, type Cell, type CellStyle } from "#/screen/cell.ts";
10
+ import type { Rect } from "#/screen/geometry.ts";
11
+ import {
12
+ emptySemanticTextStyle,
13
+ mergeSemanticTextStyles,
14
+ semanticTextStyleToCellStyle,
15
+ type SemanticTextStyle,
16
+ } from "#/semantic-text-style.ts";
17
+ import type { Styles } from "#/styles.ts";
18
+
19
+ type SemanticCell = Cell & {
20
+ readonly foregroundPaint?: Paint;
21
+ readonly backgroundPaint?: Paint;
22
+ };
23
+
24
+ /** Whether a text subtree must retain the ANSI compatibility pipeline. */
25
+ export function hasCompatibilityText(node: DOMElement): boolean {
26
+ if (node.internal_transform && !node.internal_textStyle) {
27
+ return true;
28
+ }
29
+
30
+ return node.childNodes.some((child) => child.nodeName !== "#text" && hasCompatibilityText(child));
31
+ }
32
+
33
+ /** Rasterizes an unwrapped native Text subtree into semantic cell lines. */
34
+ export function structuredTextLines(node: DOMElement): readonly (readonly SemanticCell[])[] {
35
+ const lines: SemanticCell[][] = [[]];
36
+ appendNode(node, emptySemanticTextStyle, lines, false);
37
+ return lines;
38
+ }
39
+
40
+ /** Samples semantic paints only after wrapping and final layout are known. */
41
+ export function sampleStructuredText(
42
+ lines: readonly (readonly SemanticCell[])[],
43
+ bounds: Rect,
44
+ context: PaintContext,
45
+ ): readonly (readonly Cell[])[] {
46
+ return lines.map((line, row) => {
47
+ let column = 0;
48
+ return line.map((cell) => {
49
+ const foreground = cell.foregroundPaint
50
+ ? samplePaint(cell.foregroundPaint, bounds.x + column, bounds.y + row, bounds, context)
51
+ : cell.style.foreground;
52
+ const background = cell.backgroundPaint
53
+ ? samplePaint(cell.backgroundPaint, bounds.x + column, bounds.y + row, bounds, context)
54
+ : cell.style.background;
55
+ column += cell.width;
56
+ return createCell(
57
+ cell.grapheme,
58
+ cell.width,
59
+ {
60
+ ...cell.style,
61
+ ...(foreground ? { foreground } : {}),
62
+ ...(background ? { background } : {}),
63
+ },
64
+ cell.hyperlink,
65
+ cell.reset,
66
+ );
67
+ });
68
+ });
69
+ }
70
+
71
+ export function structuredTextBaseStyle(node: DOMElement): CellStyle {
72
+ return semanticTextStyleToCellStyle(
73
+ mergeSemanticTextStyles(emptySemanticTextStyle, node.internal_textStyle),
74
+ );
75
+ }
76
+
77
+ /** Wraps or truncates semantic cells without converting them through ANSI. */
78
+ export function wrapStructuredText(
79
+ input: readonly (readonly Cell[])[],
80
+ maxWidth: number,
81
+ wrap: Styles["textWrap"],
82
+ baseStyle?: CellStyle,
83
+ ): readonly (readonly Cell[])[] {
84
+ if (wrap === "none") {
85
+ return input.map((line) => [...line]);
86
+ }
87
+
88
+ if (maxWidth < 1) {
89
+ return [[]];
90
+ }
91
+
92
+ return input.flatMap((line) => {
93
+ if (lineWidth(line) <= maxWidth) {
94
+ return [[...line]];
95
+ }
96
+
97
+ if (wrap === "hard") {
98
+ return hardWrap(line, maxWidth);
99
+ }
100
+
101
+ if (wrap === "wrap") {
102
+ return wordWrap(line, maxWidth);
103
+ }
104
+
105
+ return [truncate(line, maxWidth, wrap, baseStyle)];
106
+ });
107
+ }
108
+
109
+ function wordWrap(line: readonly Cell[], maxWidth: number): Cell[][] {
110
+ const words: Cell[][] = [[]];
111
+ const spaces: Cell[] = [];
112
+
113
+ for (const cell of line) {
114
+ if (cell.grapheme === " ") {
115
+ spaces.push(cell);
116
+ words.push([]);
117
+ } else {
118
+ words.at(-1)!.push(cell);
119
+ }
120
+ }
121
+
122
+ const output: Cell[][] = [[]];
123
+ appendHard(output, words[0]!, maxWidth);
124
+
125
+ for (let index = 1; index < words.length; index++) {
126
+ appendHard(output, [spaces[index - 1]!], maxWidth);
127
+ const word = words[index]!;
128
+ const current = output.at(-1)!;
129
+ const wordWidth = lineWidth(word);
130
+ const currentWidth = lineWidth(current);
131
+
132
+ if (wordWidth <= maxWidth && currentWidth + wordWidth > maxWidth) {
133
+ output.push([]);
134
+ } else if (wordWidth > maxWidth && currentWidth > 0) {
135
+ const remaining = maxWidth - currentWidth;
136
+ const breaksHere = 1 + Math.floor((wordWidth - remaining - 1) / maxWidth);
137
+ const breaksNext = Math.floor((wordWidth - 1) / maxWidth);
138
+ if (breaksNext < breaksHere) {
139
+ output.push([]);
140
+ }
141
+ }
142
+
143
+ appendHard(output, word, maxWidth);
144
+ }
145
+
146
+ return output;
147
+ }
148
+
149
+ function hardWrap(line: readonly Cell[], maxWidth: number): Cell[][] {
150
+ const output: Cell[][] = [[]];
151
+ appendHard(output, line, maxWidth);
152
+ return output;
153
+ }
154
+
155
+ function appendHard(output: Cell[][], cells: readonly Cell[], maxWidth: number): void {
156
+ for (const cell of cells) {
157
+ const current = output.at(-1)!;
158
+ if (current.length > 0 && lineWidth(current) + cell.width > maxWidth) {
159
+ output.push([]);
160
+ }
161
+
162
+ output.at(-1)!.push(cell);
163
+ }
164
+ }
165
+
166
+ function truncate(
167
+ line: readonly Cell[],
168
+ maxWidth: number,
169
+ wrap: Styles["textWrap"],
170
+ baseStyle: CellStyle | undefined,
171
+ ): Cell[] {
172
+ if (maxWidth === 1) {
173
+ return [ellipsis(baseStyle ?? cellStyleIntersection(line.at(0), line.at(-1)))];
174
+ }
175
+
176
+ if (wrap === "truncate-start") {
177
+ const right = sliceCells(line, lineWidth(line) - maxWidth + 1, lineWidth(line));
178
+ return [ellipsis(right[0]?.style), ...right];
179
+ }
180
+
181
+ if (wrap === "truncate-middle") {
182
+ const half = Math.min(Math.floor(maxWidth / 2), maxWidth - 1);
183
+ const left = sliceCells(line, 0, half);
184
+ const rightWidth = maxWidth - half - 1;
185
+ const right = sliceCells(line, lineWidth(line) - rightWidth, lineWidth(line));
186
+ return [
187
+ ...left,
188
+ ellipsis(baseStyle ?? cellStyleIntersection(left.at(-1), right.at(0))),
189
+ ...right,
190
+ ];
191
+ }
192
+
193
+ const left = sliceCells(line, 0, maxWidth - 1);
194
+ return [...left, ellipsis(left.at(-1)?.style)];
195
+ }
196
+
197
+ function sliceCells(line: readonly Cell[], start: number, end: number): Cell[] {
198
+ const output: Cell[] = [];
199
+ let column = 0;
200
+
201
+ for (const cell of line) {
202
+ const nextColumn = column + cell.width;
203
+ if (column >= start && nextColumn <= end) {
204
+ output.push(cell);
205
+ }
206
+
207
+ column = nextColumn;
208
+ }
209
+
210
+ return output;
211
+ }
212
+
213
+ function ellipsis(style = semanticTextStyleToCellStyle(emptySemanticTextStyle)): Cell {
214
+ return createCell("…", 1, style);
215
+ }
216
+
217
+ function cellStyleIntersection(left: Cell | undefined, right: Cell | undefined): Cell["style"] {
218
+ if (!left) {
219
+ return right?.style ?? semanticTextStyleToCellStyle(emptySemanticTextStyle);
220
+ }
221
+
222
+ if (!right) {
223
+ return left.style;
224
+ }
225
+
226
+ return {
227
+ ...(sameColor(left.style.foreground, right.style.foreground)
228
+ ? { foreground: left.style.foreground }
229
+ : {}),
230
+ ...(sameColor(left.style.background, right.style.background)
231
+ ? { background: left.style.background }
232
+ : {}),
233
+ ...(sameColor(left.style.underlineColor, right.style.underlineColor)
234
+ ? { underlineColor: left.style.underlineColor }
235
+ : {}),
236
+ underline: left.style.underline === right.style.underline ? left.style.underline : "none",
237
+ // eslint-disable-next-line no-bitwise
238
+ attributes: left.style.attributes & right.style.attributes,
239
+ };
240
+ }
241
+
242
+ function sameColor(left: Cell["style"]["foreground"], right: Cell["style"]["foreground"]): boolean {
243
+ return JSON.stringify(left) === JSON.stringify(right);
244
+ }
245
+
246
+ function lineWidth(line: readonly Cell[]): number {
247
+ return line.reduce((width, cell) => width + cell.width, 0);
248
+ }
249
+
250
+ function appendNode(
251
+ node: DOMNode,
252
+ inherited: SemanticTextStyle,
253
+ lines: SemanticCell[][],
254
+ ansi: boolean,
255
+ ): void {
256
+ if (node.nodeName === "#text") {
257
+ if (ansi) appendAnsiText(node.nodeValue, inherited, lines);
258
+ else appendText(node.nodeValue, inherited, lines);
259
+ return;
260
+ }
261
+
262
+ const style = mergeSemanticTextStyles(inherited, node.internal_textStyle);
263
+ for (const child of node.childNodes) {
264
+ appendNode(child, style, lines, ansi || node.internal_ansi === true);
265
+ }
266
+ }
267
+
268
+ function appendAnsiText(text: string, semantic: SemanticTextStyle, lines: SemanticCell[][]): void {
269
+ const base = semanticTextStyleToCellStyle(semantic);
270
+ for (const cell of cellsFromAnsi(text)) {
271
+ if (cell.grapheme === "\n" || cell.grapheme === "\r\n") {
272
+ lines.push([]);
273
+ continue;
274
+ }
275
+
276
+ const hasForeground = cell.style.foreground !== undefined;
277
+ const hasBackground = cell.style.background !== undefined;
278
+ lines.at(-1)!.push({
279
+ ...cell,
280
+ style: {
281
+ ...((cell.style.foreground ?? base.foreground)
282
+ ? { foreground: cell.style.foreground ?? base.foreground }
283
+ : {}),
284
+ ...((cell.style.background ?? base.background)
285
+ ? { background: cell.style.background ?? base.background }
286
+ : {}),
287
+ ...(cell.style.underlineColor ? { underlineColor: cell.style.underlineColor } : {}),
288
+ underline: cell.style.underline === "none" ? base.underline : cell.style.underline,
289
+ // eslint-disable-next-line no-bitwise
290
+ attributes: base.attributes | cell.style.attributes,
291
+ },
292
+ ...(!hasForeground && semantic.foreground ? { foregroundPaint: semantic.foreground } : {}),
293
+ ...(!hasBackground && semantic.background ? { backgroundPaint: semantic.background } : {}),
294
+ });
295
+ }
296
+ }
297
+
298
+ function appendText(text: string, style: SemanticTextStyle, lines: SemanticCell[][]): void {
299
+ const cellStyle = semanticTextStyleToCellStyle(style);
300
+
301
+ const plainText = tokenizeAnsi(text)
302
+ .filter((token) => token.type === "text")
303
+ .map((token) => token.value)
304
+ .join("");
305
+ for (const segment of graphemes(stripAnsi(plainText))) {
306
+ if (segment === "\n" || segment === "\r\n") {
307
+ lines.push([]);
308
+ continue;
309
+ }
310
+
311
+ lines.at(-1)!.push({
312
+ ...createCell(
313
+ segment,
314
+ Math.max(1, stringWidth(segment)),
315
+ cellStyle,
316
+ undefined,
317
+ style.resetForeground || style.resetBackground
318
+ ? { foreground: style.resetForeground, background: style.resetBackground }
319
+ : undefined,
320
+ ),
321
+ ...(style.foreground ? { foregroundPaint: style.foreground } : {}),
322
+ ...(style.background ? { backgroundPaint: style.background } : {}),
323
+ });
324
+ }
325
+ }