@earendil-works/pi-tui 0.87.1 → 0.99.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -3
- package/dist/alt-screen-search.d.ts.map +1 -1
- package/dist/alt-screen-search.js.map +1 -1
- package/dist/autocomplete.d.ts +1 -1
- package/dist/autocomplete.d.ts.map +1 -1
- package/dist/autocomplete.js +28 -8
- package/dist/autocomplete.js.map +1 -1
- package/dist/colors.d.ts +73 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +273 -0
- package/dist/colors.js.map +1 -0
- package/dist/components/alt-screen-flash.d.ts.map +1 -1
- package/dist/components/alt-screen-flash.js.map +1 -1
- package/dist/components/box.d.ts.map +1 -1
- package/dist/components/box.js +8 -8
- package/dist/components/box.js.map +1 -1
- package/dist/components/cancellable-loader.d.ts.map +1 -1
- package/dist/components/cancellable-loader.js.map +1 -1
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +4 -2
- package/dist/components/editor.js.map +1 -1
- package/dist/components/h-stack.d.ts.map +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.map +1 -1
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js.map +1 -1
- package/dist/components/loader.d.ts.map +1 -1
- package/dist/components/loader.js.map +1 -1
- package/dist/components/markdown.d.ts +1 -0
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +8 -2
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/mouse-region.d.ts.map +1 -1
- package/dist/components/mouse-region.js.map +1 -1
- package/dist/components/scroll-view.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/components/settings-list.d.ts.map +1 -1
- package/dist/components/settings-list.js.map +1 -1
- package/dist/components/spacer.d.ts.map +1 -1
- package/dist/components/spacer.js.map +1 -1
- package/dist/components/stack.d.ts.map +1 -1
- package/dist/components/stack.js.map +1 -1
- package/dist/components/text.d.ts.map +1 -1
- package/dist/components/text.js.map +1 -1
- package/dist/components/truncated-text.d.ts.map +1 -1
- 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.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 +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/keybindings.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/latex.d.ts.map +1 -1
- 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/native-module-path.d.ts.map +1 -1
- package/dist/native-module-path.js.map +1 -1
- package/dist/native-platform.d.ts +2 -0
- package/dist/native-platform.d.ts.map +1 -1
- package/dist/native-platform.js.map +1 -1
- package/dist/oklab.d.ts +43 -0
- package/dist/oklab.d.ts.map +1 -0
- package/dist/oklab.js +210 -0
- package/dist/oklab.js.map +1 -0
- package/dist/stdin-buffer.d.ts.map +1 -1
- package/dist/stdin-buffer.js.map +1 -1
- package/dist/terminal-colors.d.ts +19 -2
- package/dist/terminal-colors.d.ts.map +1 -1
- package/dist/terminal-colors.js +12 -7
- package/dist/terminal-colors.js.map +1 -1
- package/dist/terminal-image.d.ts +3 -1
- package/dist/terminal-image.d.ts.map +1 -1
- package/dist/terminal-image.js +33 -9
- package/dist/terminal-image.js.map +1 -1
- package/dist/terminal.d.ts +3 -0
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +15 -8
- package/dist/terminal.js.map +1 -1
- package/dist/tui-alt-screen.d.ts +8 -4
- package/dist/tui-alt-screen.d.ts.map +1 -1
- package/dist/tui-alt-screen.js +13 -12
- 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.map +1 -1
- package/dist/tui.d.ts +23 -22
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +85 -66
- package/dist/tui.js.map +1 -1
- package/dist/undo-stack.d.ts.map +1 -1
- package/dist/undo-stack.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +99 -55
- package/dist/utils.js.map +1 -1
- package/dist/wheel-scroll.d.ts +23 -0
- package/dist/wheel-scroll.d.ts.map +1 -0
- package/dist/wheel-scroll.js +73 -0
- package/dist/wheel-scroll.js.map +1 -0
- package/dist/word-navigation.d.ts.map +1 -1
- package/dist/word-navigation.js.map +1 -1
- package/native/clipboard.h +40 -2
- package/native/darwin/README.md +1 -1
- package/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/native/darwin/src/darwin-platform.m +39 -0
- package/native/napi.h +2 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui-main-screen.d.ts","sourceRoot":"","sources":["../src/tui-main-screen.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AA4GlE,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,EAAE,cAAc,GAAG,IAAI,CAQnE;IAED,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,gCAAgC;IAuBxC,OAAO,CAAC,wBAAwB;IAchC,SAAS,CAAC,QAAQ,IAAI,IAAI,CAiXzB;IAED;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAgC9B","sourcesContent":["import * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\nconst MAX_RENDER_WRITE_CHARS = 1024 * 1024;\n\n/**\n * Streams terminal output in 1 MiB chunks so a full render never forms one string large enough to exceed V8's limit.\n *\n * `append()` fills the current chunk and flushes it when full. Oversized input is split at chunk boundaries, preserving\n * surrogate pairs so each write remains valid UTF-16. Callers append synchronized-output begin/end sequences themselves;\n * the final `flush()` writes any remainder, including the end sequence.\n */\nclass BoundedTerminalWriter {\n\tprivate buffer = \"\";\n\tprivate writtenChars = 0;\n\tprivate readonly write: (data: string) => void;\n\n\tconstructor(write: (data: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\t/**\n\t * Append terminal data, flushing full chunks as needed. Callers must call `flush()` after the final append.\n\t * @param value Terminal data to write in order; oversized values are split without splitting surrogate pairs.\n\t */\n\tappend(value: string): void {\n\t\tlet offset = 0;\n\t\twhile (offset < value.length) {\n\t\t\tconst capacity = MAX_RENDER_WRITE_CHARS - this.buffer.length;\n\t\t\tif (capacity === 0) {\n\t\t\t\tthis.flush();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet end = Math.min(value.length, offset + capacity);\n\t\t\tif (\n\t\t\t\tend < value.length &&\n\t\t\t\tvalue.charCodeAt(end - 1) >= 0xd800 &&\n\t\t\t\tvalue.charCodeAt(end - 1) <= 0xdbff &&\n\t\t\t\tvalue.charCodeAt(end) >= 0xdc00 &&\n\t\t\t\tvalue.charCodeAt(end) <= 0xdfff\n\t\t\t) {\n\t\t\t\tend--;\n\t\t\t}\n\t\t\tif (end === offset) {\n\t\t\t\tthis.flush();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.buffer += value.slice(offset, end);\n\t\t\toffset = end;\n\t\t\tif (this.buffer.length === MAX_RENDER_WRITE_CHARS) {\n\t\t\t\tthis.flush();\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Write the current chunk, if any, and retain only its character count for debug output. */\n\tflush(): void {\n\t\tif (!this.buffer) return;\n\t\tthis.write(this.buffer);\n\t\tthis.writtenChars += this.buffer.length;\n\t\tthis.buffer = \"\";\n\t}\n\n\tget length(): number {\n\t\treturn this.writtenChars + this.buffer.length;\n\t}\n}\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: 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): { firstChanged: number; lastChanged: number } {\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\tprotected doRender(): void {\n\t\tif (this.stopped) return;\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\tlet prevViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\t\tlet viewportTop = prevViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tconst computeLineDiff = (targetRow: number): number => {\n\t\t\tconst currentScreenRow = hardwareCursorRow - prevViewportTop;\n\t\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\t\treturn targetScreenRow - currentScreenRow;\n\t\t};\n\n\t\t// Render all components to get new lines\n\t\tlet newLines = this.render(width);\n\n\t\t// Composite overlays into the rendered lines (before differential compare)\n\t\tif (this.hasOverlayEntries) {\n\t\t\tnewLines = this.compositeOverlays(newLines, width, height);\n\t\t}\n\n\t\t// Extract cursor position before applying line resets (marker must be found first)\n\t\tconst cursorPos = this.extractCursorPosition(newLines, height);\n\n\t\tnewLines = this.applyLineResets(newLines);\n\n\t\t// Helper to clear scrollback and viewport and render all new lines\n\t\tconst fullRender = (clear: boolean): void => {\n\t\t\tthis.fullRedrawCount += 1;\n\t\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\t\toutput.append(\"\\x1b[?2026h\"); // Begin synchronized output\n\t\t\tif (clear) {\n\t\t\t\toutput.append(this.deleteKittyImages(this.previousKittyImageIds));\n\t\t\t\toutput.append(\"\\x1b[2J\\x1b[H\\x1b[3J\"); // Clear screen, home, then clear scrollback\n\t\t\t}\n\t\t\tfor (let i = 0; i < newLines.length; i++) {\n\t\t\t\tif (i > 0) output.append(\"\\r\\n\");\n\t\t\t\tconst line = newLines[i];\n\t\t\t\tconst isImage = isImageLine(line);\n\t\t\t\tconst imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i) : 1;\n\t\t\t\tif (imageReservedRows > 1 && imageReservedRows <= height) {\n\t\t\t\t\tfor (let row = 1; row < imageReservedRows; row++) {\n\t\t\t\t\t\toutput.append(\"\\r\\n\");\n\t\t\t\t\t}\n\t\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}A`);\n\t\t\t\t\toutput.append(line);\n\t\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}B`);\n\t\t\t\t\ti += imageReservedRows - 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\toutput.append(line);\n\t\t\t}\n\t\t\toutput.append(\"\\x1b[?2026l\"); // End synchronized output\n\t\t\toutput.flush();\n\t\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\t\t// Reset max lines when clearing, otherwise track growth\n\t\t\tif (clear) {\n\t\t\t\tthis.maxLinesRendered = newLines.length;\n\t\t\t} else {\n\t\t\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\t\t}\n\t\t\tconst bufferLength = Math.max(height, newLines.length);\n\t\t\tthis.previousViewportTop = Math.max(0, bufferLength - height);\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t};\n\n\t\tconst redrawLogDirectory = process.env.PI_TUI_DEBUG_REDRAW === \"1\" ? this.logDirectory : undefined;\n\t\tconst logRedraw = (reason: string): void => {\n\t\t\tif (redrawLogDirectory === undefined) return;\n\t\t\tconst logPath = path.join(redrawLogDirectory, \"pi-tui-debug.log\");\n\t\t\tconst msg = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})\\n`;\n\t\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\t\tfs.appendFileSync(logPath, msg);\n\t\t};\n\n\t\t// First render - just output everything without clearing (assumes clean screen)\n\t\tif (this.previousLines.length === 0 && !widthChanged && !heightChanged) {\n\t\t\tlogRedraw(\"first render\");\n\t\t\tfullRender(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Width changes always need a full re-render because wrapping changes.\n\t\tif (widthChanged) {\n\t\t\tlogRedraw(`terminal width changed (${this.previousWidth} -> ${width})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Height changes normally need a full re-render to keep the visible viewport aligned,\n\t\t// but Termux changes height when the software keyboard shows or hides.\n\t\t// In that environment, a full redraw causes the entire history to replay on every toggle.\n\t\tif (heightChanged && !isTermuxSession()) {\n\t\t\tlogRedraw(`terminal height changed (${this.previousHeight} -> ${height})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Content shrunk below the working area and no overlays - re-render to clear empty rows\n\t\t// (overlays need the padding, so only do this when no overlays are active)\n\t\t// Configurable via setClearOnShrink()\n\t\tif (this.getClearOnShrink() && newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tlogRedraw(`clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find first and last changed lines\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(newLines.length, this.previousLines.length);\n\t\tfor (let i = 0; i < maxLines; i++) {\n\t\t\tconst oldLine = i < this.previousLines.length ? this.previousLines[i] : \"\";\n\t\t\tconst newLine = i < newLines.length ? newLines[i] : \"\";\n\n\t\t\tif (oldLine !== newLine) {\n\t\t\t\tif (firstChanged === -1) {\n\t\t\t\t\tfirstChanged = i;\n\t\t\t\t}\n\t\t\t\tlastChanged = i;\n\t\t\t}\n\t\t}\n\t\tconst appendedLines = newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) {\n\t\t\t\tfirstChanged = this.previousLines.length;\n\t\t\t}\n\t\t\tlastChanged = newLines.length - 1;\n\t\t}\n\t\tif (firstChanged !== -1) {\n\t\t\tconst expandedRange = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines);\n\t\t\tfirstChanged = expandedRange.firstChanged;\n\t\t\tlastChanged = expandedRange.lastChanged;\n\t\t}\n\t\tconst appendStart = appendedLines && firstChanged === this.previousLines.length && firstChanged > 0;\n\n\t\t// No changes - but still need to update hardware cursor position if it moved\n\t\tif (firstChanged === -1) {\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousViewportTop = prevViewportTop;\n\t\t\tthis.previousHeight = height;\n\t\t\treturn;\n\t\t}\n\n\t\t// All changes are in deleted lines (nothing to render, just clear)\n\t\tif (firstChanged >= newLines.length) {\n\t\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\t\t\toutput.append(\"\\x1b[?2026h\");\n\t\t\t\toutput.append(this.deleteChangedKittyImages(firstChanged, lastChanged));\n\t\t\t\t// Move to end of new content (clamp to 0 for empty content)\n\t\t\t\tconst targetRow = Math.max(0, newLines.length - 1);\n\t\t\t\tif (targetRow < prevViewportTop) {\n\t\t\t\t\tlogRedraw(`deleted lines moved viewport up (${targetRow} < ${prevViewportTop})`);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst lineDiff = computeLineDiff(targetRow);\n\t\t\t\tif (lineDiff > 0) output.append(`\\x1b[${lineDiff}B`);\n\t\t\t\telse if (lineDiff < 0) output.append(`\\x1b[${-lineDiff}A`);\n\t\t\t\toutput.append(\"\\r\");\n\t\t\t\t// Clear extra lines without scrolling\n\t\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\t\tif (extraLines > height) {\n\t\t\t\t\tlogRedraw(`extraLines > height (${extraLines} > ${height})`);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst clearStartOffset = newLines.length === 0 ? 0 : 1;\n\t\t\t\tif (extraLines > 0 && clearStartOffset > 0) {\n\t\t\t\t\toutput.append(`\\x1b[${clearStartOffset}B`);\n\t\t\t\t}\n\t\t\t\tfor (let i = 0; i < extraLines; i++) {\n\t\t\t\t\toutput.append(\"\\r\\x1b[2K\");\n\t\t\t\t\tif (i < extraLines - 1) output.append(\"\\x1b[1B\");\n\t\t\t\t}\n\t\t\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\t\t\tif (moveBack > 0) {\n\t\t\t\t\toutput.append(`\\x1b[${moveBack}A`);\n\t\t\t\t}\n\t\t\t\toutput.append(\"\\x1b[?2026l\");\n\t\t\t\toutput.flush();\n\t\t\t\tthis.cursorRow = targetRow;\n\t\t\t\tthis.hardwareCursorRow = targetRow;\n\t\t\t}\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t\tthis.previousViewportTop = prevViewportTop;\n\t\t\treturn;\n\t\t}\n\n\t\t// Differential rendering can only touch what was actually visible.\n\t\t// If the first changed line is above the previous viewport, we need a full redraw.\n\t\tif (firstChanged < prevViewportTop) {\n\t\t\tlogRedraw(`firstChanged < viewportTop (${firstChanged} < ${prevViewportTop})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Render from first changed line to end\n\t\t// Keep updates wrapped in synchronized output while writing bounded chunks.\n\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\toutput.append(\"\\x1b[?2026h\"); // Begin synchronized output\n\t\toutput.append(this.deleteChangedKittyImages(firstChanged, lastChanged));\n\t\tconst prevViewportBottom = prevViewportTop + height - 1;\n\t\tconst moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;\n\t\tif (moveTargetRow > prevViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));\n\t\t\tconst moveToBottom = height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) {\n\t\t\t\toutput.append(`\\x1b[${moveToBottom}B`);\n\t\t\t}\n\t\t\tconst scroll = moveTargetRow - prevViewportBottom;\n\t\t\toutput.append(\"\\r\\n\".repeat(scroll));\n\t\t\tprevViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\t// Move cursor to first changed line (use hardwareCursorRow for actual position)\n\t\tconst lineDiff = computeLineDiff(moveTargetRow);\n\t\tif (lineDiff > 0) {\n\t\t\toutput.append(`\\x1b[${lineDiff}B`); // Move down\n\t\t} else if (lineDiff < 0) {\n\t\t\toutput.append(`\\x1b[${-lineDiff}A`); // Move up\n\t\t}\n\n\t\toutput.append(appendStart ? \"\\r\\n\" : \"\\r\"); // Move to column 0\n\n\t\t// Only render changed lines (firstChanged to lastChanged), not all lines to end\n\t\t// This reduces flicker when only a single line changes (e.g., spinner animation)\n\t\tconst renderEnd = Math.min(lastChanged, newLines.length - 1);\n\t\tfor (let i = firstChanged; i <= renderEnd; i++) {\n\t\t\tif (i > firstChanged) output.append(\"\\r\\n\");\n\t\t\tconst line = newLines[i];\n\t\t\tconst isImage = isImageLine(line);\n\t\t\tconst imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i, renderEnd) : 1;\n\t\t\tif (imageReservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = i - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + imageReservedRows > height) {\n\t\t\t\t\tlogRedraw(\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${imageReservedRows} > ${height})`,\n\t\t\t\t\t);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\toutput.append(\"\\x1b[2K\");\n\t\t\t\tfor (let row = 1; row < imageReservedRows; row++) {\n\t\t\t\t\toutput.append(\"\\r\\n\\x1b[2K\");\n\t\t\t\t}\n\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}A`);\n\t\t\t\toutput.append(line);\n\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}B`);\n\t\t\t\ti += imageReservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\toutput.append(\"\\x1b[2K\"); // Clear current line\n\t\t\tif (!isImage && visibleWidth(line) > width) {\n\t\t\t\t// Log all lines to crash file for debugging\n\t\t\t\tconst crashLogPath = path.join(this.logDirectory ?? os.tmpdir(), \"pi-tui-crash.log\");\n\t\t\t\tconst crashData = [\n\t\t\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t\t\t`Terminal width: ${width}`,\n\t\t\t\t\t`Line ${i} visible width: ${visibleWidth(line)}`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"=== All rendered lines ===\",\n\t\t\t\t\t...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\");\n\t\t\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\t\t\tfs.writeFileSync(crashLogPath, crashData);\n\n\t\t\t\t// Clean up terminal state before throwing\n\t\t\t\tthis.stop();\n\n\t\t\t\tconst errorMsg = [\n\t\t\t\t\t`Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t\t].join(\"\\n\");\n\t\t\t\tthrow new Error(errorMsg);\n\t\t\t}\n\t\t\toutput.append(line);\n\t\t}\n\n\t\t// Track where cursor ended up after rendering\n\t\tlet finalCursorRow = renderEnd;\n\n\t\t// If we had more lines before, clear them and move cursor back\n\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t// Move to end of new content first if we stopped before it\n\t\t\tif (renderEnd < newLines.length - 1) {\n\t\t\t\tconst moveDown = newLines.length - 1 - renderEnd;\n\t\t\t\toutput.append(`\\x1b[${moveDown}B`);\n\t\t\t\tfinalCursorRow = newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\tfor (let i = newLines.length; i < this.previousLines.length; i++) {\n\t\t\t\toutput.append(\"\\r\\n\\x1b[2K\");\n\t\t\t}\n\t\t\t// Move cursor back to end of new content\n\t\t\toutput.append(`\\x1b[${extraLines}A`);\n\t\t}\n\n\t\toutput.append(\"\\x1b[?2026l\"); // End synchronized output\n\n\t\tif (process.env.PI_TUI_DEBUG === \"1\") {\n\t\t\tconst debugDir = \"/tmp/tui\";\n\t\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\t\tconst debugData = [\n\t\t\t\t`firstChanged: ${firstChanged}`,\n\t\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t\t`height: ${height}`,\n\t\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t\t`cursorPos: ${JSON.stringify(cursorPos)}`,\n\t\t\t\t`newLines.length: ${newLines.length}`,\n\t\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\t\"\",\n\t\t\t\t\"=== newLines ===\",\n\t\t\t\tJSON.stringify(newLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== previousLines ===\",\n\t\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== buffer ===\",\n\t\t\t\t`[${output.length} chars written in bounded chunks]`,\n\t\t\t].join(\"\\n\");\n\t\t\tfs.writeFileSync(debugPath, debugData);\n\t\t}\n\n\t\toutput.flush();\n\n\t\t// Track cursor position for next render\n\t\t// cursorRow tracks end of content (for viewport calculation)\n\t\t// hardwareCursorRow tracks actual terminal cursor position (for movement)\n\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\t// Track terminal's working area (grows but doesn't shrink unless cleared)\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\tthis.previousViewportTop = Math.max(prevViewportTop, finalCursorRow - height + 1);\n\n\t\t// Position hardware cursor for IME\n\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\n\t\tthis.previousLines = newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\tthis.previousWidth = width;\n\t\tthis.previousHeight = height;\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: { row: number; col: number } | 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":"AAIA,OAAO,EAAE,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AA4GlE,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,EAAE,cAAc,GAAG,IAAI,CAQnE;IAED,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,gCAAgC;IAuBxC,OAAO,CAAC,wBAAwB;IAchC,SAAS,CAAC,QAAQ,IAAI,IAAI,CAiXzB;IAED;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;CAgC9B"}
|
|
@@ -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 os from \"node:os\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\nconst MAX_RENDER_WRITE_CHARS = 1024 * 1024;\n\n/**\n * Streams terminal output in 1 MiB chunks so a full render never forms one string large enough to exceed V8's limit.\n *\n * `append()` fills the current chunk and flushes it when full. Oversized input is split at chunk boundaries, preserving\n * surrogate pairs so each write remains valid UTF-16. Callers append synchronized-output begin/end sequences themselves;\n * the final `flush()` writes any remainder, including the end sequence.\n */\nclass BoundedTerminalWriter {\n\tprivate buffer = \"\";\n\tprivate writtenChars = 0;\n\tprivate readonly write: (data: string) => void;\n\n\tconstructor(write: (data: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\t/**\n\t * Append terminal data, flushing full chunks as needed. Callers must call `flush()` after the final append.\n\t * @param value Terminal data to write in order; oversized values are split without splitting surrogate pairs.\n\t */\n\tappend(value: string): void {\n\t\tlet offset = 0;\n\t\twhile (offset < value.length) {\n\t\t\tconst capacity = MAX_RENDER_WRITE_CHARS - this.buffer.length;\n\t\t\tif (capacity === 0) {\n\t\t\t\tthis.flush();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet end = Math.min(value.length, offset + capacity);\n\t\t\tif (\n\t\t\t\tend < value.length &&\n\t\t\t\tvalue.charCodeAt(end - 1) >= 0xd800 &&\n\t\t\t\tvalue.charCodeAt(end - 1) <= 0xdbff &&\n\t\t\t\tvalue.charCodeAt(end) >= 0xdc00 &&\n\t\t\t\tvalue.charCodeAt(end) <= 0xdfff\n\t\t\t) {\n\t\t\t\tend--;\n\t\t\t}\n\t\t\tif (end === offset) {\n\t\t\t\tthis.flush();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.buffer += value.slice(offset, end);\n\t\t\toffset = end;\n\t\t\tif (this.buffer.length === MAX_RENDER_WRITE_CHARS) {\n\t\t\t\tthis.flush();\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Write the current chunk, if any, and retain only its character count for debug output. */\n\tflush(): void {\n\t\tif (!this.buffer) return;\n\t\tthis.write(this.buffer);\n\t\tthis.writtenChars += this.buffer.length;\n\t\tthis.buffer = \"\";\n\t}\n\n\tget length(): number {\n\t\treturn this.writtenChars + this.buffer.length;\n\t}\n}\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: 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): { firstChanged: number; lastChanged: number } {\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\tprotected doRender(): void {\n\t\tif (this.stopped) return;\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\tlet prevViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\t\tlet viewportTop = prevViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tconst computeLineDiff = (targetRow: number): number => {\n\t\t\tconst currentScreenRow = hardwareCursorRow - prevViewportTop;\n\t\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\t\treturn targetScreenRow - currentScreenRow;\n\t\t};\n\n\t\t// Render all components to get new lines\n\t\tlet newLines = this.render(width);\n\n\t\t// Composite overlays into the rendered lines (before differential compare)\n\t\tif (this.hasOverlayEntries) {\n\t\t\tnewLines = this.compositeOverlays(newLines, width, height);\n\t\t}\n\n\t\t// Extract cursor position before applying line resets (marker must be found first)\n\t\tconst cursorPos = this.extractCursorPosition(newLines, height);\n\n\t\tnewLines = this.applyLineResets(newLines);\n\n\t\t// Helper to clear scrollback and viewport and render all new lines\n\t\tconst fullRender = (clear: boolean): void => {\n\t\t\tthis.fullRedrawCount += 1;\n\t\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\t\toutput.append(\"\\x1b[?2026h\"); // Begin synchronized output\n\t\t\tif (clear) {\n\t\t\t\toutput.append(this.deleteKittyImages(this.previousKittyImageIds));\n\t\t\t\toutput.append(\"\\x1b[2J\\x1b[H\\x1b[3J\"); // Clear screen, home, then clear scrollback\n\t\t\t}\n\t\t\tfor (let i = 0; i < newLines.length; i++) {\n\t\t\t\tif (i > 0) output.append(\"\\r\\n\");\n\t\t\t\tconst line = newLines[i];\n\t\t\t\tconst isImage = isImageLine(line);\n\t\t\t\tconst imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i) : 1;\n\t\t\t\tif (imageReservedRows > 1 && imageReservedRows <= height) {\n\t\t\t\t\tfor (let row = 1; row < imageReservedRows; row++) {\n\t\t\t\t\t\toutput.append(\"\\r\\n\");\n\t\t\t\t\t}\n\t\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}A`);\n\t\t\t\t\toutput.append(line);\n\t\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}B`);\n\t\t\t\t\ti += imageReservedRows - 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\toutput.append(line);\n\t\t\t}\n\t\t\toutput.append(\"\\x1b[?2026l\"); // End synchronized output\n\t\t\toutput.flush();\n\t\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\t\t// Reset max lines when clearing, otherwise track growth\n\t\t\tif (clear) {\n\t\t\t\tthis.maxLinesRendered = newLines.length;\n\t\t\t} else {\n\t\t\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\t\t}\n\t\t\tconst bufferLength = Math.max(height, newLines.length);\n\t\t\tthis.previousViewportTop = Math.max(0, bufferLength - height);\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t};\n\n\t\tconst redrawLogDirectory = process.env.PI_TUI_DEBUG_REDRAW === \"1\" ? this.logDirectory : undefined;\n\t\tconst logRedraw = (reason: string): void => {\n\t\t\tif (redrawLogDirectory === undefined) return;\n\t\t\tconst logPath = path.join(redrawLogDirectory, \"pi-tui-debug.log\");\n\t\t\tconst msg = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})\\n`;\n\t\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\t\tfs.appendFileSync(logPath, msg);\n\t\t};\n\n\t\t// First render - just output everything without clearing (assumes clean screen)\n\t\tif (this.previousLines.length === 0 && !widthChanged && !heightChanged) {\n\t\t\tlogRedraw(\"first render\");\n\t\t\tfullRender(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Width changes always need a full re-render because wrapping changes.\n\t\tif (widthChanged) {\n\t\t\tlogRedraw(`terminal width changed (${this.previousWidth} -> ${width})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Height changes normally need a full re-render to keep the visible viewport aligned,\n\t\t// but Termux changes height when the software keyboard shows or hides.\n\t\t// In that environment, a full redraw causes the entire history to replay on every toggle.\n\t\tif (heightChanged && !isTermuxSession()) {\n\t\t\tlogRedraw(`terminal height changed (${this.previousHeight} -> ${height})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Content shrunk below the working area and no overlays - re-render to clear empty rows\n\t\t// (overlays need the padding, so only do this when no overlays are active)\n\t\t// Configurable via setClearOnShrink()\n\t\tif (this.getClearOnShrink() && newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tlogRedraw(`clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find first and last changed lines\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(newLines.length, this.previousLines.length);\n\t\tfor (let i = 0; i < maxLines; i++) {\n\t\t\tconst oldLine = i < this.previousLines.length ? this.previousLines[i] : \"\";\n\t\t\tconst newLine = i < newLines.length ? newLines[i] : \"\";\n\n\t\t\tif (oldLine !== newLine) {\n\t\t\t\tif (firstChanged === -1) {\n\t\t\t\t\tfirstChanged = i;\n\t\t\t\t}\n\t\t\t\tlastChanged = i;\n\t\t\t}\n\t\t}\n\t\tconst appendedLines = newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) {\n\t\t\t\tfirstChanged = this.previousLines.length;\n\t\t\t}\n\t\t\tlastChanged = newLines.length - 1;\n\t\t}\n\t\tif (firstChanged !== -1) {\n\t\t\tconst expandedRange = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines);\n\t\t\tfirstChanged = expandedRange.firstChanged;\n\t\t\tlastChanged = expandedRange.lastChanged;\n\t\t}\n\t\tconst appendStart = appendedLines && firstChanged === this.previousLines.length && firstChanged > 0;\n\n\t\t// No changes - but still need to update hardware cursor position if it moved\n\t\tif (firstChanged === -1) {\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousViewportTop = prevViewportTop;\n\t\t\tthis.previousHeight = height;\n\t\t\treturn;\n\t\t}\n\n\t\t// All changes are in deleted lines (nothing to render, just clear)\n\t\tif (firstChanged >= newLines.length) {\n\t\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\t\t\toutput.append(\"\\x1b[?2026h\");\n\t\t\t\toutput.append(this.deleteChangedKittyImages(firstChanged, lastChanged));\n\t\t\t\t// Move to end of new content (clamp to 0 for empty content)\n\t\t\t\tconst targetRow = Math.max(0, newLines.length - 1);\n\t\t\t\tif (targetRow < prevViewportTop) {\n\t\t\t\t\tlogRedraw(`deleted lines moved viewport up (${targetRow} < ${prevViewportTop})`);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst lineDiff = computeLineDiff(targetRow);\n\t\t\t\tif (lineDiff > 0) output.append(`\\x1b[${lineDiff}B`);\n\t\t\t\telse if (lineDiff < 0) output.append(`\\x1b[${-lineDiff}A`);\n\t\t\t\toutput.append(\"\\r\");\n\t\t\t\t// Clear extra lines without scrolling\n\t\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\t\tif (extraLines > height) {\n\t\t\t\t\tlogRedraw(`extraLines > height (${extraLines} > ${height})`);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst clearStartOffset = newLines.length === 0 ? 0 : 1;\n\t\t\t\tif (extraLines > 0 && clearStartOffset > 0) {\n\t\t\t\t\toutput.append(`\\x1b[${clearStartOffset}B`);\n\t\t\t\t}\n\t\t\t\tfor (let i = 0; i < extraLines; i++) {\n\t\t\t\t\toutput.append(\"\\r\\x1b[2K\");\n\t\t\t\t\tif (i < extraLines - 1) output.append(\"\\x1b[1B\");\n\t\t\t\t}\n\t\t\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\t\t\tif (moveBack > 0) {\n\t\t\t\t\toutput.append(`\\x1b[${moveBack}A`);\n\t\t\t\t}\n\t\t\t\toutput.append(\"\\x1b[?2026l\");\n\t\t\t\toutput.flush();\n\t\t\t\tthis.cursorRow = targetRow;\n\t\t\t\tthis.hardwareCursorRow = targetRow;\n\t\t\t}\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t\tthis.previousViewportTop = prevViewportTop;\n\t\t\treturn;\n\t\t}\n\n\t\t// Differential rendering can only touch what was actually visible.\n\t\t// If the first changed line is above the previous viewport, we need a full redraw.\n\t\tif (firstChanged < prevViewportTop) {\n\t\t\tlogRedraw(`firstChanged < viewportTop (${firstChanged} < ${prevViewportTop})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Render from first changed line to end\n\t\t// Keep updates wrapped in synchronized output while writing bounded chunks.\n\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\toutput.append(\"\\x1b[?2026h\"); // Begin synchronized output\n\t\toutput.append(this.deleteChangedKittyImages(firstChanged, lastChanged));\n\t\tconst prevViewportBottom = prevViewportTop + height - 1;\n\t\tconst moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;\n\t\tif (moveTargetRow > prevViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));\n\t\t\tconst moveToBottom = height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) {\n\t\t\t\toutput.append(`\\x1b[${moveToBottom}B`);\n\t\t\t}\n\t\t\tconst scroll = moveTargetRow - prevViewportBottom;\n\t\t\toutput.append(\"\\r\\n\".repeat(scroll));\n\t\t\tprevViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\t// Move cursor to first changed line (use hardwareCursorRow for actual position)\n\t\tconst lineDiff = computeLineDiff(moveTargetRow);\n\t\tif (lineDiff > 0) {\n\t\t\toutput.append(`\\x1b[${lineDiff}B`); // Move down\n\t\t} else if (lineDiff < 0) {\n\t\t\toutput.append(`\\x1b[${-lineDiff}A`); // Move up\n\t\t}\n\n\t\toutput.append(appendStart ? \"\\r\\n\" : \"\\r\"); // Move to column 0\n\n\t\t// Only render changed lines (firstChanged to lastChanged), not all lines to end\n\t\t// This reduces flicker when only a single line changes (e.g., spinner animation)\n\t\tconst renderEnd = Math.min(lastChanged, newLines.length - 1);\n\t\tfor (let i = firstChanged; i <= renderEnd; i++) {\n\t\t\tif (i > firstChanged) output.append(\"\\r\\n\");\n\t\t\tconst line = newLines[i];\n\t\t\tconst isImage = isImageLine(line);\n\t\t\tconst imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i, renderEnd) : 1;\n\t\t\tif (imageReservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = i - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + imageReservedRows > height) {\n\t\t\t\t\tlogRedraw(\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${imageReservedRows} > ${height})`,\n\t\t\t\t\t);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\toutput.append(\"\\x1b[2K\");\n\t\t\t\tfor (let row = 1; row < imageReservedRows; row++) {\n\t\t\t\t\toutput.append(\"\\r\\n\\x1b[2K\");\n\t\t\t\t}\n\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}A`);\n\t\t\t\toutput.append(line);\n\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}B`);\n\t\t\t\ti += imageReservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\toutput.append(\"\\x1b[2K\"); // Clear current line\n\t\t\tif (!isImage && visibleWidth(line) > width) {\n\t\t\t\t// Log all lines to crash file for debugging\n\t\t\t\tconst crashLogPath = path.join(this.logDirectory ?? os.tmpdir(), \"pi-tui-crash.log\");\n\t\t\t\tconst crashData = [\n\t\t\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t\t\t`Terminal width: ${width}`,\n\t\t\t\t\t`Line ${i} visible width: ${visibleWidth(line)}`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"=== All rendered lines ===\",\n\t\t\t\t\t...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\");\n\t\t\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\t\t\tfs.writeFileSync(crashLogPath, crashData);\n\n\t\t\t\t// Clean up terminal state before throwing\n\t\t\t\tthis.stop();\n\n\t\t\t\tconst errorMsg = [\n\t\t\t\t\t`Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t\t].join(\"\\n\");\n\t\t\t\tthrow new Error(errorMsg);\n\t\t\t}\n\t\t\toutput.append(line);\n\t\t}\n\n\t\t// Track where cursor ended up after rendering\n\t\tlet finalCursorRow = renderEnd;\n\n\t\t// If we had more lines before, clear them and move cursor back\n\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t// Move to end of new content first if we stopped before it\n\t\t\tif (renderEnd < newLines.length - 1) {\n\t\t\t\tconst moveDown = newLines.length - 1 - renderEnd;\n\t\t\t\toutput.append(`\\x1b[${moveDown}B`);\n\t\t\t\tfinalCursorRow = newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\tfor (let i = newLines.length; i < this.previousLines.length; i++) {\n\t\t\t\toutput.append(\"\\r\\n\\x1b[2K\");\n\t\t\t}\n\t\t\t// Move cursor back to end of new content\n\t\t\toutput.append(`\\x1b[${extraLines}A`);\n\t\t}\n\n\t\toutput.append(\"\\x1b[?2026l\"); // End synchronized output\n\n\t\tif (process.env.PI_TUI_DEBUG === \"1\") {\n\t\t\tconst debugDir = \"/tmp/tui\";\n\t\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\t\tconst debugData = [\n\t\t\t\t`firstChanged: ${firstChanged}`,\n\t\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t\t`height: ${height}`,\n\t\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t\t`cursorPos: ${JSON.stringify(cursorPos)}`,\n\t\t\t\t`newLines.length: ${newLines.length}`,\n\t\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\t\"\",\n\t\t\t\t\"=== newLines ===\",\n\t\t\t\tJSON.stringify(newLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== previousLines ===\",\n\t\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== buffer ===\",\n\t\t\t\t`[${output.length} chars written in bounded chunks]`,\n\t\t\t].join(\"\\n\");\n\t\t\tfs.writeFileSync(debugPath, debugData);\n\t\t}\n\n\t\toutput.flush();\n\n\t\t// Track cursor position for next render\n\t\t// cursorRow tracks end of content (for viewport calculation)\n\t\t// hardwareCursorRow tracks actual terminal cursor position (for movement)\n\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\t// Track terminal's working area (grows but doesn't shrink unless cleared)\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\tthis.previousViewportTop = Math.max(prevViewportTop, finalCursorRow - height + 1);\n\n\t\t// Position hardware cursor for IME\n\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\n\t\tthis.previousLines = newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\tthis.previousWidth = width;\n\t\tthis.previousHeight = height;\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: { row: number; col: number } | 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 os from \"node:os\";\nimport * as path from \"node:path\";\nimport { deleteKittyImage, isImageLine } from \"./terminal-image.ts\";\nimport { type TUI, TuiBase, type TuiStopOptions } from \"./tui.ts\";\nimport { visibleWidth } from \"./utils.ts\";\n\nconst KITTY_SEQUENCE_PREFIX = \"\\x1b_G\";\nconst MAX_RENDER_WRITE_CHARS = 1024 * 1024;\n\n/**\n * Streams terminal output in 1 MiB chunks so a full render never forms one string large enough to exceed V8's limit.\n *\n * `append()` fills the current chunk and flushes it when full. Oversized input is split at chunk boundaries, preserving\n * surrogate pairs so each write remains valid UTF-16. Callers append synchronized-output begin/end sequences themselves;\n * the final `flush()` writes any remainder, including the end sequence.\n */\nclass BoundedTerminalWriter {\n\tprivate buffer = \"\";\n\tprivate writtenChars = 0;\n\tprivate readonly write: (data: string) => void;\n\n\tconstructor(write: (data: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\t/**\n\t * Append terminal data, flushing full chunks as needed. Callers must call `flush()` after the final append.\n\t * @param value Terminal data to write in order; oversized values are split without splitting surrogate pairs.\n\t */\n\tappend(value: string): void {\n\t\tlet offset = 0;\n\t\twhile (offset < value.length) {\n\t\t\tconst capacity = MAX_RENDER_WRITE_CHARS - this.buffer.length;\n\t\t\tif (capacity === 0) {\n\t\t\t\tthis.flush();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet end = Math.min(value.length, offset + capacity);\n\t\t\tif (\n\t\t\t\tend < value.length &&\n\t\t\t\tvalue.charCodeAt(end - 1) >= 0xd800 &&\n\t\t\t\tvalue.charCodeAt(end - 1) <= 0xdbff &&\n\t\t\t\tvalue.charCodeAt(end) >= 0xdc00 &&\n\t\t\t\tvalue.charCodeAt(end) <= 0xdfff\n\t\t\t) {\n\t\t\t\tend--;\n\t\t\t}\n\t\t\tif (end === offset) {\n\t\t\t\tthis.flush();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.buffer += value.slice(offset, end);\n\t\t\toffset = end;\n\t\t\tif (this.buffer.length === MAX_RENDER_WRITE_CHARS) {\n\t\t\t\tthis.flush();\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Write the current chunk, if any, and retain only its character count for debug output. */\n\tflush(): void {\n\t\tif (!this.buffer) return;\n\t\tthis.write(this.buffer);\n\t\tthis.writtenChars += this.buffer.length;\n\t\tthis.buffer = \"\";\n\t}\n\n\tget length(): number {\n\t\treturn this.writtenChars + this.buffer.length;\n\t}\n}\n\ninterface KittyImageHeader {\n\tids: number[];\n\trows: 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): { firstChanged: number; lastChanged: number } {\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\tprotected doRender(): void {\n\t\tif (this.stopped) return;\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\tlet prevViewportTop = heightChanged ? Math.max(0, previousBufferLength - height) : this.previousViewportTop;\n\t\tlet viewportTop = prevViewportTop;\n\t\tlet hardwareCursorRow = this.hardwareCursorRow;\n\t\tconst computeLineDiff = (targetRow: number): number => {\n\t\t\tconst currentScreenRow = hardwareCursorRow - prevViewportTop;\n\t\t\tconst targetScreenRow = targetRow - viewportTop;\n\t\t\treturn targetScreenRow - currentScreenRow;\n\t\t};\n\n\t\t// Render all components to get new lines\n\t\tlet newLines = this.render(width);\n\n\t\t// Composite overlays into the rendered lines (before differential compare)\n\t\tif (this.hasOverlayEntries) {\n\t\t\tnewLines = this.compositeOverlays(newLines, width, height);\n\t\t}\n\n\t\t// Extract cursor position before applying line resets (marker must be found first)\n\t\tconst cursorPos = this.extractCursorPosition(newLines, height);\n\n\t\tnewLines = this.applyLineResets(newLines);\n\n\t\t// Helper to clear scrollback and viewport and render all new lines\n\t\tconst fullRender = (clear: boolean): void => {\n\t\t\tthis.fullRedrawCount += 1;\n\t\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\t\toutput.append(\"\\x1b[?2026h\"); // Begin synchronized output\n\t\t\tif (clear) {\n\t\t\t\toutput.append(this.deleteKittyImages(this.previousKittyImageIds));\n\t\t\t\toutput.append(\"\\x1b[2J\\x1b[H\\x1b[3J\"); // Clear screen, home, then clear scrollback\n\t\t\t}\n\t\t\tfor (let i = 0; i < newLines.length; i++) {\n\t\t\t\tif (i > 0) output.append(\"\\r\\n\");\n\t\t\t\tconst line = newLines[i];\n\t\t\t\tconst isImage = isImageLine(line);\n\t\t\t\tconst imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i) : 1;\n\t\t\t\tif (imageReservedRows > 1 && imageReservedRows <= height) {\n\t\t\t\t\tfor (let row = 1; row < imageReservedRows; row++) {\n\t\t\t\t\t\toutput.append(\"\\r\\n\");\n\t\t\t\t\t}\n\t\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}A`);\n\t\t\t\t\toutput.append(line);\n\t\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}B`);\n\t\t\t\t\ti += imageReservedRows - 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\toutput.append(line);\n\t\t\t}\n\t\t\toutput.append(\"\\x1b[?2026l\"); // End synchronized output\n\t\t\toutput.flush();\n\t\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\t\tthis.hardwareCursorRow = this.cursorRow;\n\t\t\t// Reset max lines when clearing, otherwise track growth\n\t\t\tif (clear) {\n\t\t\t\tthis.maxLinesRendered = newLines.length;\n\t\t\t} else {\n\t\t\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\t\t}\n\t\t\tconst bufferLength = Math.max(height, newLines.length);\n\t\t\tthis.previousViewportTop = Math.max(0, bufferLength - height);\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t};\n\n\t\tconst redrawLogDirectory = process.env.PI_TUI_DEBUG_REDRAW === \"1\" ? this.logDirectory : undefined;\n\t\tconst logRedraw = (reason: string): void => {\n\t\t\tif (redrawLogDirectory === undefined) return;\n\t\t\tconst logPath = path.join(redrawLogDirectory, \"pi-tui-debug.log\");\n\t\t\tconst msg = `[${new Date().toISOString()}] fullRender: ${reason} (prev=${this.previousLines.length}, new=${newLines.length}, height=${height})\\n`;\n\t\t\tfs.mkdirSync(path.dirname(logPath), { recursive: true });\n\t\t\tfs.appendFileSync(logPath, msg);\n\t\t};\n\n\t\t// First render - just output everything without clearing (assumes clean screen)\n\t\tif (this.previousLines.length === 0 && !widthChanged && !heightChanged) {\n\t\t\tlogRedraw(\"first render\");\n\t\t\tfullRender(false);\n\t\t\treturn;\n\t\t}\n\n\t\t// Width changes always need a full re-render because wrapping changes.\n\t\tif (widthChanged) {\n\t\t\tlogRedraw(`terminal width changed (${this.previousWidth} -> ${width})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Height changes normally need a full re-render to keep the visible viewport aligned,\n\t\t// but Termux changes height when the software keyboard shows or hides.\n\t\t// In that environment, a full redraw causes the entire history to replay on every toggle.\n\t\tif (heightChanged && !isTermuxSession()) {\n\t\t\tlogRedraw(`terminal height changed (${this.previousHeight} -> ${height})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Content shrunk below the working area and no overlays - re-render to clear empty rows\n\t\t// (overlays need the padding, so only do this when no overlays are active)\n\t\t// Configurable via setClearOnShrink()\n\t\tif (this.getClearOnShrink() && newLines.length < this.maxLinesRendered && !this.hasOverlayEntries) {\n\t\t\tlogRedraw(`clearOnShrink (maxLinesRendered=${this.maxLinesRendered})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find first and last changed lines\n\t\tlet firstChanged = -1;\n\t\tlet lastChanged = -1;\n\t\tconst maxLines = Math.max(newLines.length, this.previousLines.length);\n\t\tfor (let i = 0; i < maxLines; i++) {\n\t\t\tconst oldLine = i < this.previousLines.length ? this.previousLines[i] : \"\";\n\t\t\tconst newLine = i < newLines.length ? newLines[i] : \"\";\n\n\t\t\tif (oldLine !== newLine) {\n\t\t\t\tif (firstChanged === -1) {\n\t\t\t\t\tfirstChanged = i;\n\t\t\t\t}\n\t\t\t\tlastChanged = i;\n\t\t\t}\n\t\t}\n\t\tconst appendedLines = newLines.length > this.previousLines.length;\n\t\tif (appendedLines) {\n\t\t\tif (firstChanged === -1) {\n\t\t\t\tfirstChanged = this.previousLines.length;\n\t\t\t}\n\t\t\tlastChanged = newLines.length - 1;\n\t\t}\n\t\tif (firstChanged !== -1) {\n\t\t\tconst expandedRange = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines);\n\t\t\tfirstChanged = expandedRange.firstChanged;\n\t\t\tlastChanged = expandedRange.lastChanged;\n\t\t}\n\t\tconst appendStart = appendedLines && firstChanged === this.previousLines.length && firstChanged > 0;\n\n\t\t// No changes - but still need to update hardware cursor position if it moved\n\t\tif (firstChanged === -1) {\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousViewportTop = prevViewportTop;\n\t\t\tthis.previousHeight = height;\n\t\t\treturn;\n\t\t}\n\n\t\t// All changes are in deleted lines (nothing to render, just clear)\n\t\tif (firstChanged >= newLines.length) {\n\t\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\t\t\toutput.append(\"\\x1b[?2026h\");\n\t\t\t\toutput.append(this.deleteChangedKittyImages(firstChanged, lastChanged));\n\t\t\t\t// Move to end of new content (clamp to 0 for empty content)\n\t\t\t\tconst targetRow = Math.max(0, newLines.length - 1);\n\t\t\t\tif (targetRow < prevViewportTop) {\n\t\t\t\t\tlogRedraw(`deleted lines moved viewport up (${targetRow} < ${prevViewportTop})`);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst lineDiff = computeLineDiff(targetRow);\n\t\t\t\tif (lineDiff > 0) output.append(`\\x1b[${lineDiff}B`);\n\t\t\t\telse if (lineDiff < 0) output.append(`\\x1b[${-lineDiff}A`);\n\t\t\t\toutput.append(\"\\r\");\n\t\t\t\t// Clear extra lines without scrolling\n\t\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\t\tif (extraLines > height) {\n\t\t\t\t\tlogRedraw(`extraLines > height (${extraLines} > ${height})`);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst clearStartOffset = newLines.length === 0 ? 0 : 1;\n\t\t\t\tif (extraLines > 0 && clearStartOffset > 0) {\n\t\t\t\t\toutput.append(`\\x1b[${clearStartOffset}B`);\n\t\t\t\t}\n\t\t\t\tfor (let i = 0; i < extraLines; i++) {\n\t\t\t\t\toutput.append(\"\\r\\x1b[2K\");\n\t\t\t\t\tif (i < extraLines - 1) output.append(\"\\x1b[1B\");\n\t\t\t\t}\n\t\t\t\tconst moveBack = Math.max(0, extraLines - 1 + clearStartOffset);\n\t\t\t\tif (moveBack > 0) {\n\t\t\t\t\toutput.append(`\\x1b[${moveBack}A`);\n\t\t\t\t}\n\t\t\t\toutput.append(\"\\x1b[?2026l\");\n\t\t\t\toutput.flush();\n\t\t\t\tthis.cursorRow = targetRow;\n\t\t\t\tthis.hardwareCursorRow = targetRow;\n\t\t\t}\n\t\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\t\t\tthis.previousLines = newLines;\n\t\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\t\tthis.previousWidth = width;\n\t\t\tthis.previousHeight = height;\n\t\t\tthis.previousViewportTop = prevViewportTop;\n\t\t\treturn;\n\t\t}\n\n\t\t// Differential rendering can only touch what was actually visible.\n\t\t// If the first changed line is above the previous viewport, we need a full redraw.\n\t\tif (firstChanged < prevViewportTop) {\n\t\t\tlogRedraw(`firstChanged < viewportTop (${firstChanged} < ${prevViewportTop})`);\n\t\t\tfullRender(true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Render from first changed line to end\n\t\t// Keep updates wrapped in synchronized output while writing bounded chunks.\n\t\tconst output = new BoundedTerminalWriter((data) => this.terminal.write(data));\n\t\toutput.append(\"\\x1b[?2026h\"); // Begin synchronized output\n\t\toutput.append(this.deleteChangedKittyImages(firstChanged, lastChanged));\n\t\tconst prevViewportBottom = prevViewportTop + height - 1;\n\t\tconst moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;\n\t\tif (moveTargetRow > prevViewportBottom) {\n\t\t\tconst currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));\n\t\t\tconst moveToBottom = height - 1 - currentScreenRow;\n\t\t\tif (moveToBottom > 0) {\n\t\t\t\toutput.append(`\\x1b[${moveToBottom}B`);\n\t\t\t}\n\t\t\tconst scroll = moveTargetRow - prevViewportBottom;\n\t\t\toutput.append(\"\\r\\n\".repeat(scroll));\n\t\t\tprevViewportTop += scroll;\n\t\t\tviewportTop += scroll;\n\t\t\thardwareCursorRow = moveTargetRow;\n\t\t}\n\n\t\t// Move cursor to first changed line (use hardwareCursorRow for actual position)\n\t\tconst lineDiff = computeLineDiff(moveTargetRow);\n\t\tif (lineDiff > 0) {\n\t\t\toutput.append(`\\x1b[${lineDiff}B`); // Move down\n\t\t} else if (lineDiff < 0) {\n\t\t\toutput.append(`\\x1b[${-lineDiff}A`); // Move up\n\t\t}\n\n\t\toutput.append(appendStart ? \"\\r\\n\" : \"\\r\"); // Move to column 0\n\n\t\t// Only render changed lines (firstChanged to lastChanged), not all lines to end\n\t\t// This reduces flicker when only a single line changes (e.g., spinner animation)\n\t\tconst renderEnd = Math.min(lastChanged, newLines.length - 1);\n\t\tfor (let i = firstChanged; i <= renderEnd; i++) {\n\t\t\tif (i > firstChanged) output.append(\"\\r\\n\");\n\t\t\tconst line = newLines[i];\n\t\t\tconst isImage = isImageLine(line);\n\t\t\tconst imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i, renderEnd) : 1;\n\t\t\tif (imageReservedRows > 1) {\n\t\t\t\tconst imageStartScreenRow = i - viewportTop;\n\t\t\t\tif (imageStartScreenRow < 0 || imageStartScreenRow + imageReservedRows > height) {\n\t\t\t\t\tlogRedraw(\n\t\t\t\t\t\t`kitty image pre-clear would scroll (${imageStartScreenRow} + ${imageReservedRows} > ${height})`,\n\t\t\t\t\t);\n\t\t\t\t\tfullRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\toutput.append(\"\\x1b[2K\");\n\t\t\t\tfor (let row = 1; row < imageReservedRows; row++) {\n\t\t\t\t\toutput.append(\"\\r\\n\\x1b[2K\");\n\t\t\t\t}\n\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}A`);\n\t\t\t\toutput.append(line);\n\t\t\t\toutput.append(`\\x1b[${imageReservedRows - 1}B`);\n\t\t\t\ti += imageReservedRows - 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\toutput.append(\"\\x1b[2K\"); // Clear current line\n\t\t\tif (!isImage && visibleWidth(line) > width) {\n\t\t\t\t// Log all lines to crash file for debugging\n\t\t\t\tconst crashLogPath = path.join(this.logDirectory ?? os.tmpdir(), \"pi-tui-crash.log\");\n\t\t\t\tconst crashData = [\n\t\t\t\t\t`Crash at ${new Date().toISOString()}`,\n\t\t\t\t\t`Terminal width: ${width}`,\n\t\t\t\t\t`Line ${i} visible width: ${visibleWidth(line)}`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"=== All rendered lines ===\",\n\t\t\t\t\t...newLines.map((l, idx) => `[${idx}] (w=${visibleWidth(l)}) ${l}`),\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\");\n\t\t\t\tfs.mkdirSync(path.dirname(crashLogPath), { recursive: true });\n\t\t\t\tfs.writeFileSync(crashLogPath, crashData);\n\n\t\t\t\t// Clean up terminal state before throwing\n\t\t\t\tthis.stop();\n\n\t\t\t\tconst errorMsg = [\n\t\t\t\t\t`Rendered line ${i} exceeds terminal width (${visibleWidth(line)} > ${width}).`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"This is likely caused by a custom TUI component not truncating its output.\",\n\t\t\t\t\t\"Use visibleWidth() to measure and truncateToWidth() to truncate lines.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t`Debug log written to: ${crashLogPath}`,\n\t\t\t\t].join(\"\\n\");\n\t\t\t\tthrow new Error(errorMsg);\n\t\t\t}\n\t\t\toutput.append(line);\n\t\t}\n\n\t\t// Track where cursor ended up after rendering\n\t\tlet finalCursorRow = renderEnd;\n\n\t\t// If we had more lines before, clear them and move cursor back\n\t\tif (this.previousLines.length > newLines.length) {\n\t\t\t// Move to end of new content first if we stopped before it\n\t\t\tif (renderEnd < newLines.length - 1) {\n\t\t\t\tconst moveDown = newLines.length - 1 - renderEnd;\n\t\t\t\toutput.append(`\\x1b[${moveDown}B`);\n\t\t\t\tfinalCursorRow = newLines.length - 1;\n\t\t\t}\n\t\t\tconst extraLines = this.previousLines.length - newLines.length;\n\t\t\tfor (let i = newLines.length; i < this.previousLines.length; i++) {\n\t\t\t\toutput.append(\"\\r\\n\\x1b[2K\");\n\t\t\t}\n\t\t\t// Move cursor back to end of new content\n\t\t\toutput.append(`\\x1b[${extraLines}A`);\n\t\t}\n\n\t\toutput.append(\"\\x1b[?2026l\"); // End synchronized output\n\n\t\tif (process.env.PI_TUI_DEBUG === \"1\") {\n\t\t\tconst debugDir = \"/tmp/tui\";\n\t\t\tfs.mkdirSync(debugDir, { recursive: true });\n\t\t\tconst debugPath = path.join(debugDir, `render-${Date.now()}-${Math.random().toString(36).slice(2)}.log`);\n\t\t\tconst debugData = [\n\t\t\t\t`firstChanged: ${firstChanged}`,\n\t\t\t\t`viewportTop: ${viewportTop}`,\n\t\t\t\t`cursorRow: ${this.cursorRow}`,\n\t\t\t\t`height: ${height}`,\n\t\t\t\t`lineDiff: ${lineDiff}`,\n\t\t\t\t`hardwareCursorRow: ${hardwareCursorRow}`,\n\t\t\t\t`renderEnd: ${renderEnd}`,\n\t\t\t\t`finalCursorRow: ${finalCursorRow}`,\n\t\t\t\t`cursorPos: ${JSON.stringify(cursorPos)}`,\n\t\t\t\t`newLines.length: ${newLines.length}`,\n\t\t\t\t`previousLines.length: ${this.previousLines.length}`,\n\t\t\t\t\"\",\n\t\t\t\t\"=== newLines ===\",\n\t\t\t\tJSON.stringify(newLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== previousLines ===\",\n\t\t\t\tJSON.stringify(this.previousLines, null, 2),\n\t\t\t\t\"\",\n\t\t\t\t\"=== buffer ===\",\n\t\t\t\t`[${output.length} chars written in bounded chunks]`,\n\t\t\t].join(\"\\n\");\n\t\t\tfs.writeFileSync(debugPath, debugData);\n\t\t}\n\n\t\toutput.flush();\n\n\t\t// Track cursor position for next render\n\t\t// cursorRow tracks end of content (for viewport calculation)\n\t\t// hardwareCursorRow tracks actual terminal cursor position (for movement)\n\t\tthis.cursorRow = Math.max(0, newLines.length - 1);\n\t\tthis.hardwareCursorRow = finalCursorRow;\n\t\t// Track terminal's working area (grows but doesn't shrink unless cleared)\n\t\tthis.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);\n\t\tthis.previousViewportTop = Math.max(prevViewportTop, finalCursorRow - height + 1);\n\n\t\t// Position hardware cursor for IME\n\t\tthis.positionHardwareCursor(cursorPos, newLines.length);\n\n\t\tthis.previousLines = newLines;\n\t\tthis.previousKittyImageIds = this.collectKittyImageIds(newLines);\n\t\tthis.previousWidth = width;\n\t\tthis.previousHeight = height;\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: { row: number; col: number } | 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
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Minimal TUI implementation with differential rendering
|
|
3
3
|
*/
|
|
4
4
|
import type { Terminal } from "./terminal.ts";
|
|
5
|
-
import { type
|
|
5
|
+
import { type TerminalColorScheme, type TerminalColors } from "./terminal-colors.ts";
|
|
6
6
|
import { visibleWidth } from "./utils.ts";
|
|
7
7
|
/**
|
|
8
8
|
* Component interface - all components must implement this
|
|
@@ -235,12 +235,10 @@ export interface TUI extends Component {
|
|
|
235
235
|
removeInputListener(listener: TuiInputListener): void;
|
|
236
236
|
onTerminalColorSchemeChange(listener: (scheme: TerminalColorScheme) => void): () => void;
|
|
237
237
|
setTerminalColorSchemeNotifications(enabled: boolean): void;
|
|
238
|
-
|
|
238
|
+
queryTerminalColors(options: {
|
|
239
239
|
timeoutMs: number;
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
timeoutMs: number;
|
|
243
|
-
}): Promise<TerminalColorScheme | undefined>;
|
|
240
|
+
onLateReply?: (colors: TerminalColors) => void;
|
|
241
|
+
}): Promise<TerminalColors>;
|
|
244
242
|
}
|
|
245
243
|
export declare const VIEWPORT_TUI: unique symbol;
|
|
246
244
|
export interface ViewportTUI extends TUI {
|
|
@@ -264,8 +262,11 @@ export declare abstract class TuiBase extends Container implements TUI {
|
|
|
264
262
|
private clearOnShrink;
|
|
265
263
|
protected fullRedrawCount: number;
|
|
266
264
|
protected stopped: boolean;
|
|
267
|
-
|
|
268
|
-
|
|
265
|
+
/**
|
|
266
|
+
* Color queries waiting for their DA1 reply, oldest first. Terminals answer in order, so color
|
|
267
|
+
* replies belong to the oldest one. Queries stay here after a timeout to collect late replies.
|
|
268
|
+
*/
|
|
269
|
+
private pendingTerminalColorQueries;
|
|
269
270
|
private terminalColorSchemeListeners;
|
|
270
271
|
private terminalColorSchemeNotificationsEnabled;
|
|
271
272
|
/** Directory for debug/crash logs. When undefined, debug logging is disabled and crash dumps fall back to the OS temp directory. */
|
|
@@ -311,6 +312,8 @@ export declare abstract class TuiBase extends Container implements TUI {
|
|
|
311
312
|
showOverlay(component: Component, options?: OverlayOptions): OverlayHandle;
|
|
312
313
|
/** Hide the topmost overlay and restore previous focus. */
|
|
313
314
|
hideOverlay(): void;
|
|
315
|
+
/** Hide the cursor while running. After stop(), the shell owns the cursor and it must stay visible. */
|
|
316
|
+
private hideTerminalCursor;
|
|
314
317
|
/** Check if there are any visible overlays */
|
|
315
318
|
hasOverlay(): boolean;
|
|
316
319
|
/** Check if the focused component is a visible overlay */
|
|
@@ -340,7 +343,9 @@ export declare abstract class TuiBase extends Container implements TUI {
|
|
|
340
343
|
private cancelRenderTimer;
|
|
341
344
|
private scheduleRender;
|
|
342
345
|
private handleTerminalInput;
|
|
343
|
-
private
|
|
346
|
+
private consumeTerminalColorResponse;
|
|
347
|
+
private terminalColorQueryResult;
|
|
348
|
+
private completeTerminalColorQuery;
|
|
344
349
|
private consumeTerminalColorSchemeReport;
|
|
345
350
|
private consumeCellSizeResponse;
|
|
346
351
|
/**
|
|
@@ -367,20 +372,16 @@ export declare abstract class TuiBase extends Container implements TUI {
|
|
|
367
372
|
col: number;
|
|
368
373
|
} | null;
|
|
369
374
|
/**
|
|
370
|
-
* Query the terminal's
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}): Promise<RgbColor | undefined>;
|
|
377
|
-
/**
|
|
378
|
-
* Query the terminal's color-scheme preference with DSR (`CSI ? 996 n`).
|
|
379
|
-
* Terminals that support the color palette notification protocol reply with
|
|
380
|
-
* `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
|
|
375
|
+
* Query the terminal's theme colors: the default foreground (OSC 10), the default background
|
|
376
|
+
* (OSC 11), and ANSI colors 0-15 (OSC 4), followed by a DA1 request that marks the end of the
|
|
377
|
+
* replies. Resolves when the DA1 reply or all color replies arrive, or when the timeout expires.
|
|
378
|
+
* Colors the terminal did not report are undefined; the palette is only set when all 16 arrived.
|
|
379
|
+
* @param timeoutMs Query timeout in milliseconds, for terminals that do not answer DA1 either.
|
|
380
|
+
* @param onLateReply Receives the replies if the query completes after the timeout, e.g. over slow links.
|
|
381
381
|
*/
|
|
382
|
-
|
|
382
|
+
queryTerminalColors({ timeoutMs, onLateReply, }: {
|
|
383
383
|
timeoutMs: number;
|
|
384
|
-
|
|
384
|
+
onLateReply?: (colors: TerminalColors) => void;
|
|
385
|
+
}): Promise<TerminalColors>;
|
|
385
386
|
}
|
|
386
387
|
//# sourceMappingURL=tui.d.ts.map
|
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 { performance } from \"node:perf_hooks\";\nimport { isKeyRelease, matchesKey } from \"./keys.ts\";\nimport type { Terminal } from \"./terminal.ts\";\nimport {\n\tisOsc11BackgroundColorResponse,\n\tparseOsc11BackgroundColor,\n\tparseTerminalColorSchemeReport,\n\ttype RgbColor,\n\ttype TerminalColorScheme,\n} from \"./terminal-colors.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 type TuiMouseEventType = \"press\" | \"release\" | \"move\" | \"drag\" | \"click\" | \"wheel\";\nexport type TuiMouseButton = \"left\" | \"middle\" | \"right\" | \"none\";\n\n/** Normalized cell-based mouse event. Coordinates are zero-based. */\nexport interface TuiMouseEvent {\n\ttype: TuiMouseEventType;\n\tbutton: TuiMouseButton;\n\t/** Coordinates local to the receiving component. */\n\tx: number;\n\ty: number;\n\t/** Absolute terminal coordinates. */\n\tscreenX: number;\n\tscreenY: number;\n\t/** Current component bounds. */\n\twidth: number;\n\theight: number;\n\tshift: boolean;\n\talt: boolean;\n\tctrl: boolean;\n\t/** Logical lines. Negative values scroll up. */\n\twheelDelta?: number;\n\t/** Consecutive click count when type is click. */\n\tclickCount?: number;\n}\n\nexport interface TuiMouseEventResult {\n\t/** Stop propagation and suppress renderer-level fallback behavior. */\n\thandled?: boolean;\n\t/** Route subsequent drag/release events to this component. Implies handled. */\n\tcapture?: boolean;\n\t/** Give keyboard focus to this component. Implies handled. */\n\tfocus?: boolean;\n\t/**\n\t * Explicitly request or suppress a render. Move and release default to false;\n\t * press, click, drag, and wheel default to true.\n\t */\n\trender?: boolean;\n}\n\n/** Internal target metadata used by containers and alternate-screen dispatch. */\nexport interface TuiMouseDispatchTarget {\n\tcomponent: Component;\n\toriginX: number;\n\toriginY: number;\n\twidth: number;\n\theight: number;\n}\n\n/** Result of dispatching to a concrete component. */\nexport interface TuiMouseDispatchResult extends TuiMouseEventResult {\n\thandled: true;\n\ttarget: TuiMouseDispatchTarget;\n\t/** Keyboard focus target, which may be a delegating parent container. */\n\tfocusTarget?: Component;\n}\n\n/**\n * Dispatch an event to a component and retain the exact target and coordinate\n * transform. Containers use this when forwarding events to nested children.\n */\nexport function dispatchMouseEvent(component: Component, event: TuiMouseEvent): TuiMouseDispatchResult | undefined {\n\tconst result = component.handleMouse?.(event);\n\tif (!result) return undefined;\n\tif (\"target\" in result) return result as TuiMouseDispatchResult;\n\tif (!result.handled && !result.capture && !result.focus) return undefined;\n\treturn {\n\t\t...result,\n\t\thandled: true,\n\t\t...(result.focus ? { focusTarget: component } : {}),\n\t\ttarget: {\n\t\t\tcomponent,\n\t\t\toriginX: event.screenX - event.x,\n\t\t\toriginY: event.screenY - event.y,\n\t\t\twidth: event.width,\n\t\t\theight: event.height,\n\t\t},\n\t};\n}\n\n/** Recreate local coordinates for a previously dispatched mouse target. */\nexport function retargetMouseEvent(event: TuiMouseEvent, target: TuiMouseDispatchTarget): TuiMouseEvent {\n\treturn {\n\t\t...event,\n\t\tx: event.screenX - target.originX,\n\t\ty: event.screenY - target.originY,\n\t\twidth: target.width,\n\t\theight: target.height,\n\t};\n}\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/** Optional handler for keyboard input when component has focus. */\n\thandleInput?(data: string): void;\n\n\t/** Optional normalized mouse handler. */\n\thandleMouse?(event: TuiMouseEvent): TuiMouseEventResult | undefined;\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;\ntype PendingOsc11BackgroundQuery = {\n\tsettled: boolean;\n\tresolve: ((rgb: RgbColor | undefined) => void) | undefined;\n\ttimer: NodeJS.Timeout | undefined;\n};\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/** Last rendered terminal-relative overlay rectangle. */\nexport interface OverlayBounds {\n\trow: number;\n\tcol: number;\n\twidth: number;\n\theight: number;\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\t/** Get the most recent rendered bounds for a visible overlay. */\n\tgetBounds(): OverlayBounds | undefined;\n}\n\ntype OverlayStackEntry = {\n\tcomponent: Component;\n\toptions?: OverlayOptions;\n\tpreFocus: Component | null;\n\thidden: boolean;\n\tfocusOrder: number;\n\tbounds?: OverlayBounds;\n};\n\ntype RenderedOverlayLayout = {\n\tentry: OverlayStackEntry;\n\trow: number;\n\tcol: number;\n\twidth: number;\n\theight: number;\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\n/**\n * Container - a component that contains other components\n */\nexport class Container implements Component {\n\tchildren: Component[] = [];\n\tprivate mouseLayout?: { width: number; children: Array<{ component: Component; height: number }> };\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\thandleMouse(event: TuiMouseEvent): TuiMouseDispatchResult | undefined {\n\t\tif (event.y < 0 || event.y >= event.height) return undefined;\n\t\tconst mouseChildren =\n\t\t\tthis.mouseLayout?.width === event.width\n\t\t\t\t? this.mouseLayout.children\n\t\t\t\t: this.children.map((component) => ({ component, height: component.render(event.width).length }));\n\t\tlet childY = 0;\n\t\tfor (const { component: child, height: childHeight } of mouseChildren) {\n\t\t\tif (event.y >= childY && event.y < childY + childHeight) {\n\t\t\t\tconst result = dispatchMouseEvent(child, {\n\t\t\t\t\t...event,\n\t\t\t\t\ty: event.y - childY,\n\t\t\t\t\theight: childHeight,\n\t\t\t\t});\n\t\t\t\tif (result?.focus && (this as Component).handleInput) return { ...result, focusTarget: this };\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tchildY += childHeight;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst mouseChildren: Array<{ component: Component; height: number }> = [];\n\t\tfor (const child of this.children) {\n\t\t\tconst childLines = child.render(width);\n\t\t\tmouseChildren.push({ component: child, height: childLines.length });\n\t\t\tfor (const line of childLines) {\n\t\t\t\tlines.push(line);\n\t\t\t}\n\t\t}\n\t\tthis.mouseLayout = { width, children: mouseChildren };\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/** Leave renderer output in place for another TUI taking over the same terminal. */\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\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\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\tonTerminalColorSchemeChange(listener: (scheme: TerminalColorScheme) => void): () => void;\n\tsetTerminalColorSchemeNotifications(enabled: boolean): void;\n\tqueryTerminalBackgroundColor(options: { timeoutMs: number }): Promise<RgbColor | undefined>;\n\tqueryTerminalColorScheme(options: { timeoutMs: number }): Promise<TerminalColorScheme | undefined>;\n}\n\nexport const VIEWPORT_TUI = Symbol.for(\"@earendil-works/pi-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 = false;\n\tprivate clearOnShrink = false;\n\tprotected fullRedrawCount = 0;\n\tprotected stopped = false;\n\tprivate pendingOsc11BackgroundReplies = 0;\n\tprivate pendingOsc11BackgroundQueries: PendingOsc11BackgroundQuery[] = [];\n\tprivate terminalColorSchemeListeners = new Set<(scheme: TerminalColorScheme) => void>();\n\tprivate terminalColorSchemeNotificationsEnabled = false;\n\t/** Directory for debug/crash logs. When undefined, debug logging is disabled and crash dumps fall back to the OS temp directory. */\n\tprotected readonly logDirectory: string | undefined;\n\n\t// Overlay stack for modal components rendered on top of base content\n\tprivate focusOrderCounter = 0;\n\tprivate overlayStack: OverlayStackEntry[] = [];\n\tprivate renderedOverlayLayouts: RenderedOverlayLayout[] = [];\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 = logDirectory;\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 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, empty rows are cleared when content shrinks.\n\t * When false (default), 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 setFocusInternal({\n\t\tcomponent,\n\t\toverlayFocusRestore,\n\t}: {\n\t\tcomponent: Component | null;\n\t\toverlayFocusRestore: OverlayFocusRestorePolicy;\n\t}): void {\n\t\tconst previousFocus = this.focusedComponent;\n\t\tlet nextFocus = component;\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\tconst nextFocusIsOverlay = nextFocus ? this.overlayStack.some((entry) => entry.component === nextFocus) : false;\n\t\tconst restoreState = this.getVisibleOverlayFocusRestore();\n\t\tif (nextFocus && !nextFocusIsOverlay) {\n\t\t\tif (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n\t\t\t\tif (restoreState.resume.status === \"focus-target\" || !this.isComponentMounted(restoreState.blockedBy)) {\n\t\t\t\t\tnextFocus = this.resolveBlockedOverlayFocusResume(restoreState);\n\t\t\t\t} else {\n\t\t\t\t\tthis.overlayFocusRestore = {\n\t\t\t\t\t\tstatus: \"blocked\",\n\t\t\t\t\t\toverlay: restoreState.overlay,\n\t\t\t\t\t\tblockedBy: nextFocus,\n\t\t\t\t\t\tresume: restoreState.resume,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tpreviousFocusedOverlay &&\n\t\t\t\trestoreState.status !== \"inactive\" &&\n\t\t\t\trestoreState.overlay === previousFocusedOverlay &&\n\t\t\t\t!this.isOverlayFocusAncestor(previousFocusedOverlay, nextFocus)\n\t\t\t) {\n\t\t\t\tthis.overlayFocusRestore = {\n\t\t\t\t\tstatus: \"blocked\",\n\t\t\t\t\toverlay: previousFocusedOverlay,\n\t\t\t\t\tblockedBy: nextFocus,\n\t\t\t\t\tresume: { status: \"restore-overlay\" },\n\t\t\t\t};\n\t\t\t}\n\t\t} else if (nextFocus === null) {\n\t\t\tif (restoreState.status === \"blocked\" && restoreState.blockedBy === previousFocus) {\n\t\t\t\tnextFocus = this.resolveBlockedOverlayFocusResume(restoreState);\n\t\t\t} else if (overlayFocusRestore === \"clear\") {\n\t\t\t\tthis.clearOverlayFocusRestore();\n\t\t\t}\n\t\t}\n\n\t\tif (isFocusable(this.focusedComponent)) {\n\t\t\tthis.focusedComponent.focused = false;\n\t\t}\n\n\t\tthis.focusedComponent = nextFocus;\n\n\t\tif (isFocusable(nextFocus)) {\n\t\t\tnextFocus.focused = true;\n\t\t}\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) {\n\t\t\tthis.overlayFocusRestore = { status: \"eligible\", overlay: focusedOverlay };\n\t\t}\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 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 = this.overlayStack.find((overlay) => overlay.component === current)?.preFocus ?? 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\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};\n\t\tthis.overlayStack.push(entry);\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\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\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.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) => {\n\t\t\t\tconst isFocused = this.focusedComponent === component;\n\t\t\t\tconst restoreState = this.overlayFocusRestore;\n\t\t\t\tconst hasPendingRestore = restoreState.status !== \"inactive\" && restoreState.overlay === entry;\n\t\t\t\tif (!isFocused && !hasPendingRestore) return;\n\t\t\t\tif (\n\t\t\t\t\trestoreState.status === \"blocked\" &&\n\t\t\t\t\trestoreState.overlay === entry &&\n\t\t\t\t\tthis.focusedComponent === restoreState.blockedBy\n\t\t\t\t) {\n\t\t\t\t\tif (unfocusOptions) {\n\t\t\t\t\t\tthis.overlayFocusRestore = {\n\t\t\t\t\t\t\tstatus: \"blocked\",\n\t\t\t\t\t\t\toverlay: entry,\n\t\t\t\t\t\t\tblockedBy: restoreState.blockedBy,\n\t\t\t\t\t\t\tresume: { status: \"focus-target\", target: unfocusOptions.target },\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.clearOverlayFocusRestore();\n\t\t\t\t\t}\n\t\t\t\t\tthis.requestRender();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.clearOverlayFocusRestoreFor(entry);\n\t\t\t\tif (isFocused || unfocusOptions) {\n\t\t\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\t\t\tconst fallbackTarget = topVisible && topVisible !== entry ? topVisible.component : entry.preFocus;\n\t\t\t\t\tthis.setFocus(unfocusOptions ? unfocusOptions.target : fallbackTarget);\n\t\t\t\t}\n\t\t\t\tthis.requestRender();\n\t\t\t},\n\t\t\tisFocused: () => this.focusedComponent === component,\n\t\t\tgetBounds: () => {\n\t\t\t\tif (!this.overlayStack.includes(entry) || !this.isOverlayVisible(entry) || !entry.bounds) return undefined;\n\t\t\t\treturn { ...entry.bounds };\n\t\t\t},\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\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\t/** Check if the focused component is a visible overlay */\n\tprotected isOverlayFocused(): boolean {\n\t\treturn this.overlayStack.some(\n\t\t\t(entry) => entry.component === this.focusedComponent && this.isOverlayVisible(entry),\n\t\t);\n\t}\n\n\t/** Keep overlay containers as keyboard focus owners when a nested control is clicked. */\n\tprotected resolveMouseFocusTarget(component: Component): Component {\n\t\tfor (let index = this.overlayStack.length - 1; index >= 0; index--) {\n\t\t\tconst overlay = this.overlayStack[index]!;\n\t\t\tif (this.isOverlayVisible(overlay) && this.containsComponent(overlay.component, component)) {\n\t\t\t\treturn overlay.component;\n\t\t\t}\n\t\t}\n\t\treturn component;\n\t}\n\n\t/** Dispatch to the visually topmost overlay under the pointer. */\n\tprotected dispatchMouseToOverlay(event: TuiMouseEvent): { hit: boolean; result?: TuiMouseDispatchResult } {\n\t\tfor (let index = this.renderedOverlayLayouts.length - 1; index >= 0; index--) {\n\t\t\tconst layout = this.renderedOverlayLayouts[index]!;\n\t\t\tif (\n\t\t\t\tevent.screenX < layout.col ||\n\t\t\t\tevent.screenX >= layout.col + layout.width ||\n\t\t\t\tevent.screenY < layout.row ||\n\t\t\t\tevent.screenY >= layout.row + layout.height\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result = dispatchMouseEvent(layout.entry.component, {\n\t\t\t\t...event,\n\t\t\t\tx: event.screenX - layout.col,\n\t\t\t\ty: event.screenY - layout.row,\n\t\t\t\twidth: layout.width,\n\t\t\t\theight: layout.height,\n\t\t\t});\n\t\t\treturn result\n\t\t\t\t? {\n\t\t\t\t\t\thit: true,\n\t\t\t\t\t\tresult: result.focus ? { ...result, focusTarget: layout.entry.component } : result,\n\t\t\t\t\t}\n\t\t\t\t: { hit: true };\n\t\t}\n\t\treturn { hit: false };\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\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\tthis.beforeTerminalStart();\n\t\tthis.terminal.start(\n\t\t\t(data) => this.handleTerminalInput(data),\n\t\t\t() => this.requestRender(),\n\t\t);\n\t\tthis.afterTerminalStart();\n\t\tthis.terminal.hideCursor();\n\t\tif (this.terminalColorSchemeNotificationsEnabled) {\n\t\t\tthis.terminal.write(\"\\x1b[?2031h\");\n\t\t}\n\t\tthis.queryCellSize();\n\t\tthis.requestRender();\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\tonTerminalColorSchemeChange(listener: (scheme: TerminalColorScheme) => void): () => void {\n\t\tthis.terminalColorSchemeListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.terminalColorSchemeListeners.delete(listener);\n\t\t};\n\t}\n\n\tsetTerminalColorSchemeNotifications(enabled: boolean): void {\n\t\tif (this.terminalColorSchemeNotificationsEnabled === enabled) {\n\t\t\treturn;\n\t\t}\n\t\tthis.terminalColorSchemeNotificationsEnabled = enabled;\n\t\tif (!this.stopped) {\n\t\t\tthis.terminal.write(enabled ? \"\\x1b[?2031h\" : \"\\x1b[?2031l\");\n\t\t}\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.cancelRenderTimer();\n\t\tif (this.terminalColorSchemeNotificationsEnabled) {\n\t\t\tthis.terminal.write(\"\\x1b[?2031l\");\n\t\t}\n\t\tthis.beforeTerminalStop(options);\n\t\tthis.terminal.showCursor();\n\t\tthis.terminal.stop();\n\t\tthis.afterTerminalStop(options);\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\t// A previously queued scheduleRender() can create a timer before this\n\t\t\t// callback runs. User input must preempt that throttled frame.\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) {\n\t\t\treturn;\n\t\t}\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) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.renderRequested = false;\n\t\t\tthis.lastRenderAt = performance.now();\n\t\t\tthis.doRender();\n\t\t\tif (this.renderRequested) {\n\t\t\t\tthis.scheduleRender();\n\t\t\t}\n\t\t}, delay);\n\t}\n\n\tprivate handleTerminalInput(data: string): void {\n\t\tif (this.consumeOsc11BackgroundResponse(data)) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.consumeTerminalColorSchemeReport(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.inputListeners.size > 0) {\n\t\t\tlet current = data;\n\t\t\tfor (const listener of this.inputListeners) {\n\t\t\t\tconst result = listener(current);\n\t\t\t\tif (result?.consume) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (result?.data !== undefined) {\n\t\t\t\t\tcurrent = result.data;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (current.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdata = current;\n\t\t}\n\n\t\t// Consume terminal cell size responses without blocking unrelated input.\n\t\tif (this.consumeCellSizeResponse(data)) {\n\t\t\treturn;\n\t\t}\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// If focused component is an overlay, verify it's still visible\n\t\t// (visibility can change due to terminal resize or visible() callback)\n\t\tconst focusedOverlay = this.overlayStack.find((o) => o.component === this.focusedComponent);\n\t\tif (focusedOverlay && !this.isOverlayVisible(focusedOverlay)) {\n\t\t\t// Focused overlay is no longer visible, redirect to topmost visible overlay\n\t\t\tconst topVisible = this.getTopmostVisibleOverlay();\n\t\t\tif (topVisible) {\n\t\t\t\tthis.setFocus(topVisible.component);\n\t\t\t} else {\n\t\t\t\tthis.setFocusInternal({ component: focusedOverlay.preFocus, overlayFocusRestore: \"preserve\" });\n\t\t\t}\n\t\t}\n\n\t\tconst focusIsOverlay = this.overlayStack.some((o) => o.component === this.focusedComponent);\n\t\tif (!focusIsOverlay) {\n\t\t\tconst restoreState = this.getVisibleOverlayFocusRestore();\n\t\t\tif (restoreState.status === \"eligible\") {\n\t\t\t\tthis.setFocus(restoreState.overlay.component);\n\t\t\t} else if (restoreState.status === \"blocked\" && restoreState.blockedBy !== this.focusedComponent) {\n\t\t\t\tif (restoreState.resume.status === \"restore-overlay\") {\n\t\t\t\t\tthis.setFocus(restoreState.overlay.component);\n\t\t\t\t} else {\n\t\t\t\t\tthis.clearOverlayFocusRestore();\n\t\t\t\t\tthis.setFocus(restoreState.resume.target);\n\t\t\t\t}\n\t\t\t}\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) {\n\t\t\t// Filter out key release events unless component opts in\n\t\t\tif (isKeyRelease(data) && !this.focusedComponent.wantsKeyRelease) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.focusedComponent.handleInput(data);\n\t\t\t// Keyboard input is latency-sensitive. Avoid the throttled timer path,\n\t\t\t// where even setTimeout(0) can take a full 16 ms tick on Windows.\n\t\t\tthis.requestImmediateRender();\n\t\t}\n\t}\n\n\tprivate consumeOsc11BackgroundResponse(data: string): boolean {\n\t\tif (this.pendingOsc11BackgroundReplies <= 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!isOsc11BackgroundColorResponse(data)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst rgb = parseOsc11BackgroundColor(data);\n\t\tthis.pendingOsc11BackgroundReplies -= 1;\n\t\tconst query = this.pendingOsc11BackgroundQueries.shift();\n\t\tif (query && !query.settled) {\n\t\t\tquery.settled = true;\n\t\t\tif (query.timer) {\n\t\t\t\tclearTimeout(query.timer);\n\t\t\t\tquery.timer = undefined;\n\t\t\t}\n\t\t\tquery.resolve?.(rgb);\n\t\t\tquery.resolve = undefined;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate consumeTerminalColorSchemeReport(data: string): boolean {\n\t\tconst scheme = parseTerminalColorSchemeReport(data);\n\t\tif (!scheme) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (const listener of this.terminalColorSchemeListeners) {\n\t\t\tlistener(scheme);\n\t\t}\n\t\treturn true;\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\t/**\n\t * Resolve overlay layout from options.\n\t * Returns { width, row, col, maxHeight } for rendering.\n\t */\n\tprivate resolveOverlayLayout(\n\t\toptions: OverlayOptions | undefined,\n\t\toverlayHeight: number,\n\t\ttermWidth: number,\n\t\ttermHeight: number,\n\t): { width: number; row: number; col: number; maxHeight: number | undefined } {\n\t\tconst opt = options ?? {};\n\n\t\t// Parse margin (clamp to non-negative)\n\t\tconst margin =\n\t\t\ttypeof opt.margin === \"number\"\n\t\t\t\t? { top: opt.margin, right: opt.margin, bottom: opt.margin, left: opt.margin }\n\t\t\t\t: (opt.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\n\t\t// Available space after margins\n\t\tconst availWidth = Math.max(1, termWidth - marginLeft - marginRight);\n\t\tconst availHeight = Math.max(1, termHeight - marginTop - marginBottom);\n\n\t\t// === Resolve width ===\n\t\tlet width = parseSizeValue(opt.width, termWidth) ?? Math.min(80, availWidth);\n\t\t// Apply minWidth\n\t\tif (opt.minWidth !== undefined) {\n\t\t\twidth = Math.max(width, opt.minWidth);\n\t\t}\n\t\t// Clamp to available space\n\t\twidth = Math.max(1, Math.min(width, availWidth));\n\n\t\t// === Resolve maxHeight ===\n\t\tlet maxHeight = parseSizeValue(opt.maxHeight, termHeight);\n\t\t// Clamp to available space\n\t\tif (maxHeight !== undefined) {\n\t\t\tmaxHeight = Math.max(1, Math.min(maxHeight, availHeight));\n\t\t}\n\n\t\t// Effective overlay height (may be clamped by maxHeight)\n\t\tconst effectiveHeight = maxHeight !== undefined ? Math.min(overlayHeight, maxHeight) : overlayHeight;\n\n\t\t// === Resolve position ===\n\t\tlet row: number;\n\t\tlet col: number;\n\n\t\tif (opt.row !== undefined) {\n\t\t\tif (typeof opt.row === \"string\") {\n\t\t\t\t// Percentage: 0% = top, 100% = bottom (overlay stays within bounds)\n\t\t\t\tconst match = opt.row.match(/^(\\d+(?:\\.\\d+)?)%$/);\n\t\t\t\tif (match) {\n\t\t\t\t\tconst maxRow = Math.max(0, availHeight - effectiveHeight);\n\t\t\t\t\tconst percent = parseFloat(match[1]) / 100;\n\t\t\t\t\trow = marginTop + Math.floor(maxRow * percent);\n\t\t\t\t} else {\n\t\t\t\t\t// Invalid format, fall back to center\n\t\t\t\t\trow = this.resolveAnchorRow(\"center\", effectiveHeight, availHeight, marginTop);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Absolute row position\n\t\t\t\trow = opt.row;\n\t\t\t}\n\t\t} else {\n\t\t\t// Anchor-based (default: center)\n\t\t\tconst anchor = opt.anchor ?? \"center\";\n\t\t\trow = this.resolveAnchorRow(anchor, effectiveHeight, availHeight, marginTop);\n\t\t}\n\n\t\tif (opt.col !== undefined) {\n\t\t\tif (typeof opt.col === \"string\") {\n\t\t\t\t// Percentage: 0% = left, 100% = right (overlay stays within bounds)\n\t\t\t\tconst match = opt.col.match(/^(\\d+(?:\\.\\d+)?)%$/);\n\t\t\t\tif (match) {\n\t\t\t\t\tconst maxCol = Math.max(0, availWidth - width);\n\t\t\t\t\tconst percent = parseFloat(match[1]) / 100;\n\t\t\t\t\tcol = marginLeft + Math.floor(maxCol * percent);\n\t\t\t\t} else {\n\t\t\t\t\t// Invalid format, fall back to center\n\t\t\t\t\tcol = this.resolveAnchorCol(\"center\", width, availWidth, marginLeft);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Absolute column position\n\t\t\t\tcol = opt.col;\n\t\t\t}\n\t\t} else {\n\t\t\t// Anchor-based (default: center)\n\t\t\tconst anchor = opt.anchor ?? \"center\";\n\t\t\tcol = this.resolveAnchorCol(anchor, width, availWidth, marginLeft);\n\t\t}\n\n\t\t// Apply offsets\n\t\tif (opt.offsetY !== undefined) row += opt.offsetY;\n\t\tif (opt.offsetX !== undefined) col += opt.offsetX;\n\n\t\t// Clamp to terminal bounds (respecting margins)\n\t\trow = Math.max(marginTop, Math.min(row, termHeight - marginBottom - effectiveHeight));\n\t\tcol = Math.max(marginLeft, Math.min(col, termWidth - marginRight - width));\n\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\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) {\n\t\t\tthis.renderedOverlayLayouts = [];\n\t\t\treturn lines;\n\t\t}\n\t\tconst result = [...lines];\n\n\t\tfor (const entry of this.overlayStack) entry.bounds = undefined;\n\n\t\t// Pre-render all visible overlays and calculate positions\n\t\tconst rendered: { entry: OverlayStackEntry; overlayLines: string[]; row: number; col: number; w: number }[] = [];\n\t\tlet minLinesNeeded = result.length;\n\n\t\tconst visibleEntries = this.overlayStack.filter((e) => this.isOverlayVisible(e));\n\t\tvisibleEntries.sort((a, b) => a.focusOrder - b.focusOrder);\n\t\tfor (const entry of visibleEntries) {\n\t\t\tconst { component, options } = entry;\n\n\t\t\t// Get layout with height=0 first to determine width and maxHeight\n\t\t\t// (width and maxHeight don't depend on overlay height)\n\t\t\tconst { width, maxHeight } = this.resolveOverlayLayout(options, 0, termWidth, termHeight);\n\n\t\t\t// Render component at calculated width\n\t\t\tlet overlayLines = component.render(width);\n\n\t\t\t// Apply maxHeight if specified\n\t\t\tif (maxHeight !== undefined && overlayLines.length > maxHeight) {\n\t\t\t\toverlayLines = overlayLines.slice(0, maxHeight);\n\t\t\t}\n\n\t\t\t// Get final row/col with actual overlay height\n\t\t\tconst { row, col } = this.resolveOverlayLayout(options, overlayLines.length, termWidth, termHeight);\n\t\t\tentry.bounds = { row, col, width, height: overlayLines.length };\n\n\t\t\trendered.push({ entry, overlayLines, row, col, w: width });\n\t\t\tminLinesNeeded = Math.max(minLinesNeeded, row + overlayLines.length);\n\t\t}\n\t\tthis.renderedOverlayLayouts = rendered.map(({ entry, row, col, w, overlayLines }) => ({\n\t\t\tentry,\n\t\t\trow,\n\t\t\tcol,\n\t\t\twidth: w,\n\t\t\theight: overlayLines.length,\n\t\t}));\n\n\t\t// Pad to at least terminal height so overlays have screen-relative positions.\n\t\t// Excludes maxLinesRendered: the historical high-water mark caused self-reinforcing\n\t\t// inflation that pushed content into scrollback on terminal widen.\n\t\tconst workingHeight = Math.max(result.length, termHeight, minLinesNeeded);\n\n\t\t// Extend result with empty lines if content is too short for overlay placement or working area\n\t\twhile (result.length < workingHeight) {\n\t\t\tresult.push(\"\");\n\t\t}\n\n\t\tconst viewportStart = Math.max(0, workingHeight - termHeight);\n\n\t\t// Composite each overlay\n\t\tfor (const { overlayLines, row, col, w } of rendered) {\n\t\t\tfor (let i = 0; i < overlayLines.length; i++) {\n\t\t\t\tconst idx = viewportStart + row + i;\n\t\t\t\tif (idx >= 0 && idx < result.length) {\n\t\t\t\t\t// Defensive: truncate overlay line to declared width before compositing\n\t\t\t\t\t// (components should already respect width, but this ensures it)\n\t\t\t\t\tconst truncatedOverlayLine =\n\t\t\t\t\t\tvisibleWidth(overlayLines[i]) > w ? sliceByColumn(overlayLines[i], 0, w, true) : overlayLines[i];\n\t\t\t\t\tresult[idx] = this.compositeLineAt(result[idx], truncatedOverlayLine, col, w, termWidth);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\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): { row: number; col: number } | 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\t/**\n\t * Query the terminal's default background color with OSC 11 (`ESC ] 11 ; ? BEL`).\n\t * @param timeoutMs Query timeout in milliseconds.\n\t * @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.\n\t */\n\tqueryTerminalBackgroundColor({ timeoutMs }: { timeoutMs: number }): Promise<RgbColor | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tconst query: PendingOsc11BackgroundQuery = {\n\t\t\t\tsettled: false,\n\t\t\t\tresolve,\n\t\t\t\ttimer: undefined,\n\t\t\t};\n\n\t\t\tquery.timer = setTimeout(() => {\n\t\t\t\tif (query.settled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tquery.settled = true;\n\t\t\t\tquery.timer = undefined;\n\t\t\t\tquery.resolve?.(undefined);\n\t\t\t\tquery.resolve = undefined;\n\t\t\t}, timeoutMs);\n\t\t\tthis.pendingOsc11BackgroundQueries.push(query);\n\t\t\tthis.pendingOsc11BackgroundReplies += 1;\n\t\t\tthis.terminal.write(\"\\x1b]11;?\\x07\");\n\t\t});\n\t}\n\n\t/**\n\t * Query the terminal's color-scheme preference with DSR (`CSI ? 996 n`).\n\t * Terminals that support the color palette notification protocol reply with\n\t * `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.\n\t */\n\tqueryTerminalColorScheme({ timeoutMs }: { timeoutMs: number }): Promise<TerminalColorScheme | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tlet timer: NodeJS.Timeout | undefined;\n\t\t\tlet unsubscribe: () => void = () => {};\n\t\t\tconst settle = (scheme: TerminalColorScheme | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tif (timer) {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\ttimer = undefined;\n\t\t\t\t}\n\t\t\t\tunsubscribe();\n\t\t\t\tresolve(scheme);\n\t\t\t};\n\n\t\t\tunsubscribe = this.onTerminalColorSchemeChange(settle);\n\t\t\ttimer = setTimeout(() => settle(undefined), timeoutMs);\n\t\t\tthis.terminal.write(\"\\x1b[?996n\");\n\t\t});\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
|