Repository navigation
How Search Everywhere Works
Search Everywhere is popup with five tabs: All, Classes, Files, Symbols and Text. Three in-memory indexes in Rust answer it: a file list, a symbol index and a text search over the same files. The user side is in Search Everywhere. Replace in Files, which shares the Text tab, is in How find and replace works.
Workspaces hold many repositories and tens of thousands of files. Clicking through the Files panel does not scale, and people reach for double Shift and Cmd+O without thinking. The popup has to answer on the first key, even while a large folder is still being read, and it must cost no memory when nobody uses it.
workspaceLife.svelte.ts feeds every key to DoubleShift (search/doubleShift.ts) in the capture phase, so double Shift is seen even when the editor or the terminal handles the key; two clean taps within 350 ms count. The tab keys (workspaceShortcut) and the Edit menu items go through openFileSearch in views/workspaceActions.ts, which does nothing while a dialog or the merge tool is up (the key is dropped, not queued).
Every tab starts with the focused editor's selection. editorSelection reads it from the CodeMirror state (focusedEditor, sliceDoc), not from the page, so decorations such as whitespace dots never leak in. queryFromSelection drops blank, multi-line and over-200-character selections. The popup selects the seeded text, so typing replaces it.
fileSearch (fileSearchStore.svelte.ts) says whether the popup shows and which tab it opens on (openingTab). FileSearch.svelte is mounted only while open, so its state starts fresh every time.
tabRows in popupRows.ts builds each tab's rows: the All tab's sections of SECTION_LIMIT (6) with a "N more" row, Recent Files for an empty query, and the Text tab's file and line rows. A virtual library List driven by the field draws them and keeps the highlight while results grow.
Recent Files (recentFiles) is the active tab, then the Recent Files list, then the open tabs. A chosen row opens through navigation.openFileAt, which places the cursor and focuses the editor.
All three indexes live in one FileSearch in AppState, built in src-tauri/src/file_search.rs.
sequenceDiagram
participant P as FileSearch.svelte
participant C as commands/search.rs
participant S as FileSearch session
participant W as ignore walker threads
P->>C: file_search_open(roots, progress Channel)
C->>S: open: reuse or start a build
S->>W: build_index on a thread
C-->>P: progress so far, right away
W-->>S: chunks of up to 1024 paths
S-->>P: progress messages, at most every 100 ms
P->>C: file_search_query(roots, query, 50)
C->>S: match the chunks indexed so far
C-->>P: items, matched, indexed, done
Note over P: while not done, query again every 250 ms
P->>C: file_search_close()
The walker is ripgrep's ignore crate: parallel, respecting .gitignore, with hidden files, without following symlinked folders, and skipping .git, SKIPPED_DIRS (shared with the workspace scan) and nested workspace folders. Each walker thread hands over a Chunk (paths packed in one string) every 1024 files or 40 ms. The index stops at MAX_FILES (500,000) and says truncated.
A query never waits. parse_query splits off :LINE:COL, folder segments and a leading /, and Scorer ranks with nucleo-matcher (the fuzzy matcher of the Helix editor) in tiers: whole name or stem, then name prefix, then fuzzy name, then a match spread over the path ("srccart"). Above 16,384 files it matches on up to 8 threads. Every query bumps query_seq, and a running query stops as soon as a newer one exists.
stateDiagram-v2
[*] --> Building: first open or query
Building --> Ready: walk finished
Ready --> Rebuilding: files created or deleted (mark_stale) while open
Rebuilding --> Ready: new list complete, swapped in
Ready --> Idle: popup closed
Idle --> Ready: opened again within 2 minutes
Idle --> [*]: reaper drops it after 120 s
Ready --> [*]: unused for 30 minutes
The file watcher calls mark_stale when files are added, removed or renamed, and mark_contents_changed when source files are edited. A rebuild runs beside the current list and replaces it only when complete, so results never shrink while it runs. A small reaper thread drops the whole session IDLE_DROP (120 s) after the popup closes, or after ABANDONED_DROP (30 minutes) without use.
src-tauri/src/symbols/ builds Classes and Symbols from the same file chunks when a tab first needs them (symbol_search_open). Workers read each source file up to 1 MB, skip minified ones, and run extract: per-language line scanners in the style of universal ctags, a lexer that knows strings, comments and brace depth plus a few keyword patterns. Declarations are looked for only where they can appear, so function bodies cost one lexer pass. Each definition is a 20-byte record; the cap is MAX_SYMBOLS (2,000,000). Cart.add matches the container and the name, and the exact name in the same case ranks first.
text_search.rs runs ripgrep's grep-searcher and grep-regex over the same file list on a few threads, streaming TextSearchBatch messages every 64 lines or 40 ms. It stops at 2,000 lines or 300 files, skips files over 5 MB or with a NUL byte, and cuts lines to 240 characters around the first match. Each search has a growing id (nextSearchId); a newer id or text_search_cancel stops the old one within a file.
The MCP tools (see How MCP and the CLI work) use build_once and query_once: a file list walked for one call and dropped with it, outside the popup's session.
| File | What it does |
|---|---|
src/lib/search/FileSearch.svelte, SearchResults.svelte
|
The popup (library CommandPalette), its List, Replace row |
src/lib/search/searchQueries.svelte.ts, searchTexts.ts
|
Queries; status texts |
src/lib/search/searchTabs.ts |
Tabs, their keys, openingTab, stepTab, queryFromSelection
|
src/lib/search/doubleShift.ts |
Double Shift detection |
src/lib/search/fileSearchModel.ts |
File rows, highlighting, Recent Files, splitLocation
|
src/lib/search/popupRows.ts |
Rows per tab |
src/lib/search/symbolSearchModel.ts, textSearchModel.ts
|
Symbol and text rows |
src/lib/views/workspaceActions.ts |
openFileSearch |
src-tauri/src/commands/search.rs |
The file_search_*, symbol_search_*, text_search* and replace_in_files* commands |
src-tauri/src/file_search.rs |
Session, walker, file matching, reaper |
src-tauri/src/symbols/mod.rs, extract.rs
|
Symbol storage, matching and the scanners |
src-tauri/src/text_search.rs |
Find in Files |
src-tauri/src/watcher.rs |
Calls mark_stale and mark_contents_changed
|
In memory, and only while used. An index on disk would go stale and take space per workspace. Walking on demand is fast enough.
One file list for three searches. All three follow the same skip rules, and the symbol and text searches read chunks as they arrive (Index::wait_chunk), so the tree is walked once.
Never wait for indexing. Queries match what is indexed so far, and the UI retries every 250 ms until done.
Files first in the All tab. Most searches are for a file, so Enter right after typing opens the best one.
Line scanners, not parsers. Tree-sitter grammars for fifteen languages would add megabytes to the binary and memory. Missing an odd definition is fine.
Optimized in dev builds. Cargo.toml builds the matcher and search crates with opt-level = 3 even in debug, so bun tauri dev feels like the release.
-
src-tauri/src/file_search.rs(module tests): skip rules, the cap, ranking, folder segments,:LINE:COL, partial indexes, superseded queries and the session lifecycle. -
src-tauri/src/symbols/tests.rsandextract_tests.rs: skipped files, positions, ranking, scopes, compact storage, rebuilds and each language's scanner. -
src-tauri/src/text_search/tests.rs: options, ranges, skips, caps, batches, cancelling and the newest id. - Vitest:
countLabel.test.ts,doubleShift.test.ts,searchTabs.test.ts,fileSearchModel.test.ts,popupRows.test.ts,searchTexts.test.ts,symbolSearchModel.test.tsandtextSearchModel.test.tsinsrc/lib/search/.
- A new tab or key: update
SEARCH_TABS,workspaceShortcut, the Edit menu inmenuSpec.ts,help/shortcuts.ts, Search Everywhere and Keyboard Shortcuts. - A new symbol language:
language_forand a scanner inextract.rs, tests inextract_tests.rs, and the language list on the usage page. - Retake the
search-everywhere-*.pngscreenshots when the popup changes. See Docs and Screenshots.
The Classes tab said "2 classs".
- The issue: the count read "classs".
- Why it happened: the popup's plural helper always added "s".
-
The fix and why we chose it:
countLabel.tsnames each word's plural (tested); every tab uses it.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode