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 a SearchResult. The method signature accepts a SearchQuery parameter that includes the regex flag, 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. When query.regex is true, Zed compiles the pattern using the regex crate and processes capture groups through regex::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:

  1. 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.
  2. 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 $1 or $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:

  1. Parse the query – SearchQuery::from_string reads the UI fields, setting regex = true when the regex toggle is active.
  2. Compile the regex – RegexSearch::new is invoked; compilation errors abort the operation and emit a notification via cx.spawn(|cx| async move { cx.emit(error) }).
  3. Find matches – The searchable view calls self.search(query, token, ...), which internally selects between plain-text search (String::find) or RegexSearch::iter based on query.regex.
  4. Apply replacements – For each match, Zed constructs the replacement string. If back-references are present, Zed delegates to regex::Captures::expand to resolve $1, $2, etc. The final text is inserted using String::replace_range on the underlying buffer.
  5. 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 Searchable trait, providing a unified API across editors, terminals, and file trees.
  • The SearchQuery struct captures user input, including a regex boolean flag that toggles pattern matching between literal text and regular expressions.
  • Regex compilation and iteration are handled by the RegexSearch helper using the standard regex crate, 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 through regex::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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →