import type { TerminalRenderPlane, TerminalRenderPlanes } from "../../core/render-plane.js"; import type { Terminal } from "../../core/types.js"; import type { WidthProvider } from "../../core/buffer/width.js"; import { type CreateTuiProfilerOptions } from "../../observability/tui-profiler.js"; export type RenderRect = Readonly<{ x: number; y: number; w: number; h: number; }>; export type RenderStack = Readonly<{ id: string; parent: RenderStack | null; zIndex: number; order: number; }>; export type RenderNode = Readonly<{ id: string; stack: RenderStack; plane: TerminalRenderPlane; zIndex: number; order: number; rect: RenderRect | null; rectY0: number; rectY1: number; /** * dirtyRows are absolute terminal rows for this node's plane. * Components must ignore rows outside their rect. */ paint: (dirtyRows?: readonly number[]) => void; }>; export type RenderManager = Readonly<{ rootStack: RenderStack; createStack: (parent: RenderStack, zIndex: number) => RenderStack; invalidatePlane: (plane: TerminalRenderPlane) => void; /** * Dangerous escape hatch: shifts whole terminal rows for the target plane, not a * component-local region. Only call when the active renderer consumes terminal * scrollOperations or when the caller repaints the whole affected viewport. */ unsafeScrollPlaneRows: (plane: TerminalRenderPlane, startY: number, endY: number, delta: number) => void; register: (node: { stack: RenderStack; plane?: TerminalRenderPlane; zIndex?: number; rect?: RenderRect | null; paint: (dirtyRows?: readonly number[]) => void; }) => RenderNode; update: (id: string, next: Partial<{ stack: RenderStack; plane: TerminalRenderPlane; zIndex: number; rect: RenderRect | null; /** * Consumed synchronously during update() and must not be retained. * Callers may pass scratch arrays for hot-path invalidation. * Rows are absolute terminal Y coordinates for the node's plane. */ dirtyRowsHint: readonly number[]; paint: (dirtyRows?: readonly number[]) => void; }>) => void; /** * Hot-path dirty row marker for stable nodes. Consumed synchronously and does * not replace the RenderNode object. * * rows are absolute terminal Y coordinates, not local component row offsets. * For rect-bound nodes, rows outside the node rect are ignored. */ markDirtyRows: (id: string, rows: readonly number[]) => boolean; /** For raw terminal graphics, covered means any overlap by a higher node. */ isRectCoveredByHigherNode: (id: string, rect: RenderRect, options?: Readonly<{ ignoreSamePlane?: boolean; }>) => boolean; higherNodeCoverageRects: (id: string, rect: RenderRect, options?: Readonly<{ ignoreSamePlane?: boolean; }>) => readonly RenderRect[]; unregister: (id: string) => void; render: (options?: { activePlanes?: TerminalRenderPlanes | null; }) => RenderStats | null; dispose: () => void; }>; export type CreateRenderManagerOptions = Readonly<{ profiler?: CreateTuiProfilerOptions; widthProvider?: WidthProvider; }>; export type RowBucketFallback = Readonly<{ plane: TerminalRenderPlane; reason: "dirty-ratio" | "candidate-ratio"; dirtyRows: number; planeNodes: number; candidates?: number; }>; export type RenderStats = Readonly<{ rows: number; scannedNodes: number; paintedNodes: number; candidatePlanes: readonly TerminalRenderPlane[]; rowBucketFallbacks?: readonly RowBucketFallback[]; }>; export declare function createRenderManager(terminal: Terminal, options?: CreateRenderManagerOptions): RenderManager;