@oh-my-pi/pi-utils 18.7.0 → 18.8.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.
- package/CHANGELOG.md +16 -0
- package/dist/types/ar/index.d.ts +1 -0
- package/dist/types/ar/zip-package.d.ts +21 -0
- package/dist/types/docx/converter.d.ts +2 -0
- package/dist/types/dom/core.d.ts +15 -4
- package/dist/types/dom/parser.d.ts +5 -3
- package/dist/types/dom/selector.d.ts +7 -1
- package/dist/types/logger/rotating-file.d.ts +4 -2
- package/dist/types/marked/core.d.ts +7 -6
- package/dist/types/marked-list.d.ts +38 -0
- package/dist/types/math-delimiters.d.ts +10 -0
- package/dist/types/readability/types.d.ts +2 -0
- package/dist/types/turndown/types.d.ts +7 -0
- package/dist/types/vterm/buffer.d.ts +16 -5
- package/package.json +2 -2
- package/src/ar/index.ts +1 -0
- package/src/ar/zip-package.ts +57 -0
- package/src/chalk.ts +66 -23
- package/src/docx/converter.ts +26 -12
- package/src/dom/core.ts +354 -111
- package/src/dom/parser.ts +42 -19
- package/src/dom/selector.ts +328 -95
- package/src/fetch-retry.ts +2 -0
- package/src/json-parse.ts +21 -6
- package/src/logger/rotating-file.ts +5 -3
- package/src/logger.ts +39 -23
- package/src/marked/core.ts +42 -18
- package/src/marked-list.ts +73 -0
- package/src/math-delimiters.ts +16 -0
- package/src/prompt.ts +3 -1
- package/src/ptree.ts +28 -35
- package/src/readability/readability.ts +349 -39
- package/src/readability/types.ts +2 -0
- package/src/stream.ts +34 -13
- package/src/temp.ts +1 -10
- package/src/template.ts +7 -4
- package/src/turndown/gfm.ts +16 -5
- package/src/turndown/html.ts +28 -8
- package/src/turndown/service.ts +43 -15
- package/src/turndown/types.ts +7 -0
- package/src/vterm/buffer.ts +31 -11
- package/src/vterm/terminal.ts +185 -92
package/src/vterm/terminal.ts
CHANGED
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
BufferLine,
|
|
3
3
|
type BufferState,
|
|
4
4
|
BufferView,
|
|
5
|
-
blankCell,
|
|
6
5
|
type CellAttributes,
|
|
7
6
|
type CellData,
|
|
8
|
-
|
|
7
|
+
DEFAULT_CELL_ATTRIBUTES,
|
|
8
|
+
sharedBlankCell,
|
|
9
9
|
} from "./buffer";
|
|
10
10
|
|
|
11
11
|
const segmenter = new Intl.Segmenter();
|
|
@@ -39,7 +39,7 @@ export interface TerminalBuffers {
|
|
|
39
39
|
interface SavedCursor {
|
|
40
40
|
x: number;
|
|
41
41
|
y: number;
|
|
42
|
-
attrs: CellAttributes
|
|
42
|
+
attrs: Readonly<CellAttributes>;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function createState(columns: number, rows: number): BufferState {
|
|
@@ -52,8 +52,36 @@ function createState(columns: number, rows: number): BufferState {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function
|
|
56
|
-
return
|
|
55
|
+
function sameAttributes(a: Readonly<CellAttributes>, b: Readonly<CellAttributes>): boolean {
|
|
56
|
+
return (
|
|
57
|
+
a.bold === b.bold &&
|
|
58
|
+
a.dim === b.dim &&
|
|
59
|
+
a.italic === b.italic &&
|
|
60
|
+
a.underline === b.underline &&
|
|
61
|
+
a.inverse === b.inverse &&
|
|
62
|
+
a.strikethrough === b.strikethrough &&
|
|
63
|
+
a.overline === b.overline &&
|
|
64
|
+
a.fgMode === b.fgMode &&
|
|
65
|
+
a.fg === b.fg &&
|
|
66
|
+
a.bgMode === b.bgMode &&
|
|
67
|
+
a.bg === b.bg
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Parses CSI parameters (`;`/`:` separated); null when the body holds anything but digits. */
|
|
72
|
+
function parseCsiParams(body: string): number[] | null {
|
|
73
|
+
const params: number[] = [];
|
|
74
|
+
let value = 0;
|
|
75
|
+
for (let index = 0; index < body.length; index++) {
|
|
76
|
+
const code = body.charCodeAt(index);
|
|
77
|
+
if (code >= 0x30 && code <= 0x39) value = value * 10 + (code - 0x30);
|
|
78
|
+
else if (code === 0x3b || code === 0x3a) {
|
|
79
|
+
params.push(value);
|
|
80
|
+
value = 0;
|
|
81
|
+
} else return null;
|
|
82
|
+
}
|
|
83
|
+
params.push(value);
|
|
84
|
+
return params;
|
|
57
85
|
}
|
|
58
86
|
|
|
59
87
|
/** Behavior-compatible reimplementation of @xterm/headless's used surface. */
|
|
@@ -72,7 +100,12 @@ export class Terminal {
|
|
|
72
100
|
#alternate: BufferState;
|
|
73
101
|
#active: BufferState;
|
|
74
102
|
#usingAlternate = false;
|
|
75
|
-
|
|
103
|
+
// Renditions are immutable and shared by every cell printed with them;
|
|
104
|
+
// SGR builds a new frozen object instead of mutating this one.
|
|
105
|
+
#attrs: Readonly<CellAttributes> = DEFAULT_CELL_ATTRIBUTES;
|
|
106
|
+
// Frozen printable-ASCII cells for #attrs, indexed by char code - 0x20.
|
|
107
|
+
#asciiCells: CellData[] = [];
|
|
108
|
+
#asciiCellsAttrs: Readonly<CellAttributes> | undefined;
|
|
76
109
|
#scrollTop = 0;
|
|
77
110
|
#scrollBottom: number;
|
|
78
111
|
#originMode = false;
|
|
@@ -149,13 +182,30 @@ export class Terminal {
|
|
|
149
182
|
}
|
|
150
183
|
|
|
151
184
|
#parse(text: string): void {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
185
|
+
const length = text.length;
|
|
186
|
+
let index = 0;
|
|
187
|
+
while (index < length) {
|
|
188
|
+
if (this.#state === "ground") {
|
|
189
|
+
let end = index;
|
|
190
|
+
while (end < length) {
|
|
191
|
+
const code = text.charCodeAt(end);
|
|
192
|
+
if (code < 0x20 || code === 0x7f) break;
|
|
193
|
+
end++;
|
|
194
|
+
}
|
|
195
|
+
if (end > index) {
|
|
196
|
+
this.#printRun(text, index, end);
|
|
197
|
+
index = end;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const char = text[index]!;
|
|
201
|
+
index++;
|
|
202
|
+
if (char === "\x1b") this.#state = "escape";
|
|
203
|
+
else this.#handleControl(char);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
const code = text.codePointAt(index)!;
|
|
207
|
+
const char = code > 0xffff ? text.slice(index, index + 2) : text[index]!;
|
|
208
|
+
index += char.length;
|
|
159
209
|
if (this.#state === "string") {
|
|
160
210
|
if (this.#stringEscape && char === "\\") {
|
|
161
211
|
this.#state = "ground";
|
|
@@ -172,30 +222,41 @@ export class Terminal {
|
|
|
172
222
|
this.#handleEscape(char);
|
|
173
223
|
continue;
|
|
174
224
|
}
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
} else if (char === "\x1b") {
|
|
181
|
-
this.#state = "escape";
|
|
182
|
-
this.#sequence = "";
|
|
183
|
-
} else {
|
|
184
|
-
this.#sequence += char;
|
|
185
|
-
}
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
if (char === "\x1b") {
|
|
189
|
-
flush();
|
|
225
|
+
if (char >= "@" && char <= "~") {
|
|
226
|
+
this.#handleCsi(this.#sequence, char);
|
|
227
|
+
this.#sequence = "";
|
|
228
|
+
this.#state = "ground";
|
|
229
|
+
} else if (char === "\x1b") {
|
|
190
230
|
this.#state = "escape";
|
|
191
|
-
|
|
192
|
-
flush();
|
|
193
|
-
this.#handleControl(char);
|
|
231
|
+
this.#sequence = "";
|
|
194
232
|
} else {
|
|
195
|
-
|
|
233
|
+
this.#sequence += char;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Prints a run of non-control text. Printable ASCII is one cell wide and
|
|
240
|
+
* every boundary between two ASCII characters is a grapheme break, so ASCII
|
|
241
|
+
* stretches skip segmentation; the last ASCII character before non-ASCII text
|
|
242
|
+
* may start a cluster (combining mark, keycap) and goes to the segmenter.
|
|
243
|
+
*/
|
|
244
|
+
#printRun(text: string, start: number, end: number): void {
|
|
245
|
+
let index = start;
|
|
246
|
+
while (index < end) {
|
|
247
|
+
let asciiEnd = index;
|
|
248
|
+
while (asciiEnd < end && text.charCodeAt(asciiEnd) < 0x80) asciiEnd++;
|
|
249
|
+
if (asciiEnd < end && asciiEnd > index) asciiEnd--;
|
|
250
|
+
for (; index < asciiEnd; index++) this.#putAscii(text.charCodeAt(index));
|
|
251
|
+
if (index >= end) return;
|
|
252
|
+
// Segment up to the first break between two ASCII characters.
|
|
253
|
+
let clusterEnd = index + 1;
|
|
254
|
+
while (clusterEnd < end && !(text.charCodeAt(clusterEnd) < 0x80 && text.charCodeAt(clusterEnd - 1) < 0x80)) {
|
|
255
|
+
clusterEnd++;
|
|
196
256
|
}
|
|
257
|
+
for (const part of segmenter.segment(text.slice(index, clusterEnd))) this.#print(part.segment);
|
|
258
|
+
index = clusterEnd;
|
|
197
259
|
}
|
|
198
|
-
flush();
|
|
199
260
|
}
|
|
200
261
|
|
|
201
262
|
#handleControl(char: string): void {
|
|
@@ -262,10 +323,12 @@ export class Terminal {
|
|
|
262
323
|
const privateMode = raw.startsWith("?");
|
|
263
324
|
const greater = raw.startsWith(">");
|
|
264
325
|
const body = privateMode || greater ? raw.slice(1) : raw;
|
|
265
|
-
const params =
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
326
|
+
const params =
|
|
327
|
+
parseCsiParams(body) ??
|
|
328
|
+
body
|
|
329
|
+
.replaceAll(":", ";")
|
|
330
|
+
.split(";")
|
|
331
|
+
.map(value => (value === "" ? 0 : Number(value)));
|
|
269
332
|
const first = params[0] ?? 0;
|
|
270
333
|
const amount = Math.max(1, first);
|
|
271
334
|
switch (final) {
|
|
@@ -359,12 +422,30 @@ export class Terminal {
|
|
|
359
422
|
}
|
|
360
423
|
|
|
361
424
|
#print(grapheme: string): void {
|
|
362
|
-
|
|
425
|
+
const width = Bun.stringWidth(grapheme);
|
|
363
426
|
if (width === 0) {
|
|
364
427
|
this.#appendCombining(grapheme);
|
|
365
428
|
return;
|
|
366
429
|
}
|
|
367
|
-
|
|
430
|
+
const cellWidth = Math.min(2, width);
|
|
431
|
+
this.#placeCell(Object.freeze({ chars: grapheme, width: cellWidth, attrs: this.#attrs }), cellWidth);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
#putAscii(code: number): void {
|
|
435
|
+
if (this.#asciiCellsAttrs !== this.#attrs) {
|
|
436
|
+
this.#asciiCells = [];
|
|
437
|
+
this.#asciiCellsAttrs = this.#attrs;
|
|
438
|
+
}
|
|
439
|
+
const slot = code - 0x20;
|
|
440
|
+
let cell = this.#asciiCells[slot];
|
|
441
|
+
if (!cell) {
|
|
442
|
+
cell = Object.freeze({ chars: String.fromCharCode(code), width: 1, attrs: this.#attrs });
|
|
443
|
+
this.#asciiCells[slot] = cell;
|
|
444
|
+
}
|
|
445
|
+
this.#placeCell(cell, 1);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
#placeCell(cell: CellData, width: number): void {
|
|
368
449
|
if (this.#pendingWrap || (width === 2 && this.#active.cursorX === this.cols - 1)) {
|
|
369
450
|
if (!this.#autowrap) {
|
|
370
451
|
this.#active.cursorX = this.cols - width;
|
|
@@ -377,9 +458,9 @@ export class Terminal {
|
|
|
377
458
|
const column = Math.min(this.#active.cursorX, this.cols - 1);
|
|
378
459
|
if (this.#insertMode) this.#shiftCells(line, column, width);
|
|
379
460
|
this.#clearWideAt(line, column);
|
|
380
|
-
line.cells[column] =
|
|
461
|
+
line.cells[column] = cell;
|
|
381
462
|
if (width === 2 && column + 1 < this.cols) {
|
|
382
|
-
line.cells[column + 1] = { chars: "", width: 0, attrs:
|
|
463
|
+
line.cells[column + 1] = Object.freeze({ chars: "", width: 0, attrs: cell.attrs });
|
|
383
464
|
}
|
|
384
465
|
this.#active.cursorX = column + width;
|
|
385
466
|
this.#pendingWrap = this.#active.cursorX >= this.cols;
|
|
@@ -396,7 +477,9 @@ export class Terminal {
|
|
|
396
477
|
if (!line) return;
|
|
397
478
|
while (column >= 0 && line.cells[column]?.width === 0) column--;
|
|
398
479
|
const cell = line.cells[column];
|
|
399
|
-
|
|
480
|
+
// Cells are frozen and may be shared; replace instead of mutating.
|
|
481
|
+
if (cell?.chars)
|
|
482
|
+
line.cells[column] = Object.freeze({ chars: cell.chars + mark, width: cell.width, attrs: cell.attrs });
|
|
400
483
|
}
|
|
401
484
|
|
|
402
485
|
#lineFeed(wrapped: boolean): void {
|
|
@@ -489,8 +572,8 @@ export class Terminal {
|
|
|
489
572
|
}
|
|
490
573
|
|
|
491
574
|
#eraseRange(line: BufferLine, start: number, end: number): void {
|
|
492
|
-
|
|
493
|
-
|
|
575
|
+
const blank = sharedBlankCell(this.#attrs);
|
|
576
|
+
for (let column = Math.max(0, start); column < Math.min(this.cols, end); column++) line.cells[column] = blank;
|
|
494
577
|
this.#repairWideCells(line);
|
|
495
578
|
}
|
|
496
579
|
|
|
@@ -521,14 +604,18 @@ export class Terminal {
|
|
|
521
604
|
}
|
|
522
605
|
|
|
523
606
|
#shiftCells(line: BufferLine, column: number, count: number): void {
|
|
524
|
-
|
|
607
|
+
// Inserting more than a row's worth only pushes everything past the edge.
|
|
608
|
+
const blank = sharedBlankCell(this.#attrs);
|
|
609
|
+
const blanks = Array.from({ length: Math.min(count, this.cols) }, () => blank);
|
|
610
|
+
line.cells.splice(column, 0, ...blanks);
|
|
525
611
|
line.cells.length = this.cols;
|
|
526
612
|
}
|
|
527
613
|
|
|
528
614
|
#deleteCells(count: number): void {
|
|
529
615
|
const line = this.#currentLine();
|
|
530
616
|
line.cells.splice(this.#active.cursorX, count);
|
|
531
|
-
|
|
617
|
+
const blank = sharedBlankCell(this.#attrs);
|
|
618
|
+
while (line.cells.length < this.cols) line.cells.push(blank);
|
|
532
619
|
this.#repairWideCells(line);
|
|
533
620
|
}
|
|
534
621
|
|
|
@@ -537,64 +624,67 @@ export class Terminal {
|
|
|
537
624
|
}
|
|
538
625
|
|
|
539
626
|
#clearWideAt(line: BufferLine, column: number): void {
|
|
540
|
-
|
|
541
|
-
if (
|
|
627
|
+
const width = line.cells[column]?.width;
|
|
628
|
+
if (width === 0 && column > 0) line.cells[column - 1] = sharedBlankCell(this.#attrs);
|
|
629
|
+
if (width === 2 && column + 1 < this.cols) line.cells[column + 1] = sharedBlankCell(this.#attrs);
|
|
542
630
|
}
|
|
543
631
|
|
|
544
632
|
#repairWideCells(line: BufferLine): void {
|
|
545
633
|
for (let column = 0; column < this.cols; column++) {
|
|
546
634
|
const cell = line.cells[column]!;
|
|
547
635
|
if (cell.width === 0 && (column === 0 || line.cells[column - 1]?.width !== 2))
|
|
548
|
-
line.cells[column] =
|
|
636
|
+
line.cells[column] = sharedBlankCell(this.#attrs);
|
|
549
637
|
if (cell.width === 2 && (column === this.cols - 1 || line.cells[column + 1]?.width !== 0))
|
|
550
|
-
line.cells[column] =
|
|
638
|
+
line.cells[column] = sharedBlankCell(this.#attrs);
|
|
551
639
|
}
|
|
552
640
|
}
|
|
553
641
|
|
|
554
642
|
#setRendition(values: number[]): void {
|
|
555
643
|
const params = values.length === 0 ? [0] : values;
|
|
644
|
+
// Copy-on-write: cells keep referencing the previous rendition object.
|
|
645
|
+
const attrs: CellAttributes = { ...this.#attrs };
|
|
556
646
|
for (let index = 0; index < params.length; index++) {
|
|
557
647
|
const code = params[index] ?? 0;
|
|
558
|
-
if (code === 0)
|
|
559
|
-
else if (code === 1)
|
|
560
|
-
else if (code === 2)
|
|
561
|
-
else if (code === 3)
|
|
562
|
-
else if (code === 4 || code === 21)
|
|
563
|
-
else if (code === 7)
|
|
564
|
-
else if (code === 9)
|
|
648
|
+
if (code === 0) Object.assign(attrs, DEFAULT_CELL_ATTRIBUTES);
|
|
649
|
+
else if (code === 1) attrs.bold = true;
|
|
650
|
+
else if (code === 2) attrs.dim = true;
|
|
651
|
+
else if (code === 3) attrs.italic = true;
|
|
652
|
+
else if (code === 4 || code === 21) attrs.underline = true;
|
|
653
|
+
else if (code === 7) attrs.inverse = true;
|
|
654
|
+
else if (code === 9) attrs.strikethrough = true;
|
|
565
655
|
else if (code === 22) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
} else if (code === 23)
|
|
569
|
-
else if (code === 24)
|
|
570
|
-
else if (code === 27)
|
|
571
|
-
else if (code === 29)
|
|
572
|
-
else if (code === 53)
|
|
573
|
-
else if (code === 55)
|
|
656
|
+
attrs.bold = false;
|
|
657
|
+
attrs.dim = false;
|
|
658
|
+
} else if (code === 23) attrs.italic = false;
|
|
659
|
+
else if (code === 24) attrs.underline = false;
|
|
660
|
+
else if (code === 27) attrs.inverse = false;
|
|
661
|
+
else if (code === 29) attrs.strikethrough = false;
|
|
662
|
+
else if (code === 53) attrs.overline = true;
|
|
663
|
+
else if (code === 55) attrs.overline = false;
|
|
574
664
|
else if (code >= 30 && code <= 37) {
|
|
575
|
-
|
|
576
|
-
|
|
665
|
+
attrs.fgMode = 1;
|
|
666
|
+
attrs.fg = code - 30;
|
|
577
667
|
} else if (code >= 40 && code <= 47) {
|
|
578
|
-
|
|
579
|
-
|
|
668
|
+
attrs.bgMode = 1;
|
|
669
|
+
attrs.bg = code - 40;
|
|
580
670
|
} else if (code >= 90 && code <= 97) {
|
|
581
|
-
|
|
582
|
-
|
|
671
|
+
attrs.fgMode = 1;
|
|
672
|
+
attrs.fg = code - 82;
|
|
583
673
|
} else if (code >= 100 && code <= 107) {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
} else if (code === 39)
|
|
587
|
-
else if (code === 49)
|
|
674
|
+
attrs.bgMode = 1;
|
|
675
|
+
attrs.bg = code - 92;
|
|
676
|
+
} else if (code === 39) attrs.fgMode = 0;
|
|
677
|
+
else if (code === 49) attrs.bgMode = 0;
|
|
588
678
|
else if (code === 38 || code === 48) {
|
|
589
679
|
const foreground = code === 38;
|
|
590
680
|
const mode = params[index + 1];
|
|
591
681
|
if (mode === 5 && params[index + 2] !== undefined) {
|
|
592
682
|
if (foreground) {
|
|
593
|
-
|
|
594
|
-
|
|
683
|
+
attrs.fgMode = 1;
|
|
684
|
+
attrs.fg = params[index + 2]! & 0xff;
|
|
595
685
|
} else {
|
|
596
|
-
|
|
597
|
-
|
|
686
|
+
attrs.bgMode = 1;
|
|
687
|
+
attrs.bg = params[index + 2]! & 0xff;
|
|
598
688
|
}
|
|
599
689
|
index += 2;
|
|
600
690
|
} else if (mode === 2 && params[index + 4] !== undefined) {
|
|
@@ -603,16 +693,18 @@ export class Terminal {
|
|
|
603
693
|
((params[index + 3]! & 0xff) << 8) |
|
|
604
694
|
(params[index + 4]! & 0xff);
|
|
605
695
|
if (foreground) {
|
|
606
|
-
|
|
607
|
-
|
|
696
|
+
attrs.fgMode = 2;
|
|
697
|
+
attrs.fg = color;
|
|
608
698
|
} else {
|
|
609
|
-
|
|
610
|
-
|
|
699
|
+
attrs.bgMode = 2;
|
|
700
|
+
attrs.bg = color;
|
|
611
701
|
}
|
|
612
702
|
index += 4;
|
|
613
703
|
}
|
|
614
704
|
}
|
|
615
705
|
}
|
|
706
|
+
if (sameAttributes(attrs, this.#attrs)) return;
|
|
707
|
+
this.#attrs = sameAttributes(attrs, DEFAULT_CELL_ATTRIBUTES) ? DEFAULT_CELL_ATTRIBUTES : Object.freeze(attrs);
|
|
616
708
|
}
|
|
617
709
|
|
|
618
710
|
#setScrollRegion(params: number[]): void {
|
|
@@ -643,21 +735,20 @@ export class Terminal {
|
|
|
643
735
|
}
|
|
644
736
|
|
|
645
737
|
#saveCursor(): void {
|
|
646
|
-
this.#saved = { x: this.#active.cursorX, y: this.#active.cursorY, attrs:
|
|
738
|
+
this.#saved = { x: this.#active.cursorX, y: this.#active.cursorY, attrs: this.#attrs };
|
|
647
739
|
}
|
|
648
740
|
|
|
649
741
|
#restoreCursor(): void {
|
|
650
742
|
if (!this.#saved) return;
|
|
651
743
|
this.#active.cursorX = Math.min(this.cols - 1, this.#saved.x);
|
|
652
744
|
this.#active.cursorY = Math.min(this.rows - 1, this.#saved.y);
|
|
653
|
-
this.#attrs =
|
|
745
|
+
this.#attrs = this.#saved.attrs;
|
|
654
746
|
this.#pendingWrap = false;
|
|
655
747
|
}
|
|
656
748
|
|
|
657
749
|
#enterAlternate(saveCursor: boolean): void {
|
|
658
750
|
if (this.#usingAlternate) return;
|
|
659
|
-
if (saveCursor)
|
|
660
|
-
this.#alternateSaved = { x: this.#normal.cursorX, y: this.#normal.cursorY, attrs: { ...this.#attrs } };
|
|
751
|
+
if (saveCursor) this.#alternateSaved = { x: this.#normal.cursorX, y: this.#normal.cursorY, attrs: this.#attrs };
|
|
661
752
|
this.#alternate = createState(this.cols, this.rows);
|
|
662
753
|
this.#active = this.#alternate;
|
|
663
754
|
this.#usingAlternate = true;
|
|
@@ -673,7 +764,7 @@ export class Terminal {
|
|
|
673
764
|
if (restoreCursor && this.#alternateSaved) {
|
|
674
765
|
this.#normal.cursorX = this.#alternateSaved.x;
|
|
675
766
|
this.#normal.cursorY = this.#alternateSaved.y;
|
|
676
|
-
this.#attrs =
|
|
767
|
+
this.#attrs = this.#alternateSaved.attrs;
|
|
677
768
|
}
|
|
678
769
|
this.#scrollTop = 0;
|
|
679
770
|
this.#scrollBottom = this.rows - 1;
|
|
@@ -681,7 +772,7 @@ export class Terminal {
|
|
|
681
772
|
}
|
|
682
773
|
|
|
683
774
|
#reset(): void {
|
|
684
|
-
this.#attrs =
|
|
775
|
+
this.#attrs = DEFAULT_CELL_ATTRIBUTES;
|
|
685
776
|
this.#normal = createState(this.cols, this.rows);
|
|
686
777
|
this.#alternate = createState(this.cols, this.rows);
|
|
687
778
|
this.#usingAlternate = false;
|
|
@@ -704,7 +795,8 @@ export class Terminal {
|
|
|
704
795
|
const group = groups.at(-1)!;
|
|
705
796
|
const used = line.isWrapped || state.lines[row + 1]?.isWrapped ? line.cells.length : this.#usedColumns(line);
|
|
706
797
|
if (row === absoluteCursor) group.cursorOffset = group.cells.length + state.cursorX;
|
|
707
|
-
|
|
798
|
+
// Cells are immutable, so the reflowed grid reuses them.
|
|
799
|
+
for (let column = 0; column < used; column++) group.cells.push(line.cells[column]!);
|
|
708
800
|
}
|
|
709
801
|
const lines: BufferLine[] = [];
|
|
710
802
|
let cursorAbsolute = 0;
|
|
@@ -725,8 +817,9 @@ export class Terminal {
|
|
|
725
817
|
continue;
|
|
726
818
|
}
|
|
727
819
|
if (cell.width === 2 && target === columns - 1) break;
|
|
728
|
-
line.cells[target] =
|
|
729
|
-
if (cell.width === 2)
|
|
820
|
+
line.cells[target] = cell;
|
|
821
|
+
if (cell.width === 2)
|
|
822
|
+
line.cells[target + 1] = Object.freeze({ chars: "", width: 0, attrs: cell.attrs });
|
|
730
823
|
target += cell.width;
|
|
731
824
|
source += cell.width;
|
|
732
825
|
}
|