/** * Message formatting utilities — extracted from `App.ts`. * * These are pure (or near-pure) functions that turn a chat message * (`role` + raw `content`) into the array of styled lines the custom * screen renderer paints. Extracting them: * * - shrinks `App.ts` (the 3.2k-LoC render-loop host) by ~600 LoC, * - makes the formatter unit-testable in isolation (no App state), * - lets the quick-chat / ACP surfaces reuse the same rendering if * they ever need to paint formatted assistant output. * * Convention: a `RenderedLine` carries the already-ANSI-styled `text` * plus a `raw` flag — when true, the screen writer must NOT apply the * per-message default style (the line has its own colours baked in). * This is how code blocks and headings keep their syntax-highlight * palette instead of being washed by the body colour. */ export interface RenderedLine { text: string; style: string; raw?: boolean; } /** * Mutable counter passed by reference into `formatMessage` so the caller * (App, during a render pass) can keep a running code-block index across * messages — that index is what `/copy [n]` refers to. * * Modelled as an object (not a return value) because `formatMessage` * appends to an output array AND increments the counter; returning both * would force every caller to thread a tuple through, and the render * loop already mutates `this.codeBlockCounter` in place. */ export interface BlockCounter { current: number; } /** * Apply inline markdown formatting (bold, italic, inline code, strikethrough) * to a single line. Returns the styled string plus a flag telling the caller * whether any formatting was applied — the caller uses that to decide whether * to mark the line `raw` (so the renderer doesn't double-apply the body colour). */ export declare function applyInlineMarkdown(text: string): { formatted: string; hasFormatting: boolean; }; /** * Word-wrap `text` to `maxWidth` columns. Words wider than `maxWidth` * (typically long file paths with no spaces) are hard-broken across lines. * * Note: this is NOT the `wordWrap` exported from `ansi.ts` — that one * lets over-width words overflow. This chat-flavoured variant slices * them so a 200-char path doesn't blow out the right margin. */ export declare function wordWrap(text: string, maxWidth: number): string[]; /** * Format a chunk of prose (text between code fences) into styled lines. * * Recognises, per line: * - ATX headings (`#` … `######`) * - horizontal rules (`---`, `***`, `___`) * - blockquotes (`> …`, nestable) * - bullet/numbered list items (`-`, `*`, `1.`) * - plain text, with inline markdown + word-wrap * * `firstPrefix` / `firstStyle` apply only to the first output line — the * caller uses that to attach the role indicator (▌ for user, ▸ for system); * continuation lines get a blank/generic prefix so wrapped paragraphs stay * visually grouped under the same marker. */ export declare function formatTextLines(text: string, maxWidth: number, firstPrefix: string, firstStyle: string, rawPrefix?: boolean): RenderedLine[]; /** * Format a fenced code block: language label + block number on the first * line, then each source line indented and syntax-highlighted via * `highlightCode`. A trailing blank line separates the block from the * next paragraph. * * `blockNum` is the 1-based index used by `/copy [n]`; omitted when the * caller is rendering a non-chat context (e.g. a paste preview). */ export declare function formatCodeBlock(code: string, lang: string, maxWidth: number, blockNum?: number): RenderedLine[]; /** * Format a full chat message (role + content) into styled lines. * * Walks the content looking for `` ``` ``-fenced code blocks; anything * outside a fence goes through `formatTextLines` (headings, lists, inline * markdown), fenced regions go through `formatCodeBlock`. The fenced-block * regex is non-greedy and stops at the first closing fence, so streaming * input with an as-yet-unclosed fence still renders correctly (the open * tail is treated as plain text until the closer arrives). * * `counter` is incremented once per fenced block encountered — callers * thread the same `BlockCounter` across consecutive `formatMessage` * calls so block numbers are stable across a whole render pass. */ export declare function formatMessage(role: 'user' | 'assistant' | 'system', content: string, maxWidth: number, counter: BlockCounter): RenderedLine[];