| 74 | onFrame?: (event: FrameEvent) => void; |
| 75 | }; |
| 76 | export default class Ink { |
| 77 | private readonly log: LogUpdate; |
| 78 | private readonly terminal: Terminal; |
| 79 | private scheduleRender: (() => void) & { |
| 80 | cancel?: () => void; |
| 81 | }; |
| 82 | // Ignore last render after unmounting a tree to prevent empty output before exit |
| 83 | private isUnmounted = false; |
| 84 | private isPaused = false; |
| 85 | private readonly container: FiberRoot; |
| 86 | private rootNode: dom.DOMElement; |
| 87 | readonly focusManager: FocusManager; |
| 88 | private renderer: Renderer; |
| 89 | private readonly stylePool: StylePool; |
| 90 | private charPool: CharPool; |
| 91 | private hyperlinkPool: HyperlinkPool; |
| 92 | private exitPromise?: Promise<void>; |
| 93 | private restoreConsole?: () => void; |
| 94 | private restoreStderr?: () => void; |
| 95 | private readonly unsubscribeTTYHandlers?: () => void; |
| 96 | private terminalColumns: number; |
| 97 | private terminalRows: number; |
| 98 | private currentNode: ReactNode = null; |
| 99 | private frontFrame: Frame; |
| 100 | private backFrame: Frame; |
| 101 | private lastPoolResetTime = performance.now(); |
| 102 | private drainTimer: ReturnType<typeof setTimeout> | null = null; |
| 103 | private lastYogaCounters: { |
| 104 | ms: number; |
| 105 | visited: number; |
| 106 | measured: number; |
| 107 | cacheHits: number; |
| 108 | live: number; |
| 109 | } = { |
| 110 | ms: 0, |
| 111 | visited: 0, |
| 112 | measured: 0, |
| 113 | cacheHits: 0, |
| 114 | live: 0 |
| 115 | }; |
| 116 | private altScreenParkPatch: Readonly<{ |
| 117 | type: 'stdout'; |
| 118 | content: string; |
| 119 | }>; |
| 120 | // Text selection state (alt-screen only). Owned here so the overlay |
| 121 | // pass in onRender can read it and App.tsx can update it from mouse |
| 122 | // events. Public so instances.get() callers can access. |
| 123 | readonly selection: SelectionState = createSelectionState(); |
| 124 | // Search highlight query (alt-screen only). Setter below triggers |
| 125 | // scheduleRender; applySearchHighlight in onRender inverts matching cells. |
| 126 | private searchHighlightQuery = ''; |
| 127 | // Position-based highlight. VML scans positions ONCE (via |
| 128 | // scanElementSubtree, when the target message is mounted), stores them |
| 129 | // message-relative, sets this for every-frame apply. rowOffset = |
| 130 | // message's current screen-top. currentIdx = which position is |
| 131 | // "current" (yellow). null clears. Positions are known upfront — |
| 132 | // navigation is index arithmetic, no scan-feedback loop. |
| 133 | private searchPositions: { |
nothing calls this directly
no test coverage detected