vterm.js 0.6.1 → 0.7.1
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/README.md +63 -0
- package/dist/index.d.mts +36 -0
- package/dist/index.mjs +520 -277
- package/package.json +4 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/screen.ts
|
|
2
2
|
/** Default retained payload bound for one APC/DCS sequence (16 MiB of ASCII/base64). */
|
|
3
|
-
const DEFAULT_MAX_STRING_SEQUENCE_LENGTH =
|
|
3
|
+
const DEFAULT_MAX_STRING_SEQUENCE_LENGTH = 16777216;
|
|
4
4
|
/** Frozen sentinel for unwritten cells — never mutate, copy-on-write in writeChar(). */
|
|
5
5
|
const EMPTY_CELL = Object.freeze({
|
|
6
6
|
char: "",
|
|
@@ -17,6 +17,7 @@ const EMPTY_CELL = Object.freeze({
|
|
|
17
17
|
hidden: false,
|
|
18
18
|
blink: false,
|
|
19
19
|
wide: false,
|
|
20
|
+
protected: false,
|
|
20
21
|
url: null
|
|
21
22
|
});
|
|
22
23
|
function emptyCell() {
|
|
@@ -31,7 +32,7 @@ function emptyCell() {
|
|
|
31
32
|
* case), so the read path allocates nothing there.
|
|
32
33
|
*/
|
|
33
34
|
function stripColorIndex(c) {
|
|
34
|
-
if (c
|
|
35
|
+
if (c?.index === void 0) return c;
|
|
35
36
|
return {
|
|
36
37
|
r: c.r,
|
|
37
38
|
g: c.g,
|
|
@@ -57,11 +58,12 @@ const F_HIDDEN$1 = 64;
|
|
|
57
58
|
const F_BLINK$1 = 128;
|
|
58
59
|
const F_WIDE$1 = 256;
|
|
59
60
|
const UL_SHIFT$1 = 9;
|
|
60
|
-
const UL_MASK$1 =
|
|
61
|
+
const UL_MASK$1 = 3584;
|
|
61
62
|
const F_HAS_FG = 4096;
|
|
62
63
|
const F_HAS_BG = 8192;
|
|
63
64
|
const F_HAS_UL = 16384;
|
|
64
65
|
const F_HAS_URL = 32768;
|
|
66
|
+
const F_PROTECTED$1 = 65536;
|
|
65
67
|
const UL_STYLES = [
|
|
66
68
|
"none",
|
|
67
69
|
"single",
|
|
@@ -77,6 +79,17 @@ function underlineToBits(u) {
|
|
|
77
79
|
function bitsToUnderline(meta) {
|
|
78
80
|
return UL_STYLES[(meta & UL_MASK$1) >> UL_SHIFT$1] ?? "none";
|
|
79
81
|
}
|
|
82
|
+
/** Require an invariant-owned value and fail where the impossible state is first observed. */
|
|
83
|
+
function required(value, subject) {
|
|
84
|
+
if (value === null || value === void 0) throw new Error(`Missing ${subject}`);
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
/** Read a dense indexed value and fail at the violated invariant instead of propagating `undefined`. */
|
|
88
|
+
function itemAt(items, index, subject) {
|
|
89
|
+
const value = items[index];
|
|
90
|
+
if (value === void 0) throw new RangeError(`${subject}[${index}] is outside its ${items.length}-item range`);
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
80
93
|
/** Pack a color's 8-bit channels into a 24-bit `0xRRGGBB` word. */
|
|
81
94
|
function packRgb(c) {
|
|
82
95
|
return ((c.r & 255) << 16 | (c.g & 255) << 8 | c.b & 255) >>> 0;
|
|
@@ -108,7 +121,7 @@ function makePackedRow(width) {
|
|
|
108
121
|
let ulIdx = null;
|
|
109
122
|
let urlMap = null;
|
|
110
123
|
function setFg(col, c) {
|
|
111
|
-
if (fgRgb === null) {
|
|
124
|
+
if (fgRgb === null || fgIdx === null) {
|
|
112
125
|
fgRgb = new Uint32Array(width);
|
|
113
126
|
fgIdx = new Int16Array(width);
|
|
114
127
|
}
|
|
@@ -116,7 +129,7 @@ function makePackedRow(width) {
|
|
|
116
129
|
fgIdx[col] = c.index ?? -1;
|
|
117
130
|
}
|
|
118
131
|
function setBg(col, c) {
|
|
119
|
-
if (bgRgb === null) {
|
|
132
|
+
if (bgRgb === null || bgIdx === null) {
|
|
120
133
|
bgRgb = new Uint32Array(width);
|
|
121
134
|
bgIdx = new Int16Array(width);
|
|
122
135
|
}
|
|
@@ -124,7 +137,7 @@ function makePackedRow(width) {
|
|
|
124
137
|
bgIdx[col] = c.index ?? -1;
|
|
125
138
|
}
|
|
126
139
|
function setUl(col, c) {
|
|
127
|
-
if (ulRgb === null) {
|
|
140
|
+
if (ulRgb === null || ulIdx === null) {
|
|
128
141
|
ulRgb = new Uint32Array(width);
|
|
129
142
|
ulIdx = new Int16Array(width);
|
|
130
143
|
}
|
|
@@ -147,6 +160,7 @@ function makePackedRow(width) {
|
|
|
147
160
|
if (a.inverse) m |= F_INVERSE$1;
|
|
148
161
|
if (a.hidden) m |= F_HIDDEN$1;
|
|
149
162
|
if (a.blink) m |= F_BLINK$1;
|
|
163
|
+
if (a.protected) m |= F_PROTECTED$1;
|
|
150
164
|
if (wide) m |= F_WIDE$1;
|
|
151
165
|
return m | underlineToBits(a.underline);
|
|
152
166
|
}
|
|
@@ -208,34 +222,35 @@ function makePackedRow(width) {
|
|
|
208
222
|
} else meta[col] = 0;
|
|
209
223
|
},
|
|
210
224
|
widen(col) {
|
|
211
|
-
meta[col] = (meta
|
|
225
|
+
meta[col] = (itemAt(meta, col, "packed row metadata") | F_WIDE$1) >>> 0;
|
|
212
226
|
if (col + 1 < width) row.setEmpty(col + 1);
|
|
213
227
|
},
|
|
214
228
|
appendChar(col, ch) {
|
|
215
|
-
chars[col] = chars
|
|
229
|
+
chars[col] = itemAt(chars, col, "packed row characters") + ch;
|
|
216
230
|
},
|
|
217
231
|
copyCellFrom(col, src, srcCol) {
|
|
218
232
|
row.setCellRaw(col, src.getCellRaw(srcCol));
|
|
219
233
|
},
|
|
220
234
|
getCellRaw(col) {
|
|
221
|
-
const m = meta
|
|
235
|
+
const m = itemAt(meta, col, "packed row metadata");
|
|
222
236
|
if (m === 0 && chars[col] === "") return emptyCell();
|
|
223
237
|
return {
|
|
224
|
-
char: chars
|
|
225
|
-
fg: m & F_HAS_FG ? unpackColor(fgRgb
|
|
226
|
-
bg: m & F_HAS_BG ? unpackColor(bgRgb
|
|
238
|
+
char: itemAt(chars, col, "packed row characters"),
|
|
239
|
+
fg: m & F_HAS_FG ? unpackColor(itemAt(required(fgRgb, "foreground color plane"), col, "foreground color plane"), itemAt(required(fgIdx, "foreground color index plane"), col, "foreground color index plane")) : null,
|
|
240
|
+
bg: m & F_HAS_BG ? unpackColor(itemAt(required(bgRgb, "background color plane"), col, "background color plane"), itemAt(required(bgIdx, "background color index plane"), col, "background color index plane")) : null,
|
|
227
241
|
bold: (m & F_BOLD$1) !== 0,
|
|
228
242
|
faint: (m & F_FAINT$1) !== 0,
|
|
229
243
|
italic: (m & F_ITALIC$1) !== 0,
|
|
230
244
|
underline: bitsToUnderline(m),
|
|
231
|
-
underlineColor: m & F_HAS_UL ? unpackColor(ulRgb
|
|
245
|
+
underlineColor: m & F_HAS_UL ? unpackColor(itemAt(required(ulRgb, "underline color plane"), col, "underline color plane"), itemAt(required(ulIdx, "underline color index plane"), col, "underline color index plane")) : null,
|
|
232
246
|
overline: (m & F_OVERLINE$1) !== 0,
|
|
233
247
|
strikethrough: (m & F_STRIKE$1) !== 0,
|
|
234
248
|
inverse: (m & F_INVERSE$1) !== 0,
|
|
235
249
|
hidden: (m & F_HIDDEN$1) !== 0,
|
|
236
250
|
blink: (m & F_BLINK$1) !== 0,
|
|
251
|
+
protected: (m & F_PROTECTED$1) !== 0,
|
|
237
252
|
wide: (m & F_WIDE$1) !== 0,
|
|
238
|
-
url: m & F_HAS_URL ? urlMap.get(col) ?? null : null
|
|
253
|
+
url: m & F_HAS_URL ? required(urlMap, "packed row URL map").get(col) ?? null : null
|
|
239
254
|
};
|
|
240
255
|
},
|
|
241
256
|
toCells() {
|
|
@@ -250,10 +265,10 @@ function makePackedRow(width) {
|
|
|
250
265
|
return meta[col] === 0 && chars[col] === "";
|
|
251
266
|
},
|
|
252
267
|
getChar(col) {
|
|
253
|
-
return chars
|
|
268
|
+
return itemAt(chars, col, "packed row characters");
|
|
254
269
|
},
|
|
255
270
|
isWide(col) {
|
|
256
|
-
return (meta
|
|
271
|
+
return (itemAt(meta, col, "packed row metadata") & F_WIDE$1) !== 0;
|
|
257
272
|
}
|
|
258
273
|
};
|
|
259
274
|
return row;
|
|
@@ -357,9 +372,9 @@ function buildPalette256() {
|
|
|
357
372
|
255
|
|
358
373
|
];
|
|
359
374
|
for (let r = 0; r < 6; r++) for (let g = 0; g < 6; g++) for (let b = 0; b < 6; b++) palette.push({
|
|
360
|
-
r: levels
|
|
361
|
-
g: levels
|
|
362
|
-
b: levels
|
|
375
|
+
r: itemAt(levels, r, "ANSI cube red levels"),
|
|
376
|
+
g: itemAt(levels, g, "ANSI cube green levels"),
|
|
377
|
+
b: itemAt(levels, b, "ANSI cube blue levels")
|
|
363
378
|
});
|
|
364
379
|
for (let i = 0; i < 24; i++) {
|
|
365
380
|
const v = 8 + i * 10;
|
|
@@ -385,14 +400,14 @@ function parseColorSpec(spec) {
|
|
|
385
400
|
return Math.round(v * 255 / max);
|
|
386
401
|
};
|
|
387
402
|
return {
|
|
388
|
-
r: scale(rgbMatch
|
|
389
|
-
g: scale(rgbMatch
|
|
390
|
-
b: scale(rgbMatch
|
|
403
|
+
r: scale(itemAt(rgbMatch, 1, "X11 red capture")),
|
|
404
|
+
g: scale(itemAt(rgbMatch, 2, "X11 green capture")),
|
|
405
|
+
b: scale(itemAt(rgbMatch, 3, "X11 blue capture"))
|
|
391
406
|
};
|
|
392
407
|
}
|
|
393
408
|
const hex6 = /^#([0-9a-fA-F]{6})$/.exec(s);
|
|
394
409
|
if (hex6) {
|
|
395
|
-
const v = hex6
|
|
410
|
+
const v = itemAt(hex6, 1, "six-digit hex capture");
|
|
396
411
|
return {
|
|
397
412
|
r: parseInt(v.substring(0, 2), 16),
|
|
398
413
|
g: parseInt(v.substring(2, 4), 16),
|
|
@@ -401,12 +416,12 @@ function parseColorSpec(spec) {
|
|
|
401
416
|
}
|
|
402
417
|
const hex3 = /^#([0-9a-fA-F]{3})$/.exec(s);
|
|
403
418
|
if (hex3) {
|
|
404
|
-
const v = hex3
|
|
419
|
+
const v = itemAt(hex3, 1, "three-digit hex capture");
|
|
405
420
|
const expand = (ch) => parseInt(ch + ch, 16);
|
|
406
421
|
return {
|
|
407
|
-
r: expand(v
|
|
408
|
-
g: expand(v
|
|
409
|
-
b: expand(v
|
|
422
|
+
r: expand(itemAt(v, 0, "short hex red channel")),
|
|
423
|
+
g: expand(itemAt(v, 1, "short hex green channel")),
|
|
424
|
+
b: expand(itemAt(v, 2, "short hex blue channel"))
|
|
410
425
|
};
|
|
411
426
|
}
|
|
412
427
|
return null;
|
|
@@ -480,7 +495,9 @@ function createScreen(options = {}) {
|
|
|
480
495
|
attrs: resetAttrs(),
|
|
481
496
|
originMode: false,
|
|
482
497
|
autoWrap: true,
|
|
483
|
-
charsetG0: false
|
|
498
|
+
charsetG0: false,
|
|
499
|
+
charsetG1: false,
|
|
500
|
+
activeG1: false
|
|
484
501
|
};
|
|
485
502
|
let savedCurX = 0;
|
|
486
503
|
let savedCurY = 0;
|
|
@@ -497,6 +514,7 @@ function createScreen(options = {}) {
|
|
|
497
514
|
let focusTracking = false;
|
|
498
515
|
let originMode = false;
|
|
499
516
|
let insertMode = false;
|
|
517
|
+
let newLineMode = false;
|
|
500
518
|
let reverseVideo = false;
|
|
501
519
|
let syncOutput = false;
|
|
502
520
|
let kittyKeyboardFlags = 0;
|
|
@@ -658,6 +676,8 @@ function createScreen(options = {}) {
|
|
|
658
676
|
assertBoolean("savedState.originMode", saved.originMode);
|
|
659
677
|
assertBoolean("savedState.autoWrap", saved.autoWrap);
|
|
660
678
|
assertBoolean("savedState.charsetG0", saved.charsetG0);
|
|
679
|
+
if (Object.hasOwn(saved, "charsetG1")) assertBoolean("savedState.charsetG1", saved.charsetG1);
|
|
680
|
+
if (Object.hasOwn(saved, "activeG1")) assertBoolean("savedState.activeG1", saved.activeG1);
|
|
661
681
|
assertRecord("attrs", value.attrs);
|
|
662
682
|
const modes = value.modes;
|
|
663
683
|
assertRecord("modes", modes);
|
|
@@ -740,6 +760,8 @@ function createScreen(options = {}) {
|
|
|
740
760
|
const unicode = value.unicode;
|
|
741
761
|
assertRecord("unicode", unicode);
|
|
742
762
|
assertBoolean("unicode.charsetG0", unicode.charsetG0);
|
|
763
|
+
if (Object.hasOwn(unicode, "charsetG1")) assertBoolean("unicode.charsetG1", unicode.charsetG1);
|
|
764
|
+
if (Object.hasOwn(unicode, "activeG1")) assertBoolean("unicode.activeG1", unicode.activeG1);
|
|
743
765
|
assertString("unicode.lastChar", unicode.lastChar);
|
|
744
766
|
if (unicode.pendingRegionalIndicator !== null) assertString("unicode.pendingRegionalIndicator", unicode.pendingRegionalIndicator);
|
|
745
767
|
assertBoolean("unicode.afterZWJ", unicode.afterZWJ);
|
|
@@ -769,6 +791,8 @@ function createScreen(options = {}) {
|
|
|
769
791
|
let advancedClipboard = "";
|
|
770
792
|
let viewportOffset = 0;
|
|
771
793
|
let charsetG0 = false;
|
|
794
|
+
let charsetG1 = false;
|
|
795
|
+
let activeG1 = false;
|
|
772
796
|
let clipboard = "";
|
|
773
797
|
let cwd = "";
|
|
774
798
|
let notifications = [];
|
|
@@ -778,7 +802,68 @@ function createScreen(options = {}) {
|
|
|
778
802
|
let mainSoftWrapped = new Array(rows).fill(false);
|
|
779
803
|
let altSoftWrapped = new Array(rows).fill(false);
|
|
780
804
|
let softWrapped = mainSoftWrapped;
|
|
805
|
+
let mainLineAttrs = new Array(rows).fill(0);
|
|
806
|
+
let altLineAttrs = new Array(rows).fill(0);
|
|
807
|
+
let lineAttrs = mainLineAttrs;
|
|
781
808
|
let scrollbackSoftWrapped = [];
|
|
809
|
+
let scrollbackLineAttrs = [];
|
|
810
|
+
/**
|
|
811
|
+
* Drop every banked scrollback row AND its soft-wrap flag.
|
|
812
|
+
*
|
|
813
|
+
* These two arrays are one data structure wearing two names, and nothing in
|
|
814
|
+
* the type system says so. `ESC [ 3 J` (erase display + scrollback) once
|
|
815
|
+
* emptied the rows and left the flags, which diverged the pair permanently
|
|
816
|
+
* by however many rows were banked at that instant. Every later push
|
|
817
|
+
* extended both and preserved the gap, so the snapshot codec refused to
|
|
818
|
+
* write a frame — `soft-wrap length 3580 != rowCount 2103` — and the seat
|
|
819
|
+
* kept running with its recording silently ended
|
|
820
|
+
* (@i/5-agent-loop/vterm-codec-ends-recording).
|
|
821
|
+
*
|
|
822
|
+
* `ESC [ 3 J` is not exotic: `clear` emits it on a modern terminal. Every
|
|
823
|
+
* clear goes through here so the pairing is structural rather than
|
|
824
|
+
* remembered at each call site.
|
|
825
|
+
*/
|
|
826
|
+
/** Dense per-row attributes -> sparse `[row, attr]` pairs, skipping normal rows. */
|
|
827
|
+
function toSparseAttrs(dense) {
|
|
828
|
+
const out = [];
|
|
829
|
+
for (let r = 0; r < dense.length; r++) {
|
|
830
|
+
const a = dense[r] ?? 0;
|
|
831
|
+
if (a !== 0) out.push([r, a]);
|
|
832
|
+
}
|
|
833
|
+
return out;
|
|
834
|
+
}
|
|
835
|
+
/** Sparse pairs -> a dense array of `length`; out-of-range rows are dropped. */
|
|
836
|
+
function fromSparseAttrs(sparse, length) {
|
|
837
|
+
const dense = new Array(length).fill(0);
|
|
838
|
+
for (const pair of sparse ?? []) {
|
|
839
|
+
const [r, a] = pair;
|
|
840
|
+
if (Number.isInteger(r) && r >= 0 && r < length) dense[r] = a;
|
|
841
|
+
}
|
|
842
|
+
return dense;
|
|
843
|
+
}
|
|
844
|
+
function clearScrollback() {
|
|
845
|
+
scrollback.length = 0;
|
|
846
|
+
scrollbackSoftWrapped.length = 0;
|
|
847
|
+
scrollbackLineAttrs.length = 0;
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Bank one row into scrollback, trimming to the limit. Returns how many rows
|
|
851
|
+
* were trimmed off the front so a caller tracking absolute rows can rebase.
|
|
852
|
+
*
|
|
853
|
+
* Every scrollback mutation goes through a helper that moves BOTH arrays —
|
|
854
|
+
* see `clearScrollback` for what one unpaired mutation cost.
|
|
855
|
+
*/
|
|
856
|
+
function bankScrollbackRow(row, wrapped, lineAttr) {
|
|
857
|
+
scrollback.push(row);
|
|
858
|
+
scrollbackSoftWrapped.push(wrapped);
|
|
859
|
+
scrollbackLineAttrs.push(lineAttr);
|
|
860
|
+
if (scrollback.length <= scrollbackLimit * 2) return 0;
|
|
861
|
+
const over = scrollback.length - scrollbackLimit;
|
|
862
|
+
scrollback.splice(0, over);
|
|
863
|
+
scrollbackSoftWrapped.splice(0, over);
|
|
864
|
+
scrollbackLineAttrs.splice(0, over);
|
|
865
|
+
return over;
|
|
866
|
+
}
|
|
782
867
|
let lastChar = "";
|
|
783
868
|
let pendingRegionalIndicator = null;
|
|
784
869
|
let afterZWJ = false;
|
|
@@ -873,13 +958,12 @@ function createScreen(options = {}) {
|
|
|
873
958
|
if (bytes.length === 0) return 0;
|
|
874
959
|
let continuationCount = 0;
|
|
875
960
|
let leadIndex = bytes.length - 1;
|
|
876
|
-
while (leadIndex >= 0 && (bytes
|
|
961
|
+
while (leadIndex >= 0 && (itemAt(bytes, leadIndex, "UTF-8 pending bytes") & 192) === 128 && continuationCount < 3) {
|
|
877
962
|
continuationCount++;
|
|
878
963
|
leadIndex--;
|
|
879
964
|
}
|
|
880
965
|
if (leadIndex < 0) return bytes.length;
|
|
881
|
-
const
|
|
882
|
-
const expectedLength = utf8SequenceLength(lead);
|
|
966
|
+
const expectedLength = utf8SequenceLength(itemAt(bytes, leadIndex, "UTF-8 lead byte"));
|
|
883
967
|
if (expectedLength === 0) return bytes.length;
|
|
884
968
|
return expectedLength > bytes.length - leadIndex ? leadIndex : bytes.length;
|
|
885
969
|
}
|
|
@@ -912,6 +996,16 @@ function createScreen(options = {}) {
|
|
|
912
996
|
fn(cells);
|
|
913
997
|
row.replaceAllFromCells(cells);
|
|
914
998
|
}
|
|
999
|
+
/**
|
|
1000
|
+
* SGR 0 resets the pen but NOT DECSCA: character protection is independent
|
|
1001
|
+
* of SGR, and is cleared only by DECSTR/RIS. Using the full `resetAttrs()`
|
|
1002
|
+
* here would let any `ESC [ 0 m` silently unprotect subsequent writes.
|
|
1003
|
+
*/
|
|
1004
|
+
function resetSgrAttrs() {
|
|
1005
|
+
const next = resetAttrs();
|
|
1006
|
+
next.protected = attrs.protected;
|
|
1007
|
+
return next;
|
|
1008
|
+
}
|
|
915
1009
|
function resetAttrs() {
|
|
916
1010
|
return {
|
|
917
1011
|
fg: null,
|
|
@@ -926,37 +1020,69 @@ function createScreen(options = {}) {
|
|
|
926
1020
|
inverse: false,
|
|
927
1021
|
hidden: false,
|
|
928
1022
|
blink: false,
|
|
929
|
-
url: null
|
|
1023
|
+
url: null,
|
|
1024
|
+
protected: false
|
|
930
1025
|
};
|
|
931
1026
|
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Usable columns on a row. A DEC double-width line (DECDWL/DECDHL) renders
|
|
1029
|
+
* each cell twice as wide, so the row addresses and wraps at half the
|
|
1030
|
+
* terminal's columns — an 80-column screen wraps a double-width line at 40.
|
|
1031
|
+
*/
|
|
1032
|
+
function rowCols(row) {
|
|
1033
|
+
return (lineAttrs[row] ?? 0) === 0 ? cols : cols >> 1;
|
|
1034
|
+
}
|
|
932
1035
|
function clampCursor() {
|
|
933
1036
|
if (curX < 0) curX = 0;
|
|
934
|
-
if (curX >= cols) curX = cols - 1;
|
|
935
1037
|
if (curY < 0) curY = 0;
|
|
936
1038
|
if (curY >= rows) curY = rows - 1;
|
|
1039
|
+
const usable = rowCols(curY);
|
|
1040
|
+
if (curX >= usable) curX = usable - 1;
|
|
1041
|
+
if (originMode) {
|
|
1042
|
+
if (curY < scrollTop) curY = scrollTop;
|
|
1043
|
+
if (curY > scrollBottom) curY = scrollBottom;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Move the cursor down one line, scrolling ONLY at the region's bottom edge.
|
|
1048
|
+
*
|
|
1049
|
+
* `curY++; if (curY > scrollBottom) { curY = scrollBottom; scrollUp() }`
|
|
1050
|
+
* looks equivalent and is not. From a row BELOW the scrolling region it
|
|
1051
|
+
* clamps the cursor BACKWARDS into the region and scrolls a region the
|
|
1052
|
+
* cursor was never in — with DECSTBM at 1;10, a linefeed from row 19 landed
|
|
1053
|
+
* on row 9 instead of row 20.
|
|
1054
|
+
*
|
|
1055
|
+
* DECSTBM confines SCROLLING, not movement: a cursor outside the region
|
|
1056
|
+
* simply walks the screen.
|
|
1057
|
+
*/
|
|
1058
|
+
function lineFeedDown() {
|
|
1059
|
+
if (curY === scrollBottom) scrollUp(scrollTop, scrollBottom);
|
|
1060
|
+
else if (curY < rows - 1) curY++;
|
|
1061
|
+
}
|
|
1062
|
+
/** RI's mirror: scroll only at the region's top edge, else walk up. */
|
|
1063
|
+
function reverseIndexUp() {
|
|
1064
|
+
if (curY === scrollTop) scrollDown(scrollTop, scrollBottom);
|
|
1065
|
+
else if (curY > 0) curY--;
|
|
937
1066
|
}
|
|
938
1067
|
function scrollUp(top, bottom) {
|
|
939
1068
|
if (leftRightMarginMode && (leftMargin > 0 || rightMargin < cols - 1)) {
|
|
940
1069
|
const lm = leftMargin;
|
|
941
1070
|
const rm = rightMargin;
|
|
942
1071
|
for (let r = top; r < bottom; r++) {
|
|
943
|
-
const srcRow = grid
|
|
944
|
-
const dstRow = grid
|
|
1072
|
+
const srcRow = itemAt(grid, r + 1, "scroll source rows");
|
|
1073
|
+
const dstRow = itemAt(grid, r, "scroll destination rows");
|
|
945
1074
|
for (let c = lm; c <= rm && c < cols; c++) dstRow.copyCellFrom(c, srcRow, c);
|
|
946
1075
|
}
|
|
947
|
-
const bottomRow = grid
|
|
1076
|
+
const bottomRow = itemAt(grid, bottom, "scroll bottom row");
|
|
948
1077
|
for (let c = lm; c <= rm && c < cols; c++) bottomRow.setEmpty(c);
|
|
949
1078
|
markScreenRowsDirty(top, bottom);
|
|
950
1079
|
} else {
|
|
951
1080
|
const enteredScrollback = grid === mainGrid && top === 0;
|
|
952
1081
|
if (enteredScrollback) {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
markAbsoluteRowDirty(scrollback.length - 1);
|
|
956
|
-
if (
|
|
957
|
-
const over = scrollback.length - scrollbackLimit;
|
|
958
|
-
scrollback.splice(0, over);
|
|
959
|
-
scrollbackSoftWrapped.splice(0, over);
|
|
1082
|
+
const banked = grid[0];
|
|
1083
|
+
const over = banked === void 0 ? 0 : bankScrollbackRow(banked, softWrapped[0] ?? false, lineAttrs[0] ?? 0);
|
|
1084
|
+
markAbsoluteRowDirty(scrollback.length - 1 + over);
|
|
1085
|
+
if (over > 0) {
|
|
960
1086
|
if (!dirtyAll && dirtyRows.size > 0) {
|
|
961
1087
|
const shifted = /* @__PURE__ */ new Set();
|
|
962
1088
|
for (const r of dirtyRows) if (r >= over) shifted.add(r - over);
|
|
@@ -990,16 +1116,16 @@ function createScreen(options = {}) {
|
|
|
990
1116
|
const lm = leftMargin;
|
|
991
1117
|
const rm = rightMargin;
|
|
992
1118
|
for (let r = bottom; r > top; r--) {
|
|
993
|
-
const srcRow = grid
|
|
994
|
-
const dstRow = grid
|
|
1119
|
+
const srcRow = itemAt(grid, r - 1, "reverse-scroll source rows");
|
|
1120
|
+
const dstRow = itemAt(grid, r, "reverse-scroll destination rows");
|
|
995
1121
|
for (let c = lm; c <= rm && c < cols; c++) dstRow.copyCellFrom(c, srcRow, c);
|
|
996
1122
|
}
|
|
997
|
-
const topRow = grid
|
|
1123
|
+
const topRow = itemAt(grid, top, "reverse-scroll top row");
|
|
998
1124
|
for (let c = lm; c <= rm && c < cols; c++) topRow.setEmpty(c);
|
|
999
1125
|
} else {
|
|
1000
1126
|
for (let i = bottom; i > top; i--) {
|
|
1001
|
-
grid[i] = grid
|
|
1002
|
-
softWrapped[i] = softWrapped
|
|
1127
|
+
grid[i] = itemAt(grid, i - 1, "reverse-scroll source rows");
|
|
1128
|
+
softWrapped[i] = itemAt(softWrapped, i - 1, "reverse-scroll source wrap flags");
|
|
1003
1129
|
}
|
|
1004
1130
|
grid[top] = makeRow(cols);
|
|
1005
1131
|
softWrapped[top] = false;
|
|
@@ -1024,7 +1150,7 @@ function createScreen(options = {}) {
|
|
|
1024
1150
|
if (prevRow < 0) return null;
|
|
1025
1151
|
prevCol = cols - 1;
|
|
1026
1152
|
}
|
|
1027
|
-
const row = grid
|
|
1153
|
+
const row = itemAt(grid, prevRow, "previous-cell rows");
|
|
1028
1154
|
if (prevCol > 0 && row.getChar(prevCol) === "" && row.isWide(prevCol - 1)) prevCol--;
|
|
1029
1155
|
if (row.isEmpty(prevCol)) return null;
|
|
1030
1156
|
return {
|
|
@@ -1038,7 +1164,7 @@ function createScreen(options = {}) {
|
|
|
1038
1164
|
row.widen(col);
|
|
1039
1165
|
}
|
|
1040
1166
|
function writeChar(ch) {
|
|
1041
|
-
if (charsetG0 && ch.length === 1) {
|
|
1167
|
+
if ((activeG1 ? charsetG1 : charsetG0) && ch.length === 1) {
|
|
1042
1168
|
const mapped = DEC_SPECIAL_GRAPHICS[ch];
|
|
1043
1169
|
if (mapped) ch = mapped;
|
|
1044
1170
|
}
|
|
@@ -1088,14 +1214,16 @@ function createScreen(options = {}) {
|
|
|
1088
1214
|
return;
|
|
1089
1215
|
}
|
|
1090
1216
|
}
|
|
1091
|
-
if (isRegionalIndicator(codePoint))
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1217
|
+
if (isRegionalIndicator(codePoint)) {
|
|
1218
|
+
if (pendingRegionalIndicator !== null) {
|
|
1219
|
+
const flag = pendingRegionalIndicator + ch;
|
|
1220
|
+
pendingRegionalIndicator = null;
|
|
1221
|
+
writeCharCore(flag, true);
|
|
1222
|
+
return;
|
|
1223
|
+
} else {
|
|
1224
|
+
pendingRegionalIndicator = ch;
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1099
1227
|
}
|
|
1100
1228
|
if (pendingRegionalIndicator !== null) {
|
|
1101
1229
|
const ri = pendingRegionalIndicator;
|
|
@@ -1108,20 +1236,22 @@ function createScreen(options = {}) {
|
|
|
1108
1236
|
function writeCharCore(ch, wide) {
|
|
1109
1237
|
if (cols <= 0 || rows <= 0) return;
|
|
1110
1238
|
const charWidth = wide ? 2 : 1;
|
|
1111
|
-
const wrapBoundary = leftRightMarginMode ? rightMargin + 1 :
|
|
1239
|
+
const wrapBoundary = leftRightMarginMode ? rightMargin + 1 : rowCols(curY);
|
|
1112
1240
|
const wrapReturn = leftRightMarginMode ? leftMargin : 0;
|
|
1113
|
-
if (curX + charWidth > wrapBoundary)
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
curY
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1241
|
+
if (curX + charWidth > wrapBoundary) {
|
|
1242
|
+
if (autoWrap) {
|
|
1243
|
+
softWrapped[curY] = true;
|
|
1244
|
+
curX = wrapReturn;
|
|
1245
|
+
curY++;
|
|
1246
|
+
if (curY > scrollBottom) {
|
|
1247
|
+
curY = scrollBottom;
|
|
1248
|
+
scrollUp(scrollTop, scrollBottom);
|
|
1249
|
+
}
|
|
1250
|
+
} else curX = wrapBoundary - charWidth;
|
|
1251
|
+
}
|
|
1122
1252
|
if (insertMode) {
|
|
1123
1253
|
const insertEnd = leftRightMarginMode ? rightMargin + 1 : cols;
|
|
1124
|
-
mutateRowAsCells(grid
|
|
1254
|
+
mutateRowAsCells(itemAt(grid, curY, "cursor row"), (cells) => {
|
|
1125
1255
|
for (let i = 0; i < charWidth; i++) {
|
|
1126
1256
|
cells.splice(insertEnd - 1, 1);
|
|
1127
1257
|
cells.splice(curX, 0, emptyCell());
|
|
@@ -1133,6 +1263,7 @@ function createScreen(options = {}) {
|
|
|
1133
1263
|
if (wide) widenCell(row, curX);
|
|
1134
1264
|
markScreenRowDirty(curY);
|
|
1135
1265
|
curX += charWidth;
|
|
1266
|
+
if (!autoWrap && curX >= wrapBoundary) curX = wrapBoundary - 1;
|
|
1136
1267
|
lastChar = ch;
|
|
1137
1268
|
}
|
|
1138
1269
|
function handleCSI(params, intermediates, finalByte) {
|
|
@@ -1163,12 +1294,15 @@ function createScreen(options = {}) {
|
|
|
1163
1294
|
case 6:
|
|
1164
1295
|
cursorShape = "bar";
|
|
1165
1296
|
cursorBlinking = false;
|
|
1166
|
-
break;
|
|
1167
1297
|
}
|
|
1168
1298
|
else if (finalByte === "@") handleShiftLeft(Math.max(parts[0] ?? 1, 1));
|
|
1169
1299
|
else if (finalByte === "A") handleShiftRight(Math.max(parts[0] ?? 1, 1));
|
|
1170
1300
|
return;
|
|
1171
1301
|
}
|
|
1302
|
+
if (intermediates === "\"" && finalByte === "q") {
|
|
1303
|
+
attrs.protected = (parts[0] ?? 0) === 1;
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1172
1306
|
if (intermediates === "!") {
|
|
1173
1307
|
if (finalByte === "p") softReset();
|
|
1174
1308
|
return;
|
|
@@ -1188,7 +1322,7 @@ function createScreen(options = {}) {
|
|
|
1188
1322
|
const { t, l, b, r } = normalizeRect(parts[1] ?? 1, parts[2] ?? 1, parts[3] ?? rows, parts[4] ?? cols);
|
|
1189
1323
|
const fillChar = String.fromCharCode(charCode);
|
|
1190
1324
|
for (let row = t; row <= b && row < rows; row++) {
|
|
1191
|
-
const gr = grid
|
|
1325
|
+
const gr = itemAt(grid, row, "rectangular erase rows");
|
|
1192
1326
|
for (let col = l; col <= r && col < cols; col++) {
|
|
1193
1327
|
const cell = emptyCell();
|
|
1194
1328
|
cell.char = fillChar;
|
|
@@ -1199,7 +1333,7 @@ function createScreen(options = {}) {
|
|
|
1199
1333
|
} else if (finalByte === "z" || finalByte === "{") {
|
|
1200
1334
|
const { t, l, b, r } = normalizeRect(parts[0] ?? 1, parts[1] ?? 1, parts[2] ?? rows, parts[3] ?? cols);
|
|
1201
1335
|
for (let row = t; row <= b && row < rows; row++) {
|
|
1202
|
-
const gr = grid
|
|
1336
|
+
const gr = itemAt(grid, row, "rectangular fill rows");
|
|
1203
1337
|
for (let col = l; col <= r && col < cols; col++) gr.setEmpty(col);
|
|
1204
1338
|
}
|
|
1205
1339
|
markScreenRowsDirty(t, Math.min(b, rows - 1));
|
|
@@ -1219,11 +1353,11 @@ function createScreen(options = {}) {
|
|
|
1219
1353
|
for (let row = 0; row < h; row++) {
|
|
1220
1354
|
const dr = dstTop + row;
|
|
1221
1355
|
if (dr < 0 || dr >= rows) continue;
|
|
1222
|
-
const dstRow = grid
|
|
1356
|
+
const dstRow = itemAt(grid, dr, "rectangular copy destination rows");
|
|
1223
1357
|
for (let col = 0; col < w; col++) {
|
|
1224
1358
|
const dc = dstLeft + col;
|
|
1225
1359
|
if (dc < 0 || dc >= cols) continue;
|
|
1226
|
-
dstRow.setCellRaw(dc, snapshot
|
|
1360
|
+
dstRow.setCellRaw(dc, itemAt(itemAt(snapshot, row, "rectangular copy rows"), col, "rectangular copy cells"));
|
|
1227
1361
|
}
|
|
1228
1362
|
}
|
|
1229
1363
|
markScreenRowsDirty(Math.max(0, dstTop), Math.min(dstTop + h - 1, rows - 1));
|
|
@@ -1232,7 +1366,7 @@ function createScreen(options = {}) {
|
|
|
1232
1366
|
const sgrParts = parts.slice(4);
|
|
1233
1367
|
const reverse = finalByte === "t";
|
|
1234
1368
|
for (let row = t; row <= b && row < rows; row++) {
|
|
1235
|
-
const gr = grid
|
|
1369
|
+
const gr = itemAt(grid, row, "rectangular attribute rows");
|
|
1236
1370
|
for (let col = l; col <= r && col < cols; col++) {
|
|
1237
1371
|
const cell = gr.getCellRaw(col);
|
|
1238
1372
|
applyRectAttrs(cell, sgrParts, reverse);
|
|
@@ -1278,18 +1412,22 @@ function createScreen(options = {}) {
|
|
|
1278
1412
|
}
|
|
1279
1413
|
switch (finalByte) {
|
|
1280
1414
|
case "A":
|
|
1415
|
+
case "k":
|
|
1281
1416
|
curY -= Math.max(parts[0] ?? 1, 1);
|
|
1282
1417
|
clampCursor();
|
|
1283
1418
|
break;
|
|
1284
1419
|
case "B":
|
|
1420
|
+
case "e":
|
|
1285
1421
|
curY += Math.max(parts[0] ?? 1, 1);
|
|
1286
1422
|
clampCursor();
|
|
1287
1423
|
break;
|
|
1288
1424
|
case "C":
|
|
1425
|
+
case "a":
|
|
1289
1426
|
curX += Math.max(parts[0] ?? 1, 1);
|
|
1290
1427
|
clampCursor();
|
|
1291
1428
|
break;
|
|
1292
1429
|
case "D":
|
|
1430
|
+
case "j":
|
|
1293
1431
|
curX -= Math.max(parts[0] ?? 1, 1);
|
|
1294
1432
|
clampCursor();
|
|
1295
1433
|
break;
|
|
@@ -1342,21 +1480,21 @@ function createScreen(options = {}) {
|
|
|
1342
1480
|
case 20:
|
|
1343
1481
|
onResponse(`\x1b]L${title}\x1b\\`);
|
|
1344
1482
|
break;
|
|
1345
|
-
case 21:
|
|
1346
|
-
onResponse(`\x1b]l${title}\x1b\\`);
|
|
1347
|
-
break;
|
|
1483
|
+
case 21: onResponse(`\x1b]l${title}\x1b\\`);
|
|
1348
1484
|
}
|
|
1349
1485
|
break;
|
|
1350
1486
|
}
|
|
1351
1487
|
case "H":
|
|
1352
1488
|
case "f":
|
|
1353
1489
|
if (originMode) {
|
|
1490
|
+
const originX = leftRightMarginMode ? leftMargin : 0;
|
|
1491
|
+
const limitX = leftRightMarginMode ? rightMargin : cols - 1;
|
|
1354
1492
|
curY = scrollTop + (parts[0] ?? 1) - 1;
|
|
1355
|
-
curX = (parts[1] ?? 1) - 1;
|
|
1493
|
+
curX = originX + (parts[1] ?? 1) - 1;
|
|
1356
1494
|
if (curY < scrollTop) curY = scrollTop;
|
|
1357
1495
|
if (curY > scrollBottom) curY = scrollBottom;
|
|
1358
|
-
if (curX <
|
|
1359
|
-
if (curX
|
|
1496
|
+
if (curX < originX) curX = originX;
|
|
1497
|
+
if (curX > limitX) curX = limitX;
|
|
1360
1498
|
} else {
|
|
1361
1499
|
curY = (parts[0] ?? 1) - 1;
|
|
1362
1500
|
curX = (parts[1] ?? 1) - 1;
|
|
@@ -1427,10 +1565,16 @@ function createScreen(options = {}) {
|
|
|
1427
1565
|
}
|
|
1428
1566
|
break;
|
|
1429
1567
|
case "h":
|
|
1430
|
-
for (const code of parts)
|
|
1568
|
+
for (const code of parts) {
|
|
1569
|
+
if (code === 4) insertMode = true;
|
|
1570
|
+
if (code === 20) newLineMode = true;
|
|
1571
|
+
}
|
|
1431
1572
|
break;
|
|
1432
1573
|
case "l":
|
|
1433
|
-
for (const code of parts)
|
|
1574
|
+
for (const code of parts) {
|
|
1575
|
+
if (code === 4) insertMode = false;
|
|
1576
|
+
if (code === 20) newLineMode = false;
|
|
1577
|
+
}
|
|
1434
1578
|
break;
|
|
1435
1579
|
case "s":
|
|
1436
1580
|
if (leftRightMarginMode && intermediates === "") {
|
|
@@ -1455,8 +1599,6 @@ function createScreen(options = {}) {
|
|
|
1455
1599
|
curX = savedCurX;
|
|
1456
1600
|
curY = savedCurY;
|
|
1457
1601
|
clampCursor();
|
|
1458
|
-
break;
|
|
1459
|
-
default: break;
|
|
1460
1602
|
}
|
|
1461
1603
|
}
|
|
1462
1604
|
function handleCSIGt(params, _intermediates, finalByte) {
|
|
@@ -1551,6 +1693,9 @@ function createScreen(options = {}) {
|
|
|
1551
1693
|
case 4:
|
|
1552
1694
|
value = insertMode ? 1 : 2;
|
|
1553
1695
|
break;
|
|
1696
|
+
case 20:
|
|
1697
|
+
value = newLineMode ? 1 : 2;
|
|
1698
|
+
break;
|
|
1554
1699
|
case 3:
|
|
1555
1700
|
value = decColumnMode ? 1 : 2;
|
|
1556
1701
|
break;
|
|
@@ -1560,9 +1705,7 @@ function createScreen(options = {}) {
|
|
|
1560
1705
|
case 1007:
|
|
1561
1706
|
value = altScrollMode ? 1 : 2;
|
|
1562
1707
|
break;
|
|
1563
|
-
case 1048:
|
|
1564
|
-
value = 2;
|
|
1565
|
-
break;
|
|
1708
|
+
case 1048: value = 2;
|
|
1566
1709
|
}
|
|
1567
1710
|
onResponse(`\x1b[?${mode};${value}$y`);
|
|
1568
1711
|
}
|
|
@@ -1577,11 +1720,11 @@ function createScreen(options = {}) {
|
|
|
1577
1720
|
return;
|
|
1578
1721
|
}
|
|
1579
1722
|
if (finalByte === "J") {
|
|
1580
|
-
handleEraseDisplay(parts[0] ?? 0);
|
|
1723
|
+
handleEraseDisplay(parts[0] ?? 0, true);
|
|
1581
1724
|
return;
|
|
1582
1725
|
}
|
|
1583
1726
|
if (finalByte === "K") {
|
|
1584
|
-
handleEraseLine(parts[0] ?? 0);
|
|
1727
|
+
handleEraseLine(parts[0] ?? 0, true);
|
|
1585
1728
|
return;
|
|
1586
1729
|
}
|
|
1587
1730
|
const set = finalByte === "h";
|
|
@@ -1610,11 +1753,13 @@ function createScreen(options = {}) {
|
|
|
1610
1753
|
useAltScreen = true;
|
|
1611
1754
|
grid = altGrid;
|
|
1612
1755
|
softWrapped = altSoftWrapped;
|
|
1756
|
+
lineAttrs = altLineAttrs;
|
|
1613
1757
|
markAllDirty();
|
|
1614
1758
|
} else if (!set && useAltScreen) {
|
|
1615
1759
|
useAltScreen = false;
|
|
1616
1760
|
grid = mainGrid;
|
|
1617
1761
|
softWrapped = mainSoftWrapped;
|
|
1762
|
+
lineAttrs = mainLineAttrs;
|
|
1618
1763
|
markAllDirty();
|
|
1619
1764
|
}
|
|
1620
1765
|
break;
|
|
@@ -1643,8 +1788,10 @@ function createScreen(options = {}) {
|
|
|
1643
1788
|
useAltScreen = true;
|
|
1644
1789
|
altGrid = makeGrid(cols, rows);
|
|
1645
1790
|
altSoftWrapped = new Array(rows).fill(false);
|
|
1791
|
+
altLineAttrs = new Array(rows).fill(0);
|
|
1646
1792
|
grid = altGrid;
|
|
1647
1793
|
softWrapped = altSoftWrapped;
|
|
1794
|
+
lineAttrs = altLineAttrs;
|
|
1648
1795
|
curX = 0;
|
|
1649
1796
|
curY = 0;
|
|
1650
1797
|
markAllDirty();
|
|
@@ -1652,6 +1799,7 @@ function createScreen(options = {}) {
|
|
|
1652
1799
|
useAltScreen = false;
|
|
1653
1800
|
grid = mainGrid;
|
|
1654
1801
|
softWrapped = mainSoftWrapped;
|
|
1802
|
+
lineAttrs = mainLineAttrs;
|
|
1655
1803
|
curX = savedCurX;
|
|
1656
1804
|
curY = savedCurY;
|
|
1657
1805
|
clampCursor();
|
|
@@ -1686,55 +1834,53 @@ function createScreen(options = {}) {
|
|
|
1686
1834
|
case 1007:
|
|
1687
1835
|
altScrollMode = set;
|
|
1688
1836
|
break;
|
|
1689
|
-
case 1048:
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
}
|
|
1698
|
-
break;
|
|
1837
|
+
case 1048: if (set) {
|
|
1838
|
+
savedCurX = curX;
|
|
1839
|
+
savedCurY = curY;
|
|
1840
|
+
} else {
|
|
1841
|
+
curX = savedCurX;
|
|
1842
|
+
curY = savedCurY;
|
|
1843
|
+
clampCursor();
|
|
1844
|
+
}
|
|
1699
1845
|
}
|
|
1700
1846
|
}
|
|
1701
|
-
function handleEraseDisplay(mode) {
|
|
1847
|
+
function handleEraseDisplay(mode, selective = false) {
|
|
1702
1848
|
switch (mode) {
|
|
1703
1849
|
case 0:
|
|
1704
|
-
eraseCells(curY, curX, curY, cols - 1);
|
|
1705
|
-
for (let row = curY + 1; row < rows; row++) eraseCells(row, 0, row, cols - 1);
|
|
1850
|
+
eraseCells(curY, curX, curY, cols - 1, selective);
|
|
1851
|
+
for (let row = curY + 1; row < rows; row++) eraseCells(row, 0, row, cols - 1, selective);
|
|
1706
1852
|
break;
|
|
1707
1853
|
case 1:
|
|
1708
|
-
for (let row = 0; row < curY; row++) eraseCells(row, 0, row, cols - 1);
|
|
1709
|
-
eraseCells(curY, 0, curY, curX);
|
|
1854
|
+
for (let row = 0; row < curY; row++) eraseCells(row, 0, row, cols - 1, selective);
|
|
1855
|
+
eraseCells(curY, 0, curY, curX, selective);
|
|
1710
1856
|
break;
|
|
1711
1857
|
case 2:
|
|
1712
1858
|
case 3:
|
|
1713
|
-
for (let row = 0; row < rows; row++) eraseCells(row, 0, row, cols - 1);
|
|
1714
|
-
if (mode === 3)
|
|
1859
|
+
for (let row = 0; row < rows; row++) eraseCells(row, 0, row, cols - 1, selective);
|
|
1860
|
+
if (mode === 3) clearScrollback();
|
|
1715
1861
|
markAllDirty();
|
|
1716
|
-
break;
|
|
1717
1862
|
}
|
|
1718
1863
|
}
|
|
1719
|
-
function handleEraseLine(mode) {
|
|
1864
|
+
function handleEraseLine(mode, selective = false) {
|
|
1720
1865
|
const eraseRight = leftRightMarginMode ? rightMargin : cols - 1;
|
|
1721
1866
|
const eraseLeft = leftRightMarginMode ? leftMargin : 0;
|
|
1722
1867
|
switch (mode) {
|
|
1723
1868
|
case 0:
|
|
1724
|
-
eraseCells(curY, curX, curY, eraseRight);
|
|
1869
|
+
eraseCells(curY, curX, curY, eraseRight, selective);
|
|
1725
1870
|
break;
|
|
1726
1871
|
case 1:
|
|
1727
|
-
eraseCells(curY, eraseLeft, curY, curX);
|
|
1728
|
-
break;
|
|
1729
|
-
case 2:
|
|
1730
|
-
eraseCells(curY, eraseLeft, curY, eraseRight);
|
|
1872
|
+
eraseCells(curY, eraseLeft, curY, curX, selective);
|
|
1731
1873
|
break;
|
|
1874
|
+
case 2: eraseCells(curY, eraseLeft, curY, eraseRight, selective);
|
|
1732
1875
|
}
|
|
1733
1876
|
}
|
|
1734
|
-
function eraseCells(row, startCol, _endRow, endCol) {
|
|
1877
|
+
function eraseCells(row, startCol, _endRow, endCol, selective = false) {
|
|
1735
1878
|
const r = grid[row];
|
|
1736
1879
|
if (!r) return;
|
|
1737
|
-
for (let col = startCol; col <= endCol && col < cols; col++)
|
|
1880
|
+
for (let col = startCol; col <= endCol && col < cols; col++) {
|
|
1881
|
+
if (selective && r.getCellRaw(col).protected) continue;
|
|
1882
|
+
r.eraseWithBg(col, attrs.bg);
|
|
1883
|
+
}
|
|
1738
1884
|
markScreenRowDirty(row);
|
|
1739
1885
|
}
|
|
1740
1886
|
function handleInsertLines(count) {
|
|
@@ -1878,9 +2024,7 @@ function createScreen(options = {}) {
|
|
|
1878
2024
|
case 25:
|
|
1879
2025
|
cell.blink = false;
|
|
1880
2026
|
break;
|
|
1881
|
-
case 27:
|
|
1882
|
-
cell.inverse = false;
|
|
1883
|
-
break;
|
|
2027
|
+
case 27: cell.inverse = false;
|
|
1884
2028
|
}
|
|
1885
2029
|
}
|
|
1886
2030
|
function handleSGR(rawParams) {
|
|
@@ -1890,18 +2034,18 @@ function createScreen(options = {}) {
|
|
|
1890
2034
|
for (const seg of segments) if (seg.includes(":")) {
|
|
1891
2035
|
const subs = seg.split(":").map((s) => s === "" ? 0 : parseInt(s, 10));
|
|
1892
2036
|
subParams.set(params.length, subs);
|
|
1893
|
-
params.push(subs
|
|
2037
|
+
params.push(itemAt(subs, 0, "SGR sub-parameters"));
|
|
1894
2038
|
} else params.push(seg === "" ? 0 : parseInt(seg, 10));
|
|
1895
2039
|
if (params.length === 0 || params.length === 1 && params[0] === 0) {
|
|
1896
|
-
attrs =
|
|
2040
|
+
attrs = resetSgrAttrs();
|
|
1897
2041
|
return;
|
|
1898
2042
|
}
|
|
1899
2043
|
let i = 0;
|
|
1900
2044
|
while (i < params.length) {
|
|
1901
|
-
const code = params
|
|
2045
|
+
const code = itemAt(params, i, "SGR parameters");
|
|
1902
2046
|
switch (code) {
|
|
1903
2047
|
case 0:
|
|
1904
|
-
attrs =
|
|
2048
|
+
attrs = resetSgrAttrs();
|
|
1905
2049
|
break;
|
|
1906
2050
|
case 1:
|
|
1907
2051
|
attrs.bold = true;
|
|
@@ -1914,7 +2058,7 @@ function createScreen(options = {}) {
|
|
|
1914
2058
|
break;
|
|
1915
2059
|
case 4: {
|
|
1916
2060
|
const subs = subParams.get(i);
|
|
1917
|
-
if (subs && subs.length > 1) switch (subs
|
|
2061
|
+
if (subs && subs.length > 1) switch (itemAt(subs, 1, "underline style sub-parameters")) {
|
|
1918
2062
|
case 0:
|
|
1919
2063
|
attrs.underline = "none";
|
|
1920
2064
|
break;
|
|
@@ -1933,9 +2077,7 @@ function createScreen(options = {}) {
|
|
|
1933
2077
|
case 5:
|
|
1934
2078
|
attrs.underline = "dashed";
|
|
1935
2079
|
break;
|
|
1936
|
-
default:
|
|
1937
|
-
attrs.underline = "single";
|
|
1938
|
-
break;
|
|
2080
|
+
default: attrs.underline = "single";
|
|
1939
2081
|
}
|
|
1940
2082
|
else attrs.underline = "single";
|
|
1941
2083
|
break;
|
|
@@ -1989,7 +2131,7 @@ function createScreen(options = {}) {
|
|
|
1989
2131
|
case 36:
|
|
1990
2132
|
case 37:
|
|
1991
2133
|
attrs.fg = {
|
|
1992
|
-
...palette256
|
|
2134
|
+
...itemAt(palette256, code - 30, "basic foreground palette"),
|
|
1993
2135
|
index: code - 30
|
|
1994
2136
|
};
|
|
1995
2137
|
break;
|
|
@@ -2019,7 +2161,7 @@ function createScreen(options = {}) {
|
|
|
2019
2161
|
case 46:
|
|
2020
2162
|
case 47:
|
|
2021
2163
|
attrs.bg = {
|
|
2022
|
-
...palette256
|
|
2164
|
+
...itemAt(palette256, code - 40, "basic background palette"),
|
|
2023
2165
|
index: code - 40
|
|
2024
2166
|
};
|
|
2025
2167
|
break;
|
|
@@ -2072,7 +2214,7 @@ function createScreen(options = {}) {
|
|
|
2072
2214
|
case 96:
|
|
2073
2215
|
case 97:
|
|
2074
2216
|
attrs.fg = {
|
|
2075
|
-
...palette256
|
|
2217
|
+
...itemAt(palette256, code - 90 + 8, "bright foreground palette"),
|
|
2076
2218
|
index: code - 90 + 8
|
|
2077
2219
|
};
|
|
2078
2220
|
break;
|
|
@@ -2083,12 +2225,10 @@ function createScreen(options = {}) {
|
|
|
2083
2225
|
case 104:
|
|
2084
2226
|
case 105:
|
|
2085
2227
|
case 106:
|
|
2086
|
-
case 107:
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
};
|
|
2091
|
-
break;
|
|
2228
|
+
case 107: attrs.bg = {
|
|
2229
|
+
...itemAt(palette256, code - 100 + 8, "bright background palette"),
|
|
2230
|
+
index: code - 100 + 8
|
|
2231
|
+
};
|
|
2092
2232
|
}
|
|
2093
2233
|
i++;
|
|
2094
2234
|
}
|
|
@@ -2097,7 +2237,7 @@ function createScreen(options = {}) {
|
|
|
2097
2237
|
if (startIndex + 1 >= params.length) return null;
|
|
2098
2238
|
const type = params[startIndex + 1];
|
|
2099
2239
|
if (type === 5 && startIndex + 2 < params.length) {
|
|
2100
|
-
const idx = params
|
|
2240
|
+
const idx = itemAt(params, startIndex + 2, "indexed color parameters");
|
|
2101
2241
|
const entry = palette256[idx];
|
|
2102
2242
|
return {
|
|
2103
2243
|
color: entry ? {
|
|
@@ -2112,9 +2252,9 @@ function createScreen(options = {}) {
|
|
|
2112
2252
|
};
|
|
2113
2253
|
} else if (type === 2 && startIndex + 4 < params.length) return {
|
|
2114
2254
|
color: {
|
|
2115
|
-
r: params
|
|
2116
|
-
g: params
|
|
2117
|
-
b: params
|
|
2255
|
+
r: itemAt(params, startIndex + 2, "truecolor red parameter"),
|
|
2256
|
+
g: itemAt(params, startIndex + 3, "truecolor green parameter"),
|
|
2257
|
+
b: itemAt(params, startIndex + 4, "truecolor blue parameter")
|
|
2118
2258
|
},
|
|
2119
2259
|
nextIndex: startIndex + 5
|
|
2120
2260
|
};
|
|
@@ -2125,7 +2265,7 @@ function createScreen(options = {}) {
|
|
|
2125
2265
|
if (subs.length < 3) return null;
|
|
2126
2266
|
const type = subs[1];
|
|
2127
2267
|
if (type === 5 && subs.length >= 3) {
|
|
2128
|
-
const idx = subs
|
|
2268
|
+
const idx = itemAt(subs, 2, "indexed color sub-parameters");
|
|
2129
2269
|
const entry = palette256[idx];
|
|
2130
2270
|
return entry ? {
|
|
2131
2271
|
...entry,
|
|
@@ -2138,18 +2278,18 @@ function createScreen(options = {}) {
|
|
|
2138
2278
|
} else if (type === 2) {
|
|
2139
2279
|
if (subs.length >= 5) {
|
|
2140
2280
|
if (subs.length >= 6) return {
|
|
2141
|
-
r: subs
|
|
2142
|
-
g: subs
|
|
2143
|
-
b: subs
|
|
2281
|
+
r: itemAt(subs, 3, "colorspace red sub-parameter"),
|
|
2282
|
+
g: itemAt(subs, 4, "colorspace green sub-parameter"),
|
|
2283
|
+
b: itemAt(subs, 5, "colorspace blue sub-parameter")
|
|
2144
2284
|
};
|
|
2145
2285
|
return {
|
|
2146
|
-
r: subs
|
|
2147
|
-
g: subs
|
|
2148
|
-
b: subs
|
|
2286
|
+
r: itemAt(subs, 2, "truecolor red sub-parameter"),
|
|
2287
|
+
g: itemAt(subs, 3, "truecolor green sub-parameter"),
|
|
2288
|
+
b: itemAt(subs, 4, "truecolor blue sub-parameter")
|
|
2149
2289
|
};
|
|
2150
2290
|
} else if (subs.length >= 4) return {
|
|
2151
|
-
r: subs
|
|
2152
|
-
g: subs
|
|
2291
|
+
r: itemAt(subs, 2, "partial truecolor red sub-parameter"),
|
|
2292
|
+
g: itemAt(subs, 3, "partial truecolor green sub-parameter"),
|
|
2153
2293
|
b: 0
|
|
2154
2294
|
};
|
|
2155
2295
|
}
|
|
@@ -2181,14 +2321,11 @@ function createScreen(options = {}) {
|
|
|
2181
2321
|
startCol: curX
|
|
2182
2322
|
});
|
|
2183
2323
|
break;
|
|
2184
|
-
case "C":
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
});
|
|
2190
|
-
break;
|
|
2191
|
-
case "D": break;
|
|
2324
|
+
case "C": semanticZones.push({
|
|
2325
|
+
type: "output",
|
|
2326
|
+
startRow: curY,
|
|
2327
|
+
startCol: curX
|
|
2328
|
+
});
|
|
2192
2329
|
}
|
|
2193
2330
|
break;
|
|
2194
2331
|
case 1: break;
|
|
@@ -2206,8 +2343,8 @@ function createScreen(options = {}) {
|
|
|
2206
2343
|
case 4: {
|
|
2207
2344
|
const fields = value.split(";");
|
|
2208
2345
|
for (let fi = 0; fi + 1 < fields.length; fi += 2) {
|
|
2209
|
-
const idx = parseInt(fields
|
|
2210
|
-
const spec = fields
|
|
2346
|
+
const idx = parseInt(itemAt(fields, fi, "OSC 4 palette fields"), 10);
|
|
2347
|
+
const spec = itemAt(fields, fi + 1, "OSC 4 palette fields");
|
|
2211
2348
|
if (isNaN(idx) || idx < 0 || idx > 255) continue;
|
|
2212
2349
|
if (spec === "?") {
|
|
2213
2350
|
const c = palette256[idx];
|
|
@@ -2222,8 +2359,8 @@ function createScreen(options = {}) {
|
|
|
2222
2359
|
case 5: {
|
|
2223
2360
|
const fields = value.split(";");
|
|
2224
2361
|
for (let fi = 0; fi + 1 < fields.length; fi += 2) {
|
|
2225
|
-
const idx = parseInt(fields
|
|
2226
|
-
const spec = fields
|
|
2362
|
+
const idx = parseInt(itemAt(fields, fi, "OSC 5 special-color fields"), 10);
|
|
2363
|
+
const spec = itemAt(fields, fi + 1, "OSC 5 special-color fields");
|
|
2227
2364
|
if (isNaN(idx) || idx < 0 || idx > 4) continue;
|
|
2228
2365
|
if (spec === "?") {
|
|
2229
2366
|
const c = specialColors.get(idx);
|
|
@@ -2333,70 +2470,76 @@ function createScreen(options = {}) {
|
|
|
2333
2470
|
const isQuery = val === "?";
|
|
2334
2471
|
const paletteMatch = /^color(\d+)$/.exec(key);
|
|
2335
2472
|
if (paletteMatch) {
|
|
2336
|
-
const idx = parseInt(paletteMatch
|
|
2473
|
+
const idx = parseInt(itemAt(paletteMatch, 1, "OSC 104 palette capture"), 10);
|
|
2337
2474
|
if (idx < 0 || idx > 255) continue;
|
|
2338
2475
|
if (isQuery) {
|
|
2339
2476
|
const c = palette256[idx];
|
|
2340
2477
|
if (c) response.push(`${key}=${formatColorResponse(c)}`);
|
|
2341
2478
|
} else if (val === "") {
|
|
2342
2479
|
const fresh = buildPalette256();
|
|
2343
|
-
palette256[idx] = fresh
|
|
2480
|
+
palette256[idx] = itemAt(fresh, idx, "fresh ANSI palette");
|
|
2344
2481
|
} else {
|
|
2345
2482
|
const c = parseColorSpec(val);
|
|
2346
2483
|
if (c) palette256[idx] = c;
|
|
2347
2484
|
}
|
|
2348
|
-
} else if (key === "foreground")
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
if (
|
|
2485
|
+
} else if (key === "foreground") {
|
|
2486
|
+
if (isQuery) {
|
|
2487
|
+
const c = defaultFgColor ?? {
|
|
2488
|
+
r: 255,
|
|
2489
|
+
g: 255,
|
|
2490
|
+
b: 255
|
|
2491
|
+
};
|
|
2492
|
+
response.push(`${key}=${formatColorResponse(c)}`);
|
|
2493
|
+
} else if (val === "") defaultFgColor = null;
|
|
2494
|
+
else {
|
|
2495
|
+
const c = parseColorSpec(val);
|
|
2496
|
+
if (c) defaultFgColor = c;
|
|
2497
|
+
}
|
|
2498
|
+
} else if (key === "background") {
|
|
2499
|
+
if (isQuery) {
|
|
2500
|
+
const c = defaultBgColor ?? {
|
|
2501
|
+
r: 0,
|
|
2502
|
+
g: 0,
|
|
2503
|
+
b: 0
|
|
2504
|
+
};
|
|
2505
|
+
response.push(`${key}=${formatColorResponse(c)}`);
|
|
2506
|
+
} else if (val === "") defaultBgColor = null;
|
|
2507
|
+
else {
|
|
2508
|
+
const c = parseColorSpec(val);
|
|
2509
|
+
if (c) defaultBgColor = c;
|
|
2510
|
+
}
|
|
2511
|
+
} else if (key === "cursor") {
|
|
2512
|
+
if (isQuery) {
|
|
2513
|
+
const c = cursorColor ?? defaultFgColor ?? {
|
|
2514
|
+
r: 255,
|
|
2515
|
+
g: 255,
|
|
2516
|
+
b: 255
|
|
2517
|
+
};
|
|
2518
|
+
response.push(`${key}=${formatColorResponse(c)}`);
|
|
2519
|
+
} else if (val === "") cursorColor = null;
|
|
2520
|
+
else {
|
|
2521
|
+
const c = parseColorSpec(val);
|
|
2522
|
+
if (c) cursorColor = c;
|
|
2523
|
+
}
|
|
2524
|
+
} else if (key === "selection_background") {
|
|
2525
|
+
if (isQuery) {
|
|
2526
|
+
const c = highlightBgColor ?? defaultFgColor ?? {
|
|
2527
|
+
r: 255,
|
|
2528
|
+
g: 255,
|
|
2529
|
+
b: 255
|
|
2530
|
+
};
|
|
2531
|
+
response.push(`${key}=${formatColorResponse(c)}`);
|
|
2532
|
+
} else highlightBgColor = val === "" ? null : parseColorSpec(val);
|
|
2533
|
+
} else if (key === "selection_foreground") {
|
|
2534
|
+
if (isQuery) {
|
|
2535
|
+
const c = highlightFgColor ?? defaultBgColor ?? {
|
|
2536
|
+
r: 0,
|
|
2537
|
+
g: 0,
|
|
2538
|
+
b: 0
|
|
2539
|
+
};
|
|
2540
|
+
response.push(`${key}=${formatColorResponse(c)}`);
|
|
2541
|
+
} else highlightFgColor = val === "" ? null : parseColorSpec(val);
|
|
2383
2542
|
}
|
|
2384
|
-
else if (key === "selection_background") if (isQuery) {
|
|
2385
|
-
const c = highlightBgColor ?? defaultFgColor ?? {
|
|
2386
|
-
r: 255,
|
|
2387
|
-
g: 255,
|
|
2388
|
-
b: 255
|
|
2389
|
-
};
|
|
2390
|
-
response.push(`${key}=${formatColorResponse(c)}`);
|
|
2391
|
-
} else highlightBgColor = val === "" ? null : parseColorSpec(val);
|
|
2392
|
-
else if (key === "selection_foreground") if (isQuery) {
|
|
2393
|
-
const c = highlightFgColor ?? defaultBgColor ?? {
|
|
2394
|
-
r: 0,
|
|
2395
|
-
g: 0,
|
|
2396
|
-
b: 0
|
|
2397
|
-
};
|
|
2398
|
-
response.push(`${key}=${formatColorResponse(c)}`);
|
|
2399
|
-
} else highlightFgColor = val === "" ? null : parseColorSpec(val);
|
|
2400
2543
|
}
|
|
2401
2544
|
if (response.length > 0 && onResponse) onResponse(`\x1b]21;${response.join(";")}\x1b\\`);
|
|
2402
2545
|
break;
|
|
@@ -2407,7 +2550,7 @@ function createScreen(options = {}) {
|
|
|
2407
2550
|
const fresh = buildPalette256();
|
|
2408
2551
|
for (const tok of value.split(";")) {
|
|
2409
2552
|
const idx = parseInt(tok, 10);
|
|
2410
|
-
if (!isNaN(idx) && idx >= 0 && idx < 256) palette256[idx] = fresh
|
|
2553
|
+
if (!isNaN(idx) && idx >= 0 && idx < 256) palette256[idx] = itemAt(fresh, idx, "fresh ANSI palette");
|
|
2411
2554
|
}
|
|
2412
2555
|
}
|
|
2413
2556
|
break;
|
|
@@ -2478,14 +2621,11 @@ function createScreen(options = {}) {
|
|
|
2478
2621
|
startCol: curX
|
|
2479
2622
|
});
|
|
2480
2623
|
break;
|
|
2481
|
-
case "C":
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
});
|
|
2487
|
-
break;
|
|
2488
|
-
case "D": break;
|
|
2624
|
+
case "C": semanticZones.push({
|
|
2625
|
+
type: "output",
|
|
2626
|
+
startRow: curY,
|
|
2627
|
+
startCol: curX
|
|
2628
|
+
});
|
|
2489
2629
|
}
|
|
2490
2630
|
break;
|
|
2491
2631
|
case 66:
|
|
@@ -2558,10 +2698,8 @@ function createScreen(options = {}) {
|
|
|
2558
2698
|
advancedClipboard = "";
|
|
2559
2699
|
}
|
|
2560
2700
|
break;
|
|
2561
|
-
case 1337:
|
|
2562
|
-
|
|
2563
|
-
else if (value === "RequestCapabilities" && onResponse) onResponse("\x1B]1337;Capabilities=\x1B\\");
|
|
2564
|
-
break;
|
|
2701
|
+
case 1337: if (value === "ReportCellSize" && onResponse) onResponse("\x1B]1337;ReportCellSize=16;8\x1B\\");
|
|
2702
|
+
else if (value === "RequestCapabilities" && onResponse) onResponse("\x1B]1337;Capabilities=\x1B\\");
|
|
2565
2703
|
}
|
|
2566
2704
|
}
|
|
2567
2705
|
function handleDCS(data) {
|
|
@@ -2569,7 +2707,7 @@ function createScreen(options = {}) {
|
|
|
2569
2707
|
if (match) {
|
|
2570
2708
|
hasSixel = true;
|
|
2571
2709
|
sixelImages.push({
|
|
2572
|
-
data: match
|
|
2710
|
+
data: itemAt(match, 2, "sixel payload capture"),
|
|
2573
2711
|
row: dcsStartRow,
|
|
2574
2712
|
col: dcsStartCol
|
|
2575
2713
|
});
|
|
@@ -2602,6 +2740,7 @@ function createScreen(options = {}) {
|
|
|
2602
2740
|
}
|
|
2603
2741
|
function softReset() {
|
|
2604
2742
|
insertMode = false;
|
|
2743
|
+
newLineMode = false;
|
|
2605
2744
|
originMode = false;
|
|
2606
2745
|
autoWrap = true;
|
|
2607
2746
|
curVisible = true;
|
|
@@ -2622,6 +2761,8 @@ function createScreen(options = {}) {
|
|
|
2622
2761
|
rightMargin = cols - 1;
|
|
2623
2762
|
attrs = resetAttrs();
|
|
2624
2763
|
charsetG0 = false;
|
|
2764
|
+
charsetG1 = false;
|
|
2765
|
+
activeG1 = false;
|
|
2625
2766
|
curX = 0;
|
|
2626
2767
|
curY = 0;
|
|
2627
2768
|
}
|
|
@@ -2644,7 +2785,9 @@ function createScreen(options = {}) {
|
|
|
2644
2785
|
attrs: resetAttrs(),
|
|
2645
2786
|
originMode: false,
|
|
2646
2787
|
autoWrap: true,
|
|
2647
|
-
charsetG0: false
|
|
2788
|
+
charsetG0: false,
|
|
2789
|
+
charsetG1: false,
|
|
2790
|
+
activeG1: false
|
|
2648
2791
|
};
|
|
2649
2792
|
attrs = resetAttrs();
|
|
2650
2793
|
title = "";
|
|
@@ -2659,6 +2802,7 @@ function createScreen(options = {}) {
|
|
|
2659
2802
|
focusTracking = false;
|
|
2660
2803
|
originMode = false;
|
|
2661
2804
|
insertMode = false;
|
|
2805
|
+
newLineMode = false;
|
|
2662
2806
|
reverseVideo = false;
|
|
2663
2807
|
syncOutput = false;
|
|
2664
2808
|
kittyKeyboardFlags = 0;
|
|
@@ -2682,6 +2826,8 @@ function createScreen(options = {}) {
|
|
|
2682
2826
|
advancedClipboard = "";
|
|
2683
2827
|
viewportOffset = 0;
|
|
2684
2828
|
charsetG0 = false;
|
|
2829
|
+
charsetG1 = false;
|
|
2830
|
+
activeG1 = false;
|
|
2685
2831
|
clipboard = "";
|
|
2686
2832
|
cwd = "";
|
|
2687
2833
|
notifications = [];
|
|
@@ -2717,6 +2863,9 @@ function createScreen(options = {}) {
|
|
|
2717
2863
|
mainSoftWrapped = new Array(rows).fill(false);
|
|
2718
2864
|
altSoftWrapped = new Array(rows).fill(false);
|
|
2719
2865
|
softWrapped = mainSoftWrapped;
|
|
2866
|
+
mainLineAttrs = new Array(rows).fill(0);
|
|
2867
|
+
altLineAttrs = new Array(rows).fill(0);
|
|
2868
|
+
lineAttrs = mainLineAttrs;
|
|
2720
2869
|
markAllDirty();
|
|
2721
2870
|
dirtyScrolled = 0;
|
|
2722
2871
|
if (sigDamageActive) sigDirtyScrolled = 0;
|
|
@@ -2868,15 +3017,18 @@ function createScreen(options = {}) {
|
|
|
2868
3017
|
emitExecute(9);
|
|
2869
3018
|
} else if (code === 10 || code === 11 || code === 12) {
|
|
2870
3019
|
softWrapped[curY] = false;
|
|
2871
|
-
|
|
2872
|
-
if (
|
|
2873
|
-
curY = scrollBottom;
|
|
2874
|
-
scrollUp(scrollTop, scrollBottom);
|
|
2875
|
-
}
|
|
3020
|
+
lineFeedDown();
|
|
3021
|
+
if (newLineMode) curX = 0;
|
|
2876
3022
|
emitExecute(code);
|
|
2877
3023
|
} else if (code === 13) {
|
|
2878
3024
|
curX = 0;
|
|
2879
3025
|
emitExecute(13);
|
|
3026
|
+
} else if (code === 14) {
|
|
3027
|
+
activeG1 = true;
|
|
3028
|
+
emitExecute(14);
|
|
3029
|
+
} else if (code === 15) {
|
|
3030
|
+
activeG1 = false;
|
|
3031
|
+
emitExecute(15);
|
|
2880
3032
|
} else if (code >= 32) {
|
|
2881
3033
|
let char = ch;
|
|
2882
3034
|
if (code >= 55296 && code <= 56319 && i + 1 < text.length) {
|
|
@@ -2910,19 +3062,11 @@ function createScreen(options = {}) {
|
|
|
2910
3062
|
parserState = "ground";
|
|
2911
3063
|
emitEsc("c", "");
|
|
2912
3064
|
} else if (ch === "D") {
|
|
2913
|
-
|
|
2914
|
-
if (curY > scrollBottom) {
|
|
2915
|
-
curY = scrollBottom;
|
|
2916
|
-
scrollUp(scrollTop, scrollBottom);
|
|
2917
|
-
}
|
|
3065
|
+
lineFeedDown();
|
|
2918
3066
|
parserState = "ground";
|
|
2919
3067
|
emitEsc("D", "");
|
|
2920
3068
|
} else if (ch === "M") {
|
|
2921
|
-
|
|
2922
|
-
if (curY < scrollTop) {
|
|
2923
|
-
curY = scrollTop;
|
|
2924
|
-
scrollDown(scrollTop, scrollBottom);
|
|
2925
|
-
}
|
|
3069
|
+
reverseIndexUp();
|
|
2926
3070
|
parserState = "ground";
|
|
2927
3071
|
emitEsc("M", "");
|
|
2928
3072
|
} else if (ch === "7") {
|
|
@@ -2937,7 +3081,9 @@ function createScreen(options = {}) {
|
|
|
2937
3081
|
},
|
|
2938
3082
|
originMode,
|
|
2939
3083
|
autoWrap,
|
|
2940
|
-
charsetG0
|
|
3084
|
+
charsetG0,
|
|
3085
|
+
charsetG1,
|
|
3086
|
+
activeG1
|
|
2941
3087
|
};
|
|
2942
3088
|
parserState = "ground";
|
|
2943
3089
|
emitEsc("7", "");
|
|
@@ -2953,6 +3099,8 @@ function createScreen(options = {}) {
|
|
|
2953
3099
|
originMode = savedState.originMode;
|
|
2954
3100
|
autoWrap = savedState.autoWrap;
|
|
2955
3101
|
charsetG0 = savedState.charsetG0;
|
|
3102
|
+
charsetG1 = savedState.charsetG1;
|
|
3103
|
+
activeG1 = savedState.activeG1;
|
|
2956
3104
|
clampCursor();
|
|
2957
3105
|
parserState = "ground";
|
|
2958
3106
|
emitEsc("8", "");
|
|
@@ -2974,9 +3122,11 @@ function createScreen(options = {}) {
|
|
|
2974
3122
|
parserState = "escape_hash";
|
|
2975
3123
|
} else if (ch === "(") {
|
|
2976
3124
|
escIntermediate = "(";
|
|
3125
|
+
escBuf = "(";
|
|
2977
3126
|
parserState = "escape_charset";
|
|
2978
3127
|
} else if (ch === ")") {
|
|
2979
3128
|
escIntermediate = ")";
|
|
3129
|
+
escBuf = ")";
|
|
2980
3130
|
parserState = "escape_charset";
|
|
2981
3131
|
} else if (ch === "=") {
|
|
2982
3132
|
applicationKeypad = true;
|
|
@@ -2996,23 +3146,28 @@ function createScreen(options = {}) {
|
|
|
2996
3146
|
} else parserState = "ground";
|
|
2997
3147
|
break;
|
|
2998
3148
|
case "escape_charset":
|
|
2999
|
-
|
|
3000
|
-
|
|
3149
|
+
const designator = escBuf === ")" ? ")" : "(";
|
|
3150
|
+
if (designator === ")") charsetG1 = ch === "0";
|
|
3151
|
+
else charsetG0 = ch === "0";
|
|
3152
|
+
escBuf = "";
|
|
3001
3153
|
parserState = "ground";
|
|
3002
|
-
emitEsc(ch,
|
|
3154
|
+
emitEsc(ch, designator);
|
|
3003
3155
|
break;
|
|
3004
3156
|
case "escape_hash":
|
|
3005
3157
|
if (ch === "8") {
|
|
3006
3158
|
const alignCell = emptyCell();
|
|
3007
3159
|
alignCell.char = "E";
|
|
3008
3160
|
for (let r = 0; r < rows; r++) {
|
|
3009
|
-
const row = grid
|
|
3161
|
+
const row = itemAt(grid, r, "selective erase rows");
|
|
3010
3162
|
for (let c = 0; c < cols; c++) row.setCellRaw(c, alignCell);
|
|
3011
3163
|
softWrapped[r] = false;
|
|
3012
3164
|
}
|
|
3013
3165
|
curX = 0;
|
|
3014
3166
|
curY = 0;
|
|
3015
|
-
}
|
|
3167
|
+
} else if (ch === "3") lineAttrs[curY] = 2;
|
|
3168
|
+
else if (ch === "4") lineAttrs[curY] = 3;
|
|
3169
|
+
else if (ch === "5") lineAttrs[curY] = 0;
|
|
3170
|
+
else if (ch === "6") lineAttrs[curY] = 1;
|
|
3016
3171
|
parserState = "ground";
|
|
3017
3172
|
emitEsc(ch, escIntermediate);
|
|
3018
3173
|
break;
|
|
@@ -3090,7 +3245,6 @@ function createScreen(options = {}) {
|
|
|
3090
3245
|
apcOverflow = false;
|
|
3091
3246
|
}
|
|
3092
3247
|
parserState = "ground";
|
|
3093
|
-
break;
|
|
3094
3248
|
}
|
|
3095
3249
|
}
|
|
3096
3250
|
flushPrintRun();
|
|
@@ -3129,22 +3283,39 @@ function createScreen(options = {}) {
|
|
|
3129
3283
|
* trailing blanks or one past the last cell) lands after the last emitted
|
|
3130
3284
|
* cell, advanced by the leftover distance, clamped to the row.
|
|
3131
3285
|
*/
|
|
3286
|
+
/**
|
|
3287
|
+
* One line attribute per LOGICAL line, taken from the line's FIRST physical
|
|
3288
|
+
* row — the grouping `getLogicalLines` uses, so the two arrays line up.
|
|
3289
|
+
* A rewrap then re-applies the attribute to every row the line becomes.
|
|
3290
|
+
*/
|
|
3291
|
+
function logicalLineAttrs(srcGrid, srcSoftWrapped, srcLineAttrs, srcRows) {
|
|
3292
|
+
const out = [];
|
|
3293
|
+
let starting = true;
|
|
3294
|
+
for (let r = 0; r < srcRows; r++) {
|
|
3295
|
+
if (!srcGrid[r]) continue;
|
|
3296
|
+
if (starting) out.push(srcLineAttrs[r] ?? 0);
|
|
3297
|
+
starting = !srcSoftWrapped[r];
|
|
3298
|
+
}
|
|
3299
|
+
return out;
|
|
3300
|
+
}
|
|
3132
3301
|
function rewrapLines(logicalLines, newCols, track) {
|
|
3133
3302
|
const outRows = [];
|
|
3134
3303
|
const outWrapped = [];
|
|
3304
|
+
const outLine = [];
|
|
3135
3305
|
let tracked = null;
|
|
3136
3306
|
for (let li = 0; li < logicalLines.length; li++) {
|
|
3137
|
-
const line = logicalLines
|
|
3307
|
+
const line = itemAt(logicalLines, li, "reflow logical lines");
|
|
3138
3308
|
let lineLen = line.length;
|
|
3139
3309
|
while (lineLen > 0) {
|
|
3140
|
-
const cell = line
|
|
3310
|
+
const cell = itemAt(line, lineLen - 1, "reflow logical-line cells");
|
|
3141
3311
|
if (cell.char === "" && !cell.wide) lineLen--;
|
|
3142
3312
|
else break;
|
|
3143
3313
|
}
|
|
3144
3314
|
if (lineLen === 0) {
|
|
3145
3315
|
outRows.push(makeRow(newCols));
|
|
3146
3316
|
outWrapped.push(false);
|
|
3147
|
-
|
|
3317
|
+
outLine.push(li);
|
|
3318
|
+
if (track?.line === li) tracked = {
|
|
3148
3319
|
row: outRows.length - 1,
|
|
3149
3320
|
col: Math.min(track.offset, newCols - 1)
|
|
3150
3321
|
};
|
|
@@ -3155,9 +3326,9 @@ function createScreen(options = {}) {
|
|
|
3155
3326
|
const row = makeRow(newCols);
|
|
3156
3327
|
let col = 0;
|
|
3157
3328
|
while (col < newCols && pos < lineLen) {
|
|
3158
|
-
const cell = line
|
|
3329
|
+
const cell = itemAt(line, pos, "reflow logical-line cells");
|
|
3159
3330
|
if (cell.wide && col + 2 > newCols) break;
|
|
3160
|
-
if (track
|
|
3331
|
+
if (track?.line === li && pos === track.offset) tracked = {
|
|
3161
3332
|
row: outRows.length,
|
|
3162
3333
|
col
|
|
3163
3334
|
};
|
|
@@ -3168,7 +3339,8 @@ function createScreen(options = {}) {
|
|
|
3168
3339
|
const moreContent = pos < lineLen;
|
|
3169
3340
|
outRows.push(row);
|
|
3170
3341
|
outWrapped.push(moreContent);
|
|
3171
|
-
|
|
3342
|
+
outLine.push(li);
|
|
3343
|
+
if (!moreContent && track?.line === li && tracked === null) {
|
|
3172
3344
|
const extra = track.offset - lineLen;
|
|
3173
3345
|
tracked = {
|
|
3174
3346
|
row: outRows.length - 1,
|
|
@@ -3180,6 +3352,7 @@ function createScreen(options = {}) {
|
|
|
3180
3352
|
return {
|
|
3181
3353
|
rows: outRows,
|
|
3182
3354
|
wrapped: outWrapped,
|
|
3355
|
+
lineIndex: outLine,
|
|
3183
3356
|
tracked
|
|
3184
3357
|
};
|
|
3185
3358
|
}
|
|
@@ -3191,15 +3364,19 @@ function createScreen(options = {}) {
|
|
|
3191
3364
|
/**
|
|
3192
3365
|
* Trim trailing empty rows from reflowed result, so they don't push content off the top
|
|
3193
3366
|
* when we take the last newRows rows.
|
|
3367
|
+
*
|
|
3368
|
+
* Never trims the row the CURSOR is on. A shell that has just emitted its
|
|
3369
|
+
* final newline sits on a blank last row, and dropping it makes the content
|
|
3370
|
+
* measure one row shorter than it is — so a shrink banks one row too few and
|
|
3371
|
+
* every surviving line lands one row low, taking the cursor with it.
|
|
3194
3372
|
*/
|
|
3195
3373
|
function trimTrailingEmptyRows(result) {
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
}
|
|
3374
|
+
const floor = result.tracked == null ? 1 : Math.max(1, result.tracked.row + 1);
|
|
3375
|
+
while (result.rows.length > floor) if (packedRowIsBlank(itemAt(result.rows, result.rows.length - 1, "reflow result rows")) && !result.wrapped[result.rows.length - 2]) {
|
|
3376
|
+
result.rows.pop();
|
|
3377
|
+
result.wrapped.pop();
|
|
3378
|
+
result.lineIndex?.pop();
|
|
3379
|
+
} else break;
|
|
3203
3380
|
}
|
|
3204
3381
|
function resize(newCols, newRows) {
|
|
3205
3382
|
if (newCols === cols && newRows === rows) return;
|
|
@@ -3213,23 +3390,56 @@ function createScreen(options = {}) {
|
|
|
3213
3390
|
line: cursorLineIdx,
|
|
3214
3391
|
offset: (cursorRowPre - cursorLineStart) * cols + curX
|
|
3215
3392
|
};
|
|
3216
|
-
|
|
3393
|
+
let restoredRows = [];
|
|
3394
|
+
let restoredWrapped = [];
|
|
3395
|
+
let restoredAttrs = [];
|
|
3396
|
+
if (!useAltScreen && newRows > rows && scrollback.length > 0) {
|
|
3397
|
+
const probe = rewrapLines(getLogicalLines(mainGrid, mainSoftWrapped, rows), newCols, void 0);
|
|
3398
|
+
trimTrailingEmptyRows(probe);
|
|
3399
|
+
const take = Math.min(Math.max(0, newRows - probe.rows.length), scrollback.length);
|
|
3400
|
+
if (take > 0) {
|
|
3401
|
+
restoredRows = scrollback.splice(scrollback.length - take, take);
|
|
3402
|
+
restoredWrapped = scrollbackSoftWrapped.splice(scrollbackSoftWrapped.length - take, take);
|
|
3403
|
+
restoredAttrs = scrollbackLineAttrs.splice(scrollbackLineAttrs.length - take, take);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
if (restoredRows.length > 0) {
|
|
3407
|
+
let completed = 0;
|
|
3408
|
+
for (const wrapped of restoredWrapped) if (!wrapped) completed++;
|
|
3409
|
+
if (cursorTrack.line === 0 && restoredWrapped[restoredWrapped.length - 1] === true) for (let i = restoredWrapped.length - 1; i >= 0 && restoredWrapped[i]; i--) cursorTrack.offset += itemAt(restoredRows, i, "restored rows").length;
|
|
3410
|
+
cursorTrack.line += completed;
|
|
3411
|
+
}
|
|
3412
|
+
const mainSrc = restoredRows.length > 0 ? [...restoredRows, ...mainGrid] : mainGrid;
|
|
3413
|
+
const mainSrcWrapped = restoredRows.length > 0 ? [...restoredWrapped, ...mainSoftWrapped] : mainSoftWrapped;
|
|
3414
|
+
const mainSrcAttrs = restoredRows.length > 0 ? [...restoredAttrs, ...mainLineAttrs] : mainLineAttrs;
|
|
3415
|
+
const mainSrcRows = restoredRows.length + rows;
|
|
3416
|
+
const mainLogicalAttrs = logicalLineAttrs(mainSrc, mainSrcWrapped, mainSrcAttrs, mainSrcRows);
|
|
3417
|
+
const mainResult = rewrapLines(getLogicalLines(mainSrc, mainSrcWrapped, mainSrcRows), newCols, useAltScreen ? void 0 : cursorTrack);
|
|
3217
3418
|
trimTrailingEmptyRows(mainResult);
|
|
3419
|
+
const altLogicalAttrs = logicalLineAttrs(altGrid, altSoftWrapped, altLineAttrs, rows);
|
|
3218
3420
|
const altResult = rewrapLines(getLogicalLines(altGrid, altSoftWrapped, rows), newCols, useAltScreen ? cursorTrack : void 0);
|
|
3219
3421
|
trimTrailingEmptyRows(altResult);
|
|
3220
3422
|
const newMain = makeGrid(newCols, newRows);
|
|
3221
3423
|
const newMainWrapped = new Array(newRows).fill(false);
|
|
3424
|
+
const newMainAttrs = new Array(newRows).fill(0);
|
|
3222
3425
|
const mainStartRow = Math.max(0, mainResult.rows.length - newRows);
|
|
3426
|
+
for (let r = 0; r < mainStartRow; r++) {
|
|
3427
|
+
const overflow = mainResult.rows[r];
|
|
3428
|
+
if (overflow !== void 0) bankScrollbackRow(overflow, mainResult.wrapped[r] ?? false, mainLogicalAttrs[mainResult.lineIndex[r] ?? 0] ?? 0);
|
|
3429
|
+
}
|
|
3223
3430
|
for (let r = 0; r < newRows && mainStartRow + r < mainResult.rows.length; r++) {
|
|
3224
|
-
newMain[r] = mainResult.rows
|
|
3225
|
-
newMainWrapped[r] = mainResult.wrapped
|
|
3431
|
+
newMain[r] = itemAt(mainResult.rows, mainStartRow + r, "resized main rows");
|
|
3432
|
+
newMainWrapped[r] = itemAt(mainResult.wrapped, mainStartRow + r, "resized main wrap flags");
|
|
3433
|
+
newMainAttrs[r] = mainLogicalAttrs[mainResult.lineIndex[mainStartRow + r] ?? 0] ?? 0;
|
|
3226
3434
|
}
|
|
3227
3435
|
const newAlt = makeGrid(newCols, newRows);
|
|
3228
3436
|
const newAltWrapped = new Array(newRows).fill(false);
|
|
3437
|
+
const newAltAttrs = new Array(newRows).fill(0);
|
|
3229
3438
|
const altStartRow = Math.max(0, altResult.rows.length - newRows);
|
|
3230
3439
|
for (let r = 0; r < newRows && altStartRow + r < altResult.rows.length; r++) {
|
|
3231
|
-
newAlt[r] = altResult.rows
|
|
3232
|
-
newAltWrapped[r] = altResult.wrapped
|
|
3440
|
+
newAlt[r] = itemAt(altResult.rows, altStartRow + r, "resized alternate rows");
|
|
3441
|
+
newAltWrapped[r] = itemAt(altResult.wrapped, altStartRow + r, "resized alternate wrap flags");
|
|
3442
|
+
newAltAttrs[r] = altLogicalAttrs[altResult.lineIndex[altStartRow + r] ?? 0] ?? 0;
|
|
3233
3443
|
}
|
|
3234
3444
|
const activeResult = useAltScreen ? altResult : mainResult;
|
|
3235
3445
|
const activeStartRow = useAltScreen ? altStartRow : mainStartRow;
|
|
@@ -3241,8 +3451,11 @@ function createScreen(options = {}) {
|
|
|
3241
3451
|
altGrid = newAlt;
|
|
3242
3452
|
mainSoftWrapped = newMainWrapped;
|
|
3243
3453
|
altSoftWrapped = newAltWrapped;
|
|
3454
|
+
mainLineAttrs = newMainAttrs;
|
|
3455
|
+
altLineAttrs = newAltAttrs;
|
|
3244
3456
|
grid = useAltScreen ? altGrid : mainGrid;
|
|
3245
3457
|
softWrapped = useAltScreen ? altSoftWrapped : mainSoftWrapped;
|
|
3458
|
+
lineAttrs = useAltScreen ? altLineAttrs : mainLineAttrs;
|
|
3246
3459
|
const oldCols = cols;
|
|
3247
3460
|
cols = newCols;
|
|
3248
3461
|
rows = newRows;
|
|
@@ -3277,6 +3490,11 @@ function createScreen(options = {}) {
|
|
|
3277
3490
|
},
|
|
3278
3491
|
scrollback: cloneGridSnapshot(scrollback),
|
|
3279
3492
|
scrollbackSoftWrapped: [...scrollbackSoftWrapped],
|
|
3493
|
+
lineAttrs: {
|
|
3494
|
+
main: toSparseAttrs(mainLineAttrs),
|
|
3495
|
+
alt: toSparseAttrs(altLineAttrs),
|
|
3496
|
+
scrollback: toSparseAttrs(scrollbackLineAttrs)
|
|
3497
|
+
},
|
|
3280
3498
|
cursor: {
|
|
3281
3499
|
x: curX,
|
|
3282
3500
|
y: curY,
|
|
@@ -3292,7 +3510,9 @@ function createScreen(options = {}) {
|
|
|
3292
3510
|
attrs: cloneAttrsSnapshot(savedState.attrs),
|
|
3293
3511
|
originMode: savedState.originMode,
|
|
3294
3512
|
autoWrap: savedState.autoWrap,
|
|
3295
|
-
charsetG0: savedState.charsetG0
|
|
3513
|
+
charsetG0: savedState.charsetG0,
|
|
3514
|
+
charsetG1: savedState.charsetG1,
|
|
3515
|
+
activeG1: savedState.activeG1
|
|
3296
3516
|
},
|
|
3297
3517
|
attrs: cloneAttrsSnapshot(attrs),
|
|
3298
3518
|
modes: {
|
|
@@ -3306,6 +3526,7 @@ function createScreen(options = {}) {
|
|
|
3306
3526
|
focusTracking,
|
|
3307
3527
|
origin: originMode,
|
|
3308
3528
|
insert: insertMode,
|
|
3529
|
+
newLine: newLineMode,
|
|
3309
3530
|
reverseVideo,
|
|
3310
3531
|
syncOutput,
|
|
3311
3532
|
kittyKeyboardFlags,
|
|
@@ -3355,6 +3576,8 @@ function createScreen(options = {}) {
|
|
|
3355
3576
|
},
|
|
3356
3577
|
unicode: {
|
|
3357
3578
|
charsetG0,
|
|
3579
|
+
charsetG1,
|
|
3580
|
+
activeG1,
|
|
3358
3581
|
lastChar,
|
|
3359
3582
|
pendingRegionalIndicator,
|
|
3360
3583
|
afterZWJ
|
|
@@ -3372,9 +3595,13 @@ function createScreen(options = {}) {
|
|
|
3372
3595
|
scrollbackSoftWrapped = snapshotValue.scrollbackSoftWrapped ? [...snapshotValue.scrollbackSoftWrapped] : new Array(scrollback.length).fill(false);
|
|
3373
3596
|
mainSoftWrapped = [...snapshotValue.main.softWrapped];
|
|
3374
3597
|
altSoftWrapped = [...snapshotValue.alt.softWrapped];
|
|
3598
|
+
mainLineAttrs = fromSparseAttrs(snapshotValue.lineAttrs?.main, mainSoftWrapped.length);
|
|
3599
|
+
altLineAttrs = fromSparseAttrs(snapshotValue.lineAttrs?.alt, altSoftWrapped.length);
|
|
3600
|
+
scrollbackLineAttrs = fromSparseAttrs(snapshotValue.lineAttrs?.scrollback, scrollback.length);
|
|
3375
3601
|
useAltScreen = snapshotValue.activeBuffer === "alt";
|
|
3376
3602
|
grid = useAltScreen ? altGrid : mainGrid;
|
|
3377
3603
|
softWrapped = useAltScreen ? altSoftWrapped : mainSoftWrapped;
|
|
3604
|
+
lineAttrs = useAltScreen ? altLineAttrs : mainLineAttrs;
|
|
3378
3605
|
curX = snapshotValue.cursor.x;
|
|
3379
3606
|
curY = snapshotValue.cursor.y;
|
|
3380
3607
|
curVisible = snapshotValue.cursor.visible;
|
|
@@ -3388,7 +3615,9 @@ function createScreen(options = {}) {
|
|
|
3388
3615
|
attrs: cloneAttrsSnapshot(snapshotValue.savedState.attrs),
|
|
3389
3616
|
originMode: snapshotValue.savedState.originMode,
|
|
3390
3617
|
autoWrap: snapshotValue.savedState.autoWrap,
|
|
3391
|
-
charsetG0: snapshotValue.savedState.charsetG0
|
|
3618
|
+
charsetG0: snapshotValue.savedState.charsetG0,
|
|
3619
|
+
charsetG1: snapshotValue.savedState.charsetG1 ?? false,
|
|
3620
|
+
activeG1: snapshotValue.savedState.activeG1 ?? false
|
|
3392
3621
|
};
|
|
3393
3622
|
attrs = cloneAttrsSnapshot(snapshotValue.attrs);
|
|
3394
3623
|
bracketedPaste = snapshotValue.modes.bracketedPaste;
|
|
@@ -3401,6 +3630,7 @@ function createScreen(options = {}) {
|
|
|
3401
3630
|
focusTracking = snapshotValue.modes.focusTracking;
|
|
3402
3631
|
originMode = snapshotValue.modes.origin;
|
|
3403
3632
|
insertMode = snapshotValue.modes.insert;
|
|
3633
|
+
newLineMode = snapshotValue.modes.newLine ?? false;
|
|
3404
3634
|
reverseVideo = snapshotValue.modes.reverseVideo;
|
|
3405
3635
|
syncOutput = snapshotValue.modes.syncOutput;
|
|
3406
3636
|
kittyKeyboardFlags = snapshotValue.modes.kittyKeyboardFlags;
|
|
@@ -3439,6 +3669,8 @@ function createScreen(options = {}) {
|
|
|
3439
3669
|
apcOverflow = snapshotValue.parser.apcOverflow ?? false;
|
|
3440
3670
|
utf8PendingBytes = [...snapshotValue.parser.utf8PendingBytes];
|
|
3441
3671
|
charsetG0 = snapshotValue.unicode.charsetG0;
|
|
3672
|
+
charsetG1 = snapshotValue.unicode.charsetG1 ?? false;
|
|
3673
|
+
activeG1 = snapshotValue.unicode.activeG1 ?? false;
|
|
3442
3674
|
lastChar = snapshotValue.unicode.lastChar;
|
|
3443
3675
|
pendingRegionalIndicator = snapshotValue.unicode.pendingRegionalIndicator;
|
|
3444
3676
|
afterZWJ = snapshotValue.unicode.afterZWJ;
|
|
@@ -3472,7 +3704,7 @@ function createScreen(options = {}) {
|
|
|
3472
3704
|
}
|
|
3473
3705
|
function getText() {
|
|
3474
3706
|
const lines = [];
|
|
3475
|
-
for (let r = 0; r < rows; r++) lines.push(rowToString(grid
|
|
3707
|
+
for (let r = 0; r < rows; r++) lines.push(rowToString(itemAt(grid, r, "screen text rows")));
|
|
3476
3708
|
return lines.join("\n");
|
|
3477
3709
|
}
|
|
3478
3710
|
function getScrollbackText() {
|
|
@@ -3491,7 +3723,7 @@ function createScreen(options = {}) {
|
|
|
3491
3723
|
}
|
|
3492
3724
|
function getRowAbsolute(row) {
|
|
3493
3725
|
if (row < 0 || row >= scrollback.length + rows) return makeRow(cols).toCells();
|
|
3494
|
-
return (row < scrollback.length ? scrollback
|
|
3726
|
+
return (row < scrollback.length ? itemAt(scrollback, row, "scrollback rows") : itemAt(grid, row - scrollback.length, "screen rows")).toCells().map(stripCellColorIndex);
|
|
3495
3727
|
}
|
|
3496
3728
|
function firstRetainedRow() {
|
|
3497
3729
|
return trimmedRowCount;
|
|
@@ -3558,6 +3790,7 @@ function createScreen(options = {}) {
|
|
|
3558
3790
|
case "focusTracking": return focusTracking;
|
|
3559
3791
|
case "originMode": return originMode;
|
|
3560
3792
|
case "insertMode": return insertMode;
|
|
3793
|
+
case "newLineMode": return newLineMode;
|
|
3561
3794
|
case "reverseVideo": return reverseVideo;
|
|
3562
3795
|
case "syncOutput": return syncOutput;
|
|
3563
3796
|
case "sgrMouse": return sgrMouse;
|
|
@@ -3637,6 +3870,7 @@ function createScreen(options = {}) {
|
|
|
3637
3870
|
focusTracking,
|
|
3638
3871
|
originMode,
|
|
3639
3872
|
insertMode,
|
|
3873
|
+
newLineMode,
|
|
3640
3874
|
reverseVideo,
|
|
3641
3875
|
syncOutput,
|
|
3642
3876
|
leftRightMargin: leftRightMarginMode,
|
|
@@ -3647,7 +3881,7 @@ function createScreen(options = {}) {
|
|
|
3647
3881
|
};
|
|
3648
3882
|
}
|
|
3649
3883
|
function modesEq(a, b) {
|
|
3650
|
-
return a.altScreen === b.altScreen && a.cursorVisible === b.cursorVisible && a.bracketedPaste === b.bracketedPaste && a.applicationCursor === b.applicationCursor && a.applicationKeypad === b.applicationKeypad && a.autoWrap === b.autoWrap && a.mouseTracking === b.mouseTracking && a.mouseTrackingMode === b.mouseTrackingMode && a.sgrMouse === b.sgrMouse && a.utf8Mouse === b.utf8Mouse && a.focusTracking === b.focusTracking && a.originMode === b.originMode && a.insertMode === b.insertMode && a.reverseVideo === b.reverseVideo && a.syncOutput === b.syncOutput && a.leftRightMargin === b.leftRightMargin && a.colorSchemeReporting === b.colorSchemeReporting && a.kittyKeyboard === b.kittyKeyboard && a.kittyGraphics === b.kittyGraphics && a.sixel === b.sixel;
|
|
3884
|
+
return a.altScreen === b.altScreen && a.cursorVisible === b.cursorVisible && a.bracketedPaste === b.bracketedPaste && a.applicationCursor === b.applicationCursor && a.applicationKeypad === b.applicationKeypad && a.autoWrap === b.autoWrap && a.mouseTracking === b.mouseTracking && a.mouseTrackingMode === b.mouseTrackingMode && a.sgrMouse === b.sgrMouse && a.utf8Mouse === b.utf8Mouse && a.focusTracking === b.focusTracking && a.originMode === b.originMode && a.insertMode === b.insertMode && a.newLineMode === b.newLineMode && a.reverseVideo === b.reverseVideo && a.syncOutput === b.syncOutput && a.leftRightMargin === b.leftRightMargin && a.colorSchemeReporting === b.colorSchemeReporting && a.kittyKeyboard === b.kittyKeyboard && a.kittyGraphics === b.kittyGraphics && a.sixel === b.sixel;
|
|
3651
3885
|
}
|
|
3652
3886
|
const damageListeners = /* @__PURE__ */ new Set();
|
|
3653
3887
|
let damageLast = {
|
|
@@ -4059,7 +4293,7 @@ function serializeSnapshot(snapshot, options = {}) {
|
|
|
4059
4293
|
const wraps = snapshot.scrollbackSoftWrapped;
|
|
4060
4294
|
const last = snapshot.scrollback.length - 1;
|
|
4061
4295
|
for (let i = 0; i < snapshot.scrollback.length; i++) {
|
|
4062
|
-
const row = snapshot.scrollback
|
|
4296
|
+
const row = itemAt(snapshot.scrollback, i, "snapshot scrollback rows");
|
|
4063
4297
|
if (wraps?.[i] === true && i < last) out.push(serializeEncodeRow(row, hyperlinks, snapshot.cols), "\x1B[0m");
|
|
4064
4298
|
else out.push(serializeEncodeRow(row, hyperlinks), "\x1B[0m\r\n");
|
|
4065
4299
|
}
|
|
@@ -4098,6 +4332,8 @@ function serializeSnapshot(snapshot, options = {}) {
|
|
|
4098
4332
|
out.push(m.autoWrap ? "\x1B[?7h" : "\x1B[?7l");
|
|
4099
4333
|
if (snapshot.cursor.shape !== "block" || !snapshot.cursor.blinking) out.push(`\x1b[${String(serializeCursorStyleCode(snapshot.cursor.shape, snapshot.cursor.blinking))} q`);
|
|
4100
4334
|
if (snapshot.unicode.charsetG0) out.push("\x1B(0");
|
|
4335
|
+
if (snapshot.unicode.charsetG1) out.push("\x1B)0");
|
|
4336
|
+
if (snapshot.unicode.activeG1) out.push("");
|
|
4101
4337
|
if (m.insert && !excluded.has("insert")) out.push("\x1B[4h");
|
|
4102
4338
|
if (!serializeTabStopsAreDefault(snapshot.tabStops, snapshot.cols)) {
|
|
4103
4339
|
out.push("\x1B[3g");
|
|
@@ -4112,10 +4348,12 @@ function serializeSnapshot(snapshot, options = {}) {
|
|
|
4112
4348
|
if (hyperlinks && snapshot.attrs.url !== null) out.push(`\x1b]8;;${snapshot.attrs.url}\x1b\\`);
|
|
4113
4349
|
out.push(snapshot.cursor.visible ? "\x1B[?25h" : "\x1B[?25l");
|
|
4114
4350
|
const origin = m.origin && !excluded.has("origin");
|
|
4115
|
-
const
|
|
4351
|
+
const originX = snapshot.margins.leftRight ? snapshot.margins.left : 0;
|
|
4352
|
+
const limitX = snapshot.margins.leftRight ? snapshot.margins.right : snapshot.cols - 1;
|
|
4353
|
+
const inRegion = snapshot.cursor.y >= snapshot.margins.scrollTop && snapshot.cursor.y <= snapshot.margins.scrollBottom && snapshot.cursor.x >= originX && snapshot.cursor.x <= limitX;
|
|
4116
4354
|
if (origin && inRegion) {
|
|
4117
4355
|
out.push("\x1B[?6h");
|
|
4118
|
-
out.push(`\x1b[${String(snapshot.cursor.y - snapshot.margins.scrollTop + 1)};${String(snapshot.cursor.x + 1)}H`);
|
|
4356
|
+
out.push(`\x1b[${String(snapshot.cursor.y - snapshot.margins.scrollTop + 1)};${String(snapshot.cursor.x - originX + 1)}H`);
|
|
4119
4357
|
} else {
|
|
4120
4358
|
out.push(`\x1b[${String(snapshot.cursor.y + 1)};${String(snapshot.cursor.x + 1)}H`);
|
|
4121
4359
|
if (origin) out.push("\x1B[?6h");
|
|
@@ -4138,6 +4376,7 @@ const F_BLINK = 128;
|
|
|
4138
4376
|
const F_WIDE = 256;
|
|
4139
4377
|
const UL_SHIFT = 9;
|
|
4140
4378
|
const UL_MASK = 7;
|
|
4379
|
+
const F_PROTECTED = 65536;
|
|
4141
4380
|
const UNDERLINE_STYLES = [
|
|
4142
4381
|
"none",
|
|
4143
4382
|
"single",
|
|
@@ -4368,6 +4607,7 @@ function createInterner() {
|
|
|
4368
4607
|
if (cell.inverse) flags |= F_INVERSE;
|
|
4369
4608
|
if (cell.hidden) flags |= F_HIDDEN;
|
|
4370
4609
|
if (cell.blink) flags |= F_BLINK;
|
|
4610
|
+
if (cell.protected) flags |= F_PROTECTED;
|
|
4371
4611
|
if (cell.wide) flags |= F_WIDE;
|
|
4372
4612
|
flags |= ulIdx << UL_SHIFT;
|
|
4373
4613
|
const key = `${flags}|${fgRef}|${bgRef}|${ulRef}|${urlRef}`;
|
|
@@ -4536,6 +4776,7 @@ function makeCell(charIdx, styleIdx, strings, colors, styles) {
|
|
|
4536
4776
|
inverse: (style.flags & F_INVERSE) !== 0,
|
|
4537
4777
|
hidden: (style.flags & F_HIDDEN) !== 0,
|
|
4538
4778
|
blink: (style.flags & F_BLINK) !== 0,
|
|
4779
|
+
protected: (style.flags & F_PROTECTED) !== 0,
|
|
4539
4780
|
wide: (style.flags & F_WIDE) !== 0,
|
|
4540
4781
|
url
|
|
4541
4782
|
};
|
|
@@ -4589,6 +4830,7 @@ function encodeScreenSnapshotBinary(snapshot) {
|
|
|
4589
4830
|
savedState: snapshot.savedState,
|
|
4590
4831
|
attrs: snapshot.attrs,
|
|
4591
4832
|
modes: snapshot.modes,
|
|
4833
|
+
lineAttrs: snapshot.lineAttrs,
|
|
4592
4834
|
margins: snapshot.margins,
|
|
4593
4835
|
colors: snapshot.colors,
|
|
4594
4836
|
tabStops: snapshot.tabStops,
|
|
@@ -4656,6 +4898,7 @@ function decodeScreenSnapshotBinary(bytes) {
|
|
|
4656
4898
|
savedState: header.savedState,
|
|
4657
4899
|
attrs: header.attrs,
|
|
4658
4900
|
modes: header.modes,
|
|
4901
|
+
lineAttrs: header.lineAttrs,
|
|
4659
4902
|
margins: header.margins,
|
|
4660
4903
|
colors: header.colors,
|
|
4661
4904
|
tabStops: header.tabStops,
|