Skip to content

Add Search Everywhere feature (JetBrains-style universal search) - #44674

Closed
portseif wants to merge 1 commit into
zed-industries:mainfrom
portseif:feature/search-everywhere
Closed

Add Search Everywhere feature (JetBrains-style universal search)#44674
portseif wants to merge 1 commit into
zed-industries:mainfrom
portseif:feature/search-everywhere

Conversation

@portseif

@portseif portseif commented Dec 12, 2025

Copy link
Copy Markdown

Summary

Implements a unified "Search Everywhere" modal (similar to JetBrains' Shift+Shift) that allows users to search across files, symbols, and actions from a single interface.

  • File search using fuzzy matching across all project files
  • Symbol search using Tree-sitter outlines (works for all languages, not just LSP-supported ones)
  • Action search from the command palette
  • Tab filtering to narrow results (All, Files, Symbols, Actions)
  • Project-wide symbol indexing with progress percentage indicator
  • Global symbol cache persisted across modal open/close (avoids re-indexing)
  • File path display for each symbol result
  • Keyboard shortcut display for actions
  • Respects .gitignore for file indexing

Keybindings:

  • All platforms: Shift Shift (double-tap shift key)
  • Custom keymap action: search_everywhere::Toggle

Test Plan

  • Open Search Everywhere with double shift
  • Verify file search returns fuzzy-matched results
  • Verify symbol search indexes project and shows progress %
  • Verify symbols show file path in detail
  • Verify actions show keyboard shortcuts
  • Verify tab filtering works (All/Files/Symbols/Actions)
  • Verify selecting a file opens it
  • Verify selecting a symbol navigates to it
  • Verify selecting an action executes it
  • Close and reopen modal - verify cache persists (no re-indexing)

Release Notes

  • Added Search Everywhere feature (Shift Shift on all platforms): a unified search modal that combines file search, symbol search, and action search in one interface with tab filtering

@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Dec 12, 2025
@zed-industries-bot

zed-industries-bot commented Dec 12, 2025

Copy link
Copy Markdown
Contributor
Warnings
⚠️

This PR is missing release notes.

Please add a "Release Notes" section that describes the change:

Release Notes:

- Added/Fixed/Improved ...

If your change is not user-facing, you can use "N/A" for the entry:

Release Notes:

- N/A

Generated by 🚫 dangerJS against 98fb42a

@portseif
portseif force-pushed the feature/search-everywhere branch from 7c8bf13 to 2bccc6f Compare December 12, 2025 01:57
Implement a unified search modal (shift shift) that combines:
- File search using fuzzy matching
- Symbol search using Tree-sitter outlines (works for all languages)
- Action/command search from command palette

Features:
- Tab filtering (All, Files, Symbols, Actions)
- Project-wide symbol indexing with progress indicator
- Global symbol cache persisted across modal open/close
- File path display for each symbol result
- Keyboard shortcut display for actions
- Respects .gitignore for file indexing
@Dima-369

Copy link
Copy Markdown
Contributor

Interesting, thanks! I tested it, and I'd love those features.

  1. In JetBrains IDEs, using Tab and Shift+Tab cycles the tabs at the top. In your implementation, it cycles through the displayed candidates. I think it would be great to have the same Tab behavior from JetBrains for this.

  2. Using file_finder::Toggle, it displays old picked history items, that would be amazing to also have. JetBrains also shows recent items:

image

file_finder::Toggle also showing history items:

image

search_everywhere::Toggle does not show anything when nothing is in the query:

image
  1. Having a preview would be so amazing! It takes a bit of muscle memory getting used to what icons are doing. In JetBrains, the preview helps immensely. In my opinion, jumping to symbols is a bit of a lucky straw, since you don't know where exactly you'll jump to without a preview.

  2. Leading into 3., in JetBrains it remembers the previous confirmed query + index and restores that on next invocation, making jumping to symbol a lot less painful. Currently, search_everywhere::Toggle loses all state.

Just ideas, thanks 🙂

@portseif

Copy link
Copy Markdown
Author

Interesting, thanks! I tested it, and I'd love those features.

1. In JetBrains IDEs, using Tab and Shift+Tab cycles the tabs at the top. In your implementation, it cycles through the displayed candidates. I think it would be great to have the same Tab behavior from JetBrains for this.

2. Using `file_finder::Toggle`, it displays old picked history items, that would be amazing to also have. JetBrains also shows recent items:
image

file_finder::Toggle also showing history items:
image

search_everywhere::Toggle does not show anything when nothing is in the query:
image

3. Having a preview would be so amazing! It takes a bit of muscle memory getting used to what icons are doing. In JetBrains, the preview helps immensely. In my opinion, jumping to symbols is a bit of a lucky straw, since you don't know where exactly you'll jump to without a preview.

4. Leading into 3., in JetBrains it remembers the previous confirmed query + index and restores that on next invocation, making jumping to symbol a lot less painful. Currently, `search_everywhere::Toggle` loses all state.

Just ideas, thanks 🙂

Awe yes, great observations! I'll definitely add all of that. This was definitely like a first iteration to hopefully gain traction. I appreciate your feedback :)

@davidbonan

Copy link
Copy Markdown

If we want to go further in the integration of this PR, maybe it would be necessary to replace the command palette as well as the file search with this modal with the corresponding active tab so as not to duplicate them.
If this solution is chosen and a preview is implemented, my PR no longer has any interest : #44530

@maxbrunsfeld maxbrunsfeld moved this from Community PRs to In progress in Quality Week – December 2025 Dec 15, 2025

@maxbrunsfeld maxbrunsfeld left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Questions

@portseif Can you give more explanation about the decision to do our own symbol index, rather than relying on the language servers? I'm not necessarily opposed to this, but what concrete use case does it solve? What languages are people typically editing where there is no language server available? For languages where there is an LSP, should we prefer that instead of building our own index?

Why would you ever want command palette actions to be mixed into this dataset? They seem very different from the other targets, which are locations in code.

Concrete changes we'd need

  • Right now, it looks like the SymbolCache is never updated once it is initially populated. If we want to have a SymbolCache, we'll need to keep it up to date as buffers and files change.
  • I think the shift shift binding matches JetBrains tools. We would want that binding in the Jetbrains keymap. But by default, Zed uses the VS Code keymap. Does it make to still have shift shift as the binding?
  • We would need keyboard control over the tabs. In Zed's Run/Debug modal, you can switch between the tabs with the same bindings that you can change tabs in panes.
  • It would be nice to have previews, similar #44530. Can we share any code there, if we merge that PR?

@maxbrunsfeld

Copy link
Copy Markdown
Collaborator

One follow-up on the SymbolCache thing - I think that it might be beneficial to land this feature as a separate PR. We could use it to power the existing symbols view, for any buffer that does not have a language server associated with it with the workspaceSymbolProvider capability. It would require a bit more code to implement correctly. Like I said above, we'd need to update the symbol cache efficiently when files and buffers change.

With this primitive, we could implement the Project::symbols method in a way that worked even without language servers running, but would prefer the LSP when available.

@maxbrunsfeld

Copy link
Copy Markdown
Collaborator

I do think that we would land this feature if all of the feedback I listed were addressed.

I'm going to close this one out for now, to remove it from our review backlog, because I think some large changes are required before it'd be ready to land, but we can re-open it if you make progress on this feedback. Thanks for working on this direction!

@github-project-automation github-project-automation Bot moved this from In progress to Done in Quality Week – December 2025 Dec 15, 2025
@portseif

Copy link
Copy Markdown
Author

Questions

@portseif Can you give more explanation about the decision to do our own symbol index, rather than relying on the language servers? I'm not necessarily opposed to this, but what concrete use case does it solve? What languages are people typically editing where there is no language server available? For languages where there is an LSP, should we prefer that instead of building our own index?

Why would you ever want command palette actions to be mixed into this dataset? They seem very different from the other targets, which are locations in code.

Concrete changes we'd need

* Right now, it looks like the `SymbolCache` is never updated once it is initially populated. If we want to have a `SymbolCache`, we'll need to keep it up to date as buffers and files change.

* I think the `shift shift` binding matches JetBrains tools. We would want that binding in the Jetbrains keymap. But by default, Zed uses the VS Code keymap. Does it make to still have `shift shift` as the binding?

* We would need keyboard control over the tabs. In Zed's `Run/Debug` modal, you can switch between the tabs with the same bindings that you can change tabs in panes.

* It would be nice to have previews, similar #44530. Can we share any code there, if we merge that PR?

Hey @maxbrunsfeld, I apologize for the delay - was busy on other projects and the holidays.

TLDR: I kept running into issues when trying to use LSP symbols with web projects in HTML, CSS, PHP, and JS. That's why I added the SymbolCache as a solution. My SymbolProvider actually does both:

  1. LSP workspace symbols: via project.symbols(&query, cx)
  2. Tree-sitter outlines: via the background indexing that populates SymbolCache

The cache is specifically for the Tree-sitter path, not the LSP path. LSP symbols come fresh from the language server on each query.


1. Why build our own symbol index instead of relying on language servers?

The Tree-sitter outline indexing serves a different use case than LSP workspace symbols. LSP symbols are excellent when available, but:

  • Startup latency: LSP workspace symbols require the language server to be running and fully indexed. For quick navigation when opening a project, waiting for the server can feel slow.
  • Coverage gaps: Not every language has an LSP, and some LSPs don't implement workspace symbol search well (or at all). This was the issue I hit with web projects - HTML, CSS, and PHP. Tree-sitter outlines work for any language with a grammar.
  • Consistency: Tree-sitter outline items give a uniform structure across languages, while LSP symbol responses vary wildly from the tests I ran.

That said, when an LSP is available and responsive, it should probably take priority. The current implementation queries both sources and merges results, but we could consider preferring LSP symbols when they exist and falling back to Tree-sitter outlines otherwise.


2. Why mix command palette actions into this dataset?

Fair pushback. The original idea was to mirror JetBrains' "Search Everywhere" which combines files, symbols, and actions in one place. The thinking was: users don't always know whether what they want is a file, a symbol, or a command - they just want to find it.

In practice, you're right that actions feel different from code locations. A few options:

  • Remove actions entirely and keep this focused on code navigation
  • Keep actions but default to the "Files" or "Symbols" tab, making actions opt-in
  • Move actions to a separate tab that users can switch to explicitly

What's your preference? I'm happy to remove actions entirely or move them to an opt-in tab.


3. Concrete changes needed

SymbolCache updates: Yes, the cache is static after initial population. To keep it current, we'd need to:

  • Subscribe to buffer change events and invalidate/update entries for modified files
  • Watch for file creation/deletion/rename events from the worktree
  • Consider debouncing updates to avoid thrashing during rapid edits

Keybinding: Good point. shift shift matches JetBrains, but Zed defaults to VS Code bindings. I'd suggest moving shift shift to the JetBrains keymap and picking something like ctrl-shift-o or similar for the default VS Code keymap.

Keyboard tab switching: The debugger modal uses pane::ActivateNextItem / pane::ActivatePrevItem for tab switching (bound to ctrl-tab / ctrl-shift-tab). I'll register these same action handlers.

Previews: PR #44530 adds a QuickSearchModal with a preview panel. The preview approach there is similar - it creates an Editor for the buffer, navigates to the match location, and highlights ranges. We could share:

  • The preview panel layout (vertical/horizontal based on viewport width)
  • The debounce logic for preview updates
  • The pattern for opening files in workspace when edited in preview

If that PR merges first, we could potentially reuse its preview infrastructure directly.

@portseif

Copy link
Copy Markdown
Author

One follow-up on the SymbolCache thing - I think that it might be beneficial to land this feature as a separate PR. We could use it to power the existing symbols view, for any buffer that does not have a language server associated with it with the workspaceSymbolProvider capability. It would require a bit more code to implement correctly. Like I said above, we'd need to update the symbol cache efficiently when files and buffers change.

With this primitive, we could implement the Project::symbols method in a way that worked even without language servers running, but would prefer the LSP when available.

That makes a lot of sense. Breaking out the SymbolCache as a standalone primitive would:

  1. Make it usable across Zed (existing symbols view, this modal, potentially other features)
  2. Force us to get the incremental update logic right from the start
  3. Keep this PR focused on the Search Everywhere UI/UX

For the Project::symbols integration, I'm thinking something like:

// In project.rs
pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Vec<Symbol>> {
    let lsp_symbols = self.lsp_workspace_symbols(query, cx);
    let cached_symbols = self.symbol_cache.query(query);
    
    // Merge, preferring LSP when available for a given file
    // Fall back to cached Tree-sitter symbols otherwise
}

I can start on that separate PR. The main work would be:

- Move `SymbolCache` to the project crate
- Subscribe to `BufferEvent::Reparsed` for outline updates on open buffers
- Watch `worktree::Event::UpdatedEntries` for file changes
- Debounce updates to avoid thrashing
- Add a method to query the cache with fuzzy matching

Once that lands, this PR would just consume `Project::symbols` and the UI code stays clean.

Want me to start on that, or would you prefer to scope out the API first?

@portseif

Copy link
Copy Markdown
Author

I do think that we would land this feature if all of the feedback I listed were addressed.

I'm going to close this one out for now, to remove it from our review backlog, because I think some large changes are required before it'd be ready to land, but we can re-open it if you make progress on this feedback. Thanks for working on this direction!

Sounds good, thanks for the detailed feedback. I'll work through the changes:

  1. Break out SymbolCache as a separate PR to power Project::symbols with proper incremental updates
  2. Remove or make actions opt-in (will follow up once the cache PR is closer)
  3. Move shift shift to JetBrains keymap, pick a VS Code-friendly default
  4. Add keyboard tab switching via ActivateNextItem & ActivatePrevItem
  5. Coordinate with Add quick search modal #44530 on preview infrastructure

I'll start with the SymbolCache extraction since that's the foundation. Will ping you when it's ready for review.

@portseif

Copy link
Copy Markdown
Author

@maxbrunsfeld Added Symbol Index extraction #45719 & Search Everywhere improvements #45720

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

6 participants