import { type Rectangle } from './layout/geometry.js';
import { type Screen, type StylePool } from './screen.js';
/**
 * Collects write/blit/clear/clip operations from the render tree, then
 * applies them to a Screen buffer in `get()`. The Screen is what gets
 * diffed against the previous frame to produce terminal updates.
 */
type Options = {
    width: number;
    height: number;
    stylePool: StylePool;
    /**
     * Screen to render into. Will be reset before use.
     * For double-buffering, pass a reusable screen. Otherwise create a new one.
     */
    screen: Screen;
};
export type Operation = WriteOperation | ClipOperation | UnclipOperation | BlitOperation | ClearOperation | NoSelectOperation | ShiftOperation;
type WriteOperation = {
    type: 'write';
    x: number;
    y: number;
    text: string;
    /**
     * Per-line soft-wrap flags, parallel to text.split('\n'). softWrap[i]=true
     * means line i is a continuation of line i-1 (the `\n` before it was
     * inserted by word-wrap, not in the source). Index 0 is always false.
     * Undefined means the producer didn't track wrapping (e.g. fills,
     * raw-ansi) — the screen's per-row bitmap is left untouched.
     */
    softWrap?: boolean[];
};
type ClipOperation = {
    type: 'clip';
    clip: Clip;
};
export type Clip = {
    x1: number | undefined;
    x2: number | undefined;
    y1: number | undefined;
    y2: number | undefined;
};
type UnclipOperation = {
    type: 'unclip';
};
type BlitOperation = {
    type: 'blit';
    src: Screen;
    x: number;
    y: number;
    width: number;
    height: number;
};
type ShiftOperation = {
    type: 'shift';
    top: number;
    bottom: number;
    n: number;
};
type ClearOperation = {
    type: 'clear';
    region: Rectangle;
    /**
     * Set when the clear is for an absolute-positioned node's old bounds.
     * Absolute nodes overlay normal-flow siblings, so their stale paint is
     * what an earlier sibling's clean-subtree blit wrongly restores from
     * prevScreen. Normal-flow siblings' clears don't have this problem —
     * their old position can't have been painted on top of a sibling.
     */
    fromAbsolute?: boolean;
};
type NoSelectOperation = {
    type: 'noSelect';
    region: Rectangle;
};
export default class Output {
    width: number;
    height: number;
    private readonly stylePool;
    private screen;
    private readonly operations;
    private charCache;
    constructor(options: Options);
    /**
     * Reuse this Output for a new frame. Zeroes the screen buffer, clears
     * the operation list (backing storage is retained), and caps charCache
     * growth. Preserving charCache across frames is the main win — most
     * lines don't change between renders, so tokenize + grapheme clustering
     * becomes a cache hit.
     */
    reset(width: number, height: number, screen: Screen): void;
    /**
     * Copy cells from a source screen region (blit = block image transfer).
     */
    blit(src: Screen, x: number, y: number, width: number, height: number): void;
    /**
     * Shift full-width rows within [top, bottom] by n. n > 0 = up. Mirrors
     * what DECSTBM + SU/SD does to the terminal. Paired with blit() to reuse
     * prevScreen content during pure scroll, avoiding full child re-render.
     */
    shift(top: number, bottom: number, n: number): void;
    /**
     * Clear a region by writing empty cells. Used when a node shrinks to
     * ensure stale content from the previous frame is removed.
     */
    clear(region: Rectangle, fromAbsolute?: boolean): void;
    /**
     * Mark a region as non-selectable (excluded from fullscreen text
     * selection copy + highlight). Used by <NoSelect> to fence off
     * gutters (line numbers, diff sigils). Applied AFTER blit/write so
     * the mark wins regardless of what's blitted into the region.
     */
    noSelect(region: Rectangle): void;
    write(x: number, y: number, text: string, softWrap?: boolean[]): void;
    clip(clip: Clip): void;
    unclip(): void;
    get(): Screen;
}
export {};
