Skip to content

input: Expose editor search API - #2533

Merged
huacnlee merged 8 commits into
longbridge:mainfrom
calmondev:feat/input-search-api
Sep 17, 2026
Merged

huacnlee merged 8 commits into
longbridge:mainfrom
calmondev:feat/input-search-api

Conversation

@calmondev

@calmondev calmondev commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Description

An application that wants its own search UI on the editor — keeping the editor's matching, highlighting, scrolling and replacing, but drawing the search bar itself — had no supported way to do it: search could only be switched on or off with .searchable(true), and everything else lived inside the built-in SearchPanel.

Since this PR was opened, the engine moved into gpui-base and its API became public on the editor state (#2691, #2716, #2932, #2953, #2955, #3013): set_search_query, close_search, next_search_match, previous_search_match, the replace methods and search_session(). This PR, rebased onto that, closes the gaps that still tied a search to the built-in panel and documents the custom-UI path.

Highlights without the panel

Match highlights were painted only while search_session.open, which also shows the panel, so a query set through set_search_query counted matches the editor never showed. SearchSession now tracks active separately from open: opening the panel or setting a query activates the session, close_search ends it, and the element highlights while it is active. The panel keeps keying its own visibility on open. SearchSession is #[non_exhaustive], since it gains fields; build it with Default.

The shortcut reaches the application

An editor that is not searchable swallowed Search and Replace instead of propagating them, so a parent view could not bind Ctrl-F / Cmd-F to its own field. Both handlers now cx.propagate() when the editor is not searchable. searchable is no longer #[doc(hidden)] and is documented for what it gates: the built-in panel and its shortcut, not the search API.

current()

SearchMatcher::current() reports the current match as Option<usize>, so "no match" is not mistaken for the first one; current_match_index() stays.

Docs

The Editor guide gains a "Custom search UI" section, in English and Chinese: set_search_query from the application's own field, navigating and describing the matches, replacing, ending with close_search, and taking Ctrl-F / Cmd-F on the view that owns the field.

Breaking Changes

None. SearchSession is now #[non_exhaustive], so it must be built with Default rather than a struct literal; no code in this repository or its examples did otherwise.

How to Test

  • cargo test -p gpui-base -p gpui-component --lib -- search: covers the session staying active after set_search_query without the panel, the shortcut reaching a host view when the editor is not searchable and opening the panel when it is, and the match label/current() semantics.
  • cargo run -p example-editor: the built-in panel behaves as before, including resuming its last query on reopen.

The rebase, the Base changes and the documentation were written with Claude Code and reviewed by hand; the original API proposal is by @calmondev.

calmondev and others added 5 commits July 4, 2026 02:29
The search state and the public search API this branch introduced were
implemented on main in the meantime (longbridge#2691, longbridge#2716, longbridge#2932, longbridge#2953, longbridge#2955,
longbridge#3013), so the conflicting files take main's version. The example and
the documentation are ported to the new API in follow-up commits.
Main already exposes the search engine on the editor state, but two things
still tied it to the built-in panel. Match highlights were painted only
while `search_session.open`, which also shows the panel, so a query set
through `set_search_query` counted matches the editor never showed. And an
editor that is not `searchable` swallowed `Search` and `Replace` without
propagating them, so a parent could not bind `Ctrl-F` to its own field.

`SearchSession` now tracks `active` separately from `open`: opening the
panel or setting a query activates the session, `close_search` ends it,
and the element highlights while it is active. The two action handlers
propagate when the editor is not searchable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ports the custom search example from the branch to the `examples/`
package layout and the `EditorState` API, and documents the custom search
UI in the Editor guide, in English and Chinese.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@huacnlee
huacnlee force-pushed the feat/input-search-api branch from 3e61573 to 049f7bf Compare September 17, 2026 02:36
@huacnlee

Copy link
Copy Markdown
Member

Thanks for the PR, and sorry it sat for so long. I've merged main into this branch to resolve the conflicts. Since July the search state moved into gpui-base (InputBaseState::search_session) and the public API this PR proposed landed there through #2691, #2716, #2932, #2953, #2955 and #3013 (set_search_query, close_search, next_search_match, previous_search_match, replace_current_search_match, replace_all_search_matches, search_session().matcher.{len, current_match_index, label}), so the conflicting files take main's version.

Two things this PR wanted were still missing on main, and are added in 72310009:

  • Match highlights were painted only while the built-in panel was open, so a query set from a custom UI counted matches the editor never showed. SearchSession now tracks active separately from open.
  • An editor that is not searchable swallowed Ctrl-F / Cmd-F instead of propagating it, so a parent could not bind the shortcut to its own field.

049f7bfd ports the custom search example to the examples/ package layout (cargo run -p example-custom-search) and the EditorState API, and documents the custom search UI in the Editor guide in both languages.

Implementation in these commits was AI-generated and reviewed.

🤖 Generated with Claude Code

Icon-only buttons carry a tooltip, as the Design Guides ask.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@huacnlee

Copy link
Copy Markdown
Member

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

@huacnlee huacnlee changed the title feat(input): expose editor search api for custom uis input: Expose editor search API Sep 17, 2026
@huacnlee
huacnlee force-pushed the feat/input-search-api branch from 32593ff to 7f43c58 Compare September 17, 2026 03:11
…able`

`SearchMatcher::current` reports the current match as `Option<usize>`,
so "no match" is not mistaken for the first one; `current_match_index`
stays. `SearchSession` is `#[non_exhaustive]`, since it gains fields;
build it with `Default`. And `searchable` is documented for what it
gates — the built-in panel and its shortcut, not the search API —
instead of hidden.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@huacnlee
huacnlee force-pushed the feat/input-search-api branch from 7f43c58 to 5c87859 Compare September 17, 2026 03:19
The Editor guide's custom search section shows the whole path already.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@huacnlee
huacnlee enabled auto-merge (squash) September 17, 2026 03:22
@huacnlee
huacnlee merged commit fb26e61 into longbridge:main Sep 17, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants