/** * IME cursor anchoring for the composer. * * Ink keeps the real terminal cursor hidden and parks it just below the * dynamic tree (after the status row). IME composition text and candidate * windows anchor to that real cursor cell - VS Code's integrated terminal * positions its hidden IME textarea there, and Windows consoles behave the * same - so CJK input appeared at the bottom of the screen instead of at the * caret. The anchor moves the real cursor onto the caret cell without * touching Ink's relative erase ledger: * * - the displacement is owned: before any foreign write or re-anchor, the * wrapper cancels it (cursor down, column 1), so every writer - Ink's * log-update rewrites, the resize replay, protocol pushes - keeps seeing * the cursor exactly where it was left; * - log-update frame chunks (which start with the erase-line sequence) get * the anchor re-appended inside the same write, so a repaint can never * leave the cursor behind - in particular the caret blink keeps the anchor * stable while an IME composition is open, because the terminal parses the * rewrite and the re-anchor as one atomic update. * * @module @deepseek-ai/dsh-code/render/ime-cursor */ /** Cancel `rows` of owned upward displacement and return to column 1. */ export declare function imeCursorRestore(rows: number): string; /** Move onto the caret cell: `rows` up from Ink's parked row, 0-based column. */ export declare function imeCursorMove(rows: number, column: number): string; /** * Rows between the caret cell and Ink's parked cursor row: the band's bottom * blank row, the editor window rows below the caret, the status footer, and * Ink's own below-frame row. Rows above the composer (gutter, live content) * never enter this distance. */ export declare function imeCursorRowsUp(input: { editorWindowRows: number; caretRowInWindow: number; rowsBelowComposer: number; }): number; /** The installed anchor handle. */ export interface ImeCursorAnchor { /** Anchor on the caret cell: `rows` above Ink's parked row at the 0-based * `column`; `rows <= 0` releases the anchor. */ anchor(rows: number, column: number): void; /** Cancel the displacement, restore the original write path, and detach. */ release(): void; } /** * Take over `stream.write` so the anchor displacement stays invisible to every * other writer. Idempotent per stream: a second install returns the live * handle. Returns `undefined` on non-TTY streams where anchoring is meaningless. */ export declare function installImeCursorAnchor(stream: NodeJS.WriteStream): ImeCursorAnchor | undefined; /** * Keep the real terminal cursor on the composer's caret cell while `active` * (the editable composer). The second effect runs after every commit without * a dep list: frame rewrites restore the anchor themselves, but any other * write (protocol push, resize replay) leaves the cursor at Ink's parked * position, and the next commit re-anchors it. */ export declare function useImeCursorAnchor(active: boolean, rows: number, column: number): void;