vterm.js 0.5.1 → 0.6.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/README.md CHANGED
@@ -243,18 +243,11 @@ screen.signals.damage$.subscribe((d: DirtyRegion) => {
243
243
  })
244
244
  ```
245
245
 
246
- ## Naming — schema migration
246
+ ## Naming
247
247
 
248
- The public vocabulary is converging on the terminal domain model (name the thing, not the mechanism; **row = cells, line = text**; flat progressive shapes over discriminated unions). The canonical names below are live now; the old names remain exported as `@deprecated` aliases through the migration window, so existing code keeps compiling.
248
+ The public vocabulary follows the terminal domain model (name the thing, not the mechanism; **row = cells, line = text**; flat progressive shapes over discriminated unions): `Color`, `Snapshot`, `getRow(row)`, `getCursor(): Cursor` (`Cursor` is `{ col, row }`). The pre-§9 names — `CellColor`, `ScreenSnapshot`/`VtermScreenSnapshot`, `getLine(row)`, `getCursorPosition(): {x,y}` — rode a deprecation window as `@deprecated` aliases and have since been deleted; they no longer compile.
249
249
 
250
- | Deprecated | Canonical | Notes |
251
- | ---------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------ |
252
- | `CellColor` | `Color` | Same shape `{ r, g, b, index? }`; a type named `RGB`/`CellColor` carrying `.index` was the smell. |
253
- | `ScreenSnapshot` / `VtermScreenSnapshot` | `Snapshot` | The namespace supplies the context; `VtermScreenSnapshot` stays exported as an alias for existing consumers. |
254
- | `getLine(row): ScreenCell[]` | `getRow(row)` | Row = cells; the text readers (`getText`, `getScrollbackText`) keep "line/text". |
255
- | `getCursorPosition(): {x,y}` | `getCursor(): Cursor` | `Cursor` is `{ col, row }` — the grid's own vocabulary. |
256
-
257
- **Deferred (not renamed this slice):** the `Snapshot.cursor` / `Snapshot.savedState` fields keep `x`/`y` rather than `col`/`row`, because those field names are the wire shape read by `encodeScreenSnapshotBinary` — renaming them would silently change the persisted binary format. The `col`/`row` vocabulary is available at the read boundary via `getCursor()` / the `Cursor` type. The snapshot field rename is a codec-format concern for a coordinated schema bump.
250
+ **Deferred (not renamed):** the `Snapshot.cursor` / `Snapshot.savedState` fields keep `x`/`y` rather than `col`/`row`, because those field names are the wire shape read by `encodeScreenSnapshotBinary` — renaming them would silently change the persisted binary format. The `col`/`row` vocabulary is available at the read boundary via `getCursor()` / the `Cursor` type. The snapshot field rename is a codec-format concern for a coordinated schema bump.
258
251
 
259
252
  ## API
260
253
 
@@ -279,10 +272,8 @@ The public vocabulary is converging on the terminal domain model (name the thing
279
272
  | `getText()` | Get all text (scrollback + screen) |
280
273
  | `getTextRange(sr, sc, er, ec)` | Get text in a range |
281
274
  | `getRow(row)` | Get cells for a screen row (row = cells, line = text) |
282
- | `getLine(row)` | **Deprecated** — alias of `getRow` |
283
275
  | `getCell(row, col)` | Get a single cell |
284
276
  | `getCursor()` | Get cursor `{ col, row }` |
285
- | `getCursorPosition()` | **Deprecated** — cursor `{ x, y }`; use `getCursor()` |
286
277
  | `getCursorVisible()` | Check cursor visibility |
287
278
  | `getCursorShape()` | Get cursor shape: `"block"`, `"underline"`, or `"bar"` |
288
279
  | `getCursorBlinking()` | Check if cursor is blinking |
@@ -314,7 +305,7 @@ interface ScreenCell {
314
305
  faint: boolean
315
306
  italic: boolean
316
307
  underline: "none" | "single" | "double" | "curly" | "dotted" | "dashed"
317
- underlineColor: CellColor | null
308
+ underlineColor: Color | null
318
309
  overline: boolean
319
310
  strikethrough: boolean
320
311
  inverse: boolean
@@ -363,7 +354,7 @@ history and repaint only what changed.
363
354
  The buffer is the retained scrollback followed by the screen. **Absolute row 0 is the
364
355
  oldest retained scrollback line**; the screen occupies the last `screenRows()` rows
365
356
  (absolute `totalRows() - screenRows()` through `totalRows() - 1`). The existing
366
- screen-relative reads (`getLine`, `getCell`) are unchanged — absolute addressing is
357
+ screen-relative reads (`getRow`, `getCell`) are unchanged — absolute addressing is
367
358
  additive.
368
359
 
369
360
  ```typescript
@@ -376,7 +367,7 @@ screen.viewportTop() // absolute row of the viewport's top line
376
367
 
377
368
  Naming follows the ecosystem rule **row = cells, line = text**: `getRowAbsolute`
378
369
  returns cells; colors are stripped of palette-origin index at the read boundary (same
379
- contract as `getLine`). Out-of-range indices return a blank row.
370
+ contract as `getRow`). Out-of-range indices return a blank row.
380
371
 
381
372
  **Stability contract.** As lines scroll IN, an existing scrollback row keeps its
382
373
  absolute index (the screen shifts up in absolute terms, but its content keeps the same
package/dist/index.d.mts CHANGED
@@ -37,7 +37,7 @@
37
37
  * An RGB color, identity-preserving. `r`/`g`/`b` are always present (painters read
38
38
  * them unconditionally); `index` is optional palette provenance. Named `Color` per the
39
39
  * §9 naming ruling (rule 5: flat progressive shape over a discriminated union — a type
40
- * named `RGB` that carries `.index` would lie). {@link CellColor} is the deprecated alias.
40
+ * named `RGB` that carries `.index` would lie).
41
41
  */
42
42
  interface Color {
43
43
  r: number;
@@ -61,18 +61,16 @@ interface Color {
61
61
  */
62
62
  index?: number;
63
63
  }
64
- /** @deprecated Renamed to {@link Color} (§9 naming ruling). This alias rides the migration window. */
65
- type CellColor = Color;
66
64
  type UnderlineStyle = "none" | "single" | "double" | "curly" | "dotted" | "dashed";
67
65
  interface ScreenCell {
68
66
  char: string;
69
- fg: CellColor | null;
70
- bg: CellColor | null;
67
+ fg: Color | null;
68
+ bg: Color | null;
71
69
  bold: boolean;
72
70
  faint: boolean;
73
71
  italic: boolean;
74
72
  underline: UnderlineStyle;
75
- underlineColor: CellColor | null;
73
+ underlineColor: Color | null;
76
74
  overline: boolean;
77
75
  strikethrough: boolean;
78
76
  inverse: boolean;
@@ -87,7 +85,16 @@ interface ScreenOptions {
87
85
  scrollbackLimit?: number;
88
86
  /** Callback for DA1/DA2/DSR responses — write these back to the PTY */
89
87
  onResponse?: (data: string) => void;
88
+ /**
89
+ * Maximum UTF-16 code units retained for one APC or DCS string sequence.
90
+ * Image protocols use ASCII/base64 payloads, so this is also their byte
91
+ * bound. Longer sequences are consumed without buffering or dispatch and
92
+ * surface one typed `string-overflow` parser event at their terminator.
93
+ */
94
+ maxStringSequenceLength?: number;
90
95
  }
96
+ /** Default retained payload bound for one APC/DCS sequence (16 MiB of ASCII/base64). */
97
+ declare const DEFAULT_MAX_STRING_SEQUENCE_LENGTH: number;
91
98
  interface SemanticZone {
92
99
  type: "prompt" | "command" | "output";
93
100
  startRow: number;
@@ -99,13 +106,13 @@ interface SixelImage {
99
106
  col: number;
100
107
  }
101
108
  interface ScreenAttrsSnapshot {
102
- fg: CellColor | null;
103
- bg: CellColor | null;
109
+ fg: Color | null;
110
+ bg: Color | null;
104
111
  bold: boolean;
105
112
  faint: boolean;
106
113
  italic: boolean;
107
114
  underline: UnderlineStyle;
108
- underlineColor: CellColor | null;
115
+ underlineColor: Color | null;
109
116
  overline: boolean;
110
117
  strikethrough: boolean;
111
118
  inverse: boolean;
@@ -114,15 +121,15 @@ interface ScreenAttrsSnapshot {
114
121
  url: string | null;
115
122
  }
116
123
  interface ScreenColorStateSnapshot {
117
- palette256: CellColor[];
118
- defaultFgColor: CellColor | null;
119
- defaultBgColor: CellColor | null;
120
- cursorColor: CellColor | null;
121
- specialColors: [number, CellColor][];
122
- pointerFgColor: CellColor | null;
123
- pointerBgColor: CellColor | null;
124
- highlightBgColor: CellColor | null;
125
- highlightFgColor: CellColor | null;
124
+ palette256: Color[];
125
+ defaultFgColor: Color | null;
126
+ defaultBgColor: Color | null;
127
+ cursorColor: Color | null;
128
+ specialColors: [number, Color][];
129
+ pointerFgColor: Color | null;
130
+ pointerBgColor: Color | null;
131
+ highlightBgColor: Color | null;
132
+ highlightFgColor: Color | null;
126
133
  }
127
134
  type ScreenParserState = "ground" | "escape" | "escape_charset" | "escape_hash" | "csi" | "osc" | "dcs" | "dcs_passthrough" | "osc_st" | "dcs_st" | "apc" | "apc_st";
128
135
  interface ScreenBufferSnapshot {
@@ -132,8 +139,7 @@ interface ScreenBufferSnapshot {
132
139
  /**
133
140
  * The whole-world persist/restore value — grids, ranges, modes, cursor, colors,
134
141
  * parser transients, wrap bits. JSON-safe plain data; the persist boundary, not the
135
- * incremental read path. Named `Snapshot` per §9 (the namespace supplies the context);
136
- * {@link ScreenSnapshot} is the deprecated alias.
142
+ * incremental read path. Named `Snapshot` per §9 (the namespace supplies the context).
137
143
  *
138
144
  * Note: `cursor`/`savedState` still carry `x`/`y` (not `col`/`row`) — the §9
139
145
  * `Cursor{col,row}` field rename is DEFERRED here because these fields are the wire
@@ -223,7 +229,15 @@ interface Snapshot {
223
229
  row: number;
224
230
  col: number;
225
231
  };
232
+ dcsReceivedLength?: number;
233
+ dcsOverflow?: boolean;
226
234
  apc: string;
235
+ apcStart?: {
236
+ row: number;
237
+ col: number;
238
+ };
239
+ apcReceivedLength?: number;
240
+ apcOverflow?: boolean;
227
241
  utf8PendingBytes: number[];
228
242
  };
229
243
  unicode: {
@@ -233,13 +247,10 @@ interface Snapshot {
233
247
  afterZWJ: boolean;
234
248
  };
235
249
  }
236
- /** @deprecated Renamed to {@link Snapshot} (§9 naming ruling). This alias rides the migration window. */
237
- type ScreenSnapshot = Snapshot;
238
250
  /**
239
251
  * The cursor position at the read boundary, in the grid's own `col`/`row` vocabulary
240
252
  * (§9 naming ruling: `x`/`y` contradicted the row/col naming used everywhere else, and
241
- * the `State` suffix was redundant). Returned by {@link VtermScreen.getCursor}; the legacy
242
- * {@link VtermScreen.getCursorPosition} still returns the `{ x, y }` shape (deprecated).
253
+ * the `State` suffix was redundant). Returned by {@link VtermScreen.getCursor}.
243
254
  */
244
255
  interface Cursor {
245
256
  col: number;
@@ -279,8 +290,12 @@ type TerminalOp = {
279
290
  * charset/`#` designators); `final` is the dispatching byte, `intermediates`
280
291
  * carries the `(`/`)`/`#` designator byte when present.
281
292
  *
282
- * DCS and APC string sequences are not (yet) surfaced. A listener MUST NOT throw — taps are
283
- * fail-loud: an exception propagates out of the write call (the engine state stays consistent).
293
+ * - `dcs` / `apc` — a complete bounded string sequence with the guest-local cursor anchor at
294
+ * sequence start. Payloads beyond `maxStringSequenceLength` are not dispatched;
295
+ * their terminator emits one typed `string-overflow` event instead.
296
+ *
297
+ * A listener MUST NOT throw — taps are fail-loud: an exception propagates out of the write call
298
+ * (the engine state stays consistent).
284
299
  */
285
300
  type ParserEvent = {
286
301
  kind: "print";
@@ -302,6 +317,23 @@ type ParserEvent = {
302
317
  kind: "esc";
303
318
  final: string;
304
319
  intermediates?: string;
320
+ } | {
321
+ kind: "apc";
322
+ data: string;
323
+ row: number;
324
+ col: number;
325
+ } | {
326
+ kind: "dcs";
327
+ data: string;
328
+ row: number;
329
+ col: number;
330
+ } | {
331
+ kind: "string-overflow";
332
+ sequence: "apc" | "dcs";
333
+ maxLength: number;
334
+ receivedLength: number;
335
+ row: number;
336
+ col: number;
305
337
  };
306
338
  /**
307
339
  * Accumulated per-row damage since the previous {@link Screen.takeDirty} call — the PULL-plane
@@ -452,8 +484,6 @@ interface Screen {
452
484
  * stripped of palette-origin index at the read boundary.
453
485
  */
454
486
  getRow(row: number): ScreenCell[];
455
- /** @deprecated Renamed to {@link getRow} (§9: row = cells, line = text). */
456
- getLine(row: number): ScreenCell[];
457
487
  getText(): string;
458
488
  /** Scrollback rows above the visible grid, oldest first, rendered like getText(). */
459
489
  getScrollbackText(): string;
@@ -469,8 +499,8 @@ interface Screen {
469
499
  viewportTop(): number;
470
500
  /**
471
501
  * The row at ABSOLUTE index `row` (row 0 = oldest retained scrollback line; the screen occupies
472
- * the last `screenRows()` rows). Colors are stripped of palette-origin index like {@link getLine}.
473
- * Out-of-range indices return a blank row (matching the {@link getLine} read-boundary contract).
502
+ * the last `screenRows()` rows). Colors are stripped of palette-origin index like {@link getRow}.
503
+ * Out-of-range indices return a blank row (matching the {@link getRow} read-boundary contract).
474
504
  */
475
505
  getRowAbsolute(row: number): ScreenCell[];
476
506
  /**
@@ -488,11 +518,6 @@ interface Screen {
488
518
  takeDirty(): DirtyRegion;
489
519
  /** Cursor position in the grid's `col`/`row` vocabulary (§9). See {@link Cursor}. */
490
520
  getCursor(): Cursor;
491
- /** @deprecated Use {@link getCursor} — returns `{ col, row }` per the §9 naming ruling. */
492
- getCursorPosition(): {
493
- x: number;
494
- y: number;
495
- };
496
521
  getCursorVisible(): boolean;
497
522
  getCursorShape(): "block" | "underline" | "bar";
498
523
  getCursorBlinking(): boolean;
@@ -534,19 +559,19 @@ interface SerializeOptions {
534
559
  * color stack, and parser/pending-wrap/mid-parse state are unserializable to
535
560
  * a VT byte stream by design — the binary snapshot carries them.
536
561
  */
537
- declare function serializeSnapshot(snapshot: ScreenSnapshot, options?: SerializeOptions): string;
562
+ declare function serializeSnapshot(snapshot: Snapshot, options?: SerializeOptions): string;
538
563
  //#endregion
539
564
  //#region src/snapshot-codec.d.ts
540
565
  /**
541
- * Encode a {@link ScreenSnapshot} to a compact binary buffer. Output is
566
+ * Encode a {@link Snapshot} to a compact binary buffer. Output is
542
567
  * deterministic for identical input and decodes back to a deep-equal snapshot.
543
568
  */
544
- declare function encodeScreenSnapshotBinary(snapshot: ScreenSnapshot): Uint8Array;
569
+ declare function encodeScreenSnapshotBinary(snapshot: Snapshot): Uint8Array;
545
570
  /**
546
571
  * Decode a buffer produced by {@link encodeScreenSnapshotBinary} back into a
547
- * {@link ScreenSnapshot}. Throws loudly on an unknown version byte, truncated
572
+ * {@link Snapshot}. Throws loudly on an unknown version byte, truncated
548
573
  * input, or any internal inconsistency — never returns a partial/normalized result.
549
574
  */
550
- declare function decodeScreenSnapshotBinary(bytes: Uint8Array): ScreenSnapshot;
575
+ declare function decodeScreenSnapshotBinary(bytes: Uint8Array): Snapshot;
551
576
  //#endregion
552
- export { type CellColor, type Color, type Cursor, type DirtyRegion, type ParserEvent, type ReadSignal, type ScreenCell, type ScreenSignals, type ScreenSnapshot, type ScreenSnapshot as VtermScreenSnapshot, type SemanticZone, type SerializeOptions, type SixelImage, type Size, type Snapshot, type TerminalModes, type TerminalOp, type UnderlineStyle, type Screen as VtermScreen, type ScreenAttrsSnapshot as VtermScreenAttrsSnapshot, type ScreenBufferSnapshot as VtermScreenBufferSnapshot, type ScreenColorStateSnapshot as VtermScreenColorStateSnapshot, type ScreenOptions as VtermScreenOptions, type ScreenParserState as VtermScreenParserState, createScreen as createVtermScreen, decodeScreenSnapshotBinary, encodeScreenSnapshotBinary, serializeSnapshot };
577
+ export { type Color, type Cursor, DEFAULT_MAX_STRING_SEQUENCE_LENGTH, type DirtyRegion, type ParserEvent, type ReadSignal, type ScreenCell, type ScreenSignals, type SemanticZone, type SerializeOptions, type SixelImage, type Size, type Snapshot, type TerminalModes, type TerminalOp, type UnderlineStyle, type Screen as VtermScreen, type ScreenAttrsSnapshot as VtermScreenAttrsSnapshot, type ScreenBufferSnapshot as VtermScreenBufferSnapshot, type ScreenColorStateSnapshot as VtermScreenColorStateSnapshot, type ScreenOptions as VtermScreenOptions, type ScreenParserState as VtermScreenParserState, createScreen as createVtermScreen, decodeScreenSnapshotBinary, encodeScreenSnapshotBinary, serializeSnapshot };
package/dist/index.mjs CHANGED
@@ -1,4 +1,6 @@
1
1
  //#region src/screen.ts
2
+ /** Default retained payload bound for one APC/DCS sequence (16 MiB of ASCII/base64). */
3
+ const DEFAULT_MAX_STRING_SEQUENCE_LENGTH = 16 * 1024 * 1024;
2
4
  /** Frozen sentinel for unwritten cells — never mutate, copy-on-write in writeChar(). */
3
5
  const EMPTY_CELL = Object.freeze({
4
6
  char: "",
@@ -21,10 +23,10 @@ function emptyCell() {
21
23
  return { ...EMPTY_CELL };
22
24
  }
23
25
  /**
24
- * Drop the palette-origin {@link CellColor.index} for the public per-cell read
25
- * boundary. `getCell`/`getLine` return the RESOLVED RGB — their long-standing
26
+ * Drop the palette-origin {@link Color.index} for the public per-cell read
27
+ * boundary. `getCell`/`getRow` return the RESOLVED RGB — their long-standing
26
28
  * contract — while the origin index is serialization-only provenance that rides
27
- * {@link ScreenSnapshot} (and thus `serialize()`), not the inspection API.
29
+ * {@link Snapshot} (and thus `serialize()`), not the inspection API.
28
30
  * Returns the SAME reference when there is no index (the common truecolor/null
29
31
  * case), so the read path allocates nothing there.
30
32
  */
@@ -79,7 +81,7 @@ function bitsToUnderline(meta) {
79
81
  function packRgb(c) {
80
82
  return ((c.r & 255) << 16 | (c.g & 255) << 8 | c.b & 255) >>> 0;
81
83
  }
82
- /** Materialize a {@link CellColor} from a packed RGB word + index (`-1` = no index). */
84
+ /** Materialize a {@link Color} from a packed RGB word + index (`-1` = no index). */
83
85
  function unpackColor(rgb, idx) {
84
86
  const r = rgb >> 16 & 255;
85
87
  const g = rgb >> 8 & 255;
@@ -461,6 +463,8 @@ function createScreen(options = {}) {
461
463
  let rows = options.rows ?? 24;
462
464
  let scrollbackLimit = options.scrollbackLimit ?? 1e3;
463
465
  const onResponse = options.onResponse;
466
+ const maxStringSequenceLength = options.maxStringSequenceLength ?? 16777216;
467
+ if (!Number.isSafeInteger(maxStringSequenceLength) || maxStringSequenceLength < 0) throw new RangeError("maxStringSequenceLength must be a non-negative safe integer");
464
468
  let mainGrid = makeGrid(cols, rows);
465
469
  let altGrid = makeGrid(cols, rows);
466
470
  let grid = mainGrid;
@@ -718,7 +722,16 @@ function createScreen(options = {}) {
718
722
  assertRecord("parser.dcsStart", parser.dcsStart);
719
723
  assertInteger("parser.dcsStart.row", parser.dcsStart.row);
720
724
  assertInteger("parser.dcsStart.col", parser.dcsStart.col);
725
+ if (parser.dcsReceivedLength !== void 0) assertInteger("parser.dcsReceivedLength", parser.dcsReceivedLength, 0);
726
+ if (parser.dcsOverflow !== void 0) assertBoolean("parser.dcsOverflow", parser.dcsOverflow);
721
727
  assertString("parser.apc", parser.apc);
728
+ if (parser.apcStart !== void 0) {
729
+ assertRecord("parser.apcStart", parser.apcStart);
730
+ assertInteger("parser.apcStart.row", parser.apcStart.row);
731
+ assertInteger("parser.apcStart.col", parser.apcStart.col);
732
+ }
733
+ if (parser.apcReceivedLength !== void 0) assertInteger("parser.apcReceivedLength", parser.apcReceivedLength, 0);
734
+ if (parser.apcOverflow !== void 0) assertBoolean("parser.apcOverflow", parser.apcOverflow);
722
735
  if (!Array.isArray(parser.utf8PendingBytes)) throw new TypeError("Invalid vterm snapshot parser.utf8PendingBytes");
723
736
  for (const byte of parser.utf8PendingBytes) {
724
737
  assertInteger("parser.utf8PendingBytes", byte, 0);
@@ -775,7 +788,13 @@ function createScreen(options = {}) {
775
788
  let dcsBuf = "";
776
789
  let dcsStartRow = 0;
777
790
  let dcsStartCol = 0;
791
+ let dcsReceivedLength = 0;
792
+ let dcsOverflow = false;
778
793
  let apcBuf = "";
794
+ let apcStartRow = 0;
795
+ let apcStartCol = 0;
796
+ let apcReceivedLength = 0;
797
+ let apcOverflow = false;
779
798
  const opListeners = /* @__PURE__ */ new Set();
780
799
  const parserListeners = /* @__PURE__ */ new Set();
781
800
  let printRunParts = [];
@@ -2686,7 +2705,13 @@ function createScreen(options = {}) {
2686
2705
  dcsBuf = "";
2687
2706
  dcsStartRow = 0;
2688
2707
  dcsStartCol = 0;
2708
+ dcsReceivedLength = 0;
2709
+ dcsOverflow = false;
2689
2710
  apcBuf = "";
2711
+ apcStartRow = 0;
2712
+ apcStartCol = 0;
2713
+ apcReceivedLength = 0;
2714
+ apcOverflow = false;
2690
2715
  utf8PendingBytes = [];
2691
2716
  semanticZones = [];
2692
2717
  mainSoftWrapped = new Array(rows).fill(false);
@@ -2759,6 +2784,68 @@ function createScreen(options = {}) {
2759
2784
  if (intermediates !== "") ev.intermediates = intermediates;
2760
2785
  emitParserEvent(ev);
2761
2786
  }
2787
+ function emitStringEvent(sequence, data, row, col) {
2788
+ if (parserListeners.size === 0) return;
2789
+ flushPrintRun();
2790
+ emitParserEvent({
2791
+ kind: sequence,
2792
+ data,
2793
+ row,
2794
+ col
2795
+ });
2796
+ }
2797
+ function emitStringOverflow(sequence, receivedLength, row, col) {
2798
+ if (parserListeners.size === 0) return;
2799
+ flushPrintRun();
2800
+ emitParserEvent({
2801
+ kind: "string-overflow",
2802
+ sequence,
2803
+ maxLength: maxStringSequenceLength,
2804
+ receivedLength,
2805
+ row,
2806
+ col
2807
+ });
2808
+ }
2809
+ function appendDCS(ch) {
2810
+ dcsReceivedLength += ch.length;
2811
+ if (dcsOverflow) return;
2812
+ if (dcsReceivedLength > maxStringSequenceLength) {
2813
+ dcsOverflow = true;
2814
+ dcsBuf = "";
2815
+ return;
2816
+ }
2817
+ dcsBuf += ch;
2818
+ }
2819
+ function appendAPC(ch) {
2820
+ apcReceivedLength += ch.length;
2821
+ if (apcOverflow) return;
2822
+ if (apcReceivedLength > maxStringSequenceLength) {
2823
+ apcOverflow = true;
2824
+ apcBuf = "";
2825
+ return;
2826
+ }
2827
+ apcBuf += ch;
2828
+ }
2829
+ function finishDCS() {
2830
+ if (dcsOverflow) emitStringOverflow("dcs", dcsReceivedLength, dcsStartRow, dcsStartCol);
2831
+ else {
2832
+ handleDCS(dcsBuf);
2833
+ emitStringEvent("dcs", dcsBuf, dcsStartRow, dcsStartCol);
2834
+ }
2835
+ dcsBuf = "";
2836
+ dcsReceivedLength = 0;
2837
+ dcsOverflow = false;
2838
+ }
2839
+ function finishAPC() {
2840
+ if (apcOverflow) emitStringOverflow("apc", apcReceivedLength, apcStartRow, apcStartCol);
2841
+ else {
2842
+ handleAPC(apcBuf);
2843
+ emitStringEvent("apc", apcBuf, apcStartRow, apcStartCol);
2844
+ }
2845
+ apcBuf = "";
2846
+ apcReceivedLength = 0;
2847
+ apcOverflow = false;
2848
+ }
2762
2849
  function emitOp(op) {
2763
2850
  for (const listener of opListeners) listener(op);
2764
2851
  }
@@ -2816,6 +2903,8 @@ function createScreen(options = {}) {
2816
2903
  dcsBuf = "";
2817
2904
  dcsStartRow = curY;
2818
2905
  dcsStartCol = curX;
2906
+ dcsReceivedLength = 0;
2907
+ dcsOverflow = false;
2819
2908
  } else if (ch === "c") {
2820
2909
  fullReset();
2821
2910
  parserState = "ground";
@@ -2900,6 +2989,10 @@ function createScreen(options = {}) {
2900
2989
  } else if (ch === "_") {
2901
2990
  parserState = "apc";
2902
2991
  apcBuf = "";
2992
+ apcStartRow = curY;
2993
+ apcStartCol = curX;
2994
+ apcReceivedLength = 0;
2995
+ apcOverflow = false;
2903
2996
  } else parserState = "ground";
2904
2997
  break;
2905
2998
  case "escape_charset":
@@ -2966,12 +3059,17 @@ function createScreen(options = {}) {
2966
3059
  case "dcs":
2967
3060
  if (code === 27) parserState = "dcs_st";
2968
3061
  else if (code === 7) {
2969
- handleDCS(dcsBuf);
3062
+ finishDCS();
2970
3063
  parserState = "ground";
2971
- } else dcsBuf += ch;
3064
+ } else appendDCS(ch);
2972
3065
  break;
2973
3066
  case "dcs_st":
2974
- if (ch === "\\") handleDCS(dcsBuf);
3067
+ if (ch === "\\") finishDCS();
3068
+ else {
3069
+ dcsBuf = "";
3070
+ dcsReceivedLength = 0;
3071
+ dcsOverflow = false;
3072
+ }
2975
3073
  parserState = "ground";
2976
3074
  break;
2977
3075
  case "dcs_passthrough":
@@ -2980,12 +3078,17 @@ function createScreen(options = {}) {
2980
3078
  case "apc":
2981
3079
  if (code === 27) parserState = "apc_st";
2982
3080
  else if (code === 7) {
2983
- handleAPC(apcBuf);
3081
+ finishAPC();
2984
3082
  parserState = "ground";
2985
- } else apcBuf += ch;
3083
+ } else appendAPC(ch);
2986
3084
  break;
2987
3085
  case "apc_st":
2988
- if (ch === "\\") handleAPC(apcBuf);
3086
+ if (ch === "\\") finishAPC();
3087
+ else {
3088
+ apcBuf = "";
3089
+ apcReceivedLength = 0;
3090
+ apcOverflow = false;
3091
+ }
2989
3092
  parserState = "ground";
2990
3093
  break;
2991
3094
  }
@@ -3239,7 +3342,15 @@ function createScreen(options = {}) {
3239
3342
  row: dcsStartRow,
3240
3343
  col: dcsStartCol
3241
3344
  },
3345
+ dcsReceivedLength,
3346
+ dcsOverflow,
3242
3347
  apc: apcBuf,
3348
+ apcStart: {
3349
+ row: apcStartRow,
3350
+ col: apcStartCol
3351
+ },
3352
+ apcReceivedLength,
3353
+ apcOverflow,
3243
3354
  utf8PendingBytes: [...utf8PendingBytes]
3244
3355
  },
3245
3356
  unicode: {
@@ -3319,7 +3430,13 @@ function createScreen(options = {}) {
3319
3430
  dcsBuf = snapshotValue.parser.dcs;
3320
3431
  dcsStartRow = snapshotValue.parser.dcsStart.row;
3321
3432
  dcsStartCol = snapshotValue.parser.dcsStart.col;
3433
+ dcsReceivedLength = snapshotValue.parser.dcsReceivedLength ?? dcsBuf.length;
3434
+ dcsOverflow = snapshotValue.parser.dcsOverflow ?? false;
3322
3435
  apcBuf = snapshotValue.parser.apc;
3436
+ apcStartRow = snapshotValue.parser.apcStart?.row ?? curY;
3437
+ apcStartCol = snapshotValue.parser.apcStart?.col ?? curX;
3438
+ apcReceivedLength = snapshotValue.parser.apcReceivedLength ?? apcBuf.length;
3439
+ apcOverflow = snapshotValue.parser.apcOverflow ?? false;
3323
3440
  utf8PendingBytes = [...snapshotValue.parser.utf8PendingBytes];
3324
3441
  charsetG0 = snapshotValue.unicode.charsetG0;
3325
3442
  lastChar = snapshotValue.unicode.lastChar;
@@ -3348,7 +3465,7 @@ function createScreen(options = {}) {
3348
3465
  if (!r || col >= cols) return emptyCell();
3349
3466
  return stripCellColorIndex(r.getCellRaw(col));
3350
3467
  }
3351
- function getLine(row) {
3468
+ function getRow(row) {
3352
3469
  const r = grid[row];
3353
3470
  if (!r) return makeRow(cols).toCells();
3354
3471
  return r.toCells().map(stripCellColorIndex);
@@ -3642,8 +3759,7 @@ function createScreen(options = {}) {
3642
3759
  snapshot,
3643
3760
  restore,
3644
3761
  getCell,
3645
- getRow: getLine,
3646
- getLine,
3762
+ getRow,
3647
3763
  getText,
3648
3764
  getScrollbackText,
3649
3765
  getTextRange,
@@ -3657,10 +3773,6 @@ function createScreen(options = {}) {
3657
3773
  col: curX,
3658
3774
  row: curY
3659
3775
  }),
3660
- getCursorPosition: () => ({
3661
- x: curX,
3662
- y: curY
3663
- }),
3664
3776
  getCursorVisible: () => curVisible,
3665
3777
  getCursorShape: () => cursorShape,
3666
3778
  getCursorBlinking: () => cursorBlinking,
@@ -4462,7 +4574,7 @@ function readGridSection(r, softWrapNullable, expected, strings, colors, styles)
4462
4574
  };
4463
4575
  }
4464
4576
  /**
4465
- * Encode a {@link ScreenSnapshot} to a compact binary buffer. Output is
4577
+ * Encode a {@link Snapshot} to a compact binary buffer. Output is
4466
4578
  * deterministic for identical input and decodes back to a deep-equal snapshot.
4467
4579
  */
4468
4580
  function encodeScreenSnapshotBinary(snapshot) {
@@ -4505,7 +4617,7 @@ function encodeScreenSnapshotBinary(snapshot) {
4505
4617
  }
4506
4618
  /**
4507
4619
  * Decode a buffer produced by {@link encodeScreenSnapshotBinary} back into a
4508
- * {@link ScreenSnapshot}. Throws loudly on an unknown version byte, truncated
4620
+ * {@link Snapshot}. Throws loudly on an unknown version byte, truncated
4509
4621
  * input, or any internal inconsistency — never returns a partial/normalized result.
4510
4622
  */
4511
4623
  function decodeScreenSnapshotBinary(bytes) {
@@ -4557,4 +4669,4 @@ function decodeScreenSnapshotBinary(bytes) {
4557
4669
  };
4558
4670
  }
4559
4671
  //#endregion
4560
- export { createScreen as createVtermScreen, decodeScreenSnapshotBinary, encodeScreenSnapshotBinary, serializeSnapshot };
4672
+ export { DEFAULT_MAX_STRING_SEQUENCE_LENGTH, createScreen as createVtermScreen, decodeScreenSnapshotBinary, encodeScreenSnapshotBinary, serializeSnapshot };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vterm.js",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Modern terminal emulator — full VT/ECMA-48/xterm standards coverage. Pure TypeScript, zero dependencies.",
5
5
  "keywords": [
6
6
  "ansi",