agent_ui: Add thread search to the agent panel#54816
Closed
Tahinli wants to merge 12 commits into
Closed
Conversation
Adds the Item and SearchableItem trait impls needed to host a BufferSearchBar targeting the agent panel's thread view. Matches are keyed by (entry_index, byte_range) against each entry's markdown rendering, and the active match's byte position is tracked so that updating the query re-anchors to the nearest remaining match. No UI is wired yet; the bar deployment and rendering come in the next commit.
Wires the standard search::BufferSearchBar into ThreadView: the bar is lazily constructed the first time buffer_search::Deploy fires, bound to the thread view as its searchable target, and rendered inline above the entry list when visible. DivRegistrar routes the rest of the buffer_search actions (next/prev, toggle case, etc.) to the bar so they keep working when focus is inside the conversation area rather than the query editor.
Pushes search matches into each entry's Markdown entities so the actual matched text is highlighted inline, not just the containing entry. find_matches walks UserMessage content, each AssistantMessage chunk, ToolCall labels + content-block outputs, and plan entries, searching each Markdown entity's source independently. Matches carry the owning Markdown handle so update_matches can group per-entity and call set_search_highlights once per markdown. The active match is activated on its own markdown with its per-markdown local index while active highlights on the previously active markdown are cleared, mirroring how markdown_preview_view wires up its own search. Tracks the set of currently-highlighted markdowns on ThreadView so clear_matches and shrinking match sets can wipe the right entities.
Binds the standard buffer-search keys to the new in-thread search: Ctrl+F / the Find key on Linux & Windows, Cmd+F on macOS, and '/' when vim mode is active inside the thread view's editor. Renames test_vim_search_does_not_steal_focus_from_agent_panel to test_vim_slash_deploys_thread_search_not_center_pane to reflect the new expected behavior — pressing '/' now deploys the thread's own search bar instead of silently being swallowed, while still not leaking through to the center pane's BufferSearchBar.
WrappedLineLayout::position_for_index treated an index equal to a soft-wrap boundary as still belonging to the preceding visual line (returning end-of-prev-line instead of start-of-next-line). For callers painting selections or search highlights, this made the reported start.y of a highlight land one line above where the character is actually rendered — which in turn caused Markdown's paint_highlight_range to take its multi-line branch and paint a spurious rectangle from that phantom start to the element's right edge whenever a match began at a wrap boundary. For wrap boundaries the index belongs to the next line; keep the previous strict comparison only for the final synthesized entry whose "line_end_ix" equals self.len() and represents the end-of-text cursor.
Adds a new SearchOptions flag plus supporting UI plumbing so a SearchableItem can opt in to exposing an "include hidden context" toggle in the buffer search bar. The option renders as an eye icon next to Case / Word / Regex when supported_options().include_hidden is true, and otherwise stays hidden for items that don't need it. The flag is read back by callers via BufferSearchBar::search_options(). Release Notes: - N/A
The thread search bar now exposes the new "Include Hidden Context" eye toggle. When it's off, search only indexes visible content so the match counter matches what the user sees on screen. When it's on, search indexes thought chunks and tool-call bodies regardless of expansion, and activating a match inside a collapsed disclosure auto- expands just that section so the highlight is visible. Auto-expanded sections are collapsed back when the toggle flips off or the search bar is dismissed, skipping any thinking blocks the user had expanded themselves. Release Notes: - Added an "Include Hidden Context" toggle to the agent thread search bar that, when enabled, searches thought blocks and collapsed tool-call output and auto-expands the matching section when navigating into it.
Toggling Include Hidden may reveal matches that live inside content that was previously collapsed (e.g. agent thread tool calls and thought blocks). Other searchable items only fold/expand when the active match is activated, so without this the counter ticks up without the user seeing anything new. Await the resulting search and call `activate_current_match` when it completes; mirror the pattern from the query-edit handler. Narrowing toggles (case sensitive, whole word, regex) leave the cursor alone.
Thread search was collecting matches from `UserMessage::content` — a markdown entity used for serialization that is not rendered on screen. The `MessageEditor` that actually renders each past user message never received the highlights, so matches inside user messages were counted but invisible. Introduce a `MatchTarget` enum (`Markdown` or `Editor`) on each match and a `MatchOrigin::UserMessage` variant. For user messages, search the inner `Editor`'s buffer text directly — its text can diverge from the markdown source for image chunks, where the markdown renders `` `Image` `` but the editor renders a mention link, so the editor is the source of truth. Route highlights for editor targets through `highlight_background(HighlightKey::BufferSearchHighlights, ..)` using the same active-vs-inactive color pattern that `BufferSearchBar` uses for normal editor search, and autoscroll the editor to the active match via `request_autoscroll`. `activate_match` re-applies editor highlights on every index change because the color closure captures the active index at insertion time. Release Notes: - Fixed thread search matches inside user messages not being visually highlighted (matches were counted but invisible on screen).
Thread search was indexing `ToolCall.label` — a plain-text markdown — but the visible rendering of an Execute tool call's command is a fenced monospace block. For the pre-approval "Run Command" preview and for rejected commands the block was rendered as stacked `Label`s, which have no highlight mechanism; for running/completed commands the block uses `Terminal::command()`, a separate fenced markdown entity. Either way, highlights attached to the label never showed up. Add `ToolCall::command_markdown` — an `Entity<Markdown>` that mirrors the label wrapped in ``` fences, populated for Execute kind and kept in sync on title updates. Thread search indexes the terminal's command markdown when one exists, otherwise the tool call's `command_markdown`. Unify `render_collapsible_command` to render that entity via `MarkdownElement` with code-block chrome stripped, so both the preview and the post-execution command box flow matches through the existing markdown highlight pathway. Release Notes: - Fixed thread search matches inside terminal tool-call command boxes not being visually highlighted (matches were counted but invisible on screen).
Follow-up fixes for the thread-search feature: - Release the BufferSearchBar <-> ThreadView strong-handle cycle from AgentPanel so archived and cleaned-up threads actually free their views. - Strip fence bytes before indexing terminal command markdown and offset match byte ranges so highlights land on the visible command rather than the fence characters. - Make AlwaysCollapsed and AlwaysExpanded thinking-display modes honor search_auto_expanded_thinking_blocks, and drop that tracker when the user toggles a thinking block by hand. - Protect streaming-auto-expanded thinking blocks from search cleanup so they don't snap shut mid-stream. - Fall back to message.content.markdown() for user messages whose editor hasn't been synced into EntryViewState yet. - Switch MatchTarget and the highlighted_* collections to WeakEntity so entities dropped from EntryViewState aren't retained purely for their search-highlight membership. - Collect markdown sources as SharedString clones (via new Markdown::source_shared) to avoid per-keystroke O(N x source) String allocations on the foreground thread. - Coalesce deploy_search double defers via a search_deploy_pending flag. - Early-return from BufferSearchBar::on_query_editor_event when the bar is dismissed so a stray Edited event doesn't re-run matches on a hidden bar. - Add unit tests for LineLayout::position_for_index covering the wrap-boundary, multi-wrap, end-of-last-line, and no-wrap cases.
Extend the Include-Hidden re-activate behavior to case sensitive, whole word, and regex as well. Narrowing toggles can drop the current active match from the result set, leaving the counter and highlight pointing at nothing — the user sees "2 of 4" but the cursor sits on stale ground. Always re-activating keeps the scroll position, counter, and active highlight in sync with whatever set the toggle produces.
Contributor
Author
|
Please review carefully guys. It's a bit big update. I don't want to make any mistake that causes problem for ZED in no case. I will try my best to cooperate and fix each and every request that ZED staff provides. |
Member
|
Thanks for taking a look, but given we don't have search over historic external agents we'll need to think about how to communicate this feature, and I don't think this is the approach we want to take. Thanks though! |
dandv
added a commit
to dandv/zed
that referenced
this pull request
May 20, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
May 20, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
7 tasks
dandv
added a commit
to dandv/zed
that referenced
this pull request
May 30, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
May 30, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
May 30, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
May 30, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
Jun 1, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
Jun 2, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
Jun 3, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
Jun 3, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
Jun 5, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
Jun 6, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
Jun 8, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
dandv
added a commit
to dandv/zed
that referenced
this pull request
Jun 9, 2026
…ghts, action forwarding
Several fixes layered on top of the initial custom-bar implementation,
all confined to `agent_ui`:
- Forward `search::Toggle{CaseSensitive,WholeWord,Regex}` and
`search::FocusSearch` from `ThreadView` so they fire when the bar is
visible but focus is in the message editor. Without these the keymap
resolved the binding (because `AcpThreadSearchBar` is contributed at
the `ThreadView` level when the bar is visible) but the dispatched
action found no handler on the bubble path.
- Defer the bar's `on_activate_match` callback's `view.update` via
`cx.defer` to avoid re-entering `ThreadView`'s update from inside the
bar's `select_next_match`. Reproduced as a double-borrow panic
("cannot update X while it is already being updated") on Enter and
on Ctrl+F while the bar was open.
- Catch `editor::actions::Cancel` at the `ThreadView` level when the
bar is visible. The keymap binds `escape` to `editor::Cancel` at the
`Editor` context, which shadows `AcpThreadSearchBar`'s `escape ->
agent::DismissThreadSearch`. `Editor::cancel` propagates when there's
nothing to cancel locally; without the new handler, the propagated
`Cancel` walked up to `Workspace`, where `BufferSearchBar::register`
has a workspace-wide handler that dismissed the active pane's search
bar instead of ours.
- Highlight user-message search hits via
`Editor::highlight_background(HighlightKey::BufferSearchHighlights, …)`
on the inner `Editor` backing each `MessageEditor`. Past user messages
are rendered through `MessageEditor`, not through the markdown
attached to the entry, so highlights painted on the markdown were
counted but invisible. Introduces a `MatchTarget::{Markdown, Editor}`
enum on `ThreadMatch` so active-vs-inactive re-paint dispatches to
the right entity; splits the bar's `highlighted` field into
`highlighted_markdowns` and `highlighted_editors` for clean clearing.
`collect_markdowns` no longer pulls the user message's markdown,
avoiding double-counting.
- Mute the zero-match counter color (was `Color::Error`; mirror MPS /
`BufferSearchBar`). Red feedback comes from the query text alone, not
also from the counter.
- Search placeholder: "Search thread…" → "Search this thread…" to make
the per-thread scope explicit. Addresses the "we'll need to think
about how to communicate this feature" line from the PR zed-industries#54816
rejection — the bar searches only the currently-loaded thread,
never history or cross-agent context.
- Three new gpui tests in `crates/agent_ui/src/conversation_view.rs`:
- `test_thread_search_select_next_from_thread_view_update_does_not_panic`
drives `select_next_match` from inside a `ThreadView::update_in`
closure, reproducing the action-dispatch nesting that motivated
the `cx.defer` fix.
- `test_thread_search_editor_cancel_dismisses_bar` dispatches
`editor::actions::Cancel` while the bar is visible and asserts the
bar is dismissed before propagation reaches the workspace.
- `test_thread_search_highlights_user_message_editor` searches a
query that only matches the user message and asserts the user
message's inner `Editor` carries `BufferSearchHighlights` after
the matcher runs, and that `clear_highlights` removes them.
- Promote `MessageEditor::editor()` from `#[cfg(test)] pub(crate)` to
always-`pub(crate)` so the search bar can paint highlights on the
inner `Editor` outside tests. Kept the accessor narrow (crate-local)
and documented the contract.
Release Notes:
- Added in-thread search for the agent panel (Ctrl/Cmd+F). Searches the
currently-loaded thread only; not cross-thread or cross-agent.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Self-Review Checklist:
Closes #ISSUE #39338 partially
Release Notes:
Adds in-thread search to the agent panel: Cmd/Ctrl+F (and
/in vim mode) deploys aBufferSearchBarover the active thread, matches the query against assistant messages, user messages, tool-call labels, plan entries, and terminal commands, and highlights the matches inline. The bar's existing "next / previous / case / whole-word / regex" controls work unchanged; an "Include Hidden Context" toggle extends search into collapsed tool calls and thinking blocks on demand, auto-expanding only what the match lives inside and collapsing again on dismiss.2026-04-24.21-11-04.mp4