How Zed Implements Search and Replace with Regex Support
Zed's search and replace functionality uses the Searchable trait to provide regex-enabled replacements across editors, terminals, and file trees, compiling patterns with the regex crate and executing replacements through foreground async tasks with background scanning for large files.
Zed's architecture treats search and replace as a core workspace capability, not merely an editor feature. Every searchable view—from the text buffer to the terminal—implements the Searchable trait, enabling consistent Zed search and replace regex functionality across the entire application.
The Searchable Trait: Core Architecture
The Searchable trait, defined in crates/workspace/src/searchable.rs (lines 133-166), establishes the contract for any view that supports find-and-replace operations. This abstraction allows Zed to offer regex search and replace uniformly whether you are editing code, scanning terminal output, or browsing the project file tree.
Key Methods: replace and replace_all
The trait exposes two primary methods for executing replacements:
replace– Replaces a single match identified by aSearchResult. The method signature accepts aSearchQueryparameter that includes theregexflag, determining whether the replacement uses literal string matching or regex-based substitution.replace_all– Iterates through every match in the current view, applying the replacement string to each occurrence. Whenquery.regexis true, Zed compiles the pattern using theregexcrate and processes capture groups throughregex::Captures::expand.
Building the Search Query with Regex Support
The SearchQuery Struct
User intent is captured in the SearchQuery struct located in crates/workspace/src/search.rs (lines 45-70). This structure records all parameters entered through the search UI:
pub struct SearchQuery {
pub text: String,
pub case_sensitive: bool,
pub regex: bool, // Toggles regex mode
pub whole_word: bool,
// …
}
When a user toggles the "Regex" checkbox in the search bar, the UI sets regex: true, signaling that the text field should be treated as a regular expression pattern rather than a literal string.
Regex Compilation with RegexSearch
Zed wraps the standard regex crate in a helper struct called RegexSearch, implemented in crates/terminal/src/terminal_view.rs (lines 1095-1110). This wrapper provides two critical functions:
- Early validation –
RegexSearch::new(pattern: &str)compiles the regex immediately, returning an error if the pattern is invalid. This allows Zed to surface "Invalid regular expression" messages in the UI before any search execution begins. - Match iteration –
RegexSearch::iter(&self, text: &str)returns an iterator yielding every match, preserving capture group information necessary for replacement strings containing back-references like$1or$2.
Executing Regex Replace Operations in Zed
The Five-Step Replacement Flow
When a user executes a regex replace operation, Zed follows this precise sequence:
- Parse the query –
SearchQuery::from_stringreads the UI fields, settingregex = truewhen the regex toggle is active. - Compile the regex –
RegexSearch::newis invoked; compilation errors abort the operation and emit a notification viacx.spawn(|cx| async move { cx.emit(error) }). - Find matches – The searchable view calls
self.search(query, token, ...), which internally selects between plain-text search (String::find) orRegexSearch::iterbased onquery.regex. - Apply replacements – For each match, Zed constructs the replacement string. If back-references are present, Zed delegates to
regex::Captures::expandto resolve$1,$2, etc. The final text is inserted usingString::replace_rangeon the underlying buffer. - Update UI – After all edits complete, the view emits
cx.notify()to trigger a redraw, refreshing the "Replace All" preview panel.
Handling Capture Groups and Back-References
Zed supports standard regex capture group syntax in replacement strings. When replace_all processes a match, it passes the replacement template to the regex crate's expansion function:
// Example: Replacing "Foo123" with "Bar123" using pattern r"Foo(\d+)" -> "Bar$1"
let captures = regex.captures(matched_text).unwrap();
let mut replacement = String::new();
captures.expand("Bar$1", &mut replacement); // replacement now contains "Bar123"
This functionality is available across all Searchable implementations, ensuring consistent behavior whether replacing code in the editor or text in the terminal.
Threading Model: Foreground and Background Tasks
Because Zed runs on a single foreground thread (GPUI), all replace logic executes within a foreground async task created via cx.spawn. However, scanning large files or directories is delegated to a background task (cx.background_spawn) that streams matches back to the UI thread.
This architecture prevents UI freezes when processing massive files while maintaining atomic replace operations from the user's perspective. The background worker yields SearchResult items to the foreground, which then applies edits sequentially to preserve buffer consistency.
Integration Points: Editor, Terminal, and Vim Mode
Editor Buffer Replacements
The primary implementation of Searchable for text editing resides in crates/editor/src/buffer.rs. This module handles the replace_all logic for buffer contents, managing undo history and transactional edits. When regex mode is active, it utilizes the RegexSearch iterator to locate matches before applying String::replace_range operations.
Terminal Search Integration
Terminal views implement search through crates/terminal/src/terminal_view.rs (lines 1095-1110). The RegexSearch helper was originally designed for terminal use cases, enabling users to search scrollback buffers with regex patterns. The same infrastructure supports replacing text in terminal buffers when the terminal emulator permits editing.
Vim Mode Compatibility
For users operating in Vim mode, Zed provides integration at crates/vim/src/replace.rs. This module maps Vim replace commands (such as :s substitution) to the core Searchable API. When a Vim user executes a regex substitution, the command is translated into a SearchQuery with regex: true and forwarded to the active view's replace_all method.
Summary
- Zed implements search and replace with regex support through the
Searchabletrait, providing a unified API across editors, terminals, and file trees. - The
SearchQuerystruct captures user input, including aregexboolean flag that toggles pattern matching between literal text and regular expressions. - Regex compilation and iteration are handled by the
RegexSearchhelper using the standardregexcrate, with early validation to surface syntax errors in the UI. - Replace operations execute on the foreground GPUI thread via
cx.spawn, while large-file scanning runs on background threads to maintain UI responsiveness. - Capture groups and back-references (e.g.,
$1,$2) are supported in replacement strings throughregex::Captures::expand.
Frequently Asked Questions
How do I enable regex mode in Zed's search and replace?
Click the regex icon (usually labeled .*) in the search bar, or use the keyboard shortcut to toggle regex mode. When enabled, the regex field in the underlying SearchQuery struct is set to true, causing Zed to compile your search pattern using the regex crate rather than performing a literal string match.
Does Zed support capture groups in regex replacements?
Yes. Zed fully supports regex capture groups in replacement strings. When you use parentheses () in your search pattern to create groups, you can reference them in the replacement field using $1, $2, etc. Internally, Zed calls regex::Captures::expand to resolve these back-references before applying the replacement via String::replace_range.
What regex engine does Zed use for search and replace?
Zed uses the standard regex crate (the Rust regex library) for all regular expression operations. This engine is wrapped in a helper struct called RegexSearch (found in crates/terminal/src/terminal_view.rs), which provides methods for compiling patterns and iterating over matches while preserving capture group information for replacements.
Can I use regex search and replace in Zed's integrated terminal?
Yes. The terminal view in Zed implements the Searchable trait, enabling regex search functionality within terminal scrollback buffers. The same RegexSearch infrastructure used in the editor is utilized here, allowing you to search terminal output with patterns like error.*\d+ and perform replacements when the terminal emulator supports buffer editing.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →