/** * Query the terminal and await responses without timeouts. * * Terminal queries (DECRQM, DA1, OSC 11, etc.) share the stdin stream * with keyboard input. Response sequences are syntactically * distinguishable from key events, so the input parser recognizes them * and dispatches them here. * * To avoid timeouts, each query batch is terminated by a DA1 sentinel * (CSI c) — every terminal since VT100 responds to DA1, and terminals * answer queries in order. So: if your query's response arrives before * DA1's, the terminal supports it; if DA1 arrives first, it doesn't. * * Usage: * const [sync, grapheme] = await Promise.all([ * querier.send(decrqm(2026)), * querier.send(decrqm(2027)), * querier.flush(), * ]) * // sync and grapheme are DECRPM responses or undefined if unsupported */ import type { TerminalResponse } from './parse-keypress.js'; /** A terminal query: an outbound request sequence paired with a matcher * that recognizes the expected inbound response. Built by `decrqm()`, * `oscColor()`, `kittyKeyboard()`, etc. */ export type TerminalQuery = { /** Escape sequence to write to stdout */ request: string; /** Recognizes the expected response in the inbound stream */ match: (r: TerminalResponse) => r is T; }; type DecrpmResponse = Extract; type Da1Response = Extract; type Da2Response = Extract; type KittyResponse = Extract; type CursorPosResponse = Extract; type OscResponse = Extract; type XtversionResponse = Extract; /** * DECRQM: request DEC private mode status (CSI ? mode $ p). * Terminal replies with DECRPM (CSI ? mode ; status $ y) or ignores. * @param mode - the DEC private mode number to query. * @returns a query whose response is the DECRPM reply for mode. */ export declare function decrqm(mode: number): TerminalQuery; /** * Primary Device Attributes query (CSI c). Every terminal answers this — * used internally by flush() as a universal sentinel. Call directly if * you want the DA1 params. * @returns a query whose response is the DA1 reply. */ export declare function da1(): TerminalQuery; /** * Secondary Device Attributes query (CSI > c). Returns terminal version. * @returns a query whose response is the DA2 reply. */ export declare function da2(): TerminalQuery; /** * Query current Kitty keyboard protocol flags (CSI ? u). * Terminal replies with CSI ? flags u or ignores. * @returns a query whose response is the Kitty keyboard reply. */ export declare function kittyKeyboard(): TerminalQuery; /** * DECXCPR: request cursor position with DEC-private marker (CSI ? 6 n). * Terminal replies with CSI ? row ; col R. The `?` marker is critical — * the plain DSR form (CSI 6 n → CSI row;col R) is ambiguous with * modified F3 keys (Shift+F3 = CSI 1;2 R, etc.). * @returns a query whose response is the cursor-position reply. */ export declare function cursorPosition(): TerminalQuery; /** * OSC dynamic color query (e.g. OSC 11 for bg color, OSC 10 for fg). * The `?` data slot asks the terminal to reply with the current value. * @param code - the OSC color code to query (10 = fg, 11 = bg, etc.). * @returns a query whose response is the OSC color reply. */ export declare function oscColor(code: number): TerminalQuery; /** * XTVERSION: request terminal name/version (CSI > 0 q). * Terminal replies with DCS > | name ST (e.g. "xterm.js(5.5.0)") or ignores. * This survives SSH — the query goes through the pty, not the environment, * so it identifies the *client* terminal even when TERM_PROGRAM isn't * forwarded. Used to detect xterm.js for wheel-scroll compensation. * @returns a query whose response is the XTVERSION reply. */ export declare function xtversion(): TerminalQuery; /** * Sends terminal queries to stdout and resolves their responses, using a * flush() sentinel barrier so queries never time out. */ export declare class TerminalQuerier { private stdout; /** * Interleaved queue of queries and sentinels in send order. Terminals * respond in order, so each flush() barrier only drains queries queued * before it — concurrent batches from independent callers stay isolated. */ private queue; constructor(stdout: NodeJS.WriteStream); /** * Send a query and wait for its response. * * Resolves with the response when `query.match` matches an incoming * TerminalResponse, or with `undefined` when a flush() sentinel arrives * before any matching response (meaning the terminal ignored the query). * * Never rejects; never times out on its own. If you never call flush() * and the terminal doesn't respond, the promise remains pending. * @param query - the query to send and await a response for. * @returns the matched response, or undefined when the terminal did not * answer before the next flush() sentinel. */ send(query: TerminalQuery): Promise; /** * Send the DA1 sentinel. Resolves when DA1's response arrives. * * As a side effect, all queries still pending when DA1 arrives are * resolved with `undefined` (terminal didn't respond → doesn't support * the query). This is the barrier that makes send() timeout-free. * * Safe to call with no pending queries — still waits for a round-trip. */ flush(): Promise; /** * Dispatch a response parsed from stdin. Called by App.tsx's * processKeysInBatch for every `kind: 'response'` item. * * Matching strategy: * - First, try to match a pending query (FIFO, first match wins). * This lets callers send(da1()) explicitly if they want the DA1 * params — a separate DA1 write means the terminal sends TWO DA1 * responses. The first matches the explicit query; the second * (unmatched) fires the sentinel. * - Otherwise, if this is a DA1, fire the FIRST pending sentinel: * resolve any queries queued before that sentinel with undefined * (the terminal answered DA1 without answering them → unsupported) * and signal its flush() completion. Only draining up to the first * sentinel keeps later batches intact when multiple callers have * concurrent queries in flight. * - Unsolicited responses (no match, no sentinel) are silently dropped. * @param r - the response parsed from stdin. */ onResponse(r: TerminalResponse): void; } export {}; //# sourceMappingURL=terminal-querier.d.ts.map