vterm.js 0.3.1 → 0.5.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/dist/index.mjs ADDED
@@ -0,0 +1,2501 @@
1
+ //#region src/screen.ts
2
+ /** Frozen sentinel for unwritten cells — never mutate, copy-on-write in writeChar(). */
3
+ const EMPTY_CELL = Object.freeze({
4
+ char: "",
5
+ fg: null,
6
+ bg: null,
7
+ bold: false,
8
+ faint: false,
9
+ italic: false,
10
+ underline: "none",
11
+ underlineColor: null,
12
+ overline: false,
13
+ strikethrough: false,
14
+ inverse: false,
15
+ hidden: false,
16
+ blink: false,
17
+ wide: false,
18
+ url: null
19
+ });
20
+ function emptyCell() {
21
+ return { ...EMPTY_CELL };
22
+ }
23
+ const ANSI_16 = [
24
+ {
25
+ r: 0,
26
+ g: 0,
27
+ b: 0
28
+ },
29
+ {
30
+ r: 128,
31
+ g: 0,
32
+ b: 0
33
+ },
34
+ {
35
+ r: 0,
36
+ g: 128,
37
+ b: 0
38
+ },
39
+ {
40
+ r: 128,
41
+ g: 128,
42
+ b: 0
43
+ },
44
+ {
45
+ r: 0,
46
+ g: 0,
47
+ b: 128
48
+ },
49
+ {
50
+ r: 128,
51
+ g: 0,
52
+ b: 128
53
+ },
54
+ {
55
+ r: 0,
56
+ g: 128,
57
+ b: 128
58
+ },
59
+ {
60
+ r: 192,
61
+ g: 192,
62
+ b: 192
63
+ },
64
+ {
65
+ r: 128,
66
+ g: 128,
67
+ b: 128
68
+ },
69
+ {
70
+ r: 255,
71
+ g: 0,
72
+ b: 0
73
+ },
74
+ {
75
+ r: 0,
76
+ g: 255,
77
+ b: 0
78
+ },
79
+ {
80
+ r: 255,
81
+ g: 255,
82
+ b: 0
83
+ },
84
+ {
85
+ r: 0,
86
+ g: 0,
87
+ b: 255
88
+ },
89
+ {
90
+ r: 255,
91
+ g: 0,
92
+ b: 255
93
+ },
94
+ {
95
+ r: 0,
96
+ g: 255,
97
+ b: 255
98
+ },
99
+ {
100
+ r: 255,
101
+ g: 255,
102
+ b: 255
103
+ }
104
+ ];
105
+ function buildPalette256() {
106
+ const palette = [...ANSI_16];
107
+ const levels = [
108
+ 0,
109
+ 95,
110
+ 135,
111
+ 175,
112
+ 215,
113
+ 255
114
+ ];
115
+ for (let r = 0; r < 6; r++) for (let g = 0; g < 6; g++) for (let b = 0; b < 6; b++) palette.push({
116
+ r: levels[r],
117
+ g: levels[g],
118
+ b: levels[b]
119
+ });
120
+ for (let i = 0; i < 24; i++) {
121
+ const v = 8 + i * 10;
122
+ palette.push({
123
+ r: v,
124
+ g: v,
125
+ b: v
126
+ });
127
+ }
128
+ return palette;
129
+ }
130
+ /**
131
+ * Parse an X11-style color spec: "rgb:RR/GG/BB", "rgb:RRRR/GGGG/BBBB",
132
+ * "#RRGGBB", "#RGB". Returns null if unparseable.
133
+ */
134
+ function parseColorSpec(spec) {
135
+ const s = spec.trim();
136
+ const rgbMatch = /^rgb:([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})$/.exec(s);
137
+ if (rgbMatch) {
138
+ const scale = (hex) => {
139
+ const v = parseInt(hex, 16);
140
+ const max = Math.pow(16, hex.length) - 1;
141
+ return Math.round(v * 255 / max);
142
+ };
143
+ return {
144
+ r: scale(rgbMatch[1]),
145
+ g: scale(rgbMatch[2]),
146
+ b: scale(rgbMatch[3])
147
+ };
148
+ }
149
+ const hex6 = /^#([0-9a-fA-F]{6})$/.exec(s);
150
+ if (hex6) {
151
+ const v = hex6[1];
152
+ return {
153
+ r: parseInt(v.substring(0, 2), 16),
154
+ g: parseInt(v.substring(2, 4), 16),
155
+ b: parseInt(v.substring(4, 6), 16)
156
+ };
157
+ }
158
+ const hex3 = /^#([0-9a-fA-F]{3})$/.exec(s);
159
+ if (hex3) {
160
+ const v = hex3[1];
161
+ const expand = (ch) => parseInt(ch + ch, 16);
162
+ return {
163
+ r: expand(v[0]),
164
+ g: expand(v[1]),
165
+ b: expand(v[2])
166
+ };
167
+ }
168
+ return null;
169
+ }
170
+ /** Format a color as X11 "rgb:RRRR/GGGG/BBBB" (16-bit per channel, standard xterm reply). */
171
+ function formatColorResponse(c) {
172
+ const scale = (v) => {
173
+ return Math.round(v * 65535 / 255).toString(16).padStart(4, "0");
174
+ };
175
+ return `rgb:${scale(c.r)}/${scale(c.g)}/${scale(c.b)}`;
176
+ }
177
+ const DEC_SPECIAL_GRAPHICS = {
178
+ j: "┘",
179
+ k: "┐",
180
+ l: "┌",
181
+ m: "└",
182
+ n: "┼",
183
+ q: "─",
184
+ t: "├",
185
+ u: "┤",
186
+ v: "┴",
187
+ w: "┬",
188
+ x: "│",
189
+ a: "▒",
190
+ f: "°",
191
+ g: "±",
192
+ "~": "·",
193
+ y: "≤",
194
+ z: "≥",
195
+ "{": "π",
196
+ "|": "≠",
197
+ "}": "£"
198
+ };
199
+ function isWide(codePoint) {
200
+ return codePoint >= 4352 && codePoint <= 4447 || codePoint >= 8986 && codePoint <= 8987 || codePoint >= 9748 && codePoint <= 9749 || codePoint >= 9800 && codePoint <= 9811 || codePoint === 9855 || codePoint === 9875 || codePoint === 9889 || codePoint === 9934 || codePoint === 9940 || codePoint === 9989 || codePoint === 10024 || codePoint === 10060 || codePoint === 10062 || codePoint >= 10067 && codePoint <= 10069 || codePoint >= 10133 && codePoint <= 10135 || codePoint === 10160 || codePoint === 10175 || codePoint >= 11904 && codePoint <= 12350 || codePoint >= 12353 && codePoint <= 13247 || codePoint >= 13312 && codePoint <= 19903 || codePoint >= 19968 && codePoint <= 42191 || codePoint >= 43360 && codePoint <= 43388 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65131 || codePoint >= 65281 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint === 126980 || codePoint === 127183 || codePoint >= 127344 && codePoint <= 127345 || codePoint >= 127358 && codePoint <= 127359 || codePoint === 127374 || codePoint >= 127377 && codePoint <= 127386 || codePoint >= 127462 && codePoint <= 127487 || codePoint >= 127488 && codePoint <= 127490 || codePoint >= 127744 && codePoint <= 129535 || codePoint >= 129536 && codePoint <= 129791 || codePoint >= 131072 && codePoint <= 196605 || codePoint >= 196608 && codePoint <= 262141;
201
+ }
202
+ function isCombining(cp) {
203
+ return cp >= 768 && cp <= 879 || cp >= 1155 && cp <= 1161 || cp >= 1425 && cp <= 1469 || cp === 1471 || cp >= 1473 && cp <= 1474 || cp >= 1476 && cp <= 1477 || cp === 1479 || cp >= 1552 && cp <= 1562 || cp >= 1611 && cp <= 1631 || cp === 1648 || cp >= 1750 && cp <= 1756 || cp >= 1759 && cp <= 1764 || cp >= 1767 && cp <= 1768 || cp >= 1770 && cp <= 1773 || cp >= 1840 && cp <= 1866 || cp >= 2304 && cp <= 2307 || cp >= 2362 && cp <= 2383 || cp >= 2385 && cp <= 2391 || cp >= 2402 && cp <= 2403 || cp === 3633 || cp >= 3636 && cp <= 3642 || cp >= 3655 && cp <= 3662 || cp >= 6832 && cp <= 6911 || cp >= 7616 && cp <= 7679 || cp >= 8400 && cp <= 8447 || cp >= 65024 && cp <= 65039 || cp >= 917760 && cp <= 917999;
204
+ }
205
+ function isRegionalIndicator(cp) {
206
+ return cp >= 127462 && cp <= 127487;
207
+ }
208
+ function isZWJ(cp) {
209
+ return cp === 8205;
210
+ }
211
+ function isVS16(cp) {
212
+ return cp === 65039;
213
+ }
214
+ function isEmojiModifier(cp) {
215
+ return cp >= 127995 && cp <= 127999;
216
+ }
217
+ function createScreen(options = {}) {
218
+ let cols = options.cols ?? 80;
219
+ let rows = options.rows ?? 24;
220
+ const scrollbackLimit = options.scrollbackLimit ?? 1e3;
221
+ const onResponse = options.onResponse;
222
+ let mainGrid = makeGrid(cols, rows);
223
+ let altGrid = makeGrid(cols, rows);
224
+ let grid = mainGrid;
225
+ let scrollback = [];
226
+ let curX = 0;
227
+ let curY = 0;
228
+ let curVisible = true;
229
+ let cursorShape = "block";
230
+ let cursorBlinking = true;
231
+ let savedState = {
232
+ curX: 0,
233
+ curY: 0,
234
+ attrs: resetAttrs(),
235
+ originMode: false,
236
+ autoWrap: true,
237
+ charsetG0: false
238
+ };
239
+ let savedCurX = 0;
240
+ let savedCurY = 0;
241
+ let attrs = resetAttrs();
242
+ let title = "";
243
+ let useAltScreen = false;
244
+ let bracketedPaste = false;
245
+ let applicationCursor = false;
246
+ let applicationKeypad = false;
247
+ let autoWrap = true;
248
+ let mouseTracking = false;
249
+ let mouseTrackingMode = 0;
250
+ let sgrMouse = false;
251
+ let focusTracking = false;
252
+ let originMode = false;
253
+ let insertMode = false;
254
+ let reverseVideo = false;
255
+ let syncOutput = false;
256
+ let kittyKeyboardFlags = 0;
257
+ let kittyKeyboardStack = [];
258
+ let hasKittyGraphics = false;
259
+ let scrollTop = 0;
260
+ let scrollBottom = rows - 1;
261
+ let leftRightMarginMode = false;
262
+ let leftMargin = 0;
263
+ let rightMargin = cols - 1;
264
+ let colorSchemeReporting = false;
265
+ let decColumnMode = false;
266
+ let altScrollMode = false;
267
+ let utf8MouseMode = false;
268
+ let palette256 = buildPalette256();
269
+ let defaultFgColor = null;
270
+ let defaultBgColor = null;
271
+ let cursorColor = null;
272
+ const specialColors = /* @__PURE__ */ new Map();
273
+ let pointerFgColor = null;
274
+ let pointerBgColor = null;
275
+ let highlightBgColor = null;
276
+ let highlightFgColor = null;
277
+ const colorStack = [];
278
+ function cloneColor(c) {
279
+ return c ? { ...c } : null;
280
+ }
281
+ function snapshotColorState() {
282
+ return {
283
+ palette256: palette256.map((c) => ({ ...c })),
284
+ defaultFgColor: cloneColor(defaultFgColor),
285
+ defaultBgColor: cloneColor(defaultBgColor),
286
+ cursorColor: cloneColor(cursorColor),
287
+ specialColors: [...specialColors].map(([idx, color]) => [idx, { ...color }]),
288
+ pointerFgColor: cloneColor(pointerFgColor),
289
+ pointerBgColor: cloneColor(pointerBgColor),
290
+ highlightBgColor: cloneColor(highlightBgColor),
291
+ highlightFgColor: cloneColor(highlightFgColor)
292
+ };
293
+ }
294
+ function restoreColorState(snapshot) {
295
+ palette256 = snapshot.palette256.map((c) => ({ ...c }));
296
+ defaultFgColor = cloneColor(snapshot.defaultFgColor);
297
+ defaultBgColor = cloneColor(snapshot.defaultBgColor);
298
+ cursorColor = cloneColor(snapshot.cursorColor);
299
+ specialColors.clear();
300
+ for (const [idx, color] of snapshot.specialColors) specialColors.set(idx, { ...color });
301
+ pointerFgColor = cloneColor(snapshot.pointerFgColor);
302
+ pointerBgColor = cloneColor(snapshot.pointerBgColor);
303
+ highlightBgColor = cloneColor(snapshot.highlightBgColor);
304
+ highlightFgColor = cloneColor(snapshot.highlightFgColor);
305
+ }
306
+ let tabStops = defaultTabStops(cols);
307
+ function defaultTabStops(c) {
308
+ const s = /* @__PURE__ */ new Set();
309
+ for (let i = 8; i < c; i += 8) s.add(i);
310
+ return s;
311
+ }
312
+ function nextTabStop(x) {
313
+ for (let i = x + 1; i < cols; i++) if (tabStops.has(i)) return i;
314
+ if (tabStops.size === 0) return x;
315
+ return cols - 1;
316
+ }
317
+ function prevTabStop(x) {
318
+ for (let i = x - 1; i > 0; i--) if (tabStops.has(i)) return i;
319
+ return 0;
320
+ }
321
+ let textScale = 1;
322
+ const CELL_W_PX = 8;
323
+ const CELL_H_PX = 17;
324
+ const FONT_ASCENT_PX = 14;
325
+ let fontSize = 12;
326
+ let fontWindowSize = 12;
327
+ let locale = "en_US.UTF-8";
328
+ let advancedClipboard = "";
329
+ let viewportOffset = 0;
330
+ let charsetG0 = false;
331
+ let clipboard = "";
332
+ let cwd = "";
333
+ let notifications = [];
334
+ let semanticZones = [];
335
+ let hasSixel = false;
336
+ let sixelImages = [];
337
+ let mainSoftWrapped = new Array(rows).fill(false);
338
+ let altSoftWrapped = new Array(rows).fill(false);
339
+ let softWrapped = mainSoftWrapped;
340
+ let lastChar = "";
341
+ let pendingRegionalIndicator = null;
342
+ let afterZWJ = false;
343
+ let parserState = "ground";
344
+ let escBuf = "";
345
+ let oscBuf = "";
346
+ let dcsBuf = "";
347
+ let dcsStartRow = 0;
348
+ let dcsStartCol = 0;
349
+ let apcBuf = "";
350
+ const decoder = new TextDecoder();
351
+ function makeGrid(c, r) {
352
+ const g = [];
353
+ for (let row = 0; row < r; row++) g.push(makeRow(c));
354
+ return g;
355
+ }
356
+ function makeRow(c) {
357
+ const row = [];
358
+ for (let col = 0; col < c; col++) row.push(EMPTY_CELL);
359
+ return row;
360
+ }
361
+ function resetAttrs() {
362
+ return {
363
+ fg: null,
364
+ bg: null,
365
+ bold: false,
366
+ faint: false,
367
+ italic: false,
368
+ underline: "none",
369
+ underlineColor: null,
370
+ overline: false,
371
+ strikethrough: false,
372
+ inverse: false,
373
+ hidden: false,
374
+ blink: false,
375
+ url: null
376
+ };
377
+ }
378
+ function clampCursor() {
379
+ if (curX < 0) curX = 0;
380
+ if (curX >= cols) curX = cols - 1;
381
+ if (curY < 0) curY = 0;
382
+ if (curY >= rows) curY = rows - 1;
383
+ }
384
+ function scrollUp(top, bottom) {
385
+ if (leftRightMarginMode && (leftMargin > 0 || rightMargin < cols - 1)) {
386
+ const lm = leftMargin;
387
+ const rm = rightMargin;
388
+ for (let r = top; r < bottom; r++) {
389
+ const srcRow = grid[r + 1];
390
+ const dstRow = grid[r];
391
+ for (let c = lm; c <= rm && c < cols; c++) dstRow[c] = srcRow[c];
392
+ }
393
+ const bottomRow = grid[bottom];
394
+ for (let c = lm; c <= rm && c < cols; c++) bottomRow[c] = EMPTY_CELL;
395
+ } else {
396
+ if (grid === mainGrid && top === 0) {
397
+ scrollback.push(grid[0]);
398
+ if (scrollback.length > scrollbackLimit * 2) scrollback.splice(0, scrollback.length - scrollbackLimit);
399
+ }
400
+ for (let i = top; i < bottom; i++) {
401
+ grid[i] = grid[i + 1];
402
+ softWrapped[i] = softWrapped[i + 1];
403
+ }
404
+ grid[bottom] = makeRow(cols);
405
+ softWrapped[bottom] = false;
406
+ }
407
+ }
408
+ function scrollDown(top, bottom) {
409
+ if (leftRightMarginMode && (leftMargin > 0 || rightMargin < cols - 1)) {
410
+ const lm = leftMargin;
411
+ const rm = rightMargin;
412
+ for (let r = bottom; r > top; r--) {
413
+ const srcRow = grid[r - 1];
414
+ const dstRow = grid[r];
415
+ for (let c = lm; c <= rm && c < cols; c++) dstRow[c] = srcRow[c];
416
+ }
417
+ const topRow = grid[top];
418
+ for (let c = lm; c <= rm && c < cols; c++) topRow[c] = EMPTY_CELL;
419
+ } else {
420
+ for (let i = bottom; i > top; i--) {
421
+ grid[i] = grid[i - 1];
422
+ softWrapped[i] = softWrapped[i - 1];
423
+ }
424
+ grid[top] = makeRow(cols);
425
+ softWrapped[top] = false;
426
+ }
427
+ }
428
+ function scrollViewport(delta) {
429
+ viewportOffset = Math.max(0, Math.min(scrollback.length, viewportOffset + delta));
430
+ }
431
+ /** Find the previous non-spacer cell (the cell before curX, skipping wide-char spacers) */
432
+ function getPrevCell() {
433
+ if (curX === 0 && curY === 0) return null;
434
+ let prevCol = curX - 1;
435
+ let prevRow = curY;
436
+ if (prevCol < 0) {
437
+ prevRow--;
438
+ if (prevRow < 0) return null;
439
+ prevCol = cols - 1;
440
+ }
441
+ const row = grid[prevRow];
442
+ let cell = row[prevCol];
443
+ if (cell !== EMPTY_CELL && cell.char === "" && prevCol > 0) {
444
+ prevCol--;
445
+ cell = row[prevCol];
446
+ }
447
+ if (cell === EMPTY_CELL) return null;
448
+ return {
449
+ cell,
450
+ col: prevCol
451
+ };
452
+ }
453
+ /** Widen a cell to 2 columns, adding a spacer cell after it */
454
+ function widenCell(row, col, cell) {
455
+ cell.wide = true;
456
+ if (col + 1 < cols) {
457
+ let spacer = row[col + 1];
458
+ if (spacer === EMPTY_CELL) {
459
+ spacer = { ...EMPTY_CELL };
460
+ row[col + 1] = spacer;
461
+ }
462
+ spacer.char = "";
463
+ spacer.fg = null;
464
+ spacer.bg = null;
465
+ spacer.bold = false;
466
+ spacer.faint = false;
467
+ spacer.italic = false;
468
+ spacer.underline = "none";
469
+ spacer.underlineColor = null;
470
+ spacer.overline = false;
471
+ spacer.strikethrough = false;
472
+ spacer.inverse = false;
473
+ spacer.hidden = false;
474
+ spacer.blink = false;
475
+ spacer.wide = false;
476
+ spacer.url = null;
477
+ }
478
+ }
479
+ function writeChar(ch) {
480
+ if (charsetG0 && ch.length === 1) {
481
+ const mapped = DEC_SPECIAL_GRAPHICS[ch];
482
+ if (mapped) ch = mapped;
483
+ }
484
+ const codePoint = ch.codePointAt(0) ?? 0;
485
+ if (isVS16(codePoint)) {
486
+ const prev = getPrevCell();
487
+ if (prev && !prev.cell.wide) {
488
+ prev.cell.char += ch;
489
+ const row = grid[curY === 0 && curX === 0 ? 0 : curY];
490
+ widenCell(row, prev.col, prev.cell);
491
+ curX = prev.col + 2;
492
+ if (curX >= cols) curX = cols - 1;
493
+ }
494
+ return;
495
+ }
496
+ if (isCombining(codePoint) && !isVS16(codePoint)) {
497
+ const prev = getPrevCell();
498
+ if (prev) prev.cell.char += ch;
499
+ return;
500
+ }
501
+ if (isEmojiModifier(codePoint)) {
502
+ const prev = getPrevCell();
503
+ if (prev) prev.cell.char += ch;
504
+ return;
505
+ }
506
+ if (isZWJ(codePoint)) {
507
+ const prev = getPrevCell();
508
+ if (prev) {
509
+ prev.cell.char += ch;
510
+ afterZWJ = true;
511
+ }
512
+ return;
513
+ }
514
+ if (afterZWJ) {
515
+ afterZWJ = false;
516
+ const prev = getPrevCell();
517
+ if (prev) {
518
+ prev.cell.char += ch;
519
+ return;
520
+ }
521
+ }
522
+ if (isRegionalIndicator(codePoint)) if (pendingRegionalIndicator !== null) {
523
+ const flag = pendingRegionalIndicator + ch;
524
+ pendingRegionalIndicator = null;
525
+ writeCharCore(flag, true);
526
+ return;
527
+ } else {
528
+ pendingRegionalIndicator = ch;
529
+ return;
530
+ }
531
+ if (pendingRegionalIndicator !== null) {
532
+ const ri = pendingRegionalIndicator;
533
+ pendingRegionalIndicator = null;
534
+ writeCharCore(ri, true);
535
+ }
536
+ const wide = isWide(codePoint);
537
+ writeCharCore(ch, wide);
538
+ }
539
+ function writeCharCore(ch, wide) {
540
+ if (cols <= 0 || rows <= 0) return;
541
+ const charWidth = wide ? 2 : 1;
542
+ const wrapBoundary = leftRightMarginMode ? rightMargin + 1 : cols;
543
+ const wrapReturn = leftRightMarginMode ? leftMargin : 0;
544
+ if (curX + charWidth > wrapBoundary) if (autoWrap) {
545
+ softWrapped[curY] = true;
546
+ curX = wrapReturn;
547
+ curY++;
548
+ if (curY > scrollBottom) {
549
+ curY = scrollBottom;
550
+ scrollUp(scrollTop, scrollBottom);
551
+ }
552
+ } else curX = wrapBoundary - charWidth;
553
+ if (insertMode) {
554
+ const row = grid[curY];
555
+ const insertEnd = leftRightMarginMode ? rightMargin + 1 : cols;
556
+ for (let i = 0; i < charWidth; i++) {
557
+ row.splice(insertEnd - 1, 1);
558
+ row.splice(curX, 0, EMPTY_CELL);
559
+ }
560
+ }
561
+ const row = grid[curY];
562
+ let cell = row[curX];
563
+ if (cell === EMPTY_CELL) {
564
+ cell = { ...EMPTY_CELL };
565
+ row[curX] = cell;
566
+ }
567
+ cell.char = ch;
568
+ cell.fg = attrs.fg ? { ...attrs.fg } : null;
569
+ cell.bg = attrs.bg ? { ...attrs.bg } : null;
570
+ cell.bold = attrs.bold;
571
+ cell.faint = attrs.faint;
572
+ cell.italic = attrs.italic;
573
+ cell.underline = attrs.underline;
574
+ cell.underlineColor = attrs.underlineColor ? { ...attrs.underlineColor } : null;
575
+ cell.overline = attrs.overline;
576
+ cell.strikethrough = attrs.strikethrough;
577
+ cell.inverse = attrs.inverse;
578
+ cell.hidden = attrs.hidden;
579
+ cell.blink = attrs.blink;
580
+ cell.wide = wide;
581
+ cell.url = attrs.url;
582
+ if (wide) widenCell(row, curX, cell);
583
+ curX += charWidth;
584
+ lastChar = ch;
585
+ }
586
+ function handleCSI(params, intermediates, finalByte) {
587
+ const parts = params.split(";").map((s) => s === "" ? 0 : parseInt(s, 10));
588
+ if (intermediates === " ") {
589
+ if (finalByte === "q") switch (parts[0] ?? 0) {
590
+ case 0:
591
+ case 1:
592
+ cursorShape = "block";
593
+ cursorBlinking = true;
594
+ break;
595
+ case 2:
596
+ cursorShape = "block";
597
+ cursorBlinking = false;
598
+ break;
599
+ case 3:
600
+ cursorShape = "underline";
601
+ cursorBlinking = true;
602
+ break;
603
+ case 4:
604
+ cursorShape = "underline";
605
+ cursorBlinking = false;
606
+ break;
607
+ case 5:
608
+ cursorShape = "bar";
609
+ cursorBlinking = true;
610
+ break;
611
+ case 6:
612
+ cursorShape = "bar";
613
+ cursorBlinking = false;
614
+ break;
615
+ }
616
+ else if (finalByte === "@") handleShiftLeft(Math.max(parts[0] ?? 1, 1));
617
+ else if (finalByte === "A") handleShiftRight(Math.max(parts[0] ?? 1, 1));
618
+ return;
619
+ }
620
+ if (intermediates === "!") {
621
+ if (finalByte === "p") softReset();
622
+ return;
623
+ }
624
+ if (intermediates === "$") {
625
+ const normalizeRect = (top, left, bottom, right) => {
626
+ return {
627
+ t: Math.max(1, top) - 1,
628
+ l: Math.max(1, left) - 1,
629
+ b: (bottom <= 0 ? rows : Math.min(bottom, rows)) - 1,
630
+ r: (right <= 0 ? cols : Math.min(right, cols)) - 1
631
+ };
632
+ };
633
+ if (finalByte === "x") {
634
+ const charCode = parts[0] ?? 32;
635
+ if (charCode < 32 || charCode > 126) return;
636
+ const { t, l, b, r } = normalizeRect(parts[1] ?? 1, parts[2] ?? 1, parts[3] ?? rows, parts[4] ?? cols);
637
+ for (let row = t; row <= b && row < rows; row++) for (let col = l; col <= r && col < cols; col++) {
638
+ const cell = emptyCell();
639
+ cell.char = String.fromCharCode(charCode);
640
+ grid[row][col] = cell;
641
+ }
642
+ } else if (finalByte === "z" || finalByte === "{") {
643
+ const { t, l, b, r } = normalizeRect(parts[0] ?? 1, parts[1] ?? 1, parts[2] ?? rows, parts[3] ?? cols);
644
+ for (let row = t; row <= b && row < rows; row++) for (let col = l; col <= r && col < cols; col++) grid[row][col] = emptyCell();
645
+ } else if (finalByte === "v") {
646
+ const src = normalizeRect(parts[0] ?? 1, parts[1] ?? 1, parts[2] ?? rows, parts[3] ?? cols);
647
+ const dstTop = Math.max(1, parts[5] ?? 1) - 1;
648
+ const dstLeft = Math.max(1, parts[6] ?? 1) - 1;
649
+ const h = src.b - src.t + 1;
650
+ const w = src.r - src.l + 1;
651
+ const snapshot = [];
652
+ for (let row = 0; row < h; row++) {
653
+ const line = [];
654
+ for (let col = 0; col < w; col++) {
655
+ const srcCell = grid[src.t + row]?.[src.l + col] ?? EMPTY_CELL;
656
+ line.push(srcCell === EMPTY_CELL ? EMPTY_CELL : { ...srcCell });
657
+ }
658
+ snapshot.push(line);
659
+ }
660
+ for (let row = 0; row < h; row++) {
661
+ const dr = dstTop + row;
662
+ if (dr < 0 || dr >= rows) continue;
663
+ for (let col = 0; col < w; col++) {
664
+ const dc = dstLeft + col;
665
+ if (dc < 0 || dc >= cols) continue;
666
+ grid[dr][dc] = snapshot[row][col];
667
+ }
668
+ }
669
+ } else if (finalByte === "r" || finalByte === "t") {
670
+ const { t, l, b, r } = normalizeRect(parts[0] ?? 1, parts[1] ?? 1, parts[2] ?? rows, parts[3] ?? cols);
671
+ const sgrParts = parts.slice(4);
672
+ const reverse = finalByte === "t";
673
+ for (let row = t; row <= b && row < rows; row++) for (let col = l; col <= r && col < cols; col++) {
674
+ let cell = grid[row][col];
675
+ if (cell === EMPTY_CELL) {
676
+ cell = { ...EMPTY_CELL };
677
+ grid[row][col] = cell;
678
+ }
679
+ applyRectAttrs(cell, sgrParts, reverse);
680
+ }
681
+ }
682
+ return;
683
+ }
684
+ if (intermediates === "*") {
685
+ if (finalByte === "y") {
686
+ const pid = parts[0] ?? 0;
687
+ const tArg = parts[2] ?? 1;
688
+ const lArg = parts[3] ?? 1;
689
+ const bArg = parts[4] ?? rows;
690
+ const rArg = parts[5] ?? cols;
691
+ const t = Math.max(1, tArg) - 1;
692
+ const l = Math.max(1, lArg) - 1;
693
+ const b = Math.min(bArg, rows) - 1;
694
+ const r = Math.min(rArg, cols) - 1;
695
+ let sum = 0;
696
+ for (let row = t; row <= b && row < rows; row++) for (let col = l; col <= r && col < cols; col++) {
697
+ const cell = grid[row]?.[col];
698
+ if (cell?.char) {
699
+ const cp = cell.char.codePointAt(0) ?? 0;
700
+ sum = sum + cp & 65535;
701
+ }
702
+ }
703
+ const hex = sum.toString(16).toUpperCase().padStart(4, "0");
704
+ if (onResponse) onResponse(`\x1bP${pid}!~${hex}\x1b\\`);
705
+ } else if (finalByte === "x") {}
706
+ return;
707
+ }
708
+ if (intermediates === "'") {
709
+ if (finalByte === "}") handleInsertColumn(Math.max(parts[0] ?? 1, 1));
710
+ else if (finalByte === "~") handleDeleteColumn(Math.max(parts[0] ?? 1, 1));
711
+ return;
712
+ }
713
+ switch (finalByte) {
714
+ case "A":
715
+ curY -= Math.max(parts[0] ?? 1, 1);
716
+ clampCursor();
717
+ break;
718
+ case "B":
719
+ curY += Math.max(parts[0] ?? 1, 1);
720
+ clampCursor();
721
+ break;
722
+ case "C":
723
+ curX += Math.max(parts[0] ?? 1, 1);
724
+ clampCursor();
725
+ break;
726
+ case "D":
727
+ curX -= Math.max(parts[0] ?? 1, 1);
728
+ clampCursor();
729
+ break;
730
+ case "E":
731
+ curY += Math.max(parts[0] ?? 1, 1);
732
+ curX = 0;
733
+ clampCursor();
734
+ break;
735
+ case "F":
736
+ curY -= Math.max(parts[0] ?? 1, 1);
737
+ curX = 0;
738
+ clampCursor();
739
+ break;
740
+ case "G":
741
+ case "`":
742
+ curX = (parts[0] ?? 1) - 1;
743
+ clampCursor();
744
+ break;
745
+ case "g":
746
+ if ((parts[0] ?? 0) === 3) tabStops.clear();
747
+ else tabStops.delete(curX);
748
+ break;
749
+ case "I": {
750
+ const count = Math.max(parts[0] ?? 1, 1);
751
+ for (let t = 0; t < count; t++) curX = nextTabStop(curX);
752
+ clampCursor();
753
+ break;
754
+ }
755
+ case "Z": {
756
+ const count = Math.max(parts[0] ?? 1, 1);
757
+ for (let t = 0; t < count; t++) curX = prevTabStop(curX);
758
+ clampCursor();
759
+ break;
760
+ }
761
+ case "t": {
762
+ const op = parts[0] ?? 0;
763
+ if (!onResponse) break;
764
+ const CELL_H = 16;
765
+ const CELL_W = 8;
766
+ switch (op) {
767
+ case 14:
768
+ onResponse(`\x1b[4;${rows * CELL_H};${cols * CELL_W}t`);
769
+ break;
770
+ case 16:
771
+ onResponse(`\x1b[6;${CELL_H};${CELL_W}t`);
772
+ break;
773
+ case 18:
774
+ onResponse(`\x1b[8;${rows};${cols}t`);
775
+ break;
776
+ case 20:
777
+ onResponse(`\x1b]L${title}\x1b\\`);
778
+ break;
779
+ case 21:
780
+ onResponse(`\x1b]l${title}\x1b\\`);
781
+ break;
782
+ }
783
+ break;
784
+ }
785
+ case "H":
786
+ case "f":
787
+ if (originMode) {
788
+ curY = scrollTop + (parts[0] ?? 1) - 1;
789
+ curX = (parts[1] ?? 1) - 1;
790
+ if (curY < scrollTop) curY = scrollTop;
791
+ if (curY > scrollBottom) curY = scrollBottom;
792
+ if (curX < 0) curX = 0;
793
+ if (curX >= cols) curX = cols - 1;
794
+ } else {
795
+ curY = (parts[0] ?? 1) - 1;
796
+ curX = (parts[1] ?? 1) - 1;
797
+ clampCursor();
798
+ }
799
+ break;
800
+ case "J":
801
+ handleEraseDisplay(parts[0] ?? 0);
802
+ break;
803
+ case "K":
804
+ handleEraseLine(parts[0] ?? 0);
805
+ break;
806
+ case "L":
807
+ handleInsertLines(Math.max(parts[0] ?? 1, 1));
808
+ break;
809
+ case "M":
810
+ handleDeleteLines(Math.max(parts[0] ?? 1, 1));
811
+ break;
812
+ case "P":
813
+ handleDeleteChars(Math.max(parts[0] ?? 1, 1));
814
+ break;
815
+ case "@":
816
+ handleInsertChars(Math.max(parts[0] ?? 1, 1));
817
+ break;
818
+ case "X":
819
+ handleEraseChars(Math.max(parts[0] ?? 1, 1));
820
+ break;
821
+ case "S":
822
+ for (let i = 0; i < Math.max(parts[0] ?? 1, 1); i++) scrollUp(scrollTop, scrollBottom);
823
+ break;
824
+ case "T":
825
+ for (let i = 0; i < Math.max(parts[0] ?? 1, 1); i++) scrollDown(scrollTop, scrollBottom);
826
+ break;
827
+ case "b":
828
+ if (lastChar) {
829
+ const count = Math.max(parts[0] ?? 1, 1);
830
+ for (let i = 0; i < count; i++) writeChar(lastChar);
831
+ }
832
+ break;
833
+ case "d":
834
+ curY = (parts[0] ?? 1) - 1;
835
+ clampCursor();
836
+ break;
837
+ case "m":
838
+ handleSGR(params);
839
+ break;
840
+ case "r":
841
+ scrollTop = (parts[0] ?? 1) - 1;
842
+ scrollBottom = (parts[1] ?? rows) - 1;
843
+ if (scrollTop < 0) scrollTop = 0;
844
+ if (scrollBottom >= rows) scrollBottom = rows - 1;
845
+ if (scrollTop > scrollBottom) {
846
+ scrollTop = 0;
847
+ scrollBottom = rows - 1;
848
+ }
849
+ curX = 0;
850
+ curY = originMode ? scrollTop : 0;
851
+ break;
852
+ case "n":
853
+ if (onResponse) {
854
+ if (parts[0] === 5) onResponse("\x1B[0n");
855
+ else if (parts[0] === 6) onResponse(`\x1b[${curY + 1};${curX + 1}R`);
856
+ }
857
+ break;
858
+ case "c":
859
+ if (onResponse) {
860
+ if (params === "" || params === "0") onResponse("\x1B[?62;4c");
861
+ }
862
+ break;
863
+ case "h":
864
+ for (const code of parts) if (code === 4) insertMode = true;
865
+ break;
866
+ case "l":
867
+ for (const code of parts) if (code === 4) insertMode = false;
868
+ break;
869
+ case "s":
870
+ if (leftRightMarginMode && intermediates === "") {
871
+ const pl = parts[0] ?? 0;
872
+ const pr = parts[1] ?? 0;
873
+ leftMargin = pl > 0 ? pl - 1 : 0;
874
+ rightMargin = pr > 0 ? pr - 1 : cols - 1;
875
+ if (leftMargin >= rightMargin) {
876
+ leftMargin = 0;
877
+ rightMargin = cols - 1;
878
+ }
879
+ if (leftMargin >= cols) leftMargin = 0;
880
+ if (rightMargin >= cols) rightMargin = cols - 1;
881
+ curX = originMode ? leftMargin : 0;
882
+ curY = originMode ? scrollTop : 0;
883
+ } else {
884
+ savedCurX = curX;
885
+ savedCurY = curY;
886
+ }
887
+ break;
888
+ case "u":
889
+ curX = savedCurX;
890
+ curY = savedCurY;
891
+ clampCursor();
892
+ break;
893
+ default: break;
894
+ }
895
+ }
896
+ function handleCSIGt(params, _intermediates, finalByte) {
897
+ const parts = params.split(";").map((s) => s === "" ? 0 : parseInt(s, 10));
898
+ if (finalByte === "c") {
899
+ if (onResponse) {
900
+ if (params === "" || params === "0") onResponse("\x1B[>1;100;0c");
901
+ }
902
+ } else if (finalByte === "q") {
903
+ if (onResponse) {
904
+ if (params === "" || params === "0") onResponse("\x1BP>|vterm.js 0.1.0\x1B\\");
905
+ }
906
+ } else if (finalByte === "u") {
907
+ kittyKeyboardStack.push(kittyKeyboardFlags);
908
+ kittyKeyboardFlags = parts[0] ?? 0;
909
+ }
910
+ }
911
+ function handleCSILt(_params, _intermediates, finalByte) {
912
+ if (finalByte === "u") kittyKeyboardFlags = kittyKeyboardStack.pop() ?? 0;
913
+ }
914
+ function handleCSIEq(params, _intermediates, finalByte) {
915
+ if (finalByte === "c") {
916
+ if (onResponse) {
917
+ if (params === "" || params === "0") onResponse("\x1BP!|00000000\x1B\\");
918
+ }
919
+ }
920
+ }
921
+ function handleCSIPrivate(params, intermediates, finalByte) {
922
+ const parts = params.split(";").map((s) => s === "" ? 0 : parseInt(s, 10));
923
+ if (finalByte === "u") {
924
+ if (onResponse) onResponse(`\x1b[?${kittyKeyboardFlags}u`);
925
+ return;
926
+ }
927
+ if (intermediates === "$" && finalByte === "p") {
928
+ if (onResponse) {
929
+ const mode = parts[0] ?? 0;
930
+ let value = 0;
931
+ switch (mode) {
932
+ case 1:
933
+ value = applicationCursor ? 1 : 2;
934
+ break;
935
+ case 6:
936
+ value = originMode ? 1 : 2;
937
+ break;
938
+ case 7:
939
+ value = autoWrap ? 1 : 2;
940
+ break;
941
+ case 25:
942
+ value = curVisible ? 1 : 2;
943
+ break;
944
+ case 47:
945
+ case 1047:
946
+ case 1049:
947
+ value = useAltScreen ? 1 : 2;
948
+ break;
949
+ case 66:
950
+ value = applicationKeypad ? 1 : 2;
951
+ break;
952
+ case 1e3:
953
+ case 1002:
954
+ case 1003:
955
+ value = mouseTracking ? 1 : 2;
956
+ break;
957
+ case 1004:
958
+ value = focusTracking ? 1 : 2;
959
+ break;
960
+ case 1006:
961
+ value = sgrMouse ? 1 : 2;
962
+ break;
963
+ case 2004:
964
+ value = bracketedPaste ? 1 : 2;
965
+ break;
966
+ case 2026:
967
+ value = syncOutput ? 1 : 2;
968
+ break;
969
+ case 69:
970
+ value = leftRightMarginMode ? 1 : 2;
971
+ break;
972
+ case 2031:
973
+ value = colorSchemeReporting ? 1 : 2;
974
+ break;
975
+ case 5:
976
+ value = reverseVideo ? 1 : 2;
977
+ break;
978
+ case 4:
979
+ value = insertMode ? 1 : 2;
980
+ break;
981
+ case 3:
982
+ value = decColumnMode ? 1 : 2;
983
+ break;
984
+ case 1005:
985
+ value = utf8MouseMode ? 1 : 2;
986
+ break;
987
+ case 1007:
988
+ value = altScrollMode ? 1 : 2;
989
+ break;
990
+ case 1048:
991
+ value = 2;
992
+ break;
993
+ }
994
+ onResponse(`\x1b[?${mode};${value}$y`);
995
+ }
996
+ return;
997
+ }
998
+ if (finalByte === "n") {
999
+ if (onResponse) {
1000
+ const ps = parts[0] ?? 0;
1001
+ if (ps === 6) onResponse(`\x1b[?${curY + 1};${curX + 1}n`);
1002
+ else if (ps === 997) onResponse("\x1B[?997;1n");
1003
+ }
1004
+ return;
1005
+ }
1006
+ if (finalByte === "J") {
1007
+ handleEraseDisplay(parts[0] ?? 0);
1008
+ return;
1009
+ }
1010
+ if (finalByte === "K") {
1011
+ handleEraseLine(parts[0] ?? 0);
1012
+ return;
1013
+ }
1014
+ const set = finalByte === "h";
1015
+ for (const code of parts) switch (code) {
1016
+ case 1:
1017
+ applicationCursor = set;
1018
+ break;
1019
+ case 4:
1020
+ insertMode = set;
1021
+ break;
1022
+ case 5:
1023
+ reverseVideo = set;
1024
+ break;
1025
+ case 6:
1026
+ originMode = set;
1027
+ break;
1028
+ case 7:
1029
+ autoWrap = set;
1030
+ break;
1031
+ case 25:
1032
+ curVisible = set;
1033
+ break;
1034
+ case 47:
1035
+ case 1047:
1036
+ if (set && !useAltScreen) {
1037
+ useAltScreen = true;
1038
+ grid = altGrid;
1039
+ softWrapped = altSoftWrapped;
1040
+ } else if (!set && useAltScreen) {
1041
+ useAltScreen = false;
1042
+ grid = mainGrid;
1043
+ softWrapped = mainSoftWrapped;
1044
+ }
1045
+ break;
1046
+ case 66:
1047
+ applicationKeypad = set;
1048
+ break;
1049
+ case 9:
1050
+ case 1e3:
1051
+ case 1002:
1052
+ case 1003:
1053
+ case 1015:
1054
+ case 1016:
1055
+ mouseTracking = set;
1056
+ mouseTrackingMode = set ? code : 0;
1057
+ break;
1058
+ case 1004:
1059
+ focusTracking = set;
1060
+ break;
1061
+ case 1006:
1062
+ sgrMouse = set;
1063
+ break;
1064
+ case 1049:
1065
+ if (set && !useAltScreen) {
1066
+ savedCurX = curX;
1067
+ savedCurY = curY;
1068
+ useAltScreen = true;
1069
+ altGrid = makeGrid(cols, rows);
1070
+ altSoftWrapped = new Array(rows).fill(false);
1071
+ grid = altGrid;
1072
+ softWrapped = altSoftWrapped;
1073
+ curX = 0;
1074
+ curY = 0;
1075
+ } else if (!set && useAltScreen) {
1076
+ useAltScreen = false;
1077
+ grid = mainGrid;
1078
+ softWrapped = mainSoftWrapped;
1079
+ curX = savedCurX;
1080
+ curY = savedCurY;
1081
+ clampCursor();
1082
+ }
1083
+ break;
1084
+ case 69:
1085
+ leftRightMarginMode = set;
1086
+ if (!set) {
1087
+ leftMargin = 0;
1088
+ rightMargin = cols - 1;
1089
+ }
1090
+ break;
1091
+ case 2004:
1092
+ bracketedPaste = set;
1093
+ break;
1094
+ case 2026:
1095
+ syncOutput = set;
1096
+ break;
1097
+ case 2031:
1098
+ colorSchemeReporting = set;
1099
+ break;
1100
+ case 3:
1101
+ decColumnMode = set;
1102
+ for (let row = 0; row < rows; row++) eraseCells(row, 0, row, cols - 1);
1103
+ curX = 0;
1104
+ curY = 0;
1105
+ break;
1106
+ case 1005:
1107
+ utf8MouseMode = set;
1108
+ break;
1109
+ case 1007:
1110
+ altScrollMode = set;
1111
+ break;
1112
+ case 1048:
1113
+ if (set) {
1114
+ savedCurX = curX;
1115
+ savedCurY = curY;
1116
+ } else {
1117
+ curX = savedCurX;
1118
+ curY = savedCurY;
1119
+ clampCursor();
1120
+ }
1121
+ break;
1122
+ }
1123
+ }
1124
+ function handleEraseDisplay(mode) {
1125
+ switch (mode) {
1126
+ case 0:
1127
+ eraseCells(curY, curX, curY, cols - 1);
1128
+ for (let row = curY + 1; row < rows; row++) eraseCells(row, 0, row, cols - 1);
1129
+ break;
1130
+ case 1:
1131
+ for (let row = 0; row < curY; row++) eraseCells(row, 0, row, cols - 1);
1132
+ eraseCells(curY, 0, curY, curX);
1133
+ break;
1134
+ case 2:
1135
+ case 3:
1136
+ for (let row = 0; row < rows; row++) eraseCells(row, 0, row, cols - 1);
1137
+ if (mode === 3) scrollback.length = 0;
1138
+ break;
1139
+ }
1140
+ }
1141
+ function handleEraseLine(mode) {
1142
+ const eraseRight = leftRightMarginMode ? rightMargin : cols - 1;
1143
+ const eraseLeft = leftRightMarginMode ? leftMargin : 0;
1144
+ switch (mode) {
1145
+ case 0:
1146
+ eraseCells(curY, curX, curY, eraseRight);
1147
+ break;
1148
+ case 1:
1149
+ eraseCells(curY, eraseLeft, curY, curX);
1150
+ break;
1151
+ case 2:
1152
+ eraseCells(curY, eraseLeft, curY, eraseRight);
1153
+ break;
1154
+ }
1155
+ }
1156
+ function eraseCells(row, startCol, _endRow, endCol) {
1157
+ const r = grid[row];
1158
+ if (!r) return;
1159
+ for (let col = startCol; col <= endCol && col < cols; col++) {
1160
+ const cell = emptyCell();
1161
+ if (attrs.bg) cell.bg = { ...attrs.bg };
1162
+ r[col] = cell;
1163
+ }
1164
+ }
1165
+ function handleInsertLines(count) {
1166
+ if (curY < scrollTop || curY > scrollBottom) return;
1167
+ for (let i = 0; i < count; i++) scrollDown(curY, scrollBottom);
1168
+ }
1169
+ function handleDeleteLines(count) {
1170
+ if (curY < scrollTop || curY > scrollBottom) return;
1171
+ for (let i = 0; i < count; i++) scrollUp(curY, scrollBottom);
1172
+ }
1173
+ function handleDeleteChars(count) {
1174
+ const row = grid[curY];
1175
+ if (!row) return;
1176
+ if (leftRightMarginMode && (leftMargin > 0 || rightMargin < cols - 1)) {
1177
+ for (let i = 0; i < count; i++) if (curX <= rightMargin) {
1178
+ row.splice(curX, 1);
1179
+ row.splice(rightMargin, 0, emptyCell());
1180
+ }
1181
+ } else for (let i = 0; i < count; i++) if (curX < cols) {
1182
+ row.splice(curX, 1);
1183
+ row.push(emptyCell());
1184
+ }
1185
+ }
1186
+ function handleInsertChars(count) {
1187
+ const row = grid[curY];
1188
+ if (!row) return;
1189
+ if (leftRightMarginMode && (leftMargin > 0 || rightMargin < cols - 1)) for (let i = 0; i < count; i++) {
1190
+ row.splice(rightMargin, 1);
1191
+ row.splice(curX, 0, emptyCell());
1192
+ }
1193
+ else for (let i = 0; i < count; i++) {
1194
+ row.splice(curX, 0, emptyCell());
1195
+ row.pop();
1196
+ }
1197
+ }
1198
+ function handleEraseChars(count) {
1199
+ const row = grid[curY];
1200
+ if (!row) return;
1201
+ for (let i = 0; i < count && curX + i < cols; i++) row[curX + i] = emptyCell();
1202
+ }
1203
+ /** Bounds of the active scroll/margin rectangle (inclusive). */
1204
+ function activeRect() {
1205
+ return {
1206
+ top: scrollTop,
1207
+ bottom: scrollBottom,
1208
+ left: leftRightMarginMode ? leftMargin : 0,
1209
+ right: leftRightMarginMode ? rightMargin : cols - 1
1210
+ };
1211
+ }
1212
+ function handleShiftLeft(count) {
1213
+ const { top, left, bottom, right } = activeRect();
1214
+ for (let row = top; row <= bottom; row++) {
1215
+ const r = grid[row];
1216
+ if (!r) continue;
1217
+ for (let col = left; col <= right; col++) {
1218
+ const src = col + count;
1219
+ r[col] = src <= right ? r[src] : emptyCell();
1220
+ }
1221
+ }
1222
+ }
1223
+ function handleShiftRight(count) {
1224
+ const { top, left, bottom, right } = activeRect();
1225
+ for (let row = top; row <= bottom; row++) {
1226
+ const r = grid[row];
1227
+ if (!r) continue;
1228
+ for (let col = right; col >= left; col--) {
1229
+ const src = col - count;
1230
+ r[col] = src >= left ? r[src] : emptyCell();
1231
+ }
1232
+ }
1233
+ }
1234
+ function handleInsertColumn(count) {
1235
+ const { top, left, bottom, right } = activeRect();
1236
+ if (curX < left || curX > right) return;
1237
+ for (let row = top; row <= bottom; row++) {
1238
+ const r = grid[row];
1239
+ if (!r) continue;
1240
+ for (let col = right; col >= curX + count; col--) r[col] = r[col - count];
1241
+ for (let col = curX; col < curX + count && col <= right; col++) r[col] = emptyCell();
1242
+ }
1243
+ }
1244
+ function handleDeleteColumn(count) {
1245
+ const { top, left, bottom, right } = activeRect();
1246
+ if (curX < left || curX > right) return;
1247
+ for (let row = top; row <= bottom; row++) {
1248
+ const r = grid[row];
1249
+ if (!r) continue;
1250
+ for (let col = curX; col + count <= right; col++) r[col] = r[col + count];
1251
+ for (let col = right - count + 1; col <= right && col >= 0; col++) r[col] = emptyCell();
1252
+ }
1253
+ }
1254
+ /**
1255
+ * Apply (or reverse-toggle) a list of SGR attribute codes to a single cell.
1256
+ * Used by DECCARA (set) and DECRARA (toggle). Only attributes that DECCARA/DECRARA
1257
+ * operate on are handled: bold (1/22), underline (4/24), blink (5/25), inverse (7/27).
1258
+ */
1259
+ function applyRectAttrs(cell, sgrParts, reverse) {
1260
+ for (const p of sgrParts) switch (p) {
1261
+ case 0:
1262
+ if (reverse) {
1263
+ cell.bold = !cell.bold;
1264
+ cell.underline = cell.underline === "none" ? "single" : "none";
1265
+ cell.blink = !cell.blink;
1266
+ cell.inverse = !cell.inverse;
1267
+ } else {
1268
+ cell.bold = false;
1269
+ cell.underline = "none";
1270
+ cell.blink = false;
1271
+ cell.inverse = false;
1272
+ }
1273
+ break;
1274
+ case 1:
1275
+ cell.bold = reverse ? !cell.bold : true;
1276
+ break;
1277
+ case 4:
1278
+ if (reverse) cell.underline = cell.underline === "none" ? "single" : "none";
1279
+ else cell.underline = "single";
1280
+ break;
1281
+ case 5:
1282
+ cell.blink = reverse ? !cell.blink : true;
1283
+ break;
1284
+ case 7:
1285
+ cell.inverse = reverse ? !cell.inverse : true;
1286
+ break;
1287
+ case 22:
1288
+ cell.bold = false;
1289
+ break;
1290
+ case 24:
1291
+ cell.underline = "none";
1292
+ break;
1293
+ case 25:
1294
+ cell.blink = false;
1295
+ break;
1296
+ case 27:
1297
+ cell.inverse = false;
1298
+ break;
1299
+ }
1300
+ }
1301
+ function handleSGR(rawParams) {
1302
+ const segments = rawParams.split(";");
1303
+ const params = [];
1304
+ const subParams = /* @__PURE__ */ new Map();
1305
+ for (const seg of segments) if (seg.includes(":")) {
1306
+ const subs = seg.split(":").map((s) => s === "" ? 0 : parseInt(s, 10));
1307
+ subParams.set(params.length, subs);
1308
+ params.push(subs[0]);
1309
+ } else params.push(seg === "" ? 0 : parseInt(seg, 10));
1310
+ if (params.length === 0 || params.length === 1 && params[0] === 0) {
1311
+ attrs = resetAttrs();
1312
+ return;
1313
+ }
1314
+ let i = 0;
1315
+ while (i < params.length) {
1316
+ const code = params[i];
1317
+ switch (code) {
1318
+ case 0:
1319
+ attrs = resetAttrs();
1320
+ break;
1321
+ case 1:
1322
+ attrs.bold = true;
1323
+ break;
1324
+ case 2:
1325
+ attrs.faint = true;
1326
+ break;
1327
+ case 3:
1328
+ attrs.italic = true;
1329
+ break;
1330
+ case 4: {
1331
+ const subs = subParams.get(i);
1332
+ if (subs && subs.length > 1) switch (subs[1]) {
1333
+ case 0:
1334
+ attrs.underline = "none";
1335
+ break;
1336
+ case 1:
1337
+ attrs.underline = "single";
1338
+ break;
1339
+ case 2:
1340
+ attrs.underline = "double";
1341
+ break;
1342
+ case 3:
1343
+ attrs.underline = "curly";
1344
+ break;
1345
+ case 4:
1346
+ attrs.underline = "dotted";
1347
+ break;
1348
+ case 5:
1349
+ attrs.underline = "dashed";
1350
+ break;
1351
+ default:
1352
+ attrs.underline = "single";
1353
+ break;
1354
+ }
1355
+ else attrs.underline = "single";
1356
+ break;
1357
+ }
1358
+ case 5:
1359
+ attrs.blink = true;
1360
+ break;
1361
+ case 6:
1362
+ attrs.blink = true;
1363
+ break;
1364
+ case 7:
1365
+ attrs.inverse = true;
1366
+ break;
1367
+ case 8:
1368
+ attrs.hidden = true;
1369
+ break;
1370
+ case 9:
1371
+ attrs.strikethrough = true;
1372
+ break;
1373
+ case 21:
1374
+ attrs.underline = "double";
1375
+ break;
1376
+ case 22:
1377
+ attrs.bold = false;
1378
+ attrs.faint = false;
1379
+ break;
1380
+ case 23:
1381
+ attrs.italic = false;
1382
+ break;
1383
+ case 24:
1384
+ attrs.underline = "none";
1385
+ break;
1386
+ case 25:
1387
+ attrs.blink = false;
1388
+ break;
1389
+ case 27:
1390
+ attrs.inverse = false;
1391
+ break;
1392
+ case 28:
1393
+ attrs.hidden = false;
1394
+ break;
1395
+ case 29:
1396
+ attrs.strikethrough = false;
1397
+ break;
1398
+ case 30:
1399
+ case 31:
1400
+ case 32:
1401
+ case 33:
1402
+ case 34:
1403
+ case 35:
1404
+ case 36:
1405
+ case 37:
1406
+ attrs.fg = { ...palette256[code - 30] };
1407
+ break;
1408
+ case 38: {
1409
+ const subs = subParams.get(i);
1410
+ if (subs && subs.length >= 3) {
1411
+ const result = parseExtendedColorFromSubs(subs);
1412
+ if (result) attrs.fg = result;
1413
+ } else {
1414
+ const result = parseExtendedColor(params, i);
1415
+ if (result) {
1416
+ attrs.fg = result.color;
1417
+ i = result.nextIndex - 1;
1418
+ }
1419
+ }
1420
+ break;
1421
+ }
1422
+ case 39:
1423
+ attrs.fg = null;
1424
+ break;
1425
+ case 40:
1426
+ case 41:
1427
+ case 42:
1428
+ case 43:
1429
+ case 44:
1430
+ case 45:
1431
+ case 46:
1432
+ case 47:
1433
+ attrs.bg = { ...palette256[code - 40] };
1434
+ break;
1435
+ case 48: {
1436
+ const subs = subParams.get(i);
1437
+ if (subs && subs.length >= 3) {
1438
+ const result = parseExtendedColorFromSubs(subs);
1439
+ if (result) attrs.bg = result;
1440
+ } else {
1441
+ const result = parseExtendedColor(params, i);
1442
+ if (result) {
1443
+ attrs.bg = result.color;
1444
+ i = result.nextIndex - 1;
1445
+ }
1446
+ }
1447
+ break;
1448
+ }
1449
+ case 49:
1450
+ attrs.bg = null;
1451
+ break;
1452
+ case 53:
1453
+ attrs.overline = true;
1454
+ break;
1455
+ case 55:
1456
+ attrs.overline = false;
1457
+ break;
1458
+ case 58: {
1459
+ const subs = subParams.get(i);
1460
+ if (subs && subs.length >= 3) {
1461
+ const result = parseExtendedColorFromSubs(subs);
1462
+ if (result) attrs.underlineColor = result;
1463
+ } else {
1464
+ const result = parseExtendedColor(params, i);
1465
+ if (result) {
1466
+ attrs.underlineColor = result.color;
1467
+ i = result.nextIndex - 1;
1468
+ }
1469
+ }
1470
+ break;
1471
+ }
1472
+ case 59:
1473
+ attrs.underlineColor = null;
1474
+ break;
1475
+ case 90:
1476
+ case 91:
1477
+ case 92:
1478
+ case 93:
1479
+ case 94:
1480
+ case 95:
1481
+ case 96:
1482
+ case 97:
1483
+ attrs.fg = { ...palette256[code - 90 + 8] };
1484
+ break;
1485
+ case 100:
1486
+ case 101:
1487
+ case 102:
1488
+ case 103:
1489
+ case 104:
1490
+ case 105:
1491
+ case 106:
1492
+ case 107:
1493
+ attrs.bg = { ...palette256[code - 100 + 8] };
1494
+ break;
1495
+ }
1496
+ i++;
1497
+ }
1498
+ }
1499
+ function parseExtendedColor(params, startIndex) {
1500
+ if (startIndex + 1 >= params.length) return null;
1501
+ const type = params[startIndex + 1];
1502
+ if (type === 5 && startIndex + 2 < params.length) {
1503
+ const idx = params[startIndex + 2];
1504
+ return {
1505
+ color: { ...palette256[idx] ?? {
1506
+ r: 0,
1507
+ g: 0,
1508
+ b: 0
1509
+ } },
1510
+ nextIndex: startIndex + 3
1511
+ };
1512
+ } else if (type === 2 && startIndex + 4 < params.length) return {
1513
+ color: {
1514
+ r: params[startIndex + 2],
1515
+ g: params[startIndex + 3],
1516
+ b: params[startIndex + 4]
1517
+ },
1518
+ nextIndex: startIndex + 5
1519
+ };
1520
+ return null;
1521
+ }
1522
+ /** Parse extended color from colon sub-parameters (e.g., 38:2:R:G:B or 38:5:N) */
1523
+ function parseExtendedColorFromSubs(subs) {
1524
+ if (subs.length < 3) return null;
1525
+ const type = subs[1];
1526
+ if (type === 5 && subs.length >= 3) {
1527
+ const idx = subs[2];
1528
+ return { ...palette256[idx] ?? {
1529
+ r: 0,
1530
+ g: 0,
1531
+ b: 0
1532
+ } };
1533
+ } else if (type === 2) {
1534
+ if (subs.length >= 5) {
1535
+ if (subs.length >= 6) return {
1536
+ r: subs[3],
1537
+ g: subs[4],
1538
+ b: subs[5]
1539
+ };
1540
+ return {
1541
+ r: subs[2],
1542
+ g: subs[3],
1543
+ b: subs[4]
1544
+ };
1545
+ } else if (subs.length >= 4) return {
1546
+ r: subs[2],
1547
+ g: subs[3],
1548
+ b: 0
1549
+ };
1550
+ }
1551
+ return null;
1552
+ }
1553
+ function handleOSC(oscString) {
1554
+ const semicolonIdx = oscString.indexOf(";");
1555
+ const code = semicolonIdx === -1 ? parseInt(oscString, 10) : parseInt(oscString.substring(0, semicolonIdx), 10);
1556
+ if (isNaN(code)) return;
1557
+ const value = semicolonIdx === -1 ? "" : oscString.substring(semicolonIdx + 1);
1558
+ switch (code) {
1559
+ case 0:
1560
+ case 2:
1561
+ title = value;
1562
+ break;
1563
+ case 133:
1564
+ switch (value.charAt(0)) {
1565
+ case "A":
1566
+ semanticZones.push({
1567
+ type: "prompt",
1568
+ startRow: curY,
1569
+ startCol: curX
1570
+ });
1571
+ break;
1572
+ case "B":
1573
+ semanticZones.push({
1574
+ type: "command",
1575
+ startRow: curY,
1576
+ startCol: curX
1577
+ });
1578
+ break;
1579
+ case "C":
1580
+ semanticZones.push({
1581
+ type: "output",
1582
+ startRow: curY,
1583
+ startCol: curX
1584
+ });
1585
+ break;
1586
+ case "D": break;
1587
+ }
1588
+ break;
1589
+ case 1: break;
1590
+ case 7:
1591
+ cwd = value;
1592
+ break;
1593
+ case 8: {
1594
+ const secondSemicolon = value.indexOf(";");
1595
+ if (secondSemicolon !== -1) {
1596
+ const url = value.substring(secondSemicolon + 1);
1597
+ attrs.url = url || null;
1598
+ }
1599
+ break;
1600
+ }
1601
+ case 4: {
1602
+ const fields = value.split(";");
1603
+ for (let fi = 0; fi + 1 < fields.length; fi += 2) {
1604
+ const idx = parseInt(fields[fi], 10);
1605
+ const spec = fields[fi + 1];
1606
+ if (isNaN(idx) || idx < 0 || idx > 255) continue;
1607
+ if (spec === "?") {
1608
+ const c = palette256[idx];
1609
+ if (c && onResponse) onResponse(`\x1b]4;${idx};${formatColorResponse(c)}\x1b\\`);
1610
+ } else {
1611
+ const c = parseColorSpec(spec);
1612
+ if (c) palette256[idx] = c;
1613
+ }
1614
+ }
1615
+ break;
1616
+ }
1617
+ case 5: {
1618
+ const fields = value.split(";");
1619
+ for (let fi = 0; fi + 1 < fields.length; fi += 2) {
1620
+ const idx = parseInt(fields[fi], 10);
1621
+ const spec = fields[fi + 1];
1622
+ if (isNaN(idx) || idx < 0 || idx > 4) continue;
1623
+ if (spec === "?") {
1624
+ const c = specialColors.get(idx);
1625
+ if (onResponse) onResponse(`\x1b]5;${idx};${c ? formatColorResponse(c) : "rgb:0000/0000/0000"}\x1b\\`);
1626
+ } else {
1627
+ const c = parseColorSpec(spec);
1628
+ if (c) specialColors.set(idx, c);
1629
+ }
1630
+ }
1631
+ break;
1632
+ }
1633
+ case 10:
1634
+ if (value === "?") {
1635
+ if (onResponse) onResponse(`\x1b]10;${formatColorResponse(defaultFgColor ?? {
1636
+ r: 255,
1637
+ g: 255,
1638
+ b: 255
1639
+ })}\x1b\\`);
1640
+ } else {
1641
+ const c = parseColorSpec(value);
1642
+ if (c) defaultFgColor = c;
1643
+ }
1644
+ break;
1645
+ case 11:
1646
+ if (value === "?") {
1647
+ if (onResponse) onResponse(`\x1b]11;${formatColorResponse(defaultBgColor ?? {
1648
+ r: 0,
1649
+ g: 0,
1650
+ b: 0
1651
+ })}\x1b\\`);
1652
+ } else {
1653
+ const c = parseColorSpec(value);
1654
+ if (c) defaultBgColor = c;
1655
+ }
1656
+ break;
1657
+ case 12:
1658
+ if (value === "?") {
1659
+ if (onResponse) onResponse(`\x1b]12;${formatColorResponse(cursorColor ?? defaultFgColor ?? {
1660
+ r: 255,
1661
+ g: 255,
1662
+ b: 255
1663
+ })}\x1b\\`);
1664
+ } else {
1665
+ const c = parseColorSpec(value);
1666
+ if (c) cursorColor = c;
1667
+ }
1668
+ break;
1669
+ case 13:
1670
+ if (value === "?") {
1671
+ if (onResponse) onResponse(`\x1b]13;${formatColorResponse(pointerFgColor ?? defaultFgColor ?? {
1672
+ r: 255,
1673
+ g: 255,
1674
+ b: 255
1675
+ })}\x1b\\`);
1676
+ } else {
1677
+ const c = parseColorSpec(value);
1678
+ if (c) pointerFgColor = c;
1679
+ }
1680
+ break;
1681
+ case 14:
1682
+ if (value === "?") {
1683
+ if (onResponse) onResponse(`\x1b]14;${formatColorResponse(pointerBgColor ?? defaultBgColor ?? {
1684
+ r: 0,
1685
+ g: 0,
1686
+ b: 0
1687
+ })}\x1b\\`);
1688
+ } else {
1689
+ const c = parseColorSpec(value);
1690
+ if (c) pointerBgColor = c;
1691
+ }
1692
+ break;
1693
+ case 17:
1694
+ if (value === "?") {
1695
+ if (onResponse) onResponse(`\x1b]17;${formatColorResponse(highlightBgColor ?? defaultFgColor ?? {
1696
+ r: 255,
1697
+ g: 255,
1698
+ b: 255
1699
+ })}\x1b\\`);
1700
+ } else {
1701
+ const c = parseColorSpec(value);
1702
+ if (c) highlightBgColor = c;
1703
+ }
1704
+ break;
1705
+ case 19:
1706
+ if (value === "?") {
1707
+ if (onResponse) onResponse(`\x1b]19;${formatColorResponse(highlightFgColor ?? defaultBgColor ?? {
1708
+ r: 0,
1709
+ g: 0,
1710
+ b: 0
1711
+ })}\x1b\\`);
1712
+ } else {
1713
+ const c = parseColorSpec(value);
1714
+ if (c) highlightFgColor = c;
1715
+ }
1716
+ break;
1717
+ case 21: {
1718
+ const pairs = value.split(";").filter((p) => p.length > 0);
1719
+ const response = [];
1720
+ for (const pair of pairs) {
1721
+ const eq = pair.indexOf("=");
1722
+ if (eq === -1) continue;
1723
+ const key = pair.substring(0, eq).trim();
1724
+ const val = pair.substring(eq + 1).trim();
1725
+ const isQuery = val === "?";
1726
+ const paletteMatch = /^color(\d+)$/.exec(key);
1727
+ if (paletteMatch) {
1728
+ const idx = parseInt(paletteMatch[1], 10);
1729
+ if (idx < 0 || idx > 255) continue;
1730
+ if (isQuery) {
1731
+ const c = palette256[idx];
1732
+ if (c) response.push(`${key}=${formatColorResponse(c)}`);
1733
+ } else if (val === "") {
1734
+ const fresh = buildPalette256();
1735
+ palette256[idx] = fresh[idx];
1736
+ } else {
1737
+ const c = parseColorSpec(val);
1738
+ if (c) palette256[idx] = c;
1739
+ }
1740
+ } else if (key === "foreground") if (isQuery) {
1741
+ const c = defaultFgColor ?? {
1742
+ r: 255,
1743
+ g: 255,
1744
+ b: 255
1745
+ };
1746
+ response.push(`${key}=${formatColorResponse(c)}`);
1747
+ } else if (val === "") defaultFgColor = null;
1748
+ else {
1749
+ const c = parseColorSpec(val);
1750
+ if (c) defaultFgColor = c;
1751
+ }
1752
+ else if (key === "background") if (isQuery) {
1753
+ const c = defaultBgColor ?? {
1754
+ r: 0,
1755
+ g: 0,
1756
+ b: 0
1757
+ };
1758
+ response.push(`${key}=${formatColorResponse(c)}`);
1759
+ } else if (val === "") defaultBgColor = null;
1760
+ else {
1761
+ const c = parseColorSpec(val);
1762
+ if (c) defaultBgColor = c;
1763
+ }
1764
+ else if (key === "cursor") if (isQuery) {
1765
+ const c = cursorColor ?? defaultFgColor ?? {
1766
+ r: 255,
1767
+ g: 255,
1768
+ b: 255
1769
+ };
1770
+ response.push(`${key}=${formatColorResponse(c)}`);
1771
+ } else if (val === "") cursorColor = null;
1772
+ else {
1773
+ const c = parseColorSpec(val);
1774
+ if (c) cursorColor = c;
1775
+ }
1776
+ else if (key === "selection_background") if (isQuery) {
1777
+ const c = highlightBgColor ?? defaultFgColor ?? {
1778
+ r: 255,
1779
+ g: 255,
1780
+ b: 255
1781
+ };
1782
+ response.push(`${key}=${formatColorResponse(c)}`);
1783
+ } else highlightBgColor = val === "" ? null : parseColorSpec(val);
1784
+ else if (key === "selection_foreground") if (isQuery) {
1785
+ const c = highlightFgColor ?? defaultBgColor ?? {
1786
+ r: 0,
1787
+ g: 0,
1788
+ b: 0
1789
+ };
1790
+ response.push(`${key}=${formatColorResponse(c)}`);
1791
+ } else highlightFgColor = val === "" ? null : parseColorSpec(val);
1792
+ }
1793
+ if (response.length > 0 && onResponse) onResponse(`\x1b]21;${response.join(";")}\x1b\\`);
1794
+ break;
1795
+ }
1796
+ case 104:
1797
+ if (value === "") palette256 = buildPalette256();
1798
+ else {
1799
+ const fresh = buildPalette256();
1800
+ for (const tok of value.split(";")) {
1801
+ const idx = parseInt(tok, 10);
1802
+ if (!isNaN(idx) && idx >= 0 && idx < 256) palette256[idx] = fresh[idx];
1803
+ }
1804
+ }
1805
+ break;
1806
+ case 105:
1807
+ if (value === "") specialColors.clear();
1808
+ else for (const tok of value.split(";")) {
1809
+ const idx = parseInt(tok, 10);
1810
+ if (!isNaN(idx) && idx >= 0 && idx <= 4) specialColors.delete(idx);
1811
+ }
1812
+ break;
1813
+ case 110:
1814
+ defaultFgColor = null;
1815
+ break;
1816
+ case 111:
1817
+ defaultBgColor = null;
1818
+ break;
1819
+ case 112:
1820
+ cursorColor = null;
1821
+ break;
1822
+ case 113:
1823
+ pointerFgColor = null;
1824
+ break;
1825
+ case 114:
1826
+ pointerBgColor = null;
1827
+ break;
1828
+ case 117:
1829
+ highlightBgColor = null;
1830
+ break;
1831
+ case 119:
1832
+ highlightFgColor = null;
1833
+ break;
1834
+ case 52: {
1835
+ const clipSemi = value.indexOf(";");
1836
+ if (clipSemi !== -1) {
1837
+ const data = value.substring(clipSemi + 1);
1838
+ if (data === "?") {
1839
+ if (onResponse) onResponse(`\x1b]52;c;${btoa(clipboard)}\x1b\\`);
1840
+ } else {
1841
+ try {
1842
+ clipboard = atob(data);
1843
+ } catch {
1844
+ clipboard = "";
1845
+ }
1846
+ if (onResponse) onResponse(`\x1b]52;c;${data}\x1b\\`);
1847
+ }
1848
+ }
1849
+ break;
1850
+ }
1851
+ case 9:
1852
+ notifications.push(value);
1853
+ break;
1854
+ case 633:
1855
+ switch (value.charAt(0)) {
1856
+ case "A":
1857
+ semanticZones.push({
1858
+ type: "prompt",
1859
+ startRow: curY,
1860
+ startCol: curX
1861
+ });
1862
+ break;
1863
+ case "B":
1864
+ semanticZones.push({
1865
+ type: "command",
1866
+ startRow: curY,
1867
+ startCol: curX
1868
+ });
1869
+ break;
1870
+ case "C":
1871
+ semanticZones.push({
1872
+ type: "output",
1873
+ startRow: curY,
1874
+ startCol: curX
1875
+ });
1876
+ break;
1877
+ case "D": break;
1878
+ }
1879
+ break;
1880
+ case 66:
1881
+ if (value === "?" && onResponse) onResponse(`\x1b]66;s=${textScale}\x1b\\`);
1882
+ else {
1883
+ const kvPairs = value.split(";");
1884
+ for (const pair of kvPairs) {
1885
+ const [k, v] = pair.split("=");
1886
+ if (k === "s" && v !== void 0) {
1887
+ const n = parseInt(v, 10);
1888
+ if (!isNaN(n) && n > 0) textScale = n;
1889
+ }
1890
+ }
1891
+ }
1892
+ break;
1893
+ case 701:
1894
+ if (value === "?") {
1895
+ if (onResponse) onResponse(`\x1b]701;${locale}\x1b\\`);
1896
+ } else if (value !== "") locale = value;
1897
+ break;
1898
+ case 702:
1899
+ if (onResponse) onResponse("\x1B]702;vterm.js;vterm;0;2\x1B\\");
1900
+ break;
1901
+ case 720: {
1902
+ const n = parseInt(value, 10);
1903
+ scrollViewport(!isNaN(n) && n > 0 ? n : 1);
1904
+ break;
1905
+ }
1906
+ case 721: {
1907
+ const n = parseInt(value, 10);
1908
+ scrollViewport(-(!isNaN(n) && n > 0 ? n : 1));
1909
+ break;
1910
+ }
1911
+ case 776:
1912
+ if (onResponse) onResponse(`\x1b]776;${CELL_W_PX};${CELL_H_PX};${FONT_ASCENT_PX}\x1b\\`);
1913
+ break;
1914
+ case 7770:
1915
+ if (value === "?") {
1916
+ if (onResponse) onResponse(`\x1b]7770;${fontSize}\x1b\\`);
1917
+ } else if (value === "") fontSize = 12;
1918
+ else {
1919
+ const n = parseInt(value, 10);
1920
+ if (!isNaN(n) && n > 0) fontSize = n;
1921
+ }
1922
+ break;
1923
+ case 7777:
1924
+ if (value === "?") {
1925
+ if (onResponse) onResponse(`\x1b]7777;${fontWindowSize}\x1b\\`);
1926
+ } else if (value === "") fontWindowSize = 12;
1927
+ else {
1928
+ const n = parseInt(value, 10);
1929
+ if (!isNaN(n) && n > 0) fontWindowSize = n;
1930
+ }
1931
+ break;
1932
+ case 30001:
1933
+ colorStack.push(snapshotColorState());
1934
+ break;
1935
+ case 30101: {
1936
+ const snapshot = colorStack.pop();
1937
+ if (snapshot) restoreColorState(snapshot);
1938
+ break;
1939
+ }
1940
+ case 5522:
1941
+ if (value === "?" && onResponse) onResponse(`\x1b]5522;${btoa(advancedClipboard)}\x1b\\`);
1942
+ else try {
1943
+ advancedClipboard = atob(value);
1944
+ } catch {
1945
+ advancedClipboard = "";
1946
+ }
1947
+ break;
1948
+ case 1337:
1949
+ if (value === "ReportCellSize" && onResponse) onResponse("\x1B]1337;ReportCellSize=16;8\x1B\\");
1950
+ else if (value === "RequestCapabilities" && onResponse) onResponse("\x1B]1337;Capabilities=\x1B\\");
1951
+ break;
1952
+ }
1953
+ }
1954
+ function handleDCS(data) {
1955
+ const match = data.match(/^(\d*(?:;\d*)*)q(.*)$/s);
1956
+ if (match) {
1957
+ hasSixel = true;
1958
+ sixelImages.push({
1959
+ data: match[2],
1960
+ row: dcsStartRow,
1961
+ col: dcsStartCol
1962
+ });
1963
+ return;
1964
+ }
1965
+ if (data.startsWith("$q") && onResponse) {
1966
+ if (data.substring(2) === "\"p") onResponse("\x1BP1$r62;1\"p\x1B\\");
1967
+ else onResponse("\x1BP0$r\x1B\\");
1968
+ return;
1969
+ }
1970
+ if (data.startsWith("+q") && onResponse) {
1971
+ if (data.substring(2) === "544e") onResponse(`\x1bP1+r544e=${Array.from(new TextEncoder().encode("vterm")).map((b) => b.toString(16).padStart(2, "0")).join("")}\x1b\\`);
1972
+ else onResponse("\x1BP0+r\x1B\\");
1973
+ return;
1974
+ }
1975
+ }
1976
+ function handleAPC(data) {
1977
+ if (!data.startsWith("G")) return;
1978
+ hasKittyGraphics = true;
1979
+ const semicolonIdx = data.indexOf(";");
1980
+ const kvPart = semicolonIdx >= 0 ? data.substring(1, semicolonIdx) : data.substring(1);
1981
+ const params = {};
1982
+ for (const pair of kvPart.split(",")) {
1983
+ const eqIdx = pair.indexOf("=");
1984
+ if (eqIdx >= 0) params[pair.substring(0, eqIdx)] = pair.substring(eqIdx + 1);
1985
+ }
1986
+ if (params.a === "q" && onResponse) onResponse(`\x1b_Gi=${params.i ?? "0"};OK\x1b\\`);
1987
+ }
1988
+ function softReset() {
1989
+ insertMode = false;
1990
+ originMode = false;
1991
+ autoWrap = true;
1992
+ curVisible = true;
1993
+ kittyKeyboardFlags = 0;
1994
+ kittyKeyboardStack = [];
1995
+ cursorShape = "block";
1996
+ cursorBlinking = true;
1997
+ applicationCursor = false;
1998
+ applicationKeypad = false;
1999
+ reverseVideo = false;
2000
+ decColumnMode = false;
2001
+ altScrollMode = false;
2002
+ utf8MouseMode = false;
2003
+ scrollTop = 0;
2004
+ scrollBottom = rows - 1;
2005
+ leftRightMarginMode = false;
2006
+ leftMargin = 0;
2007
+ rightMargin = cols - 1;
2008
+ attrs = resetAttrs();
2009
+ charsetG0 = false;
2010
+ curX = 0;
2011
+ curY = 0;
2012
+ }
2013
+ function fullReset() {
2014
+ mainGrid = makeGrid(cols, rows);
2015
+ altGrid = makeGrid(cols, rows);
2016
+ grid = mainGrid;
2017
+ scrollback = [];
2018
+ curX = 0;
2019
+ curY = 0;
2020
+ curVisible = true;
2021
+ cursorShape = "block";
2022
+ cursorBlinking = true;
2023
+ savedCurX = 0;
2024
+ savedCurY = 0;
2025
+ savedState = {
2026
+ curX: 0,
2027
+ curY: 0,
2028
+ attrs: resetAttrs(),
2029
+ originMode: false,
2030
+ autoWrap: true,
2031
+ charsetG0: false
2032
+ };
2033
+ attrs = resetAttrs();
2034
+ title = "";
2035
+ useAltScreen = false;
2036
+ bracketedPaste = false;
2037
+ applicationCursor = false;
2038
+ applicationKeypad = false;
2039
+ autoWrap = true;
2040
+ mouseTracking = false;
2041
+ mouseTrackingMode = 0;
2042
+ sgrMouse = false;
2043
+ focusTracking = false;
2044
+ originMode = false;
2045
+ insertMode = false;
2046
+ reverseVideo = false;
2047
+ syncOutput = false;
2048
+ kittyKeyboardFlags = 0;
2049
+ kittyKeyboardStack = [];
2050
+ hasKittyGraphics = false;
2051
+ hasSixel = false;
2052
+ sixelImages = [];
2053
+ scrollTop = 0;
2054
+ scrollBottom = rows - 1;
2055
+ leftRightMarginMode = false;
2056
+ leftMargin = 0;
2057
+ rightMargin = cols - 1;
2058
+ colorSchemeReporting = false;
2059
+ decColumnMode = false;
2060
+ altScrollMode = false;
2061
+ utf8MouseMode = false;
2062
+ textScale = 1;
2063
+ fontSize = 12;
2064
+ fontWindowSize = 12;
2065
+ locale = "en_US.UTF-8";
2066
+ advancedClipboard = "";
2067
+ viewportOffset = 0;
2068
+ charsetG0 = false;
2069
+ clipboard = "";
2070
+ cwd = "";
2071
+ notifications = [];
2072
+ palette256 = buildPalette256();
2073
+ defaultFgColor = null;
2074
+ defaultBgColor = null;
2075
+ cursorColor = null;
2076
+ specialColors.clear();
2077
+ pointerFgColor = null;
2078
+ pointerBgColor = null;
2079
+ highlightBgColor = null;
2080
+ highlightFgColor = null;
2081
+ colorStack.length = 0;
2082
+ tabStops = defaultTabStops(cols);
2083
+ lastChar = "";
2084
+ pendingRegionalIndicator = null;
2085
+ afterZWJ = false;
2086
+ parserState = "ground";
2087
+ escBuf = "";
2088
+ oscBuf = "";
2089
+ apcBuf = "";
2090
+ semanticZones = [];
2091
+ mainSoftWrapped = new Array(rows).fill(false);
2092
+ altSoftWrapped = new Array(rows).fill(false);
2093
+ softWrapped = mainSoftWrapped;
2094
+ }
2095
+ function process(data) {
2096
+ const text = decoder.decode(data, { stream: true });
2097
+ for (let i = 0; i < text.length; i++) {
2098
+ const ch = text[i];
2099
+ const code = text.charCodeAt(i);
2100
+ switch (parserState) {
2101
+ case "ground":
2102
+ if (code === 27) {
2103
+ parserState = "escape";
2104
+ escBuf = "";
2105
+ } else if (code === 7) {} else if (code === 8) {
2106
+ if (curX > 0) curX--;
2107
+ } else if (code === 9) curX = nextTabStop(curX);
2108
+ else if (code === 10 || code === 11 || code === 12) {
2109
+ softWrapped[curY] = false;
2110
+ curY++;
2111
+ if (curY > scrollBottom) {
2112
+ curY = scrollBottom;
2113
+ scrollUp(scrollTop, scrollBottom);
2114
+ }
2115
+ } else if (code === 13) curX = 0;
2116
+ else if (code >= 32) {
2117
+ let char = ch;
2118
+ if (code >= 55296 && code <= 56319 && i + 1 < text.length) {
2119
+ const nextCode = text.charCodeAt(i + 1);
2120
+ if (nextCode >= 56320 && nextCode <= 57343) {
2121
+ char = ch + text[i + 1];
2122
+ i++;
2123
+ }
2124
+ }
2125
+ writeChar(char);
2126
+ }
2127
+ break;
2128
+ case "escape":
2129
+ if (ch === "[") {
2130
+ parserState = "csi";
2131
+ escBuf = "";
2132
+ } else if (ch === "]") {
2133
+ parserState = "osc";
2134
+ oscBuf = "";
2135
+ } else if (ch === "P") {
2136
+ parserState = "dcs";
2137
+ escBuf = "";
2138
+ dcsBuf = "";
2139
+ dcsStartRow = curY;
2140
+ dcsStartCol = curX;
2141
+ } else if (ch === "c") {
2142
+ fullReset();
2143
+ parserState = "ground";
2144
+ } else if (ch === "D") {
2145
+ curY++;
2146
+ if (curY > scrollBottom) {
2147
+ curY = scrollBottom;
2148
+ scrollUp(scrollTop, scrollBottom);
2149
+ }
2150
+ parserState = "ground";
2151
+ } else if (ch === "M") {
2152
+ curY--;
2153
+ if (curY < scrollTop) {
2154
+ curY = scrollTop;
2155
+ scrollDown(scrollTop, scrollBottom);
2156
+ }
2157
+ parserState = "ground";
2158
+ } else if (ch === "7") {
2159
+ savedState = {
2160
+ curX,
2161
+ curY,
2162
+ attrs: {
2163
+ ...attrs,
2164
+ fg: attrs.fg ? { ...attrs.fg } : null,
2165
+ bg: attrs.bg ? { ...attrs.bg } : null,
2166
+ underlineColor: attrs.underlineColor ? { ...attrs.underlineColor } : null
2167
+ },
2168
+ originMode,
2169
+ autoWrap,
2170
+ charsetG0
2171
+ };
2172
+ parserState = "ground";
2173
+ } else if (ch === "8") {
2174
+ curX = savedState.curX;
2175
+ curY = savedState.curY;
2176
+ attrs = {
2177
+ ...savedState.attrs,
2178
+ fg: savedState.attrs.fg ? { ...savedState.attrs.fg } : null,
2179
+ bg: savedState.attrs.bg ? { ...savedState.attrs.bg } : null,
2180
+ underlineColor: savedState.attrs.underlineColor ? { ...savedState.attrs.underlineColor } : null
2181
+ };
2182
+ originMode = savedState.originMode;
2183
+ autoWrap = savedState.autoWrap;
2184
+ charsetG0 = savedState.charsetG0;
2185
+ clampCursor();
2186
+ parserState = "ground";
2187
+ } else if (ch === "E") {
2188
+ curX = 0;
2189
+ curY++;
2190
+ if (curY > scrollBottom) {
2191
+ curY = scrollBottom;
2192
+ scrollUp(scrollTop, scrollBottom);
2193
+ }
2194
+ parserState = "ground";
2195
+ } else if (ch === "H") {
2196
+ tabStops.add(curX);
2197
+ parserState = "ground";
2198
+ } else if (ch === "#") parserState = "escape_hash";
2199
+ else if (ch === "(") parserState = "escape_charset";
2200
+ else if (ch === ")") parserState = "escape_charset";
2201
+ else if (ch === "=") {
2202
+ applicationKeypad = true;
2203
+ parserState = "ground";
2204
+ } else if (ch === ">") {
2205
+ applicationKeypad = false;
2206
+ parserState = "ground";
2207
+ } else if (ch === "_") {
2208
+ parserState = "apc";
2209
+ apcBuf = "";
2210
+ } else parserState = "ground";
2211
+ break;
2212
+ case "escape_charset":
2213
+ if (ch === "0") charsetG0 = true;
2214
+ else charsetG0 = false;
2215
+ parserState = "ground";
2216
+ break;
2217
+ case "escape_hash":
2218
+ if (ch === "8") {
2219
+ for (let r = 0; r < rows; r++) {
2220
+ const row = grid[r];
2221
+ for (let c = 0; c < cols; c++) {
2222
+ const cell = emptyCell();
2223
+ cell.char = "E";
2224
+ row[c] = cell;
2225
+ }
2226
+ softWrapped[r] = false;
2227
+ }
2228
+ curX = 0;
2229
+ curY = 0;
2230
+ }
2231
+ parserState = "ground";
2232
+ break;
2233
+ case "csi":
2234
+ if (code >= 64 && code <= 126) {
2235
+ let paramPart = escBuf;
2236
+ let intermediatePart = "";
2237
+ let j = paramPart.length - 1;
2238
+ while (j >= 0) {
2239
+ const c = paramPart.charCodeAt(j);
2240
+ if (c >= 32 && c <= 47) j--;
2241
+ else break;
2242
+ }
2243
+ if (j < paramPart.length - 1) {
2244
+ intermediatePart = paramPart.substring(j + 1);
2245
+ paramPart = paramPart.substring(0, j + 1);
2246
+ }
2247
+ if (paramPart.startsWith("?")) handleCSIPrivate(paramPart.substring(1), intermediatePart, ch);
2248
+ else if (paramPart.startsWith(">")) handleCSIGt(paramPart.substring(1), intermediatePart, ch);
2249
+ else if (paramPart.startsWith("<")) handleCSILt(paramPart.substring(1), intermediatePart, ch);
2250
+ else if (paramPart.startsWith("=")) handleCSIEq(paramPart.substring(1), intermediatePart, ch);
2251
+ else handleCSI(paramPart, intermediatePart, ch);
2252
+ parserState = "ground";
2253
+ } else if (escBuf.length >= 256) parserState = "ground";
2254
+ else escBuf += ch;
2255
+ break;
2256
+ case "osc":
2257
+ if (code === 7) {
2258
+ handleOSC(oscBuf);
2259
+ parserState = "ground";
2260
+ } else if (code === 27) parserState = "osc_st";
2261
+ else if (oscBuf.length >= 4096) parserState = "ground";
2262
+ else oscBuf += ch;
2263
+ break;
2264
+ case "osc_st":
2265
+ if (ch === "\\") handleOSC(oscBuf);
2266
+ parserState = "ground";
2267
+ break;
2268
+ case "dcs":
2269
+ if (code === 27) parserState = "dcs_st";
2270
+ else if (code === 7) {
2271
+ handleDCS(dcsBuf);
2272
+ parserState = "ground";
2273
+ } else dcsBuf += ch;
2274
+ break;
2275
+ case "dcs_st":
2276
+ if (ch === "\\") handleDCS(dcsBuf);
2277
+ parserState = "ground";
2278
+ break;
2279
+ case "dcs_passthrough":
2280
+ if (code === 27) parserState = "dcs_st";
2281
+ break;
2282
+ case "apc":
2283
+ if (code === 27) parserState = "apc_st";
2284
+ else if (code === 7) {
2285
+ handleAPC(apcBuf);
2286
+ parserState = "ground";
2287
+ } else apcBuf += ch;
2288
+ break;
2289
+ case "apc_st":
2290
+ if (ch === "\\") handleAPC(apcBuf);
2291
+ parserState = "ground";
2292
+ break;
2293
+ }
2294
+ }
2295
+ }
2296
+ /**
2297
+ * Reconstruct logical lines from a grid, joining rows that were soft-wrapped.
2298
+ * Returns an array of logical lines, each being an array of ScreenCells (may be longer than cols).
2299
+ */
2300
+ function getLogicalLines(srcGrid, srcSoftWrapped, srcRows) {
2301
+ const logical = [];
2302
+ let currentLine = [];
2303
+ for (let r = 0; r < srcRows; r++) {
2304
+ const row = srcGrid[r];
2305
+ if (!row) continue;
2306
+ for (let c = 0; c < row.length; c++) currentLine.push(row[c]);
2307
+ if (srcSoftWrapped[r]) continue;
2308
+ logical.push(currentLine);
2309
+ currentLine = [];
2310
+ }
2311
+ if (currentLine.length > 0) logical.push(currentLine);
2312
+ return logical;
2313
+ }
2314
+ /**
2315
+ * Re-wrap logical lines to a new column width, producing grid rows and soft-wrap flags.
2316
+ */
2317
+ function rewrapLines(logicalLines, newCols) {
2318
+ const outRows = [];
2319
+ const outWrapped = [];
2320
+ for (const line of logicalLines) {
2321
+ let lineLen = line.length;
2322
+ while (lineLen > 0) {
2323
+ const cell = line[lineLen - 1];
2324
+ if (cell === EMPTY_CELL || cell.char === "" && !cell.wide) lineLen--;
2325
+ else break;
2326
+ }
2327
+ if (lineLen === 0) {
2328
+ outRows.push(makeRow(newCols));
2329
+ outWrapped.push(false);
2330
+ continue;
2331
+ }
2332
+ let pos = 0;
2333
+ while (pos < lineLen) {
2334
+ const row = makeRow(newCols);
2335
+ let col = 0;
2336
+ while (col < newCols && pos < lineLen) {
2337
+ const cell = line[pos];
2338
+ if (cell.wide && col + 2 > newCols) break;
2339
+ row[col] = cell === EMPTY_CELL ? EMPTY_CELL : { ...cell };
2340
+ col++;
2341
+ pos++;
2342
+ }
2343
+ const moreContent = pos < lineLen;
2344
+ outRows.push(row);
2345
+ outWrapped.push(moreContent);
2346
+ }
2347
+ }
2348
+ return {
2349
+ rows: outRows,
2350
+ wrapped: outWrapped
2351
+ };
2352
+ }
2353
+ /**
2354
+ * Trim trailing empty rows from reflowed result, so they don't push content off the top
2355
+ * when we take the last newRows rows.
2356
+ */
2357
+ function trimTrailingEmptyRows(result) {
2358
+ while (result.rows.length > 1) if (result.rows[result.rows.length - 1].every((cell) => cell === EMPTY_CELL || cell.char === "" && !cell.wide) && !result.wrapped[result.rows.length - 2]) {
2359
+ result.rows.pop();
2360
+ result.wrapped.pop();
2361
+ } else break;
2362
+ }
2363
+ function resize(newCols, newRows) {
2364
+ const mainResult = rewrapLines(getLogicalLines(mainGrid, mainSoftWrapped, rows), newCols);
2365
+ trimTrailingEmptyRows(mainResult);
2366
+ const altResult = rewrapLines(getLogicalLines(altGrid, altSoftWrapped, rows), newCols);
2367
+ trimTrailingEmptyRows(altResult);
2368
+ const newMain = makeGrid(newCols, newRows);
2369
+ const newMainWrapped = new Array(newRows).fill(false);
2370
+ const mainStartRow = Math.max(0, mainResult.rows.length - newRows);
2371
+ for (let r = 0; r < newRows && mainStartRow + r < mainResult.rows.length; r++) {
2372
+ newMain[r] = mainResult.rows[mainStartRow + r];
2373
+ newMainWrapped[r] = mainResult.wrapped[mainStartRow + r];
2374
+ }
2375
+ const newAlt = makeGrid(newCols, newRows);
2376
+ const newAltWrapped = new Array(newRows).fill(false);
2377
+ const altStartRow = Math.max(0, altResult.rows.length - newRows);
2378
+ for (let r = 0; r < newRows && altStartRow + r < altResult.rows.length; r++) {
2379
+ newAlt[r] = altResult.rows[altStartRow + r];
2380
+ newAltWrapped[r] = altResult.wrapped[altStartRow + r];
2381
+ }
2382
+ mainGrid = newMain;
2383
+ altGrid = newAlt;
2384
+ mainSoftWrapped = newMainWrapped;
2385
+ altSoftWrapped = newAltWrapped;
2386
+ grid = useAltScreen ? altGrid : mainGrid;
2387
+ softWrapped = useAltScreen ? altSoftWrapped : mainSoftWrapped;
2388
+ const oldCols = cols;
2389
+ cols = newCols;
2390
+ rows = newRows;
2391
+ scrollTop = 0;
2392
+ scrollBottom = rows - 1;
2393
+ leftMargin = 0;
2394
+ rightMargin = cols - 1;
2395
+ if (newCols > oldCols) for (let i = Math.max(8, Math.ceil(oldCols / 8) * 8); i < newCols; i += 8) tabStops.add(i);
2396
+ clampCursor();
2397
+ }
2398
+ function getCell(row, col) {
2399
+ const r = grid[row];
2400
+ if (!r || col >= cols) return emptyCell();
2401
+ return { ...r[col] };
2402
+ }
2403
+ function getLine(row) {
2404
+ const r = grid[row];
2405
+ if (!r) return makeRow(cols);
2406
+ return r.map((cell) => ({ ...cell }));
2407
+ }
2408
+ function getText() {
2409
+ const lines = [];
2410
+ for (let r = 0; r < rows; r++) lines.push(rowToString(grid[r]));
2411
+ return lines.join("\n");
2412
+ }
2413
+ function rowToString(row) {
2414
+ let line = "";
2415
+ for (let i = 0; i < row.length; i++) {
2416
+ const cell = row[i];
2417
+ if (cell.wide) line += cell.char;
2418
+ else if (cell.char === "") {
2419
+ if (i > 0 && row[i - 1]?.wide) continue;
2420
+ line += " ";
2421
+ } else line += cell.char;
2422
+ }
2423
+ return line.replace(/\s+$/, "");
2424
+ }
2425
+ function getTextRange(startRow, startCol, endRow, endCol) {
2426
+ const parts = [];
2427
+ for (let row = startRow; row <= endRow; row++) {
2428
+ const r = grid[row];
2429
+ if (!r) continue;
2430
+ const colStart = row === startRow ? startCol : 0;
2431
+ const colEnd = row === endRow ? endCol : cols;
2432
+ let line = "";
2433
+ for (let col = colStart; col < colEnd; col++) {
2434
+ const cell = r[col];
2435
+ if (!cell) continue;
2436
+ if (cell.char === "" && col > 0 && r[col - 1]?.wide) continue;
2437
+ line += cell.char || " ";
2438
+ }
2439
+ parts.push(line.replace(/\s+$/, ""));
2440
+ }
2441
+ return parts.join("\n");
2442
+ }
2443
+ function getMode(mode) {
2444
+ switch (mode) {
2445
+ case "altScreen": return useAltScreen;
2446
+ case "cursorVisible": return curVisible;
2447
+ case "bracketedPaste": return bracketedPaste;
2448
+ case "applicationCursor": return applicationCursor;
2449
+ case "applicationKeypad": return applicationKeypad;
2450
+ case "autoWrap": return autoWrap;
2451
+ case "mouseTracking": return mouseTracking;
2452
+ case "focusTracking": return focusTracking;
2453
+ case "originMode": return originMode;
2454
+ case "insertMode": return insertMode;
2455
+ case "reverseVideo": return reverseVideo;
2456
+ case "syncOutput": return syncOutput;
2457
+ case "sgrMouse": return sgrMouse;
2458
+ case "pixelMouse": return mouseTrackingMode === 1016;
2459
+ case "leftRightMargin": return leftRightMarginMode;
2460
+ case "colorSchemeReporting": return colorSchemeReporting;
2461
+ case "kittyKeyboard": return kittyKeyboardFlags > 0;
2462
+ case "kittyGraphics": return hasKittyGraphics;
2463
+ case "sixel": return hasSixel;
2464
+ default: return false;
2465
+ }
2466
+ }
2467
+ return {
2468
+ get cols() {
2469
+ return cols;
2470
+ },
2471
+ get rows() {
2472
+ return rows;
2473
+ },
2474
+ process,
2475
+ resize,
2476
+ reset: fullReset,
2477
+ getCell,
2478
+ getLine,
2479
+ getText,
2480
+ getTextRange,
2481
+ getCursorPosition: () => ({
2482
+ x: curX,
2483
+ y: curY
2484
+ }),
2485
+ getCursorVisible: () => curVisible,
2486
+ getCursorShape: () => cursorShape,
2487
+ getCursorBlinking: () => cursorBlinking,
2488
+ getTitle: () => title,
2489
+ getMode,
2490
+ getClipboard: () => clipboard,
2491
+ getCwd: () => cwd,
2492
+ getNotifications: () => [...notifications],
2493
+ getScrollbackLength: () => scrollback.length,
2494
+ getViewportOffset: () => viewportOffset,
2495
+ scrollViewport,
2496
+ getSemanticZones: () => semanticZones.map((z) => ({ ...z })),
2497
+ getSixelImages: () => sixelImages.map((img) => ({ ...img }))
2498
+ };
2499
+ }
2500
+ //#endregion
2501
+ export { createScreen as createVtermScreen };