From 2c784f51b2f94d4594dc3ad51f76b04bd9fd3892 Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Thu, 29 Oct 2026 23:01:16 +0000 Subject: [PATCH 1/2] fix(types): make TerminalSnapshot.cursorVisible required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The native binding always sets it, and no published release has the optional form, so the type now says what callers get. _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ Change-Id: I19f990d6a9dedbcf1f7ee49d4f1658768bcc37e1 Signed-off-by: Thomas Kosiewski --- src/README.md | 2 +- src/types.ts | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/README.md b/src/README.md index 5bc3498..f031f0c 100644 --- a/src/README.md +++ b/src/README.md @@ -15,7 +15,7 @@ Package API (exported by `index.ts`): - `SnapshotOptions`: `{ includeScrollback?: boolean; includeCells?: boolean }` [src/types.ts:SnapshotOptions] - `VisibleLine`: `{ row: number; text: string }` [src/types.ts:VisibleLine] - `SnapshotCell`: `{ row; col; text; width; bold?; italic?; underline?; faint?; inverse?; invisible?; strikethrough?; foreground?; background? }` [src/types.ts:SnapshotCell] -- `TerminalSnapshot`: `{ cols; rows; cursorRow; cursorCol; cursorVisible?; isAltScreen; visibleLines; scrollbackLines?; cells? }` [src/types.ts:TerminalSnapshot] +- `TerminalSnapshot`: `{ cols; rows; cursorRow; cursorCol; cursorVisible; isAltScreen; visibleLines; scrollbackLines?; cells? }` [src/types.ts:TerminalSnapshot] - `MouseAction`: `"press" | "release" | "motion"`. `MouseButton`: `"left" | "right" | "middle" | "four"` to `"eleven"` [src/types.ts:MouseButton] - `MouseInputEvent`: `{ action; button?; x; y; modifiers?: MouseModifiers }`, and `MouseModifiers`: `{ shift?; ctrl?; alt? }` [src/types.ts:MouseInputEvent] [src/types.ts:MouseModifiers] - `MouseEncoderOptions`: `{ geometry: MouseGeometry; anyButtonPressed?; trackLastCell? }`. `MouseGeometry`: `{ screenWidth; screenHeight; cellWidth; cellHeight; paddingTop?; paddingBottom?; paddingRight?; paddingLeft? }` [src/types.ts:MouseEncoderOptions] [src/types.ts:MouseGeometry] diff --git a/src/types.ts b/src/types.ts index 09e4fbf..df11639 100644 --- a/src/types.ts +++ b/src/types.ts @@ -88,11 +88,8 @@ export interface TerminalSnapshot { rows: number; cursorRow: number; cursorCol: number; - /** - * Cursor visibility from DECTCEM (`ESC[?25h` shows, `ESC[?25l` hides). - * The native binding always sets it; it is optional for compatibility. - */ - cursorVisible?: boolean; + /** Cursor visibility from DECTCEM (`ESC[?25h` shows, `ESC[?25l` hides). */ + cursorVisible: boolean; isAltScreen: boolean; visibleLines: VisibleLine[]; scrollbackLines?: VisibleLine[]; From f082b9157129a612fa6cff5bd9d36fe3f0a5517c Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Thu, 29 Oct 2026 23:01:16 +0000 Subject: [PATCH 2/2] docs: document that the pinned Ghostty ignores DECSTR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A test pins the current behavior, so moving the Ghostty pin past the upstream DECSTR commit (#37) fails it and flags the README note. _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ Change-Id: Idd55a075938efaf6faaff08c4cd144947a2dae07 Signed-off-by: Thomas Kosiewski --- README.md | 2 ++ test/terminal.test.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 06b9216..d1b1bd2 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ All dimensions are validated as positive integers. Using a terminal after `dispo `snapshot()` reports the cursor position (`cursorRow`, `cursorCol`) and its DECTCEM visibility (`cursorVisible`, toggled by `ESC[?25h` and `ESC[?25l`). With `includeCells: true`, each cell reports its text, width, optional `foreground` and `background` colors, and these SGR attributes: `bold`, `faint`, `italic`, `underline`, `inverse`, `invisible`, and `strikethrough`. An attribute is present only when it is set. `inverse` is the raw SGR 7 flag: `foreground` and `background` are not swapped, so consumers apply reverse video with their own default colors. +The pinned Ghostty ignores the DECSTR soft reset (`ESC[!p`). After it, a hidden cursor stays hidden and SGR attributes stay set. Programs that reset with `ESC c` (RIS) are unaffected. + ### Mouse encoding `encodeMouse` returns a `Buffer` containing the terminal input bytes for one diff --git a/test/terminal.test.ts b/test/terminal.test.ts index e28215a..722fbd3 100644 --- a/test/terminal.test.ts +++ b/test/terminal.test.ts @@ -133,6 +133,20 @@ describeIfNative("GhosttyVtTerminal", () => { } }); + // Ghostty added DECSTR in f473f31. Moving the pin past it makes this fail: + // then drop the README's soft-reset limit and assert the reset instead. + it("ignores the DECSTR soft reset with the pinned Ghostty", () => { + const term = createTerminal({ cols: 80, rows: 24 }); + try { + term.feed("\x1b[?25l\x1b[7m\x1b[!pX"); + const snapshot = term.snapshot({ includeCells: true }); + expect(snapshot.cursorVisible).toBe(false); + expect(cellsByText(snapshot).get("X")?.inverse).toBe(true); + } finally { + term.dispose(); + } + }); + it("updates snapshot dimensions on resize", () => { const term = createTerminal({ cols: 80, rows: 24 }); try {