@jrichman/ink 6.5.1-beta.2 → 6.5.1-beta.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 (98) hide show
  1. package/build/colorize.d.ts +2 -0
  2. package/build/colorize.js +24 -0
  3. package/build/colorize.js.map +1 -1
  4. package/build/components/Static.js +2 -1
  5. package/build/components/Static.js.map +1 -1
  6. package/build/components/Text.js +8 -8
  7. package/build/components/Text.js.map +1 -1
  8. package/build/debug-log.js +3 -2
  9. package/build/debug-log.js.map +1 -1
  10. package/build/dom.js +3 -5
  11. package/build/dom.js.map +1 -1
  12. package/build/index.d.ts +2 -2
  13. package/build/index.js +2 -2
  14. package/build/index.js.map +1 -1
  15. package/build/ink.d.ts +2 -2
  16. package/build/ink.js +3 -0
  17. package/build/ink.js.map +1 -1
  18. package/build/measure-element.js +3 -3
  19. package/build/measure-element.js.map +1 -1
  20. package/build/measure-text.d.ts +14 -1
  21. package/build/measure-text.js +46 -38
  22. package/build/measure-text.js.map +1 -1
  23. package/build/output.d.ts +6 -0
  24. package/build/output.js +26 -18
  25. package/build/output.js.map +1 -1
  26. package/build/render-background.js +16 -4
  27. package/build/render-background.js.map +1 -1
  28. package/build/render-cached.d.ts +2 -2
  29. package/build/render-cached.js +7 -6
  30. package/build/render-cached.js.map +1 -1
  31. package/build/render-container.d.ts +2 -2
  32. package/build/render-node-to-output.d.ts +3 -3
  33. package/build/render-node-to-output.js +2 -0
  34. package/build/render-node-to-output.js.map +1 -1
  35. package/build/render-scrollbar.d.ts +1 -2
  36. package/build/render-scrollbar.js +14 -28
  37. package/build/render-scrollbar.js.map +1 -1
  38. package/build/render-sticky.d.ts +3 -3
  39. package/build/render-text-node.d.ts +2 -2
  40. package/build/render-text-node.js +47 -43
  41. package/build/render-text-node.js.map +1 -1
  42. package/build/render.d.ts +2 -2
  43. package/build/renderer.d.ts +2 -2
  44. package/build/renderer.js +2 -1
  45. package/build/renderer.js.map +1 -1
  46. package/build/replay.js +4 -4
  47. package/build/replay.js.map +1 -1
  48. package/build/selection.d.ts +2 -3
  49. package/build/selection.js +35 -57
  50. package/build/selection.js.map +1 -1
  51. package/build/serialization.js +2 -0
  52. package/build/serialization.js.map +1 -1
  53. package/build/styled-line.d.ts +18 -33
  54. package/build/styled-line.js +373 -156
  55. package/build/styled-line.js.map +1 -1
  56. package/build/text-wrap.d.ts +5 -0
  57. package/build/text-wrap.js +78 -79
  58. package/build/text-wrap.js.map +1 -1
  59. package/build/tokenize.d.ts +1 -1
  60. package/build/tokenize.js +2 -2
  61. package/build/tokenize.js.map +1 -1
  62. package/build/worker/canvas.d.ts +13 -1
  63. package/build/worker/canvas.js +16 -5
  64. package/build/worker/canvas.js.map +1 -1
  65. package/build/worker/compositor.js +9 -23
  66. package/build/worker/compositor.js.map +1 -1
  67. package/build/worker/render-worker.js +2 -2
  68. package/build/worker/render-worker.js.map +1 -1
  69. package/build/worker/terminal-writer.js +1 -1
  70. package/build/worker/terminal-writer.js.map +1 -1
  71. package/package.json +2 -2
  72. package/build/render-worker.d.ts +0 -25
  73. package/build/render-worker.js +0 -370
  74. package/build/render-worker.js.map +0 -1
  75. package/build/styled-lines.d.ts +0 -29
  76. package/build/styled-lines.js +0 -110
  77. package/build/styled-lines.js.map +0 -1
  78. package/build/terminal-writer.d.ts +0 -69
  79. package/build/terminal-writer.js +0 -546
  80. package/build/terminal-writer.js.map +0 -1
  81. package/build/web/ansi-to-css.d.ts +0 -16
  82. package/build/web/ansi-to-css.js +0 -147
  83. package/build/web/ansi-to-css.js.map +0 -1
  84. package/build/web/client.d.ts +0 -51
  85. package/build/web/client.js +0 -315
  86. package/build/web/client.js.map +0 -1
  87. package/build/web/server.d.ts +0 -1
  88. package/build/web/server.js +0 -179
  89. package/build/web/server.js.map +0 -1
  90. package/build/worker/dump-replay.d.ts +0 -1
  91. package/build/worker/dump-replay.js +0 -15
  92. package/build/worker/dump-replay.js.map +0 -1
  93. package/build/worker/replay.d.ts +0 -55
  94. package/build/worker/replay.js +0 -133
  95. package/build/worker/replay.js.map +0 -1
  96. package/build/wrap-text.d.ts +0 -6
  97. package/build/wrap-text.js +0 -120
  98. package/build/wrap-text.js.map +0 -1
@@ -1,52 +1,52 @@
1
- import { FULL_WIDTH_MASK, BOLD_MASK, DIM_MASK, ITALIC_MASK, UNDERLINE_MASK, STRIKETHROUGH_MASK, INVERSE_MASK, HIDDEN_MASK, } from './tokenize.js';
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { FULL_WIDTH_MASK, INVERSE_MASK } from './tokenize.js';
7
+ const MAX_SAFE_OFFSET = 0x7f_ff;
2
8
  export class StyledLine {
3
9
  static empty(length) {
10
+ const safeLength = Math.min(length, MAX_SAFE_OFFSET);
11
+ if (safeLength <= 0) {
12
+ return new StyledLine();
13
+ }
14
+ const cached = StyledLine.emptyCache.get(safeLength);
15
+ if (cached) {
16
+ return cached.clone();
17
+ }
4
18
  const line = new StyledLine();
5
- line.length = length;
6
- line.text = ' '.repeat(length);
7
- line.charData = new Uint16Array(Math.max(length, 16));
8
- for (let i = 0; i < length; i++) {
19
+ line.length = safeLength;
20
+ line.text = ' '.repeat(safeLength);
21
+ line.charData = new Uint16Array(Math.max(safeLength, 16));
22
+ for (let i = 0; i < safeLength; i++) {
9
23
  line.charData[i] = i;
10
24
  }
11
- line.spans = length > 0 ? [{ length, formatFlags: 0 }] : [];
25
+ line.spans = [{ length: safeLength, formatFlags: 0 }];
26
+ if (StyledLine.emptyCache.size > 100) {
27
+ StyledLine.emptyCache.clear();
28
+ }
29
+ Object.freeze(line.spans[0]);
30
+ Object.freeze(line.spans);
31
+ Object.freeze(line);
32
+ StyledLine.emptyCache.set(safeLength, line);
33
+ return line.clone();
34
+ }
35
+ static legacyCreateStyledLine(values = [], spans = []) {
36
+ const line = new StyledLine();
37
+ line.applyValuesAndSpans(values, spans);
12
38
  return line;
13
39
  }
40
+ static emptyCache = new Map();
14
41
  length;
15
42
  text;
16
43
  charData;
17
44
  spans;
18
- constructor(values = [], spans = []) {
19
- this.length = values.length;
20
- this.text = values.join('');
21
- this.charData = new Uint16Array(Math.max(this.length, 16));
22
- let currentOffset = 0;
23
- let spanIdx = 0;
24
- let spanPos = 0;
25
- for (let i = 0; i < this.length; i++) {
26
- const val = values[i];
27
- let isFullWidth = false;
28
- if (spans.length > 0 && spanIdx < spans.length) {
29
- const span = spans[spanIdx];
30
- if ((span.formatFlags & FULL_WIDTH_MASK) !== 0) {
31
- isFullWidth = true;
32
- }
33
- spanPos++;
34
- if (spanPos >= span.length) {
35
- spanIdx++;
36
- spanPos = 0;
37
- }
38
- }
39
- this.charData[i] = currentOffset | (isFullWidth ? 0x80_00 : 0);
40
- currentOffset += val.length;
41
- }
42
- this.spans = spans.map(s => ({
43
- ...s,
44
- formatFlags: s.formatFlags & ~FULL_WIDTH_MASK,
45
- }));
46
- this.mergeSpans();
45
+ constructor() {
46
+ this.length = 0;
47
47
  }
48
48
  getValue(index) {
49
- if (index < 0 || index >= this.length)
49
+ if (this.text === undefined || index < 0 || index >= this.length)
50
50
  return '';
51
51
  const start = this.charData[index] & 0x7f_ff;
52
52
  const end = index + 1 < this.length
@@ -55,7 +55,7 @@ export class StyledLine {
55
55
  return this.text.slice(start, end);
56
56
  }
57
57
  getSpan(index) {
58
- if (index < 0 || index >= this.length)
58
+ if (this.spans === undefined || index < 0 || index >= this.length)
59
59
  return undefined;
60
60
  let current = 0;
61
61
  for (const span of this.spans) {
@@ -66,7 +66,7 @@ export class StyledLine {
66
66
  return undefined;
67
67
  }
68
68
  getFullWidth(index) {
69
- if (index < 0 || index >= this.length)
69
+ if (this.charData === undefined || index < 0 || index >= this.length)
70
70
  return false;
71
71
  return (this.charData[index] & 0x80_00) !== 0;
72
72
  }
@@ -95,10 +95,64 @@ export class StyledLine {
95
95
  getLink(index) {
96
96
  return this.getSpan(index)?.link;
97
97
  }
98
+ setInverted(index, inverted) {
99
+ if (index < 0 || index >= this.length)
100
+ return;
101
+ this.ensureInitialized();
102
+ this.splitSpansAt(index);
103
+ this.splitSpansAt(index + 1);
104
+ let current = 0;
105
+ for (const span of this.spans) {
106
+ if (current === index && span.length === 1) {
107
+ if (inverted) {
108
+ span.formatFlags |= INVERSE_MASK;
109
+ }
110
+ else {
111
+ span.formatFlags &= ~INVERSE_MASK;
112
+ }
113
+ break;
114
+ }
115
+ current += span.length;
116
+ }
117
+ this.mergeSpans();
118
+ }
119
+ setBackgroundColor(index, color) {
120
+ if (index < 0 || index >= this.length)
121
+ return;
122
+ this.ensureInitialized();
123
+ this.splitSpansAt(index);
124
+ this.splitSpansAt(index + 1);
125
+ let current = 0;
126
+ for (const span of this.spans) {
127
+ if (current === index && span.length === 1) {
128
+ span.bgColor = color;
129
+ break;
130
+ }
131
+ current += span.length;
132
+ }
133
+ this.mergeSpans();
134
+ }
135
+ setForegroundColor(index, color) {
136
+ if (index < 0 || index >= this.length)
137
+ return;
138
+ this.ensureInitialized();
139
+ this.splitSpansAt(index);
140
+ this.splitSpansAt(index + 1);
141
+ let current = 0;
142
+ for (const span of this.spans) {
143
+ if (current === index && span.length === 1) {
144
+ span.fgColor = color;
145
+ break;
146
+ }
147
+ current += span.length;
148
+ }
149
+ this.mergeSpans();
150
+ }
98
151
  // eslint-disable-next-line max-params
99
152
  setChar(index, value, formatFlags, fgColor, bgColor, link) {
100
153
  if (index < 0 || index >= this.length)
101
154
  return;
155
+ this.ensureInitialized();
102
156
  const isFullWidth = (formatFlags & FULL_WIDTH_MASK) !== 0;
103
157
  const cleanFormatFlags = formatFlags & ~FULL_WIDTH_MASK;
104
158
  const start = this.charData[index] & 0x7f_ff;
@@ -106,12 +160,16 @@ export class StyledLine {
106
160
  ? this.charData[index + 1] & 0x7f_ff
107
161
  : this.text.length;
108
162
  const oldLen = end - start;
109
- const newLen = value.length;
163
+ let newValue = value;
164
+ if (this.text.length - oldLen + value.length > MAX_SAFE_OFFSET) {
165
+ newValue = value.slice(0, Math.max(0, MAX_SAFE_OFFSET - (this.text.length - oldLen)));
166
+ }
167
+ const newLen = newValue.length;
110
168
  if (oldLen === newLen) {
111
- this.text = this.text.slice(0, start) + value + this.text.slice(end);
169
+ this.text = this.text.slice(0, start) + newValue + this.text.slice(end);
112
170
  }
113
171
  else {
114
- this.text = this.text.slice(0, start) + value + this.text.slice(end);
172
+ this.text = this.text.slice(0, start) + newValue + this.text.slice(end);
115
173
  const diff = newLen - oldLen;
116
174
  for (let i = index + 1; i < this.length; i++) {
117
175
  const data = this.charData[i];
@@ -142,9 +200,19 @@ export class StyledLine {
142
200
  }
143
201
  // eslint-disable-next-line max-params
144
202
  pushChar(value, formatFlags, fgColor, bgColor, link) {
203
+ this.ensureInitialized();
145
204
  const isFullWidth = (formatFlags & FULL_WIDTH_MASK) !== 0;
146
205
  const cleanFormatFlags = formatFlags & ~FULL_WIDTH_MASK;
147
206
  const offset = this.text.length;
207
+ if (value !== '…' && offset + value.length > MAX_SAFE_OFFSET - 1) {
208
+ if (offset < MAX_SAFE_OFFSET && !this.text.endsWith('…')) {
209
+ this.pushChar('…', formatFlags, fgColor, bgColor, link);
210
+ }
211
+ return;
212
+ }
213
+ if (offset + value.length > MAX_SAFE_OFFSET) {
214
+ return;
215
+ }
148
216
  this.text += value;
149
217
  if (this.length >= this.charData.length) {
150
218
  const newData = new Uint16Array(this.charData.length * 2 || 16);
@@ -171,11 +239,26 @@ export class StyledLine {
171
239
  }
172
240
  this.length++;
173
241
  }
242
+ clone() {
243
+ if (this.charData === undefined)
244
+ return new StyledLine();
245
+ const result = new StyledLine();
246
+ result.length = this.length;
247
+ result.text = this.text;
248
+ result.charData = this.charData.slice(0, Math.max(this.length, 16));
249
+ result.spans = this.spans.map(span => ({ ...span }));
250
+ return result;
251
+ }
174
252
  slice(start, end) {
253
+ if (this.charData === undefined)
254
+ return new StyledLine();
175
255
  const actualStart = Math.max(0, start);
176
256
  const actualEnd = end === undefined ? this.length : Math.min(this.length, end);
177
257
  if (actualStart >= actualEnd)
178
- return new StyledLine([], []);
258
+ return new StyledLine();
259
+ if (actualStart === 0 && actualEnd === this.length) {
260
+ return this.clone();
261
+ }
179
262
  const result = new StyledLine();
180
263
  result.length = actualEnd - actualStart;
181
264
  result.charData = new Uint16Array(Math.max(result.length, 16));
@@ -211,65 +294,143 @@ export class StyledLine {
211
294
  result.mergeSpans();
212
295
  return result;
213
296
  }
214
- concat(other) {
297
+ combine(...others) {
298
+ if (others.length === 0)
299
+ return this.clone();
300
+ const allLines = [this, ...others].filter(l => l.length > 0);
301
+ if (allLines.length === 0)
302
+ return new StyledLine();
303
+ if (allLines.length === 1)
304
+ return allLines[0].clone();
305
+ let totalTextLen = 0;
306
+ let totalChars = 0;
307
+ for (const line of allLines) {
308
+ totalTextLen += line.getText().length;
309
+ totalChars += line.length;
310
+ }
311
+ if (totalTextLen > MAX_SAFE_OFFSET) {
312
+ let result = this.clone();
313
+ for (const other of others) {
314
+ result = result.instanceConcat(other);
315
+ }
316
+ return result;
317
+ }
215
318
  const result = new StyledLine();
216
- result.length = this.length + other.length;
217
- result.text = this.text + other.text;
218
- result.charData = new Uint16Array(Math.max(result.length, 16));
219
- result.charData.set(this.charData.subarray(0, this.length), 0);
220
- const textOffset = this.text.length;
221
- for (let i = 0; i < other.length; i++) {
222
- const oldData = other.charData[i];
223
- const oldOffset = oldData & 0x7f_ff;
224
- const fw = oldData & 0x80_00;
225
- result.charData[this.length + i] = (oldOffset + textOffset) | fw;
319
+ result.length = totalChars;
320
+ result.text = allLines.map(l => l.getText()).join('');
321
+ result.charData = new Uint16Array(Math.max(totalChars, 16));
322
+ let currentChar = 0;
323
+ let currentOffset = 0;
324
+ for (const line of allLines) {
325
+ const lineCharData = line.charData;
326
+ const lineText = line.getText();
327
+ if (lineCharData) {
328
+ for (let i = 0; i < line.length; i++) {
329
+ const data = lineCharData[i];
330
+ const offset = data & 0x7f_ff;
331
+ const fw = data & 0x80_00;
332
+ result.charData[currentChar + i] = (currentOffset + offset) | fw;
333
+ }
334
+ }
335
+ else {
336
+ for (let i = 0; i < line.length; i++) {
337
+ result.charData[currentChar + i] = currentOffset + i;
338
+ }
339
+ }
340
+ currentChar += line.length;
341
+ currentOffset += lineText.length;
226
342
  }
227
- result.spans = [...this.spans, ...other.spans.map(s => ({ ...s }))];
343
+ result.spans = allLines.flatMap(l => l.getSpans().map(s => ({ ...s })));
228
344
  result.mergeSpans();
229
345
  return result;
230
346
  }
231
- trimEnd() {
232
- let i = this.length - 1;
233
- while (i >= 0 && this.getValue(i) === ' ' && !this.hasStyles(i)) {
234
- i--;
347
+ getTrimmedLength() {
348
+ if (this.length === 0)
349
+ return 0;
350
+ if (this.text === undefined || this.charData === undefined)
351
+ return 0;
352
+ let currentIdx = this.length - 1;
353
+ if (this.spans) {
354
+ for (let s = this.spans.length - 1; s >= 0; s--) {
355
+ const span = this.spans[s];
356
+ const hasStyles = (span.formatFlags & ~FULL_WIDTH_MASK) !== 0 ||
357
+ span.fgColor !== undefined ||
358
+ span.bgColor !== undefined ||
359
+ span.link !== undefined;
360
+ if (hasStyles) {
361
+ return currentIdx + 1;
362
+ }
363
+ for (let i = 0; i < span.length; i++) {
364
+ const start = this.charData[currentIdx] & 0x7f_ff;
365
+ const end = currentIdx + 1 < this.length
366
+ ? this.charData[currentIdx + 1] & 0x7f_ff
367
+ : this.text.length;
368
+ if (end - start !== 1 || this.text[start] !== ' ') {
369
+ return currentIdx + 1;
370
+ }
371
+ currentIdx--;
372
+ }
373
+ }
235
374
  }
236
- return this.slice(0, i + 1);
375
+ return 0;
376
+ }
377
+ trimEnd() {
378
+ const trimmedLength = this.getTrimmedLength();
379
+ if (trimmedLength === this.length)
380
+ return this;
381
+ if (trimmedLength === 0)
382
+ return new StyledLine();
383
+ return this.slice(0, trimmedLength);
237
384
  }
238
385
  equals(other) {
239
386
  if (this.length !== other.length)
240
387
  return false;
241
- if (this.text !== other.text)
388
+ if (this.length === 0)
389
+ return true;
390
+ if (this.getText() !== other.getText())
242
391
  return false;
243
- if (this.spans.length !== other.spans.length)
392
+ const s1 = this.getSpans();
393
+ const s2 = other.getSpans();
394
+ if (s1.length !== s2.length)
244
395
  return false;
245
- for (let i = 0; i < this.spans.length; i++) {
246
- const s1 = this.spans[i];
247
- const s2 = other.spans[i];
248
- if (s1.length !== s2.length ||
249
- s1.formatFlags !== s2.formatFlags ||
250
- s1.fgColor !== s2.fgColor ||
251
- s1.bgColor !== s2.bgColor ||
252
- s1.link !== s2.link) {
396
+ for (let i = 0; i < s1.length; i++) {
397
+ const sp1 = s1[i];
398
+ const sp2 = s2[i];
399
+ if (sp1.length !== sp2.length ||
400
+ sp1.formatFlags !== sp2.formatFlags ||
401
+ sp1.fgColor !== sp2.fgColor ||
402
+ sp1.bgColor !== sp2.bgColor ||
403
+ sp1.link !== sp2.link) {
253
404
  return false;
254
405
  }
255
406
  }
256
- for (let i = 0; i < this.length; i++) {
257
- if (this.charData[i] !== other.charData[i])
258
- return false;
407
+ const thisCharData = this.charData;
408
+ const otherCharData = other.charData;
409
+ if (thisCharData && otherCharData) {
410
+ for (let i = 0; i < this.length; i++) {
411
+ if (thisCharData[i] !== otherCharData[i])
412
+ return false;
413
+ }
259
414
  }
260
415
  return true;
261
416
  }
417
+ getText() {
418
+ return this.text ?? '';
419
+ }
262
420
  getSpans() {
263
- return this.spans;
421
+ return this.spans ?? [];
264
422
  }
265
423
  getValues() {
266
424
  return Array.from({ length: this.length }, (_, i) => this.getValue(i));
267
425
  }
268
426
  *[Symbol.iterator]() {
427
+ if (this.length === 0)
428
+ return;
269
429
  let currentSpanIdx = 0;
270
430
  let currentSpanPos = 0;
431
+ const spans = this.getSpans();
271
432
  for (let i = 0; i < this.length; i++) {
272
- const span = this.spans[currentSpanIdx];
433
+ const span = spans[currentSpanIdx];
273
434
  const formatFlags = span ? span.formatFlags : 0;
274
435
  const isFullWidth = this.getFullWidth(i);
275
436
  yield {
@@ -293,8 +454,143 @@ export class StyledLine {
293
454
  }
294
455
  }
295
456
  }
457
+ ensureInitialized(initialCapacity = 16) {
458
+ if (this.charData === undefined) {
459
+ this.text = '';
460
+ this.charData = new Uint16Array(Math.max(this.length, initialCapacity));
461
+ this.spans =
462
+ this.length > 0 ? [{ length: this.length, formatFlags: 0 }] : [];
463
+ if (this.length > 0 && this.text.length === 0) {
464
+ this.text = ' '.repeat(this.length);
465
+ for (let i = 0; i < this.length; i++) {
466
+ this.charData[i] = i;
467
+ }
468
+ }
469
+ }
470
+ }
471
+ applyValuesAndSpans(values, spans) {
472
+ let totalTextLen = 0;
473
+ let visibleChars = 0;
474
+ for (const val of values) {
475
+ if (totalTextLen + val.length > MAX_SAFE_OFFSET - 1) {
476
+ break;
477
+ }
478
+ totalTextLen += val.length;
479
+ visibleChars++;
480
+ }
481
+ const truncated = visibleChars < values.length;
482
+ this.length = visibleChars + (truncated ? 1 : 0);
483
+ this.text = values.slice(0, visibleChars).join('') + (truncated ? '…' : '');
484
+ this.charData = new Uint16Array(Math.max(this.length, 16));
485
+ let currentOffset = 0;
486
+ let spanIdx = 0;
487
+ let spanPos = 0;
488
+ for (let i = 0; i < visibleChars; i++) {
489
+ const val = values[i];
490
+ let isFullWidth = false;
491
+ if (spans.length > 0 && spanIdx < spans.length) {
492
+ const span = spans[spanIdx];
493
+ if ((span.formatFlags & FULL_WIDTH_MASK) !== 0) {
494
+ isFullWidth = true;
495
+ }
496
+ spanPos++;
497
+ if (spanPos >= span.length) {
498
+ spanIdx++;
499
+ spanPos = 0;
500
+ }
501
+ }
502
+ this.charData[i] = currentOffset | (isFullWidth ? 0x80_00 : 0);
503
+ currentOffset += val.length;
504
+ }
505
+ if (truncated) {
506
+ this.charData[visibleChars] = currentOffset;
507
+ }
508
+ if (truncated) {
509
+ const newSpans = [];
510
+ let remaining = visibleChars;
511
+ let sIdx = 0;
512
+ while (remaining > 0 && sIdx < spans.length) {
513
+ const span = spans[sIdx];
514
+ const take = Math.min(remaining, span.length);
515
+ newSpans.push({ ...span, length: take });
516
+ remaining -= take;
517
+ sIdx++;
518
+ }
519
+ newSpans.push({ length: 1, formatFlags: 0 });
520
+ this.spans = newSpans;
521
+ }
522
+ else {
523
+ this.spans = spans.map(s => ({
524
+ ...s,
525
+ formatFlags: s.formatFlags & ~FULL_WIDTH_MASK,
526
+ }));
527
+ }
528
+ this.mergeSpans();
529
+ }
530
+ instanceConcat(other) {
531
+ const spaceForOther = MAX_SAFE_OFFSET - 1 - this.getText().length;
532
+ if (spaceForOther <= 0) {
533
+ if (this.getText().length < MAX_SAFE_OFFSET &&
534
+ !this.getText().endsWith('…')) {
535
+ const result = this.clone();
536
+ result.pushChar('…', 0);
537
+ return result;
538
+ }
539
+ return this.clone();
540
+ }
541
+ let otherTextLenToTake = 0;
542
+ let otherCharsToTake = 0;
543
+ for (let i = 0; i < other.length; i++) {
544
+ const val = other.getValue(i);
545
+ if (otherTextLenToTake + val.length > spaceForOther) {
546
+ break;
547
+ }
548
+ otherTextLenToTake += val.length;
549
+ otherCharsToTake++;
550
+ }
551
+ const truncated = otherCharsToTake < other.length;
552
+ const result = new StyledLine();
553
+ result.length = this.length + otherCharsToTake + (truncated ? 1 : 0);
554
+ result.text =
555
+ this.getText() +
556
+ other.getText().slice(0, otherTextLenToTake) +
557
+ (truncated ? '…' : '');
558
+ result.charData = new Uint16Array(Math.max(result.length, 16));
559
+ if (this.charData) {
560
+ result.charData.set(this.charData.subarray(0, this.length), 0);
561
+ }
562
+ const textOffset = this.getText().length;
563
+ const otherCharData = other.charData;
564
+ if (otherCharData) {
565
+ for (let i = 0; i < otherCharsToTake; i++) {
566
+ const oldData = otherCharData[i];
567
+ const oldOffset = oldData & 0x7f_ff;
568
+ const fw = oldData & 0x80_00;
569
+ result.charData[this.length + i] = (oldOffset + textOffset) | fw;
570
+ }
571
+ }
572
+ if (truncated) {
573
+ result.charData[this.length + otherCharsToTake] =
574
+ this.getText().length + otherTextLenToTake;
575
+ }
576
+ const otherSpans = [];
577
+ let remaining = otherCharsToTake;
578
+ for (const span of other.getSpans()) {
579
+ if (remaining <= 0)
580
+ break;
581
+ const take = Math.min(remaining, span.length);
582
+ otherSpans.push({ ...span, length: take });
583
+ remaining -= take;
584
+ }
585
+ result.spans = [...this.getSpans(), ...otherSpans];
586
+ if (truncated) {
587
+ result.spans.push({ length: 1, formatFlags: 0 });
588
+ }
589
+ result.mergeSpans();
590
+ return result;
591
+ }
296
592
  splitSpansAt(index) {
297
- if (index <= 0 || index >= this.length)
593
+ if (this.spans === undefined || index <= 0 || index >= this.length)
298
594
  return;
299
595
  let current = 0;
300
596
  for (let i = 0; i < this.spans.length; i++) {
@@ -309,6 +605,8 @@ export class StyledLine {
309
605
  }
310
606
  }
311
607
  mergeSpans() {
608
+ if (this.spans === undefined)
609
+ return;
312
610
  const newSpans = [];
313
611
  for (const span of this.spans) {
314
612
  if (span.length === 0)
@@ -328,85 +626,4 @@ export class StyledLine {
328
626
  this.spans = newSpans;
329
627
  }
330
628
  }
331
- export class StyledChar {
332
- _value;
333
- _formatFlags;
334
- _fgColor;
335
- _bgColor;
336
- _link;
337
- // eslint-disable-next-line max-params
338
- constructor(_value, _formatFlags, _fgColor, _bgColor, _link) {
339
- this._value = _value;
340
- this._formatFlags = _formatFlags;
341
- this._fgColor = _fgColor;
342
- this._bgColor = _bgColor;
343
- this._link = _link;
344
- }
345
- getValue() {
346
- return this._value;
347
- }
348
- getFullWidth() {
349
- return (this._formatFlags & FULL_WIDTH_MASK) !== 0;
350
- }
351
- getForegroundColor() {
352
- return this._fgColor;
353
- }
354
- getBackgroundColor() {
355
- return this._bgColor;
356
- }
357
- getBold() {
358
- return (this._formatFlags & BOLD_MASK) !== 0;
359
- }
360
- getDim() {
361
- return (this._formatFlags & DIM_MASK) !== 0;
362
- }
363
- getItalic() {
364
- return (this._formatFlags & ITALIC_MASK) !== 0;
365
- }
366
- getUnderline() {
367
- return (this._formatFlags & UNDERLINE_MASK) !== 0;
368
- }
369
- getStrikethrough() {
370
- return (this._formatFlags & STRIKETHROUGH_MASK) !== 0;
371
- }
372
- getInverse() {
373
- return (this._formatFlags & INVERSE_MASK) !== 0;
374
- }
375
- getHidden() {
376
- return (this._formatFlags & HIDDEN_MASK) !== 0;
377
- }
378
- getLink() {
379
- return this._link;
380
- }
381
- get formatFlags() {
382
- return this._formatFlags;
383
- }
384
- get fgColor() {
385
- return this._fgColor;
386
- }
387
- get bgColor() {
388
- return this._bgColor;
389
- }
390
- get link() {
391
- return this._link;
392
- }
393
- setFormatFlag(mask) {
394
- this._formatFlags |= mask;
395
- }
396
- clearFormatFlag(mask) {
397
- this._formatFlags &= ~mask;
398
- }
399
- setBackgroundColor(color) {
400
- this._bgColor = color;
401
- }
402
- hasStyles() {
403
- return ((this._formatFlags & ~FULL_WIDTH_MASK) !== 0 ||
404
- this._fgColor !== undefined ||
405
- this._bgColor !== undefined ||
406
- this._link !== undefined);
407
- }
408
- copyWith(overrides) {
409
- return new StyledChar(overrides.value ?? this._value, this._formatFlags, this._fgColor, this._bgColor, this._link);
410
- }
411
- }
412
629
  //# sourceMappingURL=styled-line.js.map