π File detail
ink/hooks/use-search-highlight.ts
π― Use case
This file lives under βink/β, which covers Ink terminal UI (layouts, TTY IO, keyboard, renderer components). On the API surface it exposes useSearchHighlight β mainly functions, hooks, or classes. Dependencies touch React UI. It composes internal code from components, dom, instances, and render-to-screen (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import { useContext, useMemo } from 'react' import StdinContext from '../components/StdinContext.js' import type { DOMElement } from '../dom.js' import instances from '../instances.js' import type { MatchPosition } from '../render-to-screen.js'
π€ Exports (heuristic)
useSearchHighlight
π External import roots
Package roots from from "β¦" (relative paths omitted).
react
π₯οΈ Source preview
import { useContext, useMemo } from 'react'
import StdinContext from '../components/StdinContext.js'
import type { DOMElement } from '../dom.js'
import instances from '../instances.js'
import type { MatchPosition } from '../render-to-screen.js'
/**
* Set the search highlight query on the Ink instance. Non-empty β all
* visible occurrences are inverted on the next frame (SGR 7, screen-buffer
* overlay, same damage machinery as selection). Empty β clears.
*
* This is a screen-space highlight β it matches the RENDERED text, not the
* source message text. Works for anything visible (bash output, file paths,
* error messages) regardless of where it came from in the message tree. A
* query that matched in source but got truncated/ellipsized in rendering
* won't highlight; that's acceptable β we highlight what you see.
*/
export function useSearchHighlight(): {
setQuery: (query: string) => void
/** Paint an existing DOM subtree (from the MAIN tree) to a fresh
* Screen at its natural height, scan. Element-relative positions
* (row 0 = element top). Zero context duplication β the element
* IS the one built with all real providers. */
scanElement: (el: DOMElement) => MatchPosition[]
/** Position-based CURRENT highlight. Every frame writes yellow at
* positions[currentIdx] + rowOffset. The scan-highlight (inverse on
* all matches) still runs β this overlays on top. rowOffset tracks
* scroll; positions stay stable (message-relative). null clears. */
setPositions: (
state: {
positions: MatchPosition[]
rowOffset: number
currentIdx: number
} | null,
) => void
} {
useContext(StdinContext) // anchor to App subtree for hook rules
const ink = instances.get(process.stdout)
return useMemo(() => {
if (!ink) {
return {
setQuery: () => {},
scanElement: () => [],
setPositions: () => {},
}
}
return {
setQuery: (query: string) => ink.setSearchHighlight(query),
scanElement: (el: DOMElement) => ink.scanElementSubtree(el),
setPositions: state => ink.setSearchPositions(state),
}
}, [ink])
}