@greppleai/grip-tui 0.1.5 → 0.1.6
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/autocomplete.d.ts +1 -1
- package/dist/autocomplete.d.ts.map +1 -1
- package/dist/autocomplete.js +0 -3
- package/dist/autocomplete.js.map +1 -1
- package/dist/components/alt-screen-flash.d.ts.map +1 -1
- package/dist/components/alt-screen-flash.js +2 -3
- package/dist/components/alt-screen-flash.js.map +1 -1
- package/dist/components/box.d.ts.map +1 -1
- package/dist/components/box.js +1 -6
- package/dist/components/box.js.map +1 -1
- package/dist/components/cancellable-loader.d.ts.map +1 -1
- package/dist/components/cancellable-loader.js +4 -3
- package/dist/components/cancellable-loader.js.map +1 -1
- package/dist/components/editor.d.ts +1 -0
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +51 -54
- package/dist/components/editor.js.map +1 -1
- package/dist/components/h-stack.d.ts.map +1 -1
- package/dist/components/h-stack.js +1 -1
- package/dist/components/h-stack.js.map +1 -1
- package/dist/components/image.d.ts.map +1 -1
- package/dist/components/image.js +0 -8
- package/dist/components/image.js.map +1 -1
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +14 -14
- package/dist/components/input.js.map +1 -1
- package/dist/components/loader.d.ts.map +1 -1
- package/dist/components/loader.js +8 -10
- package/dist/components/loader.js.map +1 -1
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +0 -11
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/scroll-view.d.ts.map +1 -1
- package/dist/components/scroll-view.js +5 -15
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/select-list.d.ts.map +1 -1
- package/dist/components/select-list.js +4 -9
- package/dist/components/select-list.js.map +1 -1
- package/dist/components/settings-list.d.ts.map +1 -1
- package/dist/components/settings-list.js +4 -12
- package/dist/components/settings-list.js.map +1 -1
- package/dist/components/spacer.d.ts.map +1 -1
- package/dist/components/spacer.js +0 -1
- package/dist/components/spacer.js.map +1 -1
- package/dist/components/stack.d.ts.map +1 -1
- package/dist/components/stack.js +1 -3
- package/dist/components/stack.js.map +1 -1
- package/dist/components/text.d.ts.map +1 -1
- package/dist/components/text.js +0 -8
- package/dist/components/text.js.map +1 -1
- package/dist/components/truncated-text.d.ts.map +1 -1
- package/dist/components/truncated-text.js +0 -3
- package/dist/components/truncated-text.js.map +1 -1
- package/dist/components/v-stack.d.ts.map +1 -1
- package/dist/components/v-stack.js +1 -1
- package/dist/components/v-stack.js.map +1 -1
- package/dist/editor-component.d.ts.map +1 -1
- package/dist/fuzzy.d.ts.map +1 -1
- package/dist/fuzzy.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js +2 -4
- package/dist/keybindings.js.map +1 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js.map +1 -1
- package/dist/kill-ring.d.ts.map +1 -1
- package/dist/kill-ring.js +3 -1
- package/dist/kill-ring.js.map +1 -1
- package/dist/latex.d.ts.map +1 -1
- package/dist/latex.js +3 -7
- package/dist/latex.js.map +1 -1
- package/dist/layout-node.d.ts.map +1 -1
- package/dist/layout-node.js.map +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js.map +1 -1
- package/dist/native-modifiers.d.ts.map +1 -1
- package/dist/native-modifiers.js.map +1 -1
- package/dist/stdin-buffer.d.ts.map +1 -1
- package/dist/stdin-buffer.js +4 -6
- package/dist/stdin-buffer.js.map +1 -1
- package/dist/terminal-control.d.ts.map +1 -1
- package/dist/terminal-control.js.map +1 -1
- package/dist/terminal-image.d.ts.map +1 -1
- package/dist/terminal-image.js.map +1 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +25 -30
- package/dist/terminal.js.map +1 -1
- package/dist/tui-alt-screen.d.ts.map +1 -1
- package/dist/tui-alt-screen.js +15 -32
- package/dist/tui-alt-screen.js.map +1 -1
- package/dist/tui-main-screen.d.ts.map +1 -1
- package/dist/tui-main-screen.js +12 -9
- package/dist/tui-main-screen.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +17 -20
- package/dist/tui.js.map +1 -1
- package/dist/undo-stack.d.ts.map +1 -1
- package/dist/undo-stack.js +3 -1
- package/dist/undo-stack.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +14 -12
- package/dist/utils.js.map +1 -1
- package/dist/word-navigation.d.ts.map +1 -1
- package/dist/word-navigation.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui-main-screen.d.ts","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+B,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAmE/F,MAAM,WAAW,wBAAwB;IACxC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,sFAAsF;AACtF,qBAAa,aAAc,SAAQ,OAAQ,YAAW,GAAG;IACxD,QAAQ,CAAC,IAAI,YAAsB;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,qBAAqB,CAAqB;IAClD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,mBAAmB,CAAK;IAEhC,kBAAkB,IAAI,wBAAwB,CAU7C;IAED,kBAAkB,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI,CASxD;IAED,UAAmB,gBAAgB,IAAI,IAAI,CAQ1C;IAED,UAAmB,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAQpE;IAED,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,gCAAgC;IAuBxC,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IA8C5B,OAAO,CAAC,sBAAsB;IA6B9B,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,yBAAyB;IAuCjC,OAAO,CAAC,yBAAyB;IAkEjC,SAAS,CAAC,QAAQ,IAAI,IAAI,CAczB;IAED;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAgC9B","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type RenderedCursorPosition, type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\nconst OSC133_ZONE_PREFIX = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: number;\n}\n\ninterface ChangedLineRange {\n\tfirstChanged: number;\n\tlastChanged: number;\n}\n\ninterface ChangedContentRange extends ChangedLineRange {\n\tappendStart: boolean;\n}\n\ninterface MainScreenRenderFrame {\n\twidth: number;\n\theight: number;\n\twidthChanged: boolean;\n\theightChanged: boolean;\n\tnewLines: string[];\n\tcursorPosition: RenderedCursorPosition | null;\n\tpreviousViewportTop: number;\n}\n\ninterface ChangedLinesRenderResult {\n\tbuffer: string;\n\trenderEnd: number;\n}\n\nfunction parseKittyImageHeader(line: string): KittyImageHeader | undefined {\n\tconst sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n\tif (sequenceStart === -1) return undefined;\n\tconst paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n\tconst paramsEnd = line.indexOf(\";\", paramsStart);\n\tif (paramsEnd === -1) return undefined;\n\n\tconst ids: number[] = [];\n\tlet rows = 1;\n\tfor (const param of line.slice(paramsStart, paramsEnd).split(\",\")) {\n\t\tconst [key, value] = param.split(\"=\", 2);\n\t\tif (value === undefined) continue;\n\t\tconst numberValue = Number(value);\n\t\tif (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff) continue;\n\t\tif (key === \"i\") ids.push(numberValue);\n\t\telse if (key === \"r\") rows = numberValue;\n\t}\n\treturn { ids, rows };\n}\n\nfunction extractKittyImageIds(line: string): number[] {\n\treturn parseKittyImageHeader(line)?.ids ?? [];\n}\n\nfunction extractKittyImageRows(line: string): number {\n\treturn parseKittyImageHeader(line)?.rows ?? 1;\n}\n\nfunction isTermuxSession(): boolean {\n\treturn Boolean(process.env.TERMUX_VERSION);\n}\n\nexport interface TuiMainScreenRenderState {\n\tpreviousLines: string[];\n\tpreviousWidth: number;\n\tpreviousHeight: number;\n\tcursorRow: number;\n\thardwareCursorRow: number;\n\tmaxLinesRendered: number;\n\tpreviousViewportTop: number;\n}\n\n/** TUI implementation that renders into the terminal's main screen and scrollback. */\nexport class TuiMainScreen extends TuiBase implements TUI {\n\treadonly mode = \"regular\" as const;\n\tprivate previousLines: string[] = [];\n\tprivate previousKittyImageIds = new Set<number>();\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate cursorRow = 0;\n\tprivate hardwareCursorRow = 0;\n\tprivate maxLinesRendered = 0;\n\tprivate previousViewportTop = 0;\n\n\tcaptureRenderState(): TuiMainScreenRenderState {\n\t\treturn {\n\t\t\tpreviousLines: [...this.previousLines],\n\t\t\tpreviousWidth: this.previousWidth,\n\t\t\tpreviousHeight: this.previousHeight,\n\t\t\tcursorRow: this.cursorRow,\n\t\t\thardwareCursorRow: this.hardwareCursorRow,\n\t\t\tmaxLinesRendered: this.maxLinesRendered,\n\t\t\tpreviousViewportTop: this.previousViewportTop,\n\t\t};\n\t}\n\n\trestoreRenderState(state: TuiMainScreenRenderState): void {\n\t\tthis.previousLines = state.previousLines.map((line) => (isImageLine(line) ? \"\" : line));\n\t\tthis.previousKittyImageIds = new Set();\n\t\tthis.previousWidth = state.previousWidth;\n\t\tthis.previousHeight = state.previousHeight;\n\t\tthis.cursorRow = state.cursorRow;\n\t\tthis.hardwareCursorRow = state.hardwareCursorRow;\n\t\tthis.maxLinesRendered = state.maxLinesRendered;\n\t\tthis.previousViewportTop = state.previousViewportTop;\n\t}\n\n\tprotected override resetRenderState(): void {\n\t\tthis.previousLines = [];\n\t\tthis.previousWidth = -1;\n\t\tthis.previousHeight = -1;\n\t\tthis.cursorRow = 0;\n\t\tthis.hardwareCursorRow = 0;\n\t\tthis.maxLinesRendered = 0;\n\t\tthis.previousViewportTop = 0;\n\t}\n\n\tprotected override beforeTerminalStop(options?: TuiStopOptions): void {\n\t\tif (options?.preserveScreen || this.previousLines.length === 0) return;\n\t\tthis.terminal.write(\" \");\n\t\tconst targetRow = this.previousLines.length;\n\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\tif (lineDiff > 0) this.terminal.write(`\\x1b[${lineDiff}B`);\n\t\telse if (lineDiff < 0) this.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\tthis.terminal.write(\"\\r\\n\");\n\t}\n\n\tprivate collectKittyImageIds(lines: string[]): Set<number> {\n\t\tconst ids = new Set<number>();\n\t\tfor (const line of lines) {\n\t\t\tfor (const id of extractKittyImageIds(line)) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\t\treturn ids;\n\t}\n\n\tprivate deleteKittyImages(ids: Iterable<number>): string {\n\t\tlet buffer = \"\";\n\t\tfor (const id of ids) {\n\t\t\tbuffer += deleteKittyImage(id);\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tprivate getKittyImageReservedRows(lines: string[], index: number, maxIndex = lines.length - 1): number {\n\t\tconst rows = extractKittyImageRows(lines[index] ?? \"\");\n\t\tif (rows <= 1) return 1;\n\n\t\tconst maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);\n\t\tlet reservedRows = 1;\n\t\twhile (reservedRows < maxRows) {\n\t\t\tconst line = lines[index + reservedRows] ?? \"\";\n\t\t\tif (isImageLine(line) || visibleWidth(line) > 0) break;\n\t\t\treservedRows++;\n\t\t}\n\t\treturn reservedRows;\n\t}\n\n\tprivate expandChangedRangeForKittyImages(\n\t\tfirstChanged: number,\n\t\tlastChanged: number,\n\t\tnewLines: string[],\n\t): ChangedLineRange {\n\t\tlet expandedFirstChanged = firstChanged;\n\t\tlet expandedLastChanged = lastChanged;\n\t\tconst expandForLines = (lines: string[]): void => {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (extractKittyImageIds(lines[i]).length === 0) continue;\n\t\t\t\tconst blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;\n\t\t\t\tif (i >= firstChanged || (i <= lastChanged && blockEnd >= firstChanged)) {\n\t\t\t\t\texpandedFirstChanged = Math.min(expandedFirstChanged, i);\n\t\t\t\t\texpandedLastChanged = Math.max(expandedLastChanged, blockEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texpandForLines(this.previousLines);\n\t\texpandForLines(newLines);\n\t\treturn { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };\n\t}\n\n\tprivate deleteChangedKittyImages(firstChanged: number, lastChanged: number): string {\n\t\tif (firstChanged < 0 || lastChanged < firstChanged) return \"\";\n\n\t\tconst ids = new Set<number>();\n\t\tconst maxLine = Math.min(lastChanged, this.previousLines.length - 1);\n\t\tfor (let i = firstChanged; i <= maxLine; i++) {\n\t\t\tfor (const id of extractKittyImageIds(this.previousLines[i] ?? \"\")) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\n\t\treturn this.deleteKittyImages(ids);\n\t}\n\n\tprivate prepareRenderFrame(): MainScreenRenderFrame {\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\t\tconst previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;\n\t\tconst previousViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\n\t\tlet newLines = this.render(width);\n\t\tif (this.hasOverlayEntries) newLines = this.compositeOverlays(newLines, width, height);\n\t\tconst cursorPosition = this.extractCursorPosition(newLines, height);\n\t\t// Preserve component zone markers for alt-screen navigation, but do not emit\n\t\t// them here: terminals draw their own gutter indicators for OSC 133.\n\t\tnewLines = this.applyLineResets(newLines.map((line) => line.replace(OSC133_ZONE_PREFIX, \"\")));\n\t\treturn { width, height, widthChanged, heightChanged, newLines, cursorPosition, previousViewportTop };\n\t}\n\n\tprivate getLineDiff(\n\t\ttargetRow: number,\n\t\thardwareCursorRow: number,\n\t\tpreviousViewportTop: number,\n\t\tviewportTop: number,\n\t): number {\n\t\tconst currentScreenRow = hardwareCursorRow - previousViewportTop;\n\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\treturn targetScreenRow - currentScreenRow;\n\t}\n\n\tprivate logFullRedraw(frame: MainScreenRenderFrame, reason: string): void {\n\t\tif (process.env.GRIP_DEBUG_REDRAW !== \"1\") return;\n\t\tconst logPath = path.join(this.logDirectory, \"grip-debug.log\");\n\t\tconst message = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${frame.newLines.length}, height=${frame.height})\\n`;\n\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\tfs.appendFileSync(logPath, message);\n\t}\n\n\tprivate renderFullFrame(frame: MainScreenRenderFrame, clear: boolean): void {\n\t\tthis.fullRedrawCount += 1;\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tif (clear) {\n\t\t\tbuffer += this.deleteKittyImages(this.previousKittyImageIds);\n\t\t\tbuffer += \"\\x1b[2J\\x1b[H\\x1b[3J\";\n\t\t}\n\t\tfor (let index = 0; index < frame.newLines.length; index++) {\n\t\t\tif (index > 0) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index) : 1;\n\t\t\tif (reservedRows > 1 && reservedRows <= frame.height) {\n\t\t\t\tbuffer += \"\\r\\n\".repeat(reservedRows - 1);\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\tthis.maxLinesRendered = clear ? frame.newLines.length : Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst bufferLength = Math.max(frame.height, frame.newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, bufferLength - frame.height);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderRequiredFullFrame(frame: MainScreenRenderFrame): boolean {\n\t\tif (this.previousLines.length === 0 && !frame.widthChanged && !frame.heightChanged) {\n\t\t\tthis.logFullRedraw(frame, \"first render\");\n\t\t\tthis.renderFullFrame(frame, false);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.widthChanged) {\n\t\t\tthis.logFullRedraw(frame, `terminal width changed (${this.previousWidth} -> ${frame.width})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.heightChanged && !isTermuxSession()) {\n\t\t\tthis.logFullRedraw(frame, `terminal height changed (${this.previousHeight} -> ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (this.getClearOnShrink() && frame.newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tthis.logFullRedraw(frame, `clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate findChangedContent(frame: MainScreenRenderFrame): ChangedContentRange | undefined {\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(frame.newLines.length, this.previousLines.length);\n\t\tfor (let index = 0; index < maxLines; index++) {\n\t\t\tconst oldLine = index < this.previousLines.length ? this.previousLines[index] : \"\";\n\t\t\tconst newLine = index < frame.newLines.length ? frame.newLines[index] : \"\";\n\t\t\tif (oldLine === newLine) continue;\n\t\t\tif (firstChanged === -1) firstChanged = index;\n\t\t\tlastChanged = index;\n\t\t}\n\n\t\tconst appendedLines = frame.newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) firstChanged = this.previousLines.length;\n\t\t\tlastChanged = frame.newLines.length - 1;\n\t\t}\n\t\tif (firstChanged === -1) return undefined;\n\n\t\tconst expanded = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, frame.newLines);\n\t\treturn {\n\t\t\t...expanded,\n\t\t\tappendStart: appendedLines && expanded.firstChanged === this.previousLines.length && expanded.firstChanged > 0,\n\t\t};\n\t}\n\n\tprivate commitFrameHistory(frame: MainScreenRenderFrame, viewportTop: number): void {\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t\tthis.previousViewportTop = viewportTop;\n\t}\n\n\tprivate handleUnchangedFrame(frame: MainScreenRenderFrame): void {\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousViewportTop = frame.previousViewportTop;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderDeletedContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (this.previousLines.length <= frame.newLines.length) {\n\t\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t\t\treturn;\n\t\t}\n\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tbuffer += this.deleteChangedKittyImages(range.firstChanged, range.lastChanged);\n\t\tconst targetRow = Math.max(0, frame.newLines.length - 1);\n\t\tif (targetRow < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `deleted lines moved viewport up (${targetRow} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst lineDiff = this.getLineDiff(\n\t\t\ttargetRow,\n\t\t\tthis.hardwareCursorRow,\n\t\t\tframe.previousViewportTop,\n\t\t\tframe.previousViewportTop,\n\t\t);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += \"\\r\";\n\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\tif (extraLines > frame.height) {\n\t\t\tthis.logFullRedraw(frame, `extraLines > height (${extraLines} > ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst clearStartOffset = frame.newLines.length === 0 ? 0 : 1;\n\t\tif (extraLines > 0 && clearStartOffset > 0) buffer += `\\x1b[${clearStartOffset}B`;\n\t\tfor (let index = 0; index < extraLines; index++) {\n\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\tif (index < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t}\n\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\tif (moveBack > 0) buffer += `\\x1b[${moveBack}A`;\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = targetRow;\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t}\n\n\tprivate assertRenderedLineFits(line: string, index: number, frame: MainScreenRenderFrame): void {\n\t\tif (isImageLine(line) || visibleWidth(line) <= frame.width) return;\n\t\tconst crashLogPath = path.join(this.logDirectory, \"grip-crash.log\");\n\t\tconst crashData = [\n\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t`Terminal width: ${frame.width}`,\n\t\t\t`Line ${index} visible width: ${visibleWidth(line)}`,\n\t\t\t\"\",\n\t\t\t\"=== All rendered lines ===\",\n\t\t\t...frame.newLines.map(\n\t\t\t\t(renderedLine, lineIndex) => `[${lineIndex}] (w=${visibleWidth(renderedLine)}) ${renderedLine}`,\n\t\t\t),\n\t\t\t\"\",\n\t\t].join(\"\\n\");\n\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\tfs.writeFileSync(crashLogPath, crashData);\n\t\tthis.stop();\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Rendered line ${index} exceeds terminal width (${visibleWidth(line)} > ${frame.width}).`,\n\t\t\t\t\"\",\n\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\"\",\n\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t}\n\n\tprivate renderChangedLines(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\tinitialBuffer: string,\n\t): ChangedLinesRenderResult | undefined {\n\t\tlet buffer = initialBuffer;\n\t\tconst renderEnd = Math.min(range.lastChanged, frame.newLines.length - 1);\n\t\tfor (let index = range.firstChanged; index <= renderEnd; index++) {\n\t\t\tif (index > range.firstChanged) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index, renderEnd) : 1;\n\t\t\tif (reservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = index - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + reservedRows > frame.height) {\n\t\t\t\t\tthis.logFullRedraw(\n\t\t\t\t\t\tframe,\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${reservedRows} > ${frame.height})`,\n\t\t\t\t\t);\n\t\t\t\t\tthis.renderFullFrame(frame, true);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\t\tfor (let row = 1; row < reservedRows; row++) buffer += \"\\r\\n\\x1b[2K\";\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\tthis.assertRenderedLineFits(line, index, frame);\n\t\t\tbuffer += line;\n\t\t}\n\t\treturn { buffer, renderEnd };\n\t}\n\n\tprivate writeDifferentialDebugLog(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\thardwareCursorRow: number,\n\t\tlineDiff: number,\n\t\trenderEnd: number,\n\t\tfinalCursorRow: number,\n\t\tbuffer: string,\n\t): void {\n\t\tif (process.env.GRIP_TUI_DEBUG !== \"1\") return;\n\t\tconst debugDir = \"/tmp/tui\";\n\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\tconst debugData = [\n\t\t\t`firstChanged: ${range.firstChanged}`,\n\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t`height: ${frame.height}`,\n\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t`cursorPos: ${JSON.stringify(frame.cursorPosition)}`,\n\t\t\t`newLines.length: ${frame.newLines.length}`,\n\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\"\",\n\t\t\t\"=== newLines ===\",\n\t\t\tJSON.stringify(frame.newLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== previousLines ===\",\n\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== buffer ===\",\n\t\t\tJSON.stringify(buffer),\n\t\t].join(\"\\n\");\n\t\tfs.writeFileSync(debugPath, debugData);\n\t}\n\n\tprivate renderDifferentialContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (range.firstChanged < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `firstChanged < viewportTop (${range.firstChanged} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\n\t\tlet previousViewportTop = frame.previousViewportTop;\n\t\tlet viewportTop = previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tlet buffer = `\\x1b[?2026h${this.deleteChangedKittyImages(range.firstChanged, range.lastChanged)}`;\n\t\tconst previousViewportBottom = previousViewportTop + frame.height - 1;\n\t\tconst moveTargetRow = range.appendStart ? range.firstChanged - 1 : range.firstChanged;\n\t\tif (moveTargetRow > previousViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(frame.height - 1, hardwareCursorRow - previousViewportTop));\n\t\t\tconst moveToBottom = frame.height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) buffer += `\\x1b[${moveToBottom}B`;\n\t\t\tconst scroll = moveTargetRow - previousViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tpreviousViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\tconst lineDiff = this.getLineDiff(moveTargetRow, hardwareCursorRow, previousViewportTop, viewportTop);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += range.appendStart ? \"\\r\\n\" : \"\\r\";\n\n\t\tconst changedLines = this.renderChangedLines(frame, range, viewportTop, buffer);\n\t\tif (!changedLines) return;\n\t\tbuffer = changedLines.buffer;\n\t\tlet finalCursorRow = changedLines.renderEnd;\n\t\tif (this.previousLines.length > frame.newLines.length) {\n\t\t\tif (changedLines.renderEnd < frame.newLines.length - 1) {\n\t\t\t\tconst moveDown = frame.newLines.length - 1 - changedLines.renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = frame.newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\t\tfor (let index = frame.newLines.length; index < this.previousLines.length; index++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\n\t\tthis.writeDifferentialDebugLog(\n\t\t\tframe,\n\t\t\trange,\n\t\t\tviewportTop,\n\t\t\thardwareCursorRow,\n\t\t\tlineDiff,\n\t\t\tchangedLines.renderEnd,\n\t\t\tfinalCursorRow,\n\t\t\tbuffer,\n\t\t);\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst committedViewportTop = Math.max(previousViewportTop, finalCursorRow - frame.height + 1);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, committedViewportTop);\n\t}\n\n\tprotected doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst frame = this.prepareRenderFrame();\n\t\tif (this.renderRequiredFullFrame(frame)) return;\n\t\tconst changedContent = this.findChangedContent(frame);\n\t\tif (!changedContent) {\n\t\t\tthis.handleUnchangedFrame(frame);\n\t\t\treturn;\n\t\t}\n\t\tif (changedContent.firstChanged >= frame.newLines.length) {\n\t\t\tthis.renderDeletedContent(frame, changedContent);\n\t\t\treturn;\n\t\t}\n\t\tthis.renderDifferentialContent(frame, changedContent);\n\t}\n\n\t/**\n\t * Position the hardware cursor for IME candidate window.\n\t * @param cursorPos The cursor position extracted from rendered output, or null\n\t * @param totalLines Total number of rendered lines\n\t */\n\tprivate positionHardwareCursor(cursorPos: RenderedCursorPosition | null, totalLines: number): void {\n\t\tif (!cursorPos || totalLines <= 0) {\n\t\t\tthis.terminal.hideCursor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Clamp cursor position to valid range\n\t\tconst targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n\t\tconst targetCol = Math.max(0, cursorPos.col);\n\n\t\t// Move cursor from current position to target\n\t\tconst rowDelta = targetRow - this.hardwareCursorRow;\n\t\tlet buffer = \"\";\n\t\tif (rowDelta > 0) {\n\t\t\tbuffer += `\\x1b[${rowDelta}B`; // Move down\n\t\t} else if (rowDelta < 0) {\n\t\t\tbuffer += `\\x1b[${-rowDelta}A`; // Move up\n\t\t}\n\t\t// Move to absolute column (1-indexed)\n\t\tbuffer += `\\x1b[${targetCol + 1}G`;\n\n\t\tif (buffer) {\n\t\t\tthis.terminal.write(buffer);\n\t\t}\n\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tif (this.getShowHardwareCursor()) {\n\t\t\tthis.terminal.showCursor();\n\t\t} else {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tui-main-screen.d.ts","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+B,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAmE/F,MAAM,WAAW,wBAAwB;IACxC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC5B;AAED,sFAAsF;AACtF,qBAAa,aAAc,SAAQ,OAAQ,YAAW,GAAG;IACxD,QAAQ,CAAC,IAAI,EAAG,SAAS,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,qBAAqB,CAAqB;IAClD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,mBAAmB,CAAK;IAEhC,kBAAkB,IAAI,wBAAwB,CAU7C;IAED,kBAAkB,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI,CASxD;IAED,UAAmB,gBAAgB,IAAI,IAAI,CAQ1C;IAED,UAAmB,kBAAkB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAQpE;IAED,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,gCAAgC;IAuBxC,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IA8C5B,OAAO,CAAC,sBAAsB;IA6B9B,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,yBAAyB;IAuCjC,OAAO,CAAC,yBAAyB;IAkEjC,SAAS,CAAC,QAAQ,IAAI,IAAI,CAczB;IAED;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAgC9B"}
|
package/dist/tui-main-screen.js
CHANGED
|
@@ -40,15 +40,18 @@ function isTermuxSession() {
|
|
|
40
40
|
}
|
|
41
41
|
/** TUI implementation that renders into the terminal's main screen and scrollback. */
|
|
42
42
|
export class TuiMainScreen extends TuiBase {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
constructor() {
|
|
44
|
+
super(...arguments);
|
|
45
|
+
this.mode = "regular";
|
|
46
|
+
this.previousLines = [];
|
|
47
|
+
this.previousKittyImageIds = new Set();
|
|
48
|
+
this.previousWidth = 0;
|
|
49
|
+
this.previousHeight = 0;
|
|
50
|
+
this.cursorRow = 0;
|
|
51
|
+
this.hardwareCursorRow = 0;
|
|
52
|
+
this.maxLinesRendered = 0;
|
|
53
|
+
this.previousViewportTop = 0;
|
|
54
|
+
}
|
|
52
55
|
captureRenderState() {
|
|
53
56
|
return {
|
|
54
57
|
previousLines: [...this.previousLines],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui-main-screen.js","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type RenderedCursorPosition, type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\nconst OSC133_ZONE_PREFIX = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: number;\n}\n\ninterface ChangedLineRange {\n\tfirstChanged: number;\n\tlastChanged: number;\n}\n\ninterface ChangedContentRange extends ChangedLineRange {\n\tappendStart: boolean;\n}\n\ninterface MainScreenRenderFrame {\n\twidth: number;\n\theight: number;\n\twidthChanged: boolean;\n\theightChanged: boolean;\n\tnewLines: string[];\n\tcursorPosition: RenderedCursorPosition | null;\n\tpreviousViewportTop: number;\n}\n\ninterface ChangedLinesRenderResult {\n\tbuffer: string;\n\trenderEnd: number;\n}\n\nfunction parseKittyImageHeader(line: string): KittyImageHeader | undefined {\n\tconst sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n\tif (sequenceStart === -1) return undefined;\n\tconst paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n\tconst paramsEnd = line.indexOf(\";\", paramsStart);\n\tif (paramsEnd === -1) return undefined;\n\n\tconst ids: number[] = [];\n\tlet rows = 1;\n\tfor (const param of line.slice(paramsStart, paramsEnd).split(\",\")) {\n\t\tconst [key, value] = param.split(\"=\", 2);\n\t\tif (value === undefined) continue;\n\t\tconst numberValue = Number(value);\n\t\tif (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff) continue;\n\t\tif (key === \"i\") ids.push(numberValue);\n\t\telse if (key === \"r\") rows = numberValue;\n\t}\n\treturn { ids, rows };\n}\n\nfunction extractKittyImageIds(line: string): number[] {\n\treturn parseKittyImageHeader(line)?.ids ?? [];\n}\n\nfunction extractKittyImageRows(line: string): number {\n\treturn parseKittyImageHeader(line)?.rows ?? 1;\n}\n\nfunction isTermuxSession(): boolean {\n\treturn Boolean(process.env.TERMUX_VERSION);\n}\n\nexport interface TuiMainScreenRenderState {\n\tpreviousLines: string[];\n\tpreviousWidth: number;\n\tpreviousHeight: number;\n\tcursorRow: number;\n\thardwareCursorRow: number;\n\tmaxLinesRendered: number;\n\tpreviousViewportTop: number;\n}\n\n/** TUI implementation that renders into the terminal's main screen and scrollback. */\nexport class TuiMainScreen extends TuiBase implements TUI {\n\treadonly mode = \"regular\" as const;\n\tprivate previousLines: string[] = [];\n\tprivate previousKittyImageIds = new Set<number>();\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate cursorRow = 0;\n\tprivate hardwareCursorRow = 0;\n\tprivate maxLinesRendered = 0;\n\tprivate previousViewportTop = 0;\n\n\tcaptureRenderState(): TuiMainScreenRenderState {\n\t\treturn {\n\t\t\tpreviousLines: [...this.previousLines],\n\t\t\tpreviousWidth: this.previousWidth,\n\t\t\tpreviousHeight: this.previousHeight,\n\t\t\tcursorRow: this.cursorRow,\n\t\t\thardwareCursorRow: this.hardwareCursorRow,\n\t\t\tmaxLinesRendered: this.maxLinesRendered,\n\t\t\tpreviousViewportTop: this.previousViewportTop,\n\t\t};\n\t}\n\n\trestoreRenderState(state: TuiMainScreenRenderState): void {\n\t\tthis.previousLines = state.previousLines.map((line) => (isImageLine(line) ? \"\" : line));\n\t\tthis.previousKittyImageIds = new Set();\n\t\tthis.previousWidth = state.previousWidth;\n\t\tthis.previousHeight = state.previousHeight;\n\t\tthis.cursorRow = state.cursorRow;\n\t\tthis.hardwareCursorRow = state.hardwareCursorRow;\n\t\tthis.maxLinesRendered = state.maxLinesRendered;\n\t\tthis.previousViewportTop = state.previousViewportTop;\n\t}\n\n\tprotected override resetRenderState(): void {\n\t\tthis.previousLines = [];\n\t\tthis.previousWidth = -1;\n\t\tthis.previousHeight = -1;\n\t\tthis.cursorRow = 0;\n\t\tthis.hardwareCursorRow = 0;\n\t\tthis.maxLinesRendered = 0;\n\t\tthis.previousViewportTop = 0;\n\t}\n\n\tprotected override beforeTerminalStop(options?: TuiStopOptions): void {\n\t\tif (options?.preserveScreen || this.previousLines.length === 0) return;\n\t\tthis.terminal.write(\" \");\n\t\tconst targetRow = this.previousLines.length;\n\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\tif (lineDiff > 0) this.terminal.write(`\\x1b[${lineDiff}B`);\n\t\telse if (lineDiff < 0) this.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\tthis.terminal.write(\"\\r\\n\");\n\t}\n\n\tprivate collectKittyImageIds(lines: string[]): Set<number> {\n\t\tconst ids = new Set<number>();\n\t\tfor (const line of lines) {\n\t\t\tfor (const id of extractKittyImageIds(line)) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\t\treturn ids;\n\t}\n\n\tprivate deleteKittyImages(ids: Iterable<number>): string {\n\t\tlet buffer = \"\";\n\t\tfor (const id of ids) {\n\t\t\tbuffer += deleteKittyImage(id);\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tprivate getKittyImageReservedRows(lines: string[], index: number, maxIndex = lines.length - 1): number {\n\t\tconst rows = extractKittyImageRows(lines[index] ?? \"\");\n\t\tif (rows <= 1) return 1;\n\n\t\tconst maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);\n\t\tlet reservedRows = 1;\n\t\twhile (reservedRows < maxRows) {\n\t\t\tconst line = lines[index + reservedRows] ?? \"\";\n\t\t\tif (isImageLine(line) || visibleWidth(line) > 0) break;\n\t\t\treservedRows++;\n\t\t}\n\t\treturn reservedRows;\n\t}\n\n\tprivate expandChangedRangeForKittyImages(\n\t\tfirstChanged: number,\n\t\tlastChanged: number,\n\t\tnewLines: string[],\n\t): ChangedLineRange {\n\t\tlet expandedFirstChanged = firstChanged;\n\t\tlet expandedLastChanged = lastChanged;\n\t\tconst expandForLines = (lines: string[]): void => {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (extractKittyImageIds(lines[i]).length === 0) continue;\n\t\t\t\tconst blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;\n\t\t\t\tif (i >= firstChanged || (i <= lastChanged && blockEnd >= firstChanged)) {\n\t\t\t\t\texpandedFirstChanged = Math.min(expandedFirstChanged, i);\n\t\t\t\t\texpandedLastChanged = Math.max(expandedLastChanged, blockEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texpandForLines(this.previousLines);\n\t\texpandForLines(newLines);\n\t\treturn { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };\n\t}\n\n\tprivate deleteChangedKittyImages(firstChanged: number, lastChanged: number): string {\n\t\tif (firstChanged < 0 || lastChanged < firstChanged) return \"\";\n\n\t\tconst ids = new Set<number>();\n\t\tconst maxLine = Math.min(lastChanged, this.previousLines.length - 1);\n\t\tfor (let i = firstChanged; i <= maxLine; i++) {\n\t\t\tfor (const id of extractKittyImageIds(this.previousLines[i] ?? \"\")) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\n\t\treturn this.deleteKittyImages(ids);\n\t}\n\n\tprivate prepareRenderFrame(): MainScreenRenderFrame {\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\t\tconst previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;\n\t\tconst previousViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\n\t\tlet newLines = this.render(width);\n\t\tif (this.hasOverlayEntries) newLines = this.compositeOverlays(newLines, width, height);\n\t\tconst cursorPosition = this.extractCursorPosition(newLines, height);\n\t\t// Preserve component zone markers for alt-screen navigation, but do not emit\n\t\t// them here: terminals draw their own gutter indicators for OSC 133.\n\t\tnewLines = this.applyLineResets(newLines.map((line) => line.replace(OSC133_ZONE_PREFIX, \"\")));\n\t\treturn { width, height, widthChanged, heightChanged, newLines, cursorPosition, previousViewportTop };\n\t}\n\n\tprivate getLineDiff(\n\t\ttargetRow: number,\n\t\thardwareCursorRow: number,\n\t\tpreviousViewportTop: number,\n\t\tviewportTop: number,\n\t): number {\n\t\tconst currentScreenRow = hardwareCursorRow - previousViewportTop;\n\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\treturn targetScreenRow - currentScreenRow;\n\t}\n\n\tprivate logFullRedraw(frame: MainScreenRenderFrame, reason: string): void {\n\t\tif (process.env.GRIP_DEBUG_REDRAW !== \"1\") return;\n\t\tconst logPath = path.join(this.logDirectory, \"grip-debug.log\");\n\t\tconst message = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${frame.newLines.length}, height=${frame.height})\\n`;\n\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\tfs.appendFileSync(logPath, message);\n\t}\n\n\tprivate renderFullFrame(frame: MainScreenRenderFrame, clear: boolean): void {\n\t\tthis.fullRedrawCount += 1;\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tif (clear) {\n\t\t\tbuffer += this.deleteKittyImages(this.previousKittyImageIds);\n\t\t\tbuffer += \"\\x1b[2J\\x1b[H\\x1b[3J\";\n\t\t}\n\t\tfor (let index = 0; index < frame.newLines.length; index++) {\n\t\t\tif (index > 0) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index) : 1;\n\t\t\tif (reservedRows > 1 && reservedRows <= frame.height) {\n\t\t\t\tbuffer += \"\\r\\n\".repeat(reservedRows - 1);\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\tthis.maxLinesRendered = clear ? frame.newLines.length : Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst bufferLength = Math.max(frame.height, frame.newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, bufferLength - frame.height);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderRequiredFullFrame(frame: MainScreenRenderFrame): boolean {\n\t\tif (this.previousLines.length === 0 && !frame.widthChanged && !frame.heightChanged) {\n\t\t\tthis.logFullRedraw(frame, \"first render\");\n\t\t\tthis.renderFullFrame(frame, false);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.widthChanged) {\n\t\t\tthis.logFullRedraw(frame, `terminal width changed (${this.previousWidth} -> ${frame.width})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.heightChanged && !isTermuxSession()) {\n\t\t\tthis.logFullRedraw(frame, `terminal height changed (${this.previousHeight} -> ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (this.getClearOnShrink() && frame.newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tthis.logFullRedraw(frame, `clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate findChangedContent(frame: MainScreenRenderFrame): ChangedContentRange | undefined {\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(frame.newLines.length, this.previousLines.length);\n\t\tfor (let index = 0; index < maxLines; index++) {\n\t\t\tconst oldLine = index < this.previousLines.length ? this.previousLines[index] : \"\";\n\t\t\tconst newLine = index < frame.newLines.length ? frame.newLines[index] : \"\";\n\t\t\tif (oldLine === newLine) continue;\n\t\t\tif (firstChanged === -1) firstChanged = index;\n\t\t\tlastChanged = index;\n\t\t}\n\n\t\tconst appendedLines = frame.newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) firstChanged = this.previousLines.length;\n\t\t\tlastChanged = frame.newLines.length - 1;\n\t\t}\n\t\tif (firstChanged === -1) return undefined;\n\n\t\tconst expanded = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, frame.newLines);\n\t\treturn {\n\t\t\t...expanded,\n\t\t\tappendStart: appendedLines && expanded.firstChanged === this.previousLines.length && expanded.firstChanged > 0,\n\t\t};\n\t}\n\n\tprivate commitFrameHistory(frame: MainScreenRenderFrame, viewportTop: number): void {\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t\tthis.previousViewportTop = viewportTop;\n\t}\n\n\tprivate handleUnchangedFrame(frame: MainScreenRenderFrame): void {\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousViewportTop = frame.previousViewportTop;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderDeletedContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (this.previousLines.length <= frame.newLines.length) {\n\t\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t\t\treturn;\n\t\t}\n\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tbuffer += this.deleteChangedKittyImages(range.firstChanged, range.lastChanged);\n\t\tconst targetRow = Math.max(0, frame.newLines.length - 1);\n\t\tif (targetRow < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `deleted lines moved viewport up (${targetRow} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst lineDiff = this.getLineDiff(\n\t\t\ttargetRow,\n\t\t\tthis.hardwareCursorRow,\n\t\t\tframe.previousViewportTop,\n\t\t\tframe.previousViewportTop,\n\t\t);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += \"\\r\";\n\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\tif (extraLines > frame.height) {\n\t\t\tthis.logFullRedraw(frame, `extraLines > height (${extraLines} > ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst clearStartOffset = frame.newLines.length === 0 ? 0 : 1;\n\t\tif (extraLines > 0 && clearStartOffset > 0) buffer += `\\x1b[${clearStartOffset}B`;\n\t\tfor (let index = 0; index < extraLines; index++) {\n\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\tif (index < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t}\n\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\tif (moveBack > 0) buffer += `\\x1b[${moveBack}A`;\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = targetRow;\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t}\n\n\tprivate assertRenderedLineFits(line: string, index: number, frame: MainScreenRenderFrame): void {\n\t\tif (isImageLine(line) || visibleWidth(line) <= frame.width) return;\n\t\tconst crashLogPath = path.join(this.logDirectory, \"grip-crash.log\");\n\t\tconst crashData = [\n\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t`Terminal width: ${frame.width}`,\n\t\t\t`Line ${index} visible width: ${visibleWidth(line)}`,\n\t\t\t\"\",\n\t\t\t\"=== All rendered lines ===\",\n\t\t\t...frame.newLines.map(\n\t\t\t\t(renderedLine, lineIndex) => `[${lineIndex}] (w=${visibleWidth(renderedLine)}) ${renderedLine}`,\n\t\t\t),\n\t\t\t\"\",\n\t\t].join(\"\\n\");\n\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\tfs.writeFileSync(crashLogPath, crashData);\n\t\tthis.stop();\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Rendered line ${index} exceeds terminal width (${visibleWidth(line)} > ${frame.width}).`,\n\t\t\t\t\"\",\n\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\"\",\n\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t}\n\n\tprivate renderChangedLines(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\tinitialBuffer: string,\n\t): ChangedLinesRenderResult | undefined {\n\t\tlet buffer = initialBuffer;\n\t\tconst renderEnd = Math.min(range.lastChanged, frame.newLines.length - 1);\n\t\tfor (let index = range.firstChanged; index <= renderEnd; index++) {\n\t\t\tif (index > range.firstChanged) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index, renderEnd) : 1;\n\t\t\tif (reservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = index - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + reservedRows > frame.height) {\n\t\t\t\t\tthis.logFullRedraw(\n\t\t\t\t\t\tframe,\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${reservedRows} > ${frame.height})`,\n\t\t\t\t\t);\n\t\t\t\t\tthis.renderFullFrame(frame, true);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\t\tfor (let row = 1; row < reservedRows; row++) buffer += \"\\r\\n\\x1b[2K\";\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\tthis.assertRenderedLineFits(line, index, frame);\n\t\t\tbuffer += line;\n\t\t}\n\t\treturn { buffer, renderEnd };\n\t}\n\n\tprivate writeDifferentialDebugLog(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\thardwareCursorRow: number,\n\t\tlineDiff: number,\n\t\trenderEnd: number,\n\t\tfinalCursorRow: number,\n\t\tbuffer: string,\n\t): void {\n\t\tif (process.env.GRIP_TUI_DEBUG !== \"1\") return;\n\t\tconst debugDir = \"/tmp/tui\";\n\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\tconst debugData = [\n\t\t\t`firstChanged: ${range.firstChanged}`,\n\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t`height: ${frame.height}`,\n\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t`cursorPos: ${JSON.stringify(frame.cursorPosition)}`,\n\t\t\t`newLines.length: ${frame.newLines.length}`,\n\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\"\",\n\t\t\t\"=== newLines ===\",\n\t\t\tJSON.stringify(frame.newLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== previousLines ===\",\n\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== buffer ===\",\n\t\t\tJSON.stringify(buffer),\n\t\t].join(\"\\n\");\n\t\tfs.writeFileSync(debugPath, debugData);\n\t}\n\n\tprivate renderDifferentialContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (range.firstChanged < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `firstChanged < viewportTop (${range.firstChanged} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\n\t\tlet previousViewportTop = frame.previousViewportTop;\n\t\tlet viewportTop = previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tlet buffer = `\\x1b[?2026h${this.deleteChangedKittyImages(range.firstChanged, range.lastChanged)}`;\n\t\tconst previousViewportBottom = previousViewportTop + frame.height - 1;\n\t\tconst moveTargetRow = range.appendStart ? range.firstChanged - 1 : range.firstChanged;\n\t\tif (moveTargetRow > previousViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(frame.height - 1, hardwareCursorRow - previousViewportTop));\n\t\t\tconst moveToBottom = frame.height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) buffer += `\\x1b[${moveToBottom}B`;\n\t\t\tconst scroll = moveTargetRow - previousViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tpreviousViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\tconst lineDiff = this.getLineDiff(moveTargetRow, hardwareCursorRow, previousViewportTop, viewportTop);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += range.appendStart ? \"\\r\\n\" : \"\\r\";\n\n\t\tconst changedLines = this.renderChangedLines(frame, range, viewportTop, buffer);\n\t\tif (!changedLines) return;\n\t\tbuffer = changedLines.buffer;\n\t\tlet finalCursorRow = changedLines.renderEnd;\n\t\tif (this.previousLines.length > frame.newLines.length) {\n\t\t\tif (changedLines.renderEnd < frame.newLines.length - 1) {\n\t\t\t\tconst moveDown = frame.newLines.length - 1 - changedLines.renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = frame.newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\t\tfor (let index = frame.newLines.length; index < this.previousLines.length; index++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\n\t\tthis.writeDifferentialDebugLog(\n\t\t\tframe,\n\t\t\trange,\n\t\t\tviewportTop,\n\t\t\thardwareCursorRow,\n\t\t\tlineDiff,\n\t\t\tchangedLines.renderEnd,\n\t\t\tfinalCursorRow,\n\t\t\tbuffer,\n\t\t);\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst committedViewportTop = Math.max(previousViewportTop, finalCursorRow - frame.height + 1);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, committedViewportTop);\n\t}\n\n\tprotected doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst frame = this.prepareRenderFrame();\n\t\tif (this.renderRequiredFullFrame(frame)) return;\n\t\tconst changedContent = this.findChangedContent(frame);\n\t\tif (!changedContent) {\n\t\t\tthis.handleUnchangedFrame(frame);\n\t\t\treturn;\n\t\t}\n\t\tif (changedContent.firstChanged >= frame.newLines.length) {\n\t\t\tthis.renderDeletedContent(frame, changedContent);\n\t\t\treturn;\n\t\t}\n\t\tthis.renderDifferentialContent(frame, changedContent);\n\t}\n\n\t/**\n\t * Position the hardware cursor for IME candidate window.\n\t * @param cursorPos The cursor position extracted from rendered output, or null\n\t * @param totalLines Total number of rendered lines\n\t */\n\tprivate positionHardwareCursor(cursorPos: RenderedCursorPosition | null, totalLines: number): void {\n\t\tif (!cursorPos || totalLines <= 0) {\n\t\t\tthis.terminal.hideCursor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Clamp cursor position to valid range\n\t\tconst targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n\t\tconst targetCol = Math.max(0, cursorPos.col);\n\n\t\t// Move cursor from current position to target\n\t\tconst rowDelta = targetRow - this.hardwareCursorRow;\n\t\tlet buffer = \"\";\n\t\tif (rowDelta > 0) {\n\t\t\tbuffer += `\\x1b[${rowDelta}B`; // Move down\n\t\t} else if (rowDelta < 0) {\n\t\t\tbuffer += `\\x1b[${-rowDelta}A`; // Move up\n\t\t}\n\t\t// Move to absolute column (1-indexed)\n\t\tbuffer += `\\x1b[${targetCol + 1}G`;\n\n\t\tif (buffer) {\n\t\t\tthis.terminal.write(buffer);\n\t\t}\n\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tif (this.getShowHardwareCursor()) {\n\t\t\tthis.terminal.showCursor();\n\t\t} else {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tui-main-screen.js","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type RenderedCursorPosition, type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\nconst OSC133_ZONE_PREFIX = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: number;\n}\n\ninterface ChangedLineRange {\n\tfirstChanged: number;\n\tlastChanged: number;\n}\n\ninterface ChangedContentRange extends ChangedLineRange {\n\tappendStart: boolean;\n}\n\ninterface MainScreenRenderFrame {\n\twidth: number;\n\theight: number;\n\twidthChanged: boolean;\n\theightChanged: boolean;\n\tnewLines: string[];\n\tcursorPosition: RenderedCursorPosition | null;\n\tpreviousViewportTop: number;\n}\n\ninterface ChangedLinesRenderResult {\n\tbuffer: string;\n\trenderEnd: number;\n}\n\nfunction parseKittyImageHeader(line: string): KittyImageHeader | undefined {\n\tconst sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);\n\tif (sequenceStart === -1) return undefined;\n\tconst paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;\n\tconst paramsEnd = line.indexOf(\";\", paramsStart);\n\tif (paramsEnd === -1) return undefined;\n\n\tconst ids: number[] = [];\n\tlet rows = 1;\n\tfor (const param of line.slice(paramsStart, paramsEnd).split(\",\")) {\n\t\tconst [key, value] = param.split(\"=\", 2);\n\t\tif (value === undefined) continue;\n\t\tconst numberValue = Number(value);\n\t\tif (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff) continue;\n\t\tif (key === \"i\") ids.push(numberValue);\n\t\telse if (key === \"r\") rows = numberValue;\n\t}\n\treturn { ids, rows };\n}\n\nfunction extractKittyImageIds(line: string): number[] {\n\treturn parseKittyImageHeader(line)?.ids ?? [];\n}\n\nfunction extractKittyImageRows(line: string): number {\n\treturn parseKittyImageHeader(line)?.rows ?? 1;\n}\n\nfunction isTermuxSession(): boolean {\n\treturn Boolean(process.env.TERMUX_VERSION);\n}\n\nexport interface TuiMainScreenRenderState {\n\tpreviousLines: string[];\n\tpreviousWidth: number;\n\tpreviousHeight: number;\n\tcursorRow: number;\n\thardwareCursorRow: number;\n\tmaxLinesRendered: number;\n\tpreviousViewportTop: number;\n}\n\n/** TUI implementation that renders into the terminal's main screen and scrollback. */\nexport class TuiMainScreen extends TuiBase implements TUI {\n\treadonly mode = \"regular\" as const;\n\tprivate previousLines: string[] = [];\n\tprivate previousKittyImageIds = new Set<number>();\n\tprivate previousWidth = 0;\n\tprivate previousHeight = 0;\n\tprivate cursorRow = 0;\n\tprivate hardwareCursorRow = 0;\n\tprivate maxLinesRendered = 0;\n\tprivate previousViewportTop = 0;\n\n\tcaptureRenderState(): TuiMainScreenRenderState {\n\t\treturn {\n\t\t\tpreviousLines: [...this.previousLines],\n\t\t\tpreviousWidth: this.previousWidth,\n\t\t\tpreviousHeight: this.previousHeight,\n\t\t\tcursorRow: this.cursorRow,\n\t\t\thardwareCursorRow: this.hardwareCursorRow,\n\t\t\tmaxLinesRendered: this.maxLinesRendered,\n\t\t\tpreviousViewportTop: this.previousViewportTop,\n\t\t};\n\t}\n\n\trestoreRenderState(state: TuiMainScreenRenderState): void {\n\t\tthis.previousLines = state.previousLines.map((line) => (isImageLine(line) ? \"\" : line));\n\t\tthis.previousKittyImageIds = new Set();\n\t\tthis.previousWidth = state.previousWidth;\n\t\tthis.previousHeight = state.previousHeight;\n\t\tthis.cursorRow = state.cursorRow;\n\t\tthis.hardwareCursorRow = state.hardwareCursorRow;\n\t\tthis.maxLinesRendered = state.maxLinesRendered;\n\t\tthis.previousViewportTop = state.previousViewportTop;\n\t}\n\n\tprotected override resetRenderState(): void {\n\t\tthis.previousLines = [];\n\t\tthis.previousWidth = -1;\n\t\tthis.previousHeight = -1;\n\t\tthis.cursorRow = 0;\n\t\tthis.hardwareCursorRow = 0;\n\t\tthis.maxLinesRendered = 0;\n\t\tthis.previousViewportTop = 0;\n\t}\n\n\tprotected override beforeTerminalStop(options?: TuiStopOptions): void {\n\t\tif (options?.preserveScreen || this.previousLines.length === 0) return;\n\t\tthis.terminal.write(\" \");\n\t\tconst targetRow = this.previousLines.length;\n\t\tconst lineDiff = targetRow - this.hardwareCursorRow;\n\t\tif (lineDiff > 0) this.terminal.write(`\\x1b[${lineDiff}B`);\n\t\telse if (lineDiff < 0) this.terminal.write(`\\x1b[${-lineDiff}A`);\n\t\tthis.terminal.write(\"\\r\\n\");\n\t}\n\n\tprivate collectKittyImageIds(lines: string[]): Set<number> {\n\t\tconst ids = new Set<number>();\n\t\tfor (const line of lines) {\n\t\t\tfor (const id of extractKittyImageIds(line)) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\t\treturn ids;\n\t}\n\n\tprivate deleteKittyImages(ids: Iterable<number>): string {\n\t\tlet buffer = \"\";\n\t\tfor (const id of ids) {\n\t\t\tbuffer += deleteKittyImage(id);\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tprivate getKittyImageReservedRows(lines: string[], index: number, maxIndex = lines.length - 1): number {\n\t\tconst rows = extractKittyImageRows(lines[index] ?? \"\");\n\t\tif (rows <= 1) return 1;\n\n\t\tconst maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);\n\t\tlet reservedRows = 1;\n\t\twhile (reservedRows < maxRows) {\n\t\t\tconst line = lines[index + reservedRows] ?? \"\";\n\t\t\tif (isImageLine(line) || visibleWidth(line) > 0) break;\n\t\t\treservedRows++;\n\t\t}\n\t\treturn reservedRows;\n\t}\n\n\tprivate expandChangedRangeForKittyImages(\n\t\tfirstChanged: number,\n\t\tlastChanged: number,\n\t\tnewLines: string[],\n\t): ChangedLineRange {\n\t\tlet expandedFirstChanged = firstChanged;\n\t\tlet expandedLastChanged = lastChanged;\n\t\tconst expandForLines = (lines: string[]): void => {\n\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\tif (extractKittyImageIds(lines[i]).length === 0) continue;\n\t\t\t\tconst blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;\n\t\t\t\tif (i >= firstChanged || (i <= lastChanged && blockEnd >= firstChanged)) {\n\t\t\t\t\texpandedFirstChanged = Math.min(expandedFirstChanged, i);\n\t\t\t\t\texpandedLastChanged = Math.max(expandedLastChanged, blockEnd);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texpandForLines(this.previousLines);\n\t\texpandForLines(newLines);\n\t\treturn { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };\n\t}\n\n\tprivate deleteChangedKittyImages(firstChanged: number, lastChanged: number): string {\n\t\tif (firstChanged < 0 || lastChanged < firstChanged) return \"\";\n\n\t\tconst ids = new Set<number>();\n\t\tconst maxLine = Math.min(lastChanged, this.previousLines.length - 1);\n\t\tfor (let i = firstChanged; i <= maxLine; i++) {\n\t\t\tfor (const id of extractKittyImageIds(this.previousLines[i] ?? \"\")) {\n\t\t\t\tids.add(id);\n\t\t\t}\n\t\t}\n\n\t\treturn this.deleteKittyImages(ids);\n\t}\n\n\tprivate prepareRenderFrame(): MainScreenRenderFrame {\n\t\tconst width = this.terminal.columns;\n\t\tconst height = this.terminal.rows;\n\t\tconst widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;\n\t\tconst heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;\n\t\tconst previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;\n\t\tconst previousViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\n\t\tlet newLines = this.render(width);\n\t\tif (this.hasOverlayEntries) newLines = this.compositeOverlays(newLines, width, height);\n\t\tconst cursorPosition = this.extractCursorPosition(newLines, height);\n\t\t// Preserve component zone markers for alt-screen navigation, but do not emit\n\t\t// them here: terminals draw their own gutter indicators for OSC 133.\n\t\tnewLines = this.applyLineResets(newLines.map((line) => line.replace(OSC133_ZONE_PREFIX, \"\")));\n\t\treturn { width, height, widthChanged, heightChanged, newLines, cursorPosition, previousViewportTop };\n\t}\n\n\tprivate getLineDiff(\n\t\ttargetRow: number,\n\t\thardwareCursorRow: number,\n\t\tpreviousViewportTop: number,\n\t\tviewportTop: number,\n\t): number {\n\t\tconst currentScreenRow = hardwareCursorRow - previousViewportTop;\n\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\treturn targetScreenRow - currentScreenRow;\n\t}\n\n\tprivate logFullRedraw(frame: MainScreenRenderFrame, reason: string): void {\n\t\tif (process.env.GRIP_DEBUG_REDRAW !== \"1\") return;\n\t\tconst logPath = path.join(this.logDirectory, \"grip-debug.log\");\n\t\tconst message = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${frame.newLines.length}, height=${frame.height})\\n`;\n\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\tfs.appendFileSync(logPath, message);\n\t}\n\n\tprivate renderFullFrame(frame: MainScreenRenderFrame, clear: boolean): void {\n\t\tthis.fullRedrawCount += 1;\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tif (clear) {\n\t\t\tbuffer += this.deleteKittyImages(this.previousKittyImageIds);\n\t\t\tbuffer += \"\\x1b[2J\\x1b[H\\x1b[3J\";\n\t\t}\n\t\tfor (let index = 0; index < frame.newLines.length; index++) {\n\t\t\tif (index > 0) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index) : 1;\n\t\t\tif (reservedRows > 1 && reservedRows <= frame.height) {\n\t\t\t\tbuffer += \"\\r\\n\".repeat(reservedRows - 1);\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += line;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\tthis.maxLinesRendered = clear ? frame.newLines.length : Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst bufferLength = Math.max(frame.height, frame.newLines.length);\n\t\tthis.previousViewportTop = Math.max(0, bufferLength - frame.height);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderRequiredFullFrame(frame: MainScreenRenderFrame): boolean {\n\t\tif (this.previousLines.length === 0 && !frame.widthChanged && !frame.heightChanged) {\n\t\t\tthis.logFullRedraw(frame, \"first render\");\n\t\t\tthis.renderFullFrame(frame, false);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.widthChanged) {\n\t\t\tthis.logFullRedraw(frame, `terminal width changed (${this.previousWidth} -> ${frame.width})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (frame.heightChanged && !isTermuxSession()) {\n\t\t\tthis.logFullRedraw(frame, `terminal height changed (${this.previousHeight} -> ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\tif (this.getClearOnShrink() && frame.newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tthis.logFullRedraw(frame, `clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate findChangedContent(frame: MainScreenRenderFrame): ChangedContentRange | undefined {\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(frame.newLines.length, this.previousLines.length);\n\t\tfor (let index = 0; index < maxLines; index++) {\n\t\t\tconst oldLine = index < this.previousLines.length ? this.previousLines[index] : \"\";\n\t\t\tconst newLine = index < frame.newLines.length ? frame.newLines[index] : \"\";\n\t\t\tif (oldLine === newLine) continue;\n\t\t\tif (firstChanged === -1) firstChanged = index;\n\t\t\tlastChanged = index;\n\t\t}\n\n\t\tconst appendedLines = frame.newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) firstChanged = this.previousLines.length;\n\t\t\tlastChanged = frame.newLines.length - 1;\n\t\t}\n\t\tif (firstChanged === -1) return undefined;\n\n\t\tconst expanded = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, frame.newLines);\n\t\treturn {\n\t\t\t...expanded,\n\t\t\tappendStart: appendedLines && expanded.firstChanged === this.previousLines.length && expanded.firstChanged > 0,\n\t\t};\n\t}\n\n\tprivate commitFrameHistory(frame: MainScreenRenderFrame, viewportTop: number): void {\n\t\tthis.previousLines = frame.newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(frame.newLines);\n\t\tthis.previousWidth = frame.width;\n\t\tthis.previousHeight = frame.height;\n\t\tthis.previousViewportTop = viewportTop;\n\t}\n\n\tprivate handleUnchangedFrame(frame: MainScreenRenderFrame): void {\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.previousViewportTop = frame.previousViewportTop;\n\t\tthis.previousHeight = frame.height;\n\t}\n\n\tprivate renderDeletedContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (this.previousLines.length <= frame.newLines.length) {\n\t\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t\t\treturn;\n\t\t}\n\n\t\tlet buffer = \"\\x1b[?2026h\";\n\t\tbuffer += this.deleteChangedKittyImages(range.firstChanged, range.lastChanged);\n\t\tconst targetRow = Math.max(0, frame.newLines.length - 1);\n\t\tif (targetRow < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `deleted lines moved viewport up (${targetRow} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst lineDiff = this.getLineDiff(\n\t\t\ttargetRow,\n\t\t\tthis.hardwareCursorRow,\n\t\t\tframe.previousViewportTop,\n\t\t\tframe.previousViewportTop,\n\t\t);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += \"\\r\";\n\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\tif (extraLines > frame.height) {\n\t\t\tthis.logFullRedraw(frame, `extraLines > height (${extraLines} > ${frame.height})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\t\tconst clearStartOffset = frame.newLines.length === 0 ? 0 : 1;\n\t\tif (extraLines > 0 && clearStartOffset > 0) buffer += `\\x1b[${clearStartOffset}B`;\n\t\tfor (let index = 0; index < extraLines; index++) {\n\t\t\tbuffer += \"\\r\\x1b[2K\";\n\t\t\tif (index < extraLines - 1) buffer += \"\\x1b[1B\";\n\t\t}\n\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\tif (moveBack > 0) buffer += `\\x1b[${moveBack}A`;\n\t\tbuffer += \"\\x1b[?2026l\";\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = targetRow;\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, frame.previousViewportTop);\n\t}\n\n\tprivate assertRenderedLineFits(line: string, index: number, frame: MainScreenRenderFrame): void {\n\t\tif (isImageLine(line) || visibleWidth(line) <= frame.width) return;\n\t\tconst crashLogPath = path.join(this.logDirectory, \"grip-crash.log\");\n\t\tconst crashData = [\n\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t`Terminal width: ${frame.width}`,\n\t\t\t`Line ${index} visible width: ${visibleWidth(line)}`,\n\t\t\t\"\",\n\t\t\t\"=== All rendered lines ===\",\n\t\t\t...frame.newLines.map(\n\t\t\t\t(renderedLine, lineIndex) => `[${lineIndex}] (w=${visibleWidth(renderedLine)}) ${renderedLine}`,\n\t\t\t),\n\t\t\t\"\",\n\t\t].join(\"\\n\");\n\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\tfs.writeFileSync(crashLogPath, crashData);\n\t\tthis.stop();\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Rendered line ${index} exceeds terminal width (${visibleWidth(line)} > ${frame.width}).`,\n\t\t\t\t\"\",\n\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\"\",\n\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t}\n\n\tprivate renderChangedLines(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\tinitialBuffer: string,\n\t): ChangedLinesRenderResult | undefined {\n\t\tlet buffer = initialBuffer;\n\t\tconst renderEnd = Math.min(range.lastChanged, frame.newLines.length - 1);\n\t\tfor (let index = range.firstChanged; index <= renderEnd; index++) {\n\t\t\tif (index > range.firstChanged) buffer += \"\\r\\n\";\n\t\t\tconst line = frame.newLines[index];\n\t\t\tconst reservedRows = isImageLine(line) ? this.getKittyImageReservedRows(frame.newLines, index, renderEnd) : 1;\n\t\t\tif (reservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = index - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + reservedRows > frame.height) {\n\t\t\t\t\tthis.logFullRedraw(\n\t\t\t\t\t\tframe,\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${reservedRows} > ${frame.height})`,\n\t\t\t\t\t);\n\t\t\t\t\tthis.renderFullFrame(frame, true);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\t\tfor (let row = 1; row < reservedRows; row++) buffer += \"\\r\\n\\x1b[2K\";\n\t\t\t\tbuffer += `\\x1b[${reservedRows - 1}A${line}\\x1b[${reservedRows - 1}B`;\n\t\t\t\tindex += reservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuffer += \"\\x1b[2K\";\n\t\t\tthis.assertRenderedLineFits(line, index, frame);\n\t\t\tbuffer += line;\n\t\t}\n\t\treturn { buffer, renderEnd };\n\t}\n\n\tprivate writeDifferentialDebugLog(\n\t\tframe: MainScreenRenderFrame,\n\t\trange: ChangedContentRange,\n\t\tviewportTop: number,\n\t\thardwareCursorRow: number,\n\t\tlineDiff: number,\n\t\trenderEnd: number,\n\t\tfinalCursorRow: number,\n\t\tbuffer: string,\n\t): void {\n\t\tif (process.env.GRIP_TUI_DEBUG !== \"1\") return;\n\t\tconst debugDir = \"/tmp/tui\";\n\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\tconst debugData = [\n\t\t\t`firstChanged: ${range.firstChanged}`,\n\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t`height: ${frame.height}`,\n\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t`cursorPos: ${JSON.stringify(frame.cursorPosition)}`,\n\t\t\t`newLines.length: ${frame.newLines.length}`,\n\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\"\",\n\t\t\t\"=== newLines ===\",\n\t\t\tJSON.stringify(frame.newLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== previousLines ===\",\n\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\"\",\n\t\t\t\"=== buffer ===\",\n\t\t\tJSON.stringify(buffer),\n\t\t].join(\"\\n\");\n\t\tfs.writeFileSync(debugPath, debugData);\n\t}\n\n\tprivate renderDifferentialContent(frame: MainScreenRenderFrame, range: ChangedContentRange): void {\n\t\tif (range.firstChanged < frame.previousViewportTop) {\n\t\t\tthis.logFullRedraw(frame, `firstChanged < viewportTop (${range.firstChanged} < ${frame.previousViewportTop})`);\n\t\t\tthis.renderFullFrame(frame, true);\n\t\t\treturn;\n\t\t}\n\n\t\tlet previousViewportTop = frame.previousViewportTop;\n\t\tlet viewportTop = previousViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tlet buffer = `\\x1b[?2026h${this.deleteChangedKittyImages(range.firstChanged, range.lastChanged)}`;\n\t\tconst previousViewportBottom = previousViewportTop + frame.height - 1;\n\t\tconst moveTargetRow = range.appendStart ? range.firstChanged - 1 : range.firstChanged;\n\t\tif (moveTargetRow > previousViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(frame.height - 1, hardwareCursorRow - previousViewportTop));\n\t\t\tconst moveToBottom = frame.height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) buffer += `\\x1b[${moveToBottom}B`;\n\t\t\tconst scroll = moveTargetRow - previousViewportBottom;\n\t\t\tbuffer += \"\\r\\n\".repeat(scroll);\n\t\t\tpreviousViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\tconst lineDiff = this.getLineDiff(moveTargetRow, hardwareCursorRow, previousViewportTop, viewportTop);\n\t\tif (lineDiff > 0) buffer += `\\x1b[${lineDiff}B`;\n\t\telse if (lineDiff < 0) buffer += `\\x1b[${-lineDiff}A`;\n\t\tbuffer += range.appendStart ? \"\\r\\n\" : \"\\r\";\n\n\t\tconst changedLines = this.renderChangedLines(frame, range, viewportTop, buffer);\n\t\tif (!changedLines) return;\n\t\tbuffer = changedLines.buffer;\n\t\tlet finalCursorRow = changedLines.renderEnd;\n\t\tif (this.previousLines.length > frame.newLines.length) {\n\t\t\tif (changedLines.renderEnd < frame.newLines.length - 1) {\n\t\t\t\tconst moveDown = frame.newLines.length - 1 - changedLines.renderEnd;\n\t\t\t\tbuffer += `\\x1b[${moveDown}B`;\n\t\t\t\tfinalCursorRow = frame.newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - frame.newLines.length;\n\t\t\tfor (let index = frame.newLines.length; index < this.previousLines.length; index++) {\n\t\t\t\tbuffer += \"\\r\\n\\x1b[2K\";\n\t\t\t}\n\t\t\tbuffer += `\\x1b[${extraLines}A`;\n\t\t}\n\t\tbuffer += \"\\x1b[?2026l\";\n\n\t\tthis.writeDifferentialDebugLog(\n\t\t\tframe,\n\t\t\trange,\n\t\t\tviewportTop,\n\t\t\thardwareCursorRow,\n\t\t\tlineDiff,\n\t\t\tchangedLines.renderEnd,\n\t\t\tfinalCursorRow,\n\t\t\tbuffer,\n\t\t);\n\t\tthis.terminal.write(buffer);\n\t\tthis.cursorRow = Math.max(0, frame.newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, frame.newLines.length);\n\t\tconst committedViewportTop = Math.max(previousViewportTop, finalCursorRow - frame.height + 1);\n\t\tthis.positionHardwareCursor(frame.cursorPosition, frame.newLines.length);\n\t\tthis.commitFrameHistory(frame, committedViewportTop);\n\t}\n\n\tprotected doRender(): void {\n\t\tif (this.stopped) return;\n\t\tconst frame = this.prepareRenderFrame();\n\t\tif (this.renderRequiredFullFrame(frame)) return;\n\t\tconst changedContent = this.findChangedContent(frame);\n\t\tif (!changedContent) {\n\t\t\tthis.handleUnchangedFrame(frame);\n\t\t\treturn;\n\t\t}\n\t\tif (changedContent.firstChanged >= frame.newLines.length) {\n\t\t\tthis.renderDeletedContent(frame, changedContent);\n\t\t\treturn;\n\t\t}\n\t\tthis.renderDifferentialContent(frame, changedContent);\n\t}\n\n\t/**\n\t * Position the hardware cursor for IME candidate window.\n\t * @param cursorPos The cursor position extracted from rendered output, or null\n\t * @param totalLines Total number of rendered lines\n\t */\n\tprivate positionHardwareCursor(cursorPos: RenderedCursorPosition | null, totalLines: number): void {\n\t\tif (!cursorPos || totalLines <= 0) {\n\t\t\tthis.terminal.hideCursor();\n\t\t\treturn;\n\t\t}\n\n\t\t// Clamp cursor position to valid range\n\t\tconst targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1));\n\t\tconst targetCol = Math.max(0, cursorPos.col);\n\n\t\t// Move cursor from current position to target\n\t\tconst rowDelta = targetRow - this.hardwareCursorRow;\n\t\tlet buffer = \"\";\n\t\tif (rowDelta > 0) {\n\t\t\tbuffer += `\\x1b[${rowDelta}B`; // Move down\n\t\t} else if (rowDelta < 0) {\n\t\t\tbuffer += `\\x1b[${-rowDelta}A`; // Move up\n\t\t}\n\t\t// Move to absolute column (1-indexed)\n\t\tbuffer += `\\x1b[${targetCol + 1}G`;\n\n\t\tif (buffer) {\n\t\t\tthis.terminal.write(buffer);\n\t\t}\n\n\t\tthis.hardwareCursorRow = targetRow;\n\t\tif (this.getShowHardwareCursor()) {\n\t\t\tthis.terminal.showCursor();\n\t\t} else {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t}\n}\n"]}
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Minimal TUI implementation with differential rendering\n */\n\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\nimport { isKeyRelease, matchesKey } from \"./keys.ts\";\nimport type { Terminal } from \"./terminal.ts\";\nimport { getCapabilities, isImageLine, setCellDimensions } from \"./terminal-image.ts\";\nimport { extractSegments, normalizeTerminalOutput, sliceByColumn, sliceWithWidth, visibleWidth } from \"./utils.ts\";\n\n/**\n * Component interface - all components must implement this\n */\nexport interface Component {\n\t/**\n\t * Render the component to lines for the given viewport width\n\t * @param width - Current viewport width\n\t * @returns Array of strings, each representing a line\n\t */\n\trender(width: number): string[];\n\n\t/**\n\t * Optional handler for keyboard input when component has focus\n\t */\n\thandleInput?(data: string): void;\n\n\t/**\n\t * If true, component receives key release events (Kitty protocol).\n\t * Default is false - release events are filtered out.\n\t */\n\twantsKeyRelease?: boolean;\n\n\t/**\n\t * Invalidate any cached rendering state.\n\t * Called when theme changes or when component needs to re-render from scratch.\n\t */\n\tinvalidate(): void;\n}\n\nexport type TuiInputListenerResult = { consume?: boolean; data?: string } | undefined;\nexport type TuiInputListener = (data: string) => TuiInputListenerResult;\n\n/**\n * Interface for components that can receive focus and display a hardware cursor.\n * When focused, the component should emit CURSOR_MARKER at the cursor position\n * in its render output. TUI will find this marker and position the hardware\n * cursor there for proper IME candidate window positioning.\n */\nexport interface Focusable {\n\t/** Set by TUI when focus changes. Component should emit CURSOR_MARKER when true. */\n\tfocused: boolean;\n}\n\n/** Type guard to check if a component implements Focusable */\nexport function isFocusable(component: Component | null): component is Component & Focusable {\n\treturn component !== null && \"focused\" in component;\n}\n\n/**\n * Cursor position marker - APC (Application Program Command) sequence.\n * This is a zero-width escape sequence that terminals ignore.\n * Components emit this at the cursor position when focused.\n * TUI finds and strips this marker, then positions the hardware cursor there.\n */\nexport const CURSOR_MARKER = \"\\x1b_pi:c\\x07\";\n\nexport { visibleWidth };\n\n/**\n * Anchor position for overlays\n */\nexport type OverlayAnchor =\n\t| \"center\"\n\t| \"top-left\"\n\t| \"top-right\"\n\t| \"bottom-left\"\n\t| \"bottom-right\"\n\t| \"top-center\"\n\t| \"bottom-center\"\n\t| \"left-center\"\n\t| \"right-center\";\n\n/**\n * Margin configuration for overlays\n */\nexport interface OverlayMargin {\n\ttop?: number;\n\tright?: number;\n\tbottom?: number;\n\tleft?: number;\n}\n\n/** Value that can be absolute (number) or percentage (string like \"50%\") */\nexport type SizeValue = number | `${number}%`;\n\n/** Parse a SizeValue into absolute value given a reference size */\nfunction parseSizeValue(value: SizeValue | undefined, referenceSize: number): number | undefined {\n\tif (value === undefined) return undefined;\n\tif (typeof value === \"number\") return value;\n\t// Parse percentage string like \"50%\"\n\tconst match = value.match(/^(\\d+(?:\\.\\d+)?)%$/);\n\tif (match) {\n\t\treturn Math.floor((referenceSize * parseFloat(match[1])) / 100);\n\t}\n\treturn undefined;\n}\n\n/**\n * Options for overlay positioning and sizing.\n * Values can be absolute numbers or percentage strings (e.g., \"50%\").\n */\nexport interface OverlayOptions {\n\t// === Sizing ===\n\t/** Width in columns, or percentage of terminal width (e.g., \"50%\") */\n\twidth?: SizeValue;\n\t/** Minimum width in columns */\n\tminWidth?: number;\n\t/** Maximum height in rows, or percentage of terminal height (e.g., \"50%\") */\n\tmaxHeight?: SizeValue;\n\n\t// === Positioning - anchor-based ===\n\t/** Anchor point for positioning (default: 'center') */\n\tanchor?: OverlayAnchor;\n\t/** Horizontal offset from anchor position (positive = right) */\n\toffsetX?: number;\n\t/** Vertical offset from anchor position (positive = down) */\n\toffsetY?: number;\n\n\t// === Positioning - percentage or absolute ===\n\t/** Row position: absolute number, or percentage (e.g., \"25%\" = 25% from top) */\n\trow?: SizeValue;\n\t/** Column position: absolute number, or percentage (e.g., \"50%\" = centered horizontally) */\n\tcol?: SizeValue;\n\n\t// === Margin from terminal edges ===\n\t/** Margin from terminal edges. Number applies to all sides. */\n\tmargin?: OverlayMargin | number;\n\n\t// === Visibility ===\n\t/**\n\t * Control overlay visibility based on terminal dimensions.\n\t * If provided, overlay is only rendered when this returns true.\n\t * Called each render cycle with current terminal dimensions.\n\t */\n\tvisible?: (termWidth: number, termHeight: number) => boolean;\n\t/** If true, don't capture keyboard focus when shown */\n\tnonCapturing?: boolean;\n}\n\n/** Options for {@link OverlayHandle.unfocus}. */\nexport interface OverlayUnfocusOptions {\n\t/** Explicit target to focus after releasing this overlay. */\n\ttarget: Component | null;\n}\n\n/**\n * Handle returned by showOverlay for controlling the overlay\n */\nexport interface OverlayHandle {\n\t/** Permanently remove the overlay (cannot be shown again) */\n\thide(): void;\n\t/** Temporarily hide or show the overlay */\n\tsetHidden(hidden: boolean): void;\n\t/** Check if overlay is temporarily hidden */\n\tisHidden(): boolean;\n\t/** Focus this overlay and bring it to the visual front */\n\tfocus(): void;\n\t/** Release focus to the next visible capturing overlay or previous target, or to an explicit target when provided */\n\tunfocus(options?: OverlayUnfocusOptions): void;\n\t/** Check if this overlay currently has focus */\n\tisFocused(): boolean;\n}\n\ntype OverlayStackEntry = {\n\tcomponent: Component;\n\toptions?: OverlayOptions;\n\tpreFocus: Component | null;\n\thidden: boolean;\n\tfocusOrder: number;\n\tvisible: boolean;\n};\n\ntype OverlayBlockedFocusResume = { status: \"restore-overlay\" } | { status: \"focus-target\"; target: Component | null };\ntype EligibleOverlayFocusRestoreState = { status: \"eligible\"; overlay: OverlayStackEntry };\ntype BlockedOverlayFocusRestoreState = {\n\tstatus: \"blocked\";\n\toverlay: OverlayStackEntry;\n\tblockedBy: Component;\n\tresume: OverlayBlockedFocusResume;\n};\ntype ActiveOverlayFocusRestoreState = EligibleOverlayFocusRestoreState | BlockedOverlayFocusRestoreState;\ntype OverlayFocusRestoreState = { status: \"inactive\" } | ActiveOverlayFocusRestoreState;\ntype OverlayFocusRestorePolicy = \"clear\" | \"preserve\";\n\ninterface FocusTransitionRequest {\n\tcomponent: Component | null;\n\toverlayFocusRestore: OverlayFocusRestorePolicy;\n}\n\ninterface ResolvedOverlayLayout {\n\twidth: number;\n\trow: number;\n\tcol: number;\n\tmaxHeight: number | undefined;\n}\n\ninterface RenderedOverlay {\n\tlines: string[];\n\trow: number;\n\tcol: number;\n\twidth: number;\n}\n\ninterface OverlayRenderPlan {\n\toverlays: RenderedOverlay[];\n\tminimumLineCount: number;\n}\n\ninterface OverlayLayoutBounds {\n\tmarginTop: number;\n\tmarginRight: number;\n\tmarginBottom: number;\n\tmarginLeft: number;\n\tavailableWidth: number;\n\tavailableHeight: number;\n}\n\nexport interface RenderedCursorPosition {\n\trow: number;\n\tcol: number;\n}\n/**\n * Container - a component that contains other components\n */\nexport class Container implements Component {\n\tchildren: Component[] = [];\n\n\taddChild(component: Component): void {\n\t\tthis.children.push(component);\n\t}\n\n\tremoveChild(component: Component): void {\n\t\tconst index = this.children.indexOf(component);\n\t\tif (index !== -1) {\n\t\t\tthis.children.splice(index, 1);\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.children = [];\n\t}\n\n\tinvalidate(): void {\n\t\tfor (const child of this.children) {\n\t\t\tchild.invalidate?.();\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tfor (const child of this.children) {\n\t\t\tconst childLines = child.render(width);\n\t\t\tfor (const line of childLines) {\n\t\t\t\tlines.push(line);\n\t\t\t}\n\t\t}\n\t\treturn lines;\n\t}\n}\n\n/**\n * TUI - Main class for managing terminal UI with differential rendering\n */\nconst SEGMENT_RESET = \"\\x1b[0m\\x1b]8;;\\x07\";\n\n/** Composite overlay content into a terminal line at a fixed column. */\nexport function compositeTuiLine(\n\tbaseLine: string,\n\toverlayLine: string,\n\tstartCol: number,\n\toverlayWidth: number,\n\ttotalWidth: number,\n): string {\n\tif (isImageLine(baseLine)) return baseLine;\n\n\tconst afterStart = startCol + overlayWidth;\n\tconst base = extractSegments(baseLine, startCol, afterStart, totalWidth - afterStart, true);\n\tconst overlay = sliceWithWidth(overlayLine, 0, overlayWidth, true);\n\tconst beforePad = Math.max(0, startCol - base.beforeWidth);\n\tconst overlayPad = Math.max(0, overlayWidth - overlay.width);\n\tconst actualBeforeWidth = Math.max(startCol, base.beforeWidth);\n\tconst actualOverlayWidth = Math.max(overlayWidth, overlay.width);\n\tconst afterTarget = Math.max(0, totalWidth - actualBeforeWidth - actualOverlayWidth);\n\tconst afterPad = Math.max(0, afterTarget - base.afterWidth);\n\tconst result =\n\t\tbase.before +\n\t\t\" \".repeat(beforePad) +\n\t\tSEGMENT_RESET +\n\t\toverlay.text +\n\t\t\" \".repeat(overlayPad) +\n\t\tSEGMENT_RESET +\n\t\tbase.after +\n\t\t\" \".repeat(afterPad);\n\n\treturn visibleWidth(result) <= totalWidth ? result : sliceByColumn(result, 0, totalWidth, true);\n}\n\nexport type TuiMode = \"regular\" | \"fullscreen\";\n\nexport interface TuiStopOptions {\n\t/** Restore the previous main buffer without replaying renderer content. */\n\tpreserveScreen?: boolean;\n}\n\nexport interface TUI extends Component {\n\treadonly mode: TuiMode;\n\tchildren: Component[];\n\tterminal: Terminal;\n\tonDebug?: () => void;\n\treadonly fullRedraws: number;\n\treadonly hasOverlayEntries: boolean;\n\taddChild(component: Component): void;\n\tremoveChild(component: Component): void;\n\tclear(): void;\n\tgetShowHardwareCursor(): boolean;\n\tsetShowHardwareCursor(enabled: boolean): void;\n\tgetClearOnShrink(): boolean;\n\tsetClearOnShrink(enabled: boolean): void;\n\tgetFocusedComponent(): Component | null;\n\tsetFocus(component: Component | null): void;\n\tshowOverlay(component: Component, options?: OverlayOptions): OverlayHandle;\n\thideOverlay(): void;\n\thasOverlay(): boolean;\n\tstart(): void;\n\tstop(options?: TuiStopOptions): void;\n\trenderNow(force?: boolean): void;\n\trequestRender(force?: boolean): void;\n\taddInputListener(listener: TuiInputListener): () => void;\n\tremoveInputListener(listener: TuiInputListener): void;\n}\n\nexport const VIEWPORT_TUI = Symbol.for(\"@greppleai/grip-tui/viewport\");\n\nexport interface ViewportTUI extends TUI {\n\treadonly [VIEWPORT_TUI]: true;\n\tsetLayoutRoot(component: Component | undefined): void;\n}\n\nexport function isViewportTUI(tui: TUI): tui is ViewportTUI {\n\treturn (tui as Partial<ViewportTUI>)[VIEWPORT_TUI] === true;\n}\n\nexport abstract class TuiBase extends Container implements TUI {\n\tabstract readonly mode: TuiMode;\n\tpublic terminal: Terminal;\n\tprivate focusedComponent: Component | null = null;\n\tprivate inputListeners = new Set<TuiInputListener>();\n\n\t/** Global callback for debug key (Shift+Ctrl+D). Called before input is forwarded to focused component. */\n\tpublic onDebug?: () => void;\n\tprivate renderRequested = false;\n\tprivate immediateRenderScheduled = false;\n\tprivate renderTimer: NodeJS.Timeout | undefined;\n\tprivate lastRenderAt = 0;\n\tprivate static readonly MIN_RENDER_INTERVAL_MS = 16;\n\tprivate showHardwareCursor = process.env.GRIP_HARDWARE_CURSOR === \"1\";\n\tprivate clearOnShrink = process.env.GRIP_CLEAR_ON_SHRINK === \"1\";\n\tprotected fullRedrawCount = 0;\n\tprotected stopped = false;\n\tprotected readonly logDirectory: string;\n\n\t// Overlay stack for modal components rendered on top of base content\n\tprivate focusOrderCounter = 0;\n\tprivate overlayStack: OverlayStackEntry[] = [];\n\n\tget hasOverlayEntries(): boolean {\n\t\treturn this.overlayStack.length > 0;\n\t}\n\tprivate overlayFocusRestore: OverlayFocusRestoreState = { status: \"inactive\" };\n\n\tconstructor(terminal: Terminal, showHardwareCursor?: boolean, logDirectory?: string) {\n\t\tsuper();\n\t\tthis.terminal = terminal;\n\t\tthis.logDirectory =\n\t\t\tlogDirectory ?? process.env.GRIP_CODING_AGENT_DIR ?? path.join(os.homedir(), \".grip\", \"agent\");\n\t\tif (showHardwareCursor !== undefined) {\n\t\t\tthis.showHardwareCursor = showHardwareCursor;\n\t\t}\n\t}\n\n\tprotected abstract doRender(): void;\n\n\tprotected resetRenderState(): void {}\n\n\tprotected beforeTerminalStart(): void {}\n\n\tprotected afterTerminalStart(): void {}\n\n\tprotected onTerminalResize(): void {}\n\n\tprotected onOverlayStackChanged(): void {}\n\n\tprotected beforeTerminalStop(_options?: TuiStopOptions): void {}\n\n\tprotected afterTerminalStop(_options?: TuiStopOptions): void {}\n\n\tget fullRedraws(): number {\n\t\treturn this.fullRedrawCount;\n\t}\n\n\tgetShowHardwareCursor(): boolean {\n\t\treturn this.showHardwareCursor;\n\t}\n\n\tsetShowHardwareCursor(enabled: boolean): void {\n\t\tif (this.showHardwareCursor === enabled) return;\n\t\tthis.showHardwareCursor = enabled;\n\t\tif (!enabled) {\n\t\t\tthis.terminal.hideCursor();\n\t\t}\n\t\tthis.requestRender();\n\t}\n\n\tgetClearOnShrink(): boolean {\n\t\treturn this.clearOnShrink;\n\t}\n\n\t/**\n\t * Set whether to trigger full re-render when content shrinks.\n\t * When true (default), empty rows are cleared when content shrinks.\n\t * When false, empty rows remain (reduces redraws on slower terminals).\n\t */\n\tsetClearOnShrink(enabled: boolean): void {\n\t\tthis.clearOnShrink = enabled;\n\t}\n\n\tgetFocusedComponent(): Component | null {\n\t\treturn this.focusedComponent;\n\t}\n\n\tsetFocus(component: Component | null): void {\n\t\tthis.setFocusInternal({ component, overlayFocusRestore: \"clear\" });\n\t}\n\n\tprivate resolveNonOverlayFocus(\n\t\tnextFocus: Component,\n\t\tpreviousFocus: Component | null,\n\t\trestoreState: OverlayFocusRestoreState,\n\t): Component | null {\n\t\tif (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n\t\t\tif (restoreState.resume.status === \"focus-target\" || !this.isComponentMounted(restoreState.blockedBy)) {\n\t\t\t\treturn this.resolveBlockedOverlayFocusResume(restoreState);\n\t\t\t}\n\t\t\tthis.overlayFocusRestore = {\n\t\t\t\tstatus: \"blocked\",\n\t\t\t\toverlay: restoreState.overlay,\n\t\t\t\tblockedBy: nextFocus,\n\t\t\t\tresume: restoreState.resume,\n\t\t\t};\n\t\t\treturn nextFocus;\n\t\t}\n\n\t\tconst previousFocusedOverlay = previousFocus\n\t\t\t? this.overlayStack.find((entry) => entry.component === previousFocus && this.isOverlayVisible(entry))\n\t\t\t: undefined;\n\t\tif (\n\t\t\tpreviousFocusedOverlay &&\n\t\t\trestoreState.status !== \"inactive\" &&\n\t\t\trestoreState.overlay === previousFocusedOverlay &&\n\t\t\t!this.isOverlayFocusAncestor(previousFocusedOverlay, nextFocus)\n\t\t) {\n\t\t\tthis.overlayFocusRestore = {\n\t\t\t\tstatus: \"blocked\",\n\t\t\t\toverlay: previousFocusedOverlay,\n\t\t\t\tblockedBy: nextFocus,\n\t\t\t\tresume: { status: \"restore-overlay\" },\n\t\t\t};\n\t\t}\n\t\treturn nextFocus;\n\t}\n\n\tprivate resolveNullFocus(\n\t\tpreviousFocus: Component | null,\n\t\trestoreState: OverlayFocusRestoreState,\n\t\toverlayFocusRestore: OverlayFocusRestorePolicy,\n\t): Component | null {\n\t\tif (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n\t\t\treturn this.resolveBlockedOverlayFocusResume(restoreState);\n\t\t}\n\t\tif (overlayFocusRestore === \"clear\") this.clearOverlayFocusRestore();\n\t\treturn null;\n\t}\n\n\tprivate resolveFocusTarget(\n\t\tcomponent: Component | null,\n\t\toverlayFocusRestore: OverlayFocusRestorePolicy,\n\t): Component | null {\n\t\tconst previousFocus = this.focusedComponent;\n\t\tconst restoreState = this.getVisibleOverlayFocusRestore();\n\t\tif (component === null) return this.resolveNullFocus(previousFocus, restoreState, overlayFocusRestore);\n\t\tconst isOverlay = this.overlayStack.some((entry) => entry.component === component);\n\t\tif (isOverlay) return component;\n\t\treturn this.resolveNonOverlayFocus(component, previousFocus, restoreState);\n\t}\n\n\tprivate applyFocus(nextFocus: Component | null): void {\n\t\tif (isFocusable(this.focusedComponent)) this.focusedComponent.focused = false;\n\t\tthis.focusedComponent = nextFocus;\n\t\tif (isFocusable(nextFocus)) nextFocus.focused = true;\n\n\t\tconst focusedOverlay = nextFocus\n\t\t\t? this.overlayStack.find((entry) => entry.component === nextFocus && this.isOverlayVisible(entry))\n\t\t\t: undefined;\n\t\tif (focusedOverlay) this.overlayFocusRestore = { status: \"eligible\", overlay: focusedOverlay };\n\t}\n\n\tprivate setFocusInternal({ component, overlayFocusRestore }: FocusTransitionRequest): void {\n\t\tconst nextFocus = this.resolveFocusTarget(component, overlayFocusRestore);\n\t\tthis.applyFocus(nextFocus);\n\t}\n\n\tprivate clearOverlayFocusRestore(): void {\n\t\tthis.overlayFocusRestore = { status: \"inactive\" };\n\t}\n\n\tprivate clearOverlayFocusRestoreFor(overlay: OverlayStackEntry): void {\n\t\tif (this.overlayFocusRestore.status !== \"inactive\" && this.overlayFocusRestore.overlay === overlay) {\n\t\t\tthis.clearOverlayFocusRestore();\n\t\t}\n\t}\n\n\tprivate resolveBlockedOverlayFocusResume(restoreState: BlockedOverlayFocusRestoreState): Component | null {\n\t\tif (restoreState.resume.status === \"restore-overlay\") return restoreState.overlay.component;\n\t\tthis.clearOverlayFocusRestore();\n\t\treturn restoreState.resume.target;\n\t}\n\n\tprivate getVisibleOverlayFocusRestore(): OverlayFocusRestoreState {\n\t\tconst restoreState = this.overlayFocusRestore;\n\t\tif (restoreState.status === \"inactive\") return restoreState;\n\t\tif (!this.overlayStack.includes(restoreState.overlay) || !this.isOverlayVisible(restoreState.overlay)) {\n\t\t\treturn { status: \"inactive\" };\n\t\t}\n\t\treturn restoreState;\n\t}\n\n\tprivate isOverlayFocusAncestor(entry: OverlayStackEntry, component: Component): boolean {\n\t\tconst preFocusByComponent = new Map<Component, Component | null>();\n\t\tfor (const overlay of this.overlayStack) {\n\t\t\tif (!preFocusByComponent.has(overlay.component)) {\n\t\t\t\tpreFocusByComponent.set(overlay.component, overlay.preFocus);\n\t\t\t}\n\t\t}\n\n\t\tconst visited = new Set<Component>();\n\t\tlet current = entry.preFocus;\n\t\twhile (current && !visited.has(current)) {\n\t\t\tvisited.add(current);\n\t\t\tif (current === component) return true;\n\t\t\tcurrent = preFocusByComponent.get(current) ?? null;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate retargetOverlayPreFocus(removed: OverlayStackEntry): void {\n\t\tfor (const overlay of this.overlayStack) {\n\t\t\tif (overlay !== removed && overlay.preFocus === removed.component) {\n\t\t\t\toverlay.preFocus = removed.preFocus;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected getMountedRoots(): readonly Component[] {\n\t\treturn this.children;\n\t}\n\n\tprivate isComponentMounted(component: Component): boolean {\n\t\treturn this.getMountedRoots().some((child) => this.containsComponent(child, component));\n\t}\n\n\tprivate containsComponent(root: Component, target: Component): boolean {\n\t\tif (root === target) return true;\n\t\tif (!(root instanceof Container)) return false;\n\t\treturn root.children.some((child) => this.containsComponent(child, target));\n\t}\n\n\tprivate applyBlockedOverlayUnfocus(\n\t\tentry: OverlayStackEntry,\n\t\trestoreState: OverlayFocusRestoreState,\n\t\toptions: OverlayUnfocusOptions | undefined,\n\t): boolean {\n\t\tif (\n\t\t\trestoreState.status !== \"blocked\" ||\n\t\t\trestoreState.overlay !== entry ||\n\t\t\tthis.focusedComponent !== restoreState.blockedBy\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tif (options) {\n\t\t\tthis.overlayFocusRestore = {\n\t\t\t\tstatus: \"blocked\",\n\t\t\t\toverlay: entry,\n\t\t\t\tblockedBy: restoreState.blockedBy,\n\t\t\t\tresume: { status: \"focus-target\", target: options.target },\n\t\t\t};\n\t\t} else {\n\t\t\tthis.clearOverlayFocusRestore();\n\t\t}\n\t\tthis.requestRender();\n\t\treturn true;\n\t}\n\n\tprivate unfocusOverlay(entry: OverlayStackEntry, options: OverlayUnfocusOptions | undefined): void {\n\t\tconst isFocused = this.focusedComponent === entry.component;\n\t\tconst restoreState = this.overlayFocusRestore;\n\t\tconst hasPendingRestore = restoreState.status !== \"inactive\" && restoreState.overlay === entry;\n\t\tif (!isFocused && !hasPendingRestore) return;\n\t\tif (this.applyBlockedOverlayUnfocus(entry, restoreState, options)) return;\n\n\t\tthis.clearOverlayFocusRestoreFor(entry);\n\t\tif (isFocused || options) {\n\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\tconst fallbackTarget = topVisible && topVisible !== entry ? topVisible.component : entry.preFocus;\n\t\t\tthis.setFocus(options ? options.target : fallbackTarget);\n\t\t}\n\t\tthis.requestRender();\n\t}\n\n\t/**\n\t * Show an overlay component with configurable positioning and sizing.\n\t * Returns a handle to control the overlay's visibility.\n\t */\n\tshowOverlay(component: Component, options?: OverlayOptions): OverlayHandle {\n\t\tconst entry: OverlayStackEntry = {\n\t\t\tcomponent,\n\t\t\t...(options === undefined ? {} : { options }),\n\t\t\tpreFocus: this.focusedComponent,\n\t\t\thidden: false,\n\t\t\tfocusOrder: ++this.focusOrderCounter,\n\t\t\tvisible: false,\n\t\t};\n\t\tthis.overlayStack.push(entry);\n\t\tentry.visible = this.isOverlayVisible(entry);\n\t\tthis.onOverlayStackChanged();\n\t\t// Only focus if overlay is actually visible\n\t\tif (!options?.nonCapturing && this.isOverlayVisible(entry)) {\n\t\t\tthis.setFocus(component);\n\t\t}\n\t\tthis.terminal.hideCursor();\n\t\tthis.requestRender();\n\n\t\t// Return handle for controlling this overlay\n\t\treturn {\n\t\t\thide: () => {\n\t\t\t\tconst index = this.overlayStack.indexOf(entry);\n\t\t\t\tif (index !== -1) {\n\t\t\t\t\tthis.clearOverlayFocusRestoreFor(entry);\n\t\t\t\t\tthis.retargetOverlayPreFocus(entry);\n\t\t\t\t\tthis.overlayStack.splice(index, 1);\n\t\t\t\t\tthis.onOverlayStackChanged();\n\t\t\t\t\t// Restore focus if this overlay had focus\n\t\t\t\t\tif (this.focusedComponent === component) {\n\t\t\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\t\t\tthis.setFocus(topVisible?.component ?? entry.preFocus);\n\t\t\t\t\t}\n\t\t\t\t\tif (this.overlayStack.length === 0) this.terminal.hideCursor();\n\t\t\t\t\tthis.requestRender();\n\t\t\t\t}\n\t\t\t},\n\t\t\tsetHidden: (hidden: boolean) => {\n\t\t\t\tif (entry.hidden === hidden) return;\n\t\t\t\tentry.hidden = hidden;\n\t\t\t\tentry.visible = this.isOverlayVisible(entry);\n\t\t\t\t// Update focus when hiding/showing\n\t\t\t\tif (hidden) {\n\t\t\t\t\tthis.clearOverlayFocusRestoreFor(entry);\n\t\t\t\t\t// If this overlay had focus, move focus to next visible or preFocus\n\t\t\t\t\tif (this.focusedComponent === component) {\n\t\t\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\t\t\tthis.setFocus(topVisible?.component ?? entry.preFocus);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Restore focus to this overlay when showing (if it's actually visible)\n\t\t\t\t\tif (!options?.nonCapturing && this.isOverlayVisible(entry)) {\n\t\t\t\t\t\tentry.focusOrder = ++this.focusOrderCounter;\n\t\t\t\t\t\tthis.setFocus(component);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.onOverlayStackChanged();\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tisHidden: () => entry.hidden,\n\t\t\tfocus: () => {\n\t\t\t\tif (!this.overlayStack.includes(entry) || !this.isOverlayVisible(entry)) return;\n\t\t\t\tentry.focusOrder = ++this.focusOrderCounter;\n\t\t\t\tthis.setFocus(component);\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tunfocus: (unfocusOptions) => this.unfocusOverlay(entry, unfocusOptions),\n\t\t\tisFocused: () => this.focusedComponent === component,\n\t\t};\n\t}\n\n\t/** Hide the topmost overlay and restore previous focus. */\n\thideOverlay(): void {\n\t\tconst overlay = this.overlayStack[this.overlayStack.length - 1];\n\t\tif (!overlay) return;\n\t\tthis.clearOverlayFocusRestoreFor(overlay);\n\t\tthis.retargetOverlayPreFocus(overlay);\n\t\tthis.overlayStack.pop();\n\t\tthis.onOverlayStackChanged();\n\t\tif (this.focusedComponent === overlay.component) {\n\t\t\t// Find topmost visible overlay, or fall back to preFocus\n\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\tthis.setFocus(topVisible?.component ?? overlay.preFocus);\n\t\t}\n\t\tif (this.overlayStack.length === 0) this.terminal.hideCursor();\n\t\tthis.requestRender();\n\t}\n\n\t/** Check if there are any visible overlays */\n\thasOverlay(): boolean {\n\t\treturn this.overlayStack.some((o) => this.isOverlayVisible(o));\n\t}\n\n\tprotected hasCapturingOverlay(): boolean {\n\t\treturn this.overlayStack.some((o) => !o.options?.nonCapturing && this.isOverlayVisible(o));\n\t}\n\n\t/** Check if an overlay entry is currently visible */\n\tprivate isOverlayVisible(entry: OverlayStackEntry): boolean {\n\t\tif (entry.hidden) return false;\n\t\tif (entry.options?.visible) {\n\t\t\treturn entry.options.visible(this.terminal.columns, this.terminal.rows);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Find the visual-frontmost visible capturing overlay, if any */\n\tprivate getTopmostVisibleOverlay(): OverlayStackEntry | undefined {\n\t\tlet topmost: OverlayStackEntry | undefined;\n\t\tfor (const overlay of this.overlayStack) {\n\t\t\tif (overlay.options?.nonCapturing || !this.isOverlayVisible(overlay)) continue;\n\t\t\tif (!topmost || overlay.focusOrder > topmost.focusOrder) {\n\t\t\t\ttopmost = overlay;\n\t\t\t}\n\t\t}\n\t\treturn topmost;\n\t}\n\n\tprivate refreshOverlayVisibility(): OverlayStackEntry | undefined {\n\t\tlet newlyVisible: OverlayStackEntry | undefined;\n\t\tfor (const overlay of this.overlayStack) {\n\t\t\tconst visible = this.isOverlayVisible(overlay);\n\t\t\tif (visible && !overlay.visible && !overlay.options?.nonCapturing) {\n\t\t\t\tif (!newlyVisible || overlay.focusOrder > newlyVisible.focusOrder) newlyVisible = overlay;\n\t\t\t}\n\t\t\toverlay.visible = visible;\n\t\t}\n\t\treturn newlyVisible;\n\t}\n\n\tprivate retargetFocusFromHiddenOverlay(): void {\n\t\tconst focusedOverlay = this.overlayStack.find((overlay) => overlay.component === this.focusedComponent);\n\t\tif (!focusedOverlay || this.isOverlayVisible(focusedOverlay)) return;\n\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\tif (topVisible) {\n\t\t\tthis.setFocus(topVisible.component);\n\t\t\treturn;\n\t\t}\n\t\tthis.setFocusInternal({ component: focusedOverlay.preFocus, overlayFocusRestore: \"preserve\" });\n\t}\n\n\tprivate focusNewlyVisibleOverlay(newlyVisible: OverlayStackEntry | undefined): void {\n\t\tif (!newlyVisible) return;\n\t\tconst currentFocusedOverlay = this.overlayStack.find(\n\t\t\t(overlay) => overlay.component === this.focusedComponent && this.isOverlayVisible(overlay),\n\t\t);\n\t\tif (!currentFocusedOverlay || newlyVisible.focusOrder > currentFocusedOverlay.focusOrder) {\n\t\t\tthis.setFocus(newlyVisible.component);\n\t\t}\n\t}\n\n\tprivate restoreVisibleOverlayFocus(): void {\n\t\tif (this.overlayStack.some((overlay) => overlay.component === this.focusedComponent)) return;\n\t\tconst restoreState = this.getVisibleOverlayFocusRestore();\n\t\tif (restoreState.status === \"eligible\") {\n\t\t\tthis.setFocus(restoreState.overlay.component);\n\t\t\treturn;\n\t\t}\n\t\tif (restoreState.status !== \"blocked\" || restoreState.blockedBy === this.focusedComponent) return;\n\t\tif (restoreState.resume.status === \"restore-overlay\") {\n\t\t\tthis.setFocus(restoreState.overlay.component);\n\t\t\treturn;\n\t\t}\n\t\tthis.clearOverlayFocusRestore();\n\t\tthis.setFocus(restoreState.resume.target);\n\t}\n\n\tprivate reconcileOverlayFocus(): void {\n\t\tconst newlyVisible = this.refreshOverlayVisibility();\n\t\tthis.retargetFocusFromHiddenOverlay();\n\t\tthis.focusNewlyVisibleOverlay(newlyVisible);\n\t\tthis.restoreVisibleOverlayFocus();\n\t}\n\n\toverride invalidate(): void {\n\t\tfor (const root of this.getMountedRoots()) root.invalidate();\n\t\tfor (const overlay of this.overlayStack) overlay.component.invalidate?.();\n\t}\n\n\tstart(): void {\n\t\tthis.stopped = false;\n\t\ttry {\n\t\t\tthis.beforeTerminalStart();\n\t\t\tthis.terminal.start(\n\t\t\t\t(data) => this.handleTerminalInput(data),\n\t\t\t\t() => {\n\t\t\t\t\tthis.reconcileOverlayFocus();\n\t\t\t\t\tthis.onTerminalResize();\n\t\t\t\t\tthis.requestRender();\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.afterTerminalStart();\n\t\t\tthis.terminal.hideCursor();\n\t\t\tthis.queryCellSize();\n\t\t\tthis.requestRender();\n\t\t} catch (error) {\n\t\t\t// A terminal may throw after partially entering raw or alternate-screen mode.\n\t\t\t// Route startup failures through the same complete cleanup path as signals.\n\t\t\ttry {\n\t\t\t\tthis.stop();\n\t\t\t} catch {\n\t\t\t\t// Preserve the startup failure; cleanup is best-effort but exhaustive.\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\taddInputListener(listener: TuiInputListener): () => void {\n\t\tthis.inputListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.inputListeners.delete(listener);\n\t\t};\n\t}\n\n\tremoveInputListener(listener: TuiInputListener): void {\n\t\tthis.inputListeners.delete(listener);\n\t}\n\n\tprivate queryCellSize(): void {\n\t\t// Only query if terminal supports images (cell size is only used for image rendering)\n\t\tif (!getCapabilities().images) {\n\t\t\treturn;\n\t\t}\n\t\t// Query terminal for cell size in pixels: CSI 16 t\n\t\t// Response format: CSI 6 ; height ; width t\n\t\tthis.terminal.write(\"\\x1b[16t\");\n\t}\n\n\tstop(options?: TuiStopOptions): void {\n\t\tthis.stopped = true;\n\t\tthis.renderRequested = false;\n\t\tthis.cancelRenderTimer();\n\t\tlet failure: unknown;\n\t\tconst cleanup = (action: () => void): void => {\n\t\t\ttry {\n\t\t\t\taction();\n\t\t\t} catch (error) {\n\t\t\t\tfailure ??= error;\n\t\t\t}\n\t\t};\n\t\tcleanup(() => this.beforeTerminalStop(options));\n\t\tcleanup(() => this.terminal.showCursor());\n\t\tcleanup(() => this.terminal.stop());\n\t\t// Alternate-screen exit and capability restoration must run even when\n\t\t// keyboard/raw-mode shutdown reports an error.\n\t\tcleanup(() => this.afterTerminalStop(options));\n\t\tif (failure !== undefined) throw failure;\n\t}\n\n\trenderNow(force = false): void {\n\t\tif (force) this.resetRenderState();\n\t\tthis.renderRequested = false;\n\t\tthis.cancelRenderTimer();\n\t\tthis.lastRenderAt = performance.now();\n\t\tthis.doRender();\n\t}\n\n\trequestRender(force = false): void {\n\t\tif (force) {\n\t\t\tthis.resetRenderState();\n\t\t\tthis.requestImmediateRender();\n\t\t\treturn;\n\t\t}\n\t\tif (this.renderRequested) return;\n\t\tthis.renderRequested = true;\n\t\tprocess.nextTick(() => this.scheduleRender());\n\t}\n\n\tprivate requestImmediateRender(): void {\n\t\tthis.cancelRenderTimer();\n\t\tthis.renderRequested = true;\n\t\tif (this.immediateRenderScheduled) return;\n\t\tthis.immediateRenderScheduled = true;\n\t\tprocess.nextTick(() => {\n\t\t\tthis.immediateRenderScheduled = false;\n\t\t\tif (this.stopped || !this.renderRequested) return;\n\t\t\tthis.cancelRenderTimer();\n\t\t\tthis.renderRequested = false;\n\t\t\tthis.lastRenderAt = performance.now();\n\t\t\tthis.doRender();\n\t\t});\n\t}\n\n\tprivate cancelRenderTimer(): void {\n\t\tif (!this.renderTimer) return;\n\t\tclearTimeout(this.renderTimer);\n\t\tthis.renderTimer = undefined;\n\t}\n\n\tprivate scheduleRender(): void {\n\t\tif (this.stopped || this.renderTimer || !this.renderRequested) return;\n\t\tconst elapsed = performance.now() - this.lastRenderAt;\n\t\tconst delay = Math.max(0, TuiBase.MIN_RENDER_INTERVAL_MS - elapsed);\n\t\tthis.renderTimer = setTimeout(() => {\n\t\t\tthis.renderTimer = undefined;\n\t\t\tif (this.stopped || !this.renderRequested) return;\n\t\t\tthis.renderRequested = false;\n\t\t\tthis.lastRenderAt = performance.now();\n\t\t\tthis.doRender();\n\t\t\tif (this.renderRequested) this.scheduleRender();\n\t\t}, delay);\n\t}\n\n\tprivate applyInputListeners(data: string): string | undefined {\n\t\tif (this.inputListeners.size === 0) return data;\n\t\tlet current = data;\n\t\tfor (const listener of this.inputListeners) {\n\t\t\tconst result = listener(current);\n\t\t\tif (result?.consume) return undefined;\n\t\t\tif (result?.data !== undefined) current = result.data;\n\t\t}\n\t\treturn current.length === 0 ? undefined : current;\n\t}\n\n\tprivate handleTerminalInput(data: string): void {\n\t\tthis.reconcileOverlayFocus();\n\t\tconst filteredData = this.applyInputListeners(data);\n\t\tif (filteredData === undefined) return;\n\t\tdata = filteredData;\n\n\t\t// Consume terminal cell size responses without blocking unrelated input.\n\t\tif (this.consumeCellSizeResponse(data)) return;\n\n\t\t// Global debug key handler (Shift+Ctrl+D)\n\t\tif (matchesKey(data, \"shift+ctrl+d\") && this.onDebug) {\n\t\t\tthis.onDebug();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass input to focused component (including Ctrl+C).\n\t\t// The focused component can decide how to handle Ctrl+C.\n\t\tif (!this.focusedComponent?.handleInput) return;\n\t\t// Filter out key release events unless component opts in.\n\t\tif (isKeyRelease(data) && !this.focusedComponent.wantsKeyRelease) return;\n\t\tthis.focusedComponent.handleInput(data);\n\t\tthis.requestImmediateRender();\n\t}\n\n\tprivate consumeCellSizeResponse(data: string): boolean {\n\t\t// Response format: ESC [ 6 ; height ; width t\n\t\tconst match = data.match(/^\\x1b\\[6;(\\d+);(\\d+)t$/);\n\t\tif (!match) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst heightPx = parseInt(match[1], 10);\n\t\tconst widthPx = parseInt(match[2], 10);\n\t\tif (heightPx <= 0 || widthPx <= 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tsetCellDimensions({ widthPx, heightPx });\n\t\t// Invalidate all components so images re-render with correct dimensions.\n\t\tthis.invalidate();\n\t\tthis.requestRender();\n\t\treturn true;\n\t}\n\n\tprivate resolveOverlayBounds(options: OverlayOptions, termWidth: number, termHeight: number): OverlayLayoutBounds {\n\t\tconst margin =\n\t\t\ttypeof options.margin === \"number\"\n\t\t\t\t? { top: options.margin, right: options.margin, bottom: options.margin, left: options.margin }\n\t\t\t\t: (options.margin ?? {});\n\t\tconst marginTop = Math.max(0, margin.top ?? 0);\n\t\tconst marginRight = Math.max(0, margin.right ?? 0);\n\t\tconst marginBottom = Math.max(0, margin.bottom ?? 0);\n\t\tconst marginLeft = Math.max(0, margin.left ?? 0);\n\t\treturn {\n\t\t\tmarginTop,\n\t\t\tmarginRight,\n\t\t\tmarginBottom,\n\t\t\tmarginLeft,\n\t\t\tavailableWidth: Math.max(1, termWidth - marginLeft - marginRight),\n\t\t\tavailableHeight: Math.max(1, termHeight - marginTop - marginBottom),\n\t\t};\n\t}\n\n\tprivate resolveOverlayWidth(options: OverlayOptions, termWidth: number, bounds: OverlayLayoutBounds): number {\n\t\tlet width = parseSizeValue(options.width, termWidth) ?? Math.min(80, bounds.availableWidth);\n\t\tif (options.minWidth !== undefined) width = Math.max(width, options.minWidth);\n\t\treturn Math.max(1, Math.min(width, bounds.availableWidth));\n\t}\n\n\tprivate resolveOverlayMaxHeight(\n\t\toptions: OverlayOptions,\n\t\ttermHeight: number,\n\t\tbounds: OverlayLayoutBounds,\n\t): number | undefined {\n\t\tconst maxHeight = parseSizeValue(options.maxHeight, termHeight);\n\t\treturn maxHeight === undefined ? undefined : Math.max(1, Math.min(maxHeight, bounds.availableHeight));\n\t}\n\n\tprivate resolveOverlayRow(options: OverlayOptions, overlayHeight: number, bounds: OverlayLayoutBounds): number {\n\t\tif (options.row === undefined) {\n\t\t\treturn this.resolveAnchorRow(\n\t\t\t\toptions.anchor ?? \"center\",\n\t\t\t\toverlayHeight,\n\t\t\t\tbounds.availableHeight,\n\t\t\t\tbounds.marginTop,\n\t\t\t);\n\t\t}\n\t\tif (typeof options.row === \"number\") return options.row;\n\t\tconst match = options.row.match(/^(\\d+(?:\\.\\d+)?)%$/);\n\t\tif (!match) return this.resolveAnchorRow(\"center\", overlayHeight, bounds.availableHeight, bounds.marginTop);\n\t\tconst maxRow = Math.max(0, bounds.availableHeight - overlayHeight);\n\t\treturn bounds.marginTop + Math.floor(maxRow * (parseFloat(match[1]) / 100));\n\t}\n\n\tprivate resolveOverlayColumn(options: OverlayOptions, width: number, bounds: OverlayLayoutBounds): number {\n\t\tif (options.col === undefined) {\n\t\t\treturn this.resolveAnchorCol(options.anchor ?? \"center\", width, bounds.availableWidth, bounds.marginLeft);\n\t\t}\n\t\tif (typeof options.col === \"number\") return options.col;\n\t\tconst match = options.col.match(/^(\\d+(?:\\.\\d+)?)%$/);\n\t\tif (!match) return this.resolveAnchorCol(\"center\", width, bounds.availableWidth, bounds.marginLeft);\n\t\tconst maxCol = Math.max(0, bounds.availableWidth - width);\n\t\treturn bounds.marginLeft + Math.floor(maxCol * (parseFloat(match[1]) / 100));\n\t}\n\n\t/** Resolve overlay layout from options. */\n\tprivate resolveOverlayLayout(\n\t\toptions: OverlayOptions | undefined,\n\t\toverlayHeight: number,\n\t\ttermWidth: number,\n\t\ttermHeight: number,\n\t): ResolvedOverlayLayout {\n\t\tconst resolvedOptions = options ?? {};\n\t\tconst bounds = this.resolveOverlayBounds(resolvedOptions, termWidth, termHeight);\n\t\tconst width = this.resolveOverlayWidth(resolvedOptions, termWidth, bounds);\n\t\tconst maxHeight = this.resolveOverlayMaxHeight(resolvedOptions, termHeight, bounds);\n\t\tconst effectiveHeight = maxHeight === undefined ? overlayHeight : Math.min(overlayHeight, maxHeight);\n\t\tlet row = this.resolveOverlayRow(resolvedOptions, effectiveHeight, bounds) + (resolvedOptions.offsetY ?? 0);\n\t\tlet col = this.resolveOverlayColumn(resolvedOptions, width, bounds) + (resolvedOptions.offsetX ?? 0);\n\t\trow = Math.max(bounds.marginTop, Math.min(row, termHeight - bounds.marginBottom - effectiveHeight));\n\t\tcol = Math.max(bounds.marginLeft, Math.min(col, termWidth - bounds.marginRight - width));\n\t\treturn { width, row, col, maxHeight };\n\t}\n\n\tprivate resolveAnchorRow(anchor: OverlayAnchor, height: number, availHeight: number, marginTop: number): number {\n\t\tswitch (anchor) {\n\t\t\tcase \"top-left\":\n\t\t\tcase \"top-center\":\n\t\t\tcase \"top-right\":\n\t\t\t\treturn marginTop;\n\t\t\tcase \"bottom-left\":\n\t\t\tcase \"bottom-center\":\n\t\t\tcase \"bottom-right\":\n\t\t\t\treturn marginTop + availHeight - height;\n\t\t\tcase \"left-center\":\n\t\t\tcase \"center\":\n\t\t\tcase \"right-center\":\n\t\t\t\treturn marginTop + Math.floor((availHeight - height) / 2);\n\t\t}\n\t}\n\n\tprivate resolveAnchorCol(anchor: OverlayAnchor, width: number, availWidth: number, marginLeft: number): number {\n\t\tswitch (anchor) {\n\t\t\tcase \"top-left\":\n\t\t\tcase \"left-center\":\n\t\t\tcase \"bottom-left\":\n\t\t\t\treturn marginLeft;\n\t\t\tcase \"top-right\":\n\t\t\tcase \"right-center\":\n\t\t\tcase \"bottom-right\":\n\t\t\t\treturn marginLeft + availWidth - width;\n\t\t\tcase \"top-center\":\n\t\t\tcase \"center\":\n\t\t\tcase \"bottom-center\":\n\t\t\t\treturn marginLeft + Math.floor((availWidth - width) / 2);\n\t\t}\n\t}\n\n\tprivate prepareOverlayRenderPlan(baseLineCount: number, termWidth: number, termHeight: number): OverlayRenderPlan {\n\t\tconst visibleEntries = this.overlayStack.filter((entry) => this.isOverlayVisible(entry));\n\t\tvisibleEntries.sort((left, right) => left.focusOrder - right.focusOrder);\n\t\tconst overlays: RenderedOverlay[] = [];\n\t\tlet minimumLineCount = baseLineCount;\n\t\tfor (const entry of visibleEntries) {\n\t\t\tconst { width, maxHeight } = this.resolveOverlayLayout(entry.options, 0, termWidth, termHeight);\n\t\t\tlet overlayLines = entry.component.render(width);\n\t\t\tif (maxHeight !== undefined && overlayLines.length > maxHeight) {\n\t\t\t\toverlayLines = overlayLines.slice(0, maxHeight);\n\t\t\t}\n\t\t\tconst { row, col } = this.resolveOverlayLayout(entry.options, overlayLines.length, termWidth, termHeight);\n\t\t\toverlays.push({ lines: overlayLines, row, col, width });\n\t\t\tminimumLineCount = Math.max(minimumLineCount, row + overlayLines.length);\n\t\t}\n\t\treturn { overlays, minimumLineCount };\n\t}\n\n\tprivate compositeRenderedOverlay(\n\t\tresult: string[],\n\t\toverlay: RenderedOverlay,\n\t\tviewportStart: number,\n\t\ttermWidth: number,\n\t): void {\n\t\tfor (let lineIndex = 0; lineIndex < overlay.lines.length; lineIndex++) {\n\t\t\tconst targetIndex = viewportStart + overlay.row + lineIndex;\n\t\t\tif (targetIndex < 0 || targetIndex >= result.length) continue;\n\t\t\tconst overlayLine = overlay.lines[lineIndex]!;\n\t\t\tconst truncatedLine =\n\t\t\t\tvisibleWidth(overlayLine) > overlay.width\n\t\t\t\t\t? sliceByColumn(overlayLine, 0, overlay.width, true)\n\t\t\t\t\t: overlayLine;\n\t\t\tresult[targetIndex] = this.compositeLineAt(\n\t\t\t\tresult[targetIndex]!,\n\t\t\t\ttruncatedLine,\n\t\t\t\toverlay.col,\n\t\t\t\toverlay.width,\n\t\t\t\ttermWidth,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Composite all overlays into content lines (sorted by focusOrder, higher = on top). */\n\tprotected compositeOverlays(lines: string[], termWidth: number, termHeight: number): string[] {\n\t\tif (this.overlayStack.length === 0) return lines;\n\t\tconst result = [...lines];\n\t\tconst plan = this.prepareOverlayRenderPlan(result.length, termWidth, termHeight);\n\t\tconst workingHeight = Math.max(result.length, termHeight, plan.minimumLineCount);\n\t\twhile (result.length < workingHeight) result.push(\"\");\n\t\tconst viewportStart = Math.max(0, workingHeight - termHeight);\n\t\tfor (const overlay of plan.overlays) {\n\t\t\tthis.compositeRenderedOverlay(result, overlay, viewportStart, termWidth);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprotected applyLineResets(lines: string[]): string[] {\n\t\tconst reset = SEGMENT_RESET;\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\tconst line = lines[i];\n\t\t\tif (!isImageLine(line)) {\n\t\t\t\tlines[i] = normalizeTerminalOutput(line) + reset;\n\t\t\t}\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate compositeLineAt(\n\t\tbaseLine: string,\n\t\toverlayLine: string,\n\t\tstartCol: number,\n\t\toverlayWidth: number,\n\t\ttotalWidth: number,\n\t): string {\n\t\treturn compositeTuiLine(baseLine, overlayLine, startCol, overlayWidth, totalWidth);\n\t}\n\n\t/**\n\t * Find and extract cursor position from rendered lines.\n\t * Searches for CURSOR_MARKER, calculates its position, and strips it from the output.\n\t * Only scans the bottom terminal height lines (visible viewport).\n\t * @param lines - Rendered lines to search\n\t * @param height - Terminal height (visible viewport size)\n\t * @returns Cursor position { row, col } or null if no marker found\n\t */\n\tprotected extractCursorPosition(lines: string[], height: number): RenderedCursorPosition | null {\n\t\t// Only scan the bottom `height` lines (visible viewport)\n\t\tconst viewportTop = Math.max(0, lines.length - height);\n\t\tfor (let row = lines.length - 1; row >= viewportTop; row--) {\n\t\t\tconst line = lines[row];\n\t\t\tconst markerIndex = line.indexOf(CURSOR_MARKER);\n\t\t\tif (markerIndex !== -1) {\n\t\t\t\t// Calculate visual column (width of text before marker)\n\t\t\t\tconst beforeMarker = line.slice(0, markerIndex);\n\t\t\t\tconst col = visibleWidth(beforeMarker);\n\n\t\t\t\t// Strip marker from the line\n\t\t\t\tlines[row] = line.slice(0, markerIndex) + line.slice(markerIndex + CURSOR_MARKER.length);\n\n\t\t\t\treturn { row, col };\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
|
package/dist/tui.js
CHANGED
|
@@ -36,7 +36,9 @@ function parseSizeValue(value, referenceSize) {
|
|
|
36
36
|
* Container - a component that contains other components
|
|
37
37
|
*/
|
|
38
38
|
export class Container {
|
|
39
|
-
|
|
39
|
+
constructor() {
|
|
40
|
+
this.children = [];
|
|
41
|
+
}
|
|
40
42
|
addChild(component) {
|
|
41
43
|
this.children.push(component);
|
|
42
44
|
}
|
|
@@ -97,30 +99,25 @@ export function isViewportTUI(tui) {
|
|
|
97
99
|
return tui[VIEWPORT_TUI] === true;
|
|
98
100
|
}
|
|
99
101
|
export class TuiBase extends Container {
|
|
100
|
-
|
|
101
|
-
focusedComponent = null;
|
|
102
|
-
inputListeners = new Set();
|
|
103
|
-
/** Global callback for debug key (Shift+Ctrl+D). Called before input is forwarded to focused component. */
|
|
104
|
-
onDebug;
|
|
105
|
-
renderRequested = false;
|
|
106
|
-
immediateRenderScheduled = false;
|
|
107
|
-
renderTimer;
|
|
108
|
-
lastRenderAt = 0;
|
|
109
|
-
static MIN_RENDER_INTERVAL_MS = 16;
|
|
110
|
-
showHardwareCursor = process.env.GRIP_HARDWARE_CURSOR === "1";
|
|
111
|
-
clearOnShrink = process.env.GRIP_CLEAR_ON_SHRINK === "1";
|
|
112
|
-
fullRedrawCount = 0;
|
|
113
|
-
stopped = false;
|
|
114
|
-
logDirectory;
|
|
115
|
-
// Overlay stack for modal components rendered on top of base content
|
|
116
|
-
focusOrderCounter = 0;
|
|
117
|
-
overlayStack = [];
|
|
102
|
+
static { this.MIN_RENDER_INTERVAL_MS = 16; }
|
|
118
103
|
get hasOverlayEntries() {
|
|
119
104
|
return this.overlayStack.length > 0;
|
|
120
105
|
}
|
|
121
|
-
overlayFocusRestore = { status: "inactive" };
|
|
122
106
|
constructor(terminal, showHardwareCursor, logDirectory) {
|
|
123
107
|
super();
|
|
108
|
+
this.focusedComponent = null;
|
|
109
|
+
this.inputListeners = new Set();
|
|
110
|
+
this.renderRequested = false;
|
|
111
|
+
this.immediateRenderScheduled = false;
|
|
112
|
+
this.lastRenderAt = 0;
|
|
113
|
+
this.showHardwareCursor = process.env.GRIP_HARDWARE_CURSOR === "1";
|
|
114
|
+
this.clearOnShrink = process.env.GRIP_CLEAR_ON_SHRINK === "1";
|
|
115
|
+
this.fullRedrawCount = 0;
|
|
116
|
+
this.stopped = false;
|
|
117
|
+
// Overlay stack for modal components rendered on top of base content
|
|
118
|
+
this.focusOrderCounter = 0;
|
|
119
|
+
this.overlayStack = [];
|
|
120
|
+
this.overlayFocusRestore = { status: "inactive" };
|
|
124
121
|
this.terminal = terminal;
|
|
125
122
|
this.logDirectory =
|
|
126
123
|
logDirectory ?? process.env.GRIP_CODING_AGENT_DIR ?? path.join(os.homedir(), ".grip", "agent");
|