libghostty-vt 0.0.0
Loading...
Searching...
No Matches

Find a string in a terminal, including its scrollback. More...

Detailed Description

Find a string in a terminal, including its scrollback.

Search a terminal for a string, covering the active area and scrollback of both the primary and alternate screens.

You need a terminal to search. For a one-shot search, ghostty_search_run() does all of the work. For a find bar over a lot of scrollback, you decide when the work happens.

Example

int main() {
// Create a terminal and fill it with some content to search.
GhosttyTerminal terminal;
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, 80, 24);
assert(result == GHOSTTY_SUCCESS);
const char *lines[] = {
"$ make test\r\n",
"compiling module A... ok\r\n",
"compiling module B... error: missing semicolon\r\n",
"linking... error: undefined symbol\r\n",
"$ grep -n ERROR build.log\r\n",
};
for (size_t i = 0; i < sizeof(lines) / sizeof(lines[0]); i++) {
ghostty_terminal_vt_write(terminal, (const uint8_t *)lines[i],
strlen(lines[i]));
}
// The user opened the find bar, so create a search bound to the
// terminal. It starts idle until it has a needle.
GhosttySearch search;
result = ghostty_search_new(NULL, &search, terminal);
assert(result == GHOSTTY_SUCCESS);
// The user typed a query. Matching is byte-exact except ASCII
// letters, which compare case-insensitively, so "error" also finds
// "ERROR". Retyping just sets the needle again: a changed needle
// restarts the search and an unchanged one keeps its results.
GhosttyString needle = { (const uint8_t *)"error", 5 };
result = ghostty_search_set(search, GHOSTTY_SEARCH_OPT_NEEDLE, &needle);
assert(result == GHOSTTY_SUCCESS);
// Drive the search. Interactive embedders interleave
// ghostty_search_tick() and ghostty_search_feed() with their event
// loop, but for a one-shot search we can just run it to completion.
result = ghostty_search_run(search);
assert(result == GHOSTTY_SUCCESS);
// The total match count, for find bar text like "1 of 3".
size_t total = 0;
&total);
assert(result == GHOSTTY_SUCCESS);
printf("%zu matches for \"error\"\n", total);
// The user pressed Enter, so select the next match. Selection starts
// at the newest match, moves toward older content, and wraps around.
// This scrolls the viewport to the match if it isn't visible, per
// the GHOSTTY_SEARCH_OPT_SELECT_SCROLL policy.
while (true) {
result = ghostty_search_select_next(search);
if (result != GHOSTTY_SUCCESS) break;
// Read the selection state in one call. Index 0 is the newest
// match, so a "k of n" find bar renders index + 1.
size_t idx = 0;
GhosttySelection match = {0};
const GhosttySearchData keys[] = {
};
void *values[] = { &idx, &match };
search, sizeof(keys) / sizeof(keys[0]), keys, values, NULL);
assert(result == GHOSTTY_SUCCESS);
printf("selected %zu of %zu\n", idx + 1, total);
// Wrapped back around to the first match: stop.
if (idx + 1 == total) break;
}
// Each frame while the find bar is open, feed to catch up with any
// terminal changes and then read the viewport matches to draw
// highlights. The list can include matches just past the viewport
// when they share a page with it, so convert each endpoint to
// viewport coordinates and skip matches outside the visible rows.
result = ghostty_search_feed(search);
assert(result == GHOSTTY_SUCCESS);
GhosttySelection viewport_storage[64];
.ptr = viewport_storage,
.cap = sizeof(viewport_storage) / sizeof(viewport_storage[0]),
};
&viewport);
assert(result == GHOSTTY_SUCCESS);
for (size_t i = 0; i < viewport.len; i++) {
terminal, &viewport_storage[i].start, GHOSTTY_POINT_TAG_VIEWPORT,
&start) != GHOSTTY_SUCCESS) continue;
terminal, &viewport_storage[i].end, GHOSTTY_POINT_TAG_VIEWPORT,
&end) != GHOSTTY_SUCCESS) continue;
if (start.y >= 24 || end.y >= 24) continue;
// A real embedder draws a highlight rect from start to end here.
printf("highlight rows %u-%u, cols %u-%u\n",
(unsigned)start.y, (unsigned)end.y,
(unsigned)start.x, (unsigned)end.x);
}
// Closing the find bar. The search borrows the terminal, but the
// two can be freed in either order.
return 0;
}

Full program: c-vt-search/src/main.c

The Search guide covers driving a search, reading matches, lifetime, and threads.

Typedefs

typedef struct GhosttySearchImpl * GhosttySearch

Enumerations

enum  GhosttySearchStatus { GHOSTTY_SEARCH_STATUS_RUNNING = 0 , GHOSTTY_SEARCH_STATUS_FEED_REQUIRED = 1 , GHOSTTY_SEARCH_STATUS_COMPLETE = 2 , GHOSTTY_SEARCH_STATUS_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE }
enum  GhosttySearchScroll { GHOSTTY_SEARCH_SCROLL_IF_NEEDED = 0 , GHOSTTY_SEARCH_SCROLL_NONE = 1 , GHOSTTY_SEARCH_SCROLL_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE }
enum  GhosttySearchData {
  GHOSTTY_SEARCH_DATA_INVALID = 0 , GHOSTTY_SEARCH_DATA_STATUS = 1 , GHOSTTY_SEARCH_DATA_NEEDLE = 2 , GHOSTTY_SEARCH_DATA_TOTAL_MATCHES = 3 ,
  GHOSTTY_SEARCH_DATA_SELECTED_INDEX = 4 , GHOSTTY_SEARCH_DATA_SELECTED_MATCH = 5 , GHOSTTY_SEARCH_DATA_MATCHES = 6 , GHOSTTY_SEARCH_DATA_VIEWPORT_MATCHES = 7 ,
  GHOSTTY_SEARCH_DATA_SELECT_SCROLL = 8 , GHOSTTY_SEARCH_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE
}
enum  GhosttySearchOption { GHOSTTY_SEARCH_OPT_INVALID = 0 , GHOSTTY_SEARCH_OPT_NEEDLE = 1 , GHOSTTY_SEARCH_OPT_SELECT_SCROLL = 4 , GHOSTTY_SEARCH_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE }

Functions

GHOSTTY_API GhosttyResult ghostty_search_new (const GhosttyAllocator *allocator, GhosttySearch *out_search, GhosttyTerminal terminal)
GHOSTTY_API void ghostty_search_free (GhosttySearch search)
GHOSTTY_API GhosttyResult ghostty_search_tick (GhosttySearch search, GhosttySearchStatus *out_status)
GHOSTTY_API GhosttyResult ghostty_search_feed (GhosttySearch search)
GHOSTTY_API GhosttyResult ghostty_search_run (GhosttySearch search)
GHOSTTY_API GhosttyResult ghostty_search_select_next (GhosttySearch search)
GHOSTTY_API GhosttyResult ghostty_search_select_prev (GhosttySearch search)
GHOSTTY_API GhosttyResult ghostty_search_set (GhosttySearch search, GhosttySearchOption option, const void *value)
GHOSTTY_API GhosttyResult ghostty_search_get (GhosttySearch search, GhosttySearchData data, void *value)
GHOSTTY_API GhosttyResult ghostty_search_get_multi (GhosttySearch search, size_t count, const GhosttySearchData *keys, void **values, size_t *out_written)

Typedef Documentation

◆ GhosttySearch

typedef struct GhosttySearchImpl* GhosttySearch

Opaque handle to a terminal search.

A search is bound to the terminal it was created with. It borrows the terminal, so it never frees it, and the search must be freed with ghostty_search_free(). If the terminal is freed first, the search detects this: calls that need the terminal fail cleanly and the search can still be freed.

Examples
c-vt-search/src/main.c.

Definition at line 287 of file types.h.

Enumeration Type Documentation

◆ GhosttySearchData

Data fields readable with ghostty_search_get(). The output value type is documented per field.

All reads reflect the terminal's active screen as of the last feed. When the running application switches to the alternate screen, the next feed switches counts, matches, and selection to that screen's results. Primary screen results, including completed scrollback searches, are retained and restored on the way back.

Enumerator
GHOSTTY_SEARCH_DATA_INVALID 

Not a real data type. ghostty_search_get() returns GHOSTTY_INVALID_VALUE for it. Its value is 0, so a zeroed or uninitialized variable is never mistaken for a real data type.

GHOSTTY_SEARCH_DATA_STATUS 

Current search status: GhosttySearchStatus*.

GHOSTTY_SEARCH_DATA_NEEDLE 

The needle this search is looking for: GhosttyString*. The bytes are borrowed from the search and remain valid until the needle is changed or the search is freed. Returns GHOSTTY_NO_VALUE when no needle is set.

GHOSTTY_SEARCH_DATA_TOTAL_MATCHES 

Total matches found so far on the active screen: size_t*. Zero until the first feed.

GHOSTTY_SEARCH_DATA_SELECTED_INDEX 

Index of the selected match: size_t*. This indexes the newest to oldest ordering of GHOSTTY_SEARCH_DATA_MATCHES, where 0 is the newest match, so a "k of n" find bar renders index + 1 of GHOSTTY_SEARCH_DATA_TOTAL_MATCHES. Returns GHOSTTY_NO_VALUE when nothing is selected.

GHOSTTY_SEARCH_DATA_SELECTED_MATCH 

The selected match: GhosttySelection*. This is an untracked snapshot with standard GhosttySelection lifetime rules. Returns GHOSTTY_NO_VALUE when nothing is selected.

GHOSTTY_SEARCH_DATA_MATCHES 

All matches on the active screen, ordered newest to oldest, from the bottom of the active area up through scrollback: GhosttySelectionBuffer*. Set ptr to NULL with cap 0 to query the required capacity. An undersized buffer returns GHOSTTY_OUT_OF_SPACE with the required capacity in len.

GHOSTTY_SEARCH_DATA_VIEWPORT_MATCHES 

Matches on the pages covering the viewport, for drawing highlight rectangles: GhosttySelectionBuffer*. The list is computed during feeds and cached, so it reflects the viewport as of the last feed.

Matches are found a page at a time, so the list can include matches slightly outside the visible viewport when they share a page with it. Ghostty's own renderer behaves the same way. Converting each match to viewport coordinates with ghostty_terminal_point_from_grid_ref() clips this naturally: skip matches that fail the conversion or whose row is beyond the visible row count.

GHOSTTY_SEARCH_DATA_SELECT_SCROLL 

Current scroll policy: GhosttySearchScroll*.

Examples
c-vt-search/src/main.c.

Definition at line 98 of file search.h.

◆ GhosttySearchOption

Options writable with ghostty_search_set(). The value type, and what a NULL value means, is documented per option.

Enumerator
GHOSTTY_SEARCH_OPT_INVALID 

Not a real option. ghostty_search_set() returns GHOSTTY_INVALID_VALUE for it. Its value is 0, so a zeroed or uninitialized variable is never mistaken for a real option.

GHOSTTY_SEARCH_OPT_NEEDLE 

Set the needle to search for: const GhosttyString*. The bytes are copied, so your memory does not need to outlive the call. Matching is byte-exact except ASCII letters, which compare case-insensitively.

Changing the needle restarts the search from scratch and drops all results. As an exception, setting a needle equal to the current one (compared the same way as matching) keeps existing results, so find bars can resubmit freely. A NULL or empty value clears the needle and returns the search to idle.

Replacing or clearing a needle releases tracked state held within the terminal, so you must serialize this with all other access to the same terminal. Returns GHOSTTY_INVALID_VALUE after the terminal was freed.

GHOSTTY_SEARCH_OPT_SELECT_SCROLL 

Set the scroll policy applied by ghostty_search_select_next() and ghostty_search_select_prev(): const GhosttySearchScroll*. The policy persists until changed. A NULL value resets it to GHOSTTY_SEARCH_SCROLL_IF_NEEDED. This only modifies search-owned state and never reads the terminal.

Definition at line 176 of file search.h.

◆ GhosttySearchScroll

Scroll policy applied when a match becomes selected via ghostty_search_select_next() or ghostty_search_select_prev().

Enumerator
GHOSTTY_SEARCH_SCROLL_IF_NEEDED 

Scroll the viewport so the match is visible, only if it is not already visible. This is the default.

GHOSTTY_SEARCH_SCROLL_NONE 

Never scroll the viewport.

Definition at line 75 of file search.h.

◆ GhosttySearchStatus

Progress state of a search.

Enumerator
GHOSTTY_SEARCH_STATUS_RUNNING 

ghostty_search_tick() can make progress without terminal access.

GHOSTTY_SEARCH_STATUS_FEED_REQUIRED 

Blocked until ghostty_search_feed(). This is also the state right after a needle is set, since the search has not yet seen the terminal.

GHOSTTY_SEARCH_STATUS_COMPLETE 

Caught up with the terminal state as of the last feed. This never means finished forever, since later terminal writes require another feed to be seen. A search with no needle set also reports complete, since there is nothing to look for.

Definition at line 45 of file search.h.

Function Documentation

◆ ghostty_search_feed()

GHOSTTY_API GhosttyResult ghostty_search_feed ( GhosttySearch search)

Read the terminal to update the search.

Each feed catches the search up with the terminal: it reconciles the tracked screens against the live ones, re-scans the active area, refreshes the viewport match list, gives the scrollback searcher its next chunk of data, and prunes results that scrollback eviction invalidated. Feeding is also the only way the search learns about terminal changes, so keep feeding periodically while the search is in use, even after it reports complete.

This reads the terminal, so you must serialize it with all other access to the same terminal. Each call does a bounded amount of work so that any caller-held terminal lock is held only briefly.

Parameters
searchSearch handle (NULL returns GHOSTTY_INVALID_VALUE)
Returns
GHOSTTY_SUCCESS on success, or GHOSTTY_INVALID_VALUE if search is NULL or the terminal was freed
Examples
c-vt-search/src/main.c.

◆ ghostty_search_free()

GHOSTTY_API void ghostty_search_free ( GhosttySearch search)

Free a search.

If the bound terminal is still alive, this releases tracked state the search holds within it, so you must serialize this call with all other access to the same terminal. If the terminal was already freed, the search has been detached and this releases only search-owned memory. Passing NULL is allowed and is a no-op.

Parameters
searchSearch handle to free
Examples
c-vt-search/src/main.c.

◆ ghostty_search_get()

GHOSTTY_API GhosttyResult ghostty_search_get ( GhosttySearch search,
GhosttySearchData data,
void * value )

Read a data field from a search.

The output value type depends on data and is documented by GhosttySearchData. This never reads the terminal, so it is safe to call while another thread modifies the terminal. Returned selections are untracked snapshots with standard GhosttySelection lifetime rules.

Parameters
searchSearch handle (NULL returns GHOSTTY_INVALID_VALUE)
dataData field to read
valueOutput pointer whose type depends on data
Returns
GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the requested data has no value, GHOSTTY_OUT_OF_SPACE if a provided GhosttySelectionBuffer is too small (required capacity in its len), GHOSTTY_OUT_OF_MEMORY if collecting viewport matches fails, GHOSTTY_INVALID_VALUE if Search or value is invalid, or GHOSTTY_UNSUPPORTED if data is not known to this version of the library
Examples
c-vt-search/src/main.c.

◆ ghostty_search_get_multi()

GHOSTTY_API GhosttyResult ghostty_search_get_multi ( GhosttySearch search,
size_t count,
const GhosttySearchData * keys,
void ** values,
size_t * out_written )

Read multiple data fields from a search in a single call.

Use this when each call into the library is expensive, for example from WebAssembly or from another language through its foreign function interface. It reads every key in one call. From C in the same process it costs the same as calling ghostty_search_get() once per key, so use whichever reads better.

Each entry in values must point to storage of the type documented by the corresponding GhosttySearchData key.

If any individual read fails, the function returns that error and writes the index of the failing key to out_written when out_written is non-NULL. Earlier keys have already been written. On success, out_written receives count when non-NULL. A too-small GhosttySelectionBuffer stops the batch with GHOSTTY_OUT_OF_SPACE at that key's index with the required capacity in its len, so order buffer-valued keys after scalar keys.

Parameters
searchSearch handle (NULL returns GHOSTTY_INVALID_VALUE)
countNumber of data fields to read
keysData fields to read (must not be NULL)
valuesOutput pointers corresponding to keys (must not be NULL)
out_writtenOptional number of fields read, or failing index on error
Returns
GHOSTTY_SUCCESS if every key succeeds. Otherwise the result of the first key that failed, for example GHOSTTY_UNSUPPORTED for a key that is not known to this version of the library.
Examples
c-vt-search/src/main.c.

◆ ghostty_search_new()

GHOSTTY_API GhosttyResult ghostty_search_new ( const GhosttyAllocator * allocator,
GhosttySearch * out_search,
GhosttyTerminal terminal )

Create a search bound to a terminal.

The search borrows the terminal and never frees it. The search and the terminal can be freed in either order; see ghostty_search_free().

The search starts idle with no needle: it reports GHOSTTY_SEARCH_STATUS_COMPLETE and finds nothing. Set GHOSTTY_SEARCH_OPT_NEEDLE to start searching.

Creation is cheap and does not read terminal contents, but it registers the search with the terminal so the two can be freed in any order. You must serialize this call with all other access to the same terminal.

Parameters
allocatorAllocator, or NULL for the default allocator
out_searchReceives the created search handle
terminalTerminal to bind the search to
Returns
GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if out_search or terminal is invalid, or GHOSTTY_OUT_OF_MEMORY if allocation fails
Examples
c-vt-search/src/main.c.

◆ ghostty_search_run()

GHOSTTY_API GhosttyResult ghostty_search_run ( GhosttySearch search)

Feed and tick until the search is caught up with the terminal.

This is a blocking convenience for one-shot and single-threaded embedders. It always performs at least one feed, so it also picks up any terminal changes since the last feed, then loops until the status is GHOSTTY_SEARCH_STATUS_COMPLETE. Searching a large scrollback can take a while, so interactive embedders should drive ghostty_search_tick() and ghostty_search_feed() themselves.

This reads the terminal for the entire call, so you must serialize it with all other access to the same terminal.

Parameters
searchSearch handle (NULL returns GHOSTTY_INVALID_VALUE)
Returns
GHOSTTY_SUCCESS on success, or GHOSTTY_INVALID_VALUE if search is NULL or the terminal was freed
Examples
c-vt-search/src/main.c.

◆ ghostty_search_select_next()

GHOSTTY_API GhosttyResult ghostty_search_select_next ( GhosttySearch search)

Select the next match, moving toward older content.

"Next" goes from the bottom of the screen upward into history, the direction a search from the prompt usually wants. After the oldest match, selection wraps around to the newest one.

You can call this at any time, even if the terminal changed since the last feed, because it first brings the search up to date with the terminal. The viewport then scrolls to the selected match as set by GHOSTTY_SEARCH_OPT_SELECT_SCROLL. This reads the terminal, so you must serialize it with all other access to the same terminal.

A find bar typically calls this when the user presses Enter, then reads the selected match to highlight it:

GhosttySelection match = {0};
// Highlight `match` and show its position in the find bar.
}
@ GHOSTTY_SUCCESS
Definition types.h:145
GHOSTTY_API GhosttyResult ghostty_search_select_next(GhosttySearch search)
GHOSTTY_API GhosttyResult ghostty_search_get(GhosttySearch search, GhosttySearchData data, void *value)
@ GHOSTTY_SEARCH_DATA_SELECTED_MATCH
Definition search.h:137
Parameters
searchSearch handle (NULL returns GHOSTTY_INVALID_VALUE)
Returns
GHOSTTY_SUCCESS if a match is now selected, GHOSTTY_NO_VALUE if there are no matches, GHOSTTY_OUT_OF_MEMORY if allocation fails, or GHOSTTY_INVALID_VALUE if Search is NULL or the terminal was freed
Examples
c-vt-search/src/main.c.

◆ ghostty_search_select_prev()

GHOSTTY_API GhosttyResult ghostty_search_select_prev ( GhosttySearch search)

Select the previous match, moving toward newer content.

This is the opposite direction of ghostty_search_select_next(). After the newest match, selection wraps around to the oldest one. Everything else, including scrolling and thread safety, works the same as ghostty_search_select_next().

Parameters
searchSearch handle (NULL returns GHOSTTY_INVALID_VALUE)
Returns
GHOSTTY_SUCCESS if a match is now selected, GHOSTTY_NO_VALUE if there are no matches, GHOSTTY_OUT_OF_MEMORY if allocation fails, or GHOSTTY_INVALID_VALUE if Search is NULL or the terminal was freed

◆ ghostty_search_set()

GHOSTTY_API GhosttyResult ghostty_search_set ( GhosttySearch search,
GhosttySearchOption option,
const void * value )

Write an option to a search.

The value type, and what a NULL value means, depends on the option and is documented by GhosttySearchOption. GHOSTTY_SEARCH_OPT_NEEDLE touches the terminal, so you must serialize it with all other access to the same terminal. GHOSTTY_SEARCH_OPT_SELECT_SCROLL only modifies search-owned state.

To move between matches, use ghostty_search_select_next() and ghostty_search_select_prev().

Parameters
searchSearch handle (NULL returns GHOSTTY_INVALID_VALUE)
optionOption to write
valuePointer to the input value for the option. The meaning of NULL is documented per option.
Returns
GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY if allocation fails, GHOSTTY_INVALID_VALUE if Search or value is invalid or the option needs a terminal that was already freed, or GHOSTTY_UNSUPPORTED if option is not known to this version of the library
Examples
c-vt-search/src/main.c.

◆ ghostty_search_tick()

GHOSTTY_API GhosttyResult ghostty_search_tick ( GhosttySearch search,
GhosttySearchStatus * out_status )

Make a bounded amount of search progress.

This only works on data the search has already copied and never reads the terminal, so it is safe to call while another thread modifies the terminal. Call it in a loop while the status is GHOSTTY_SEARCH_STATUS_RUNNING. When the status becomes GHOSTTY_SEARCH_STATUS_FEED_REQUIRED, call ghostty_search_feed() to unblock it.

Parameters
searchSearch handle (NULL returns GHOSTTY_INVALID_VALUE)
[out]out_statusReceives the status after the tick (may be NULL)
Returns
GHOSTTY_SUCCESS on success, or GHOSTTY_INVALID_VALUE if search is NULL or the terminal was freed