zed/crates/project/src
Ibrahim Khan 828544342d
search: Fix regex replace with lookahead and lookbehind (#61900)
# Objective

- Fixes #25905
- Regex search-and-replace silently does nothing when a same-line
pattern contains a lookahead or lookbehind. Searching highlights the
correct hits, but Replace All or `:s` in Vim mode leaves the buffer
untouched.

Reproduce with `316227766016837933199`, search `(\d)(?=(\d{4})+$)` in
regex mode, and replace with `$1,`. Expected:
`3,1622,7766,0168,3793,3199`. Actual before this change: nothing
changes. The same problem affects `(?<=foo: )bar` replaced with `BAZ`.

`SearchQuery::replacement_for` expanded the replacement by re-running
the whole pattern against the matched text alone. Lookaround assertions
inspect text outside the match, so the isolated hit no longer matched
and the edit replaced the hit with itself.

## Solution

- `replacement_for` now expands from captures located at the exact hit
range within its source context.
- Single-line regex hits use the complete source line, so lookahead,
lookbehind, and line anchors see the same surrounding text used by
search.
- Literal and escaped-regex searches bypass context reconstruction
because their replacements do not use captures.
- Multi-line hits retain the exact matched text, preserving the prior
cross-line behavior.
- If selection boundaries prevent the pattern from matching the
reconstructed line, replacement falls back to the isolated hit,
preserving prior behavior.
- Replace All caches the source line across hits on the same line.

Cross-line lookaround remains unchanged: assertions that need text
outside a multi-line hit still produce a no-op replacement.
Search-within-selection can also retain the prior no-op behavior when
the selection boundary changes assertion context.

## Testing

- `cargo test -p search test_replace_with_lookaround` (2 passed)
- `cargo fmt --all -- --check`
- `./script/clippy -p editor -p project -p search`
- Tested on Linux arm64. The change is platform independent.

## Self-Review Checklist:

- [x] I have reviewed the diff for quality, security, and reliability
- [x] Unsafe blocks, if any, have justifying comments
- [x] The content adheres to Zed UI standards
- [x] Tests cover the changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed same-line regex replacements that use lookahead or lookbehind
2026-08-19 15:55:24 +00:00
..
context_server_store
debugger Remove deprecated std::usize import from uniform_list.rs (#62841) 2026-08-18 22:41:54 +00:00
git_store git: Add diff_base setting for showing changes since the default branch (#61501) 2026-07-31 19:57:13 +00:00
lsp_command
lsp_store lsp: Separate timed RPC log groups (#61452) 2026-08-08 13:01:16 +00:00
manifest_tree Split out RelPath into a separate crate (#61029) 2026-07-15 08:33:25 +00:00
agent_registry_store.rs acp: Validate registry agent checksums (#61334) 2026-07-20 13:21:18 +00:00
agent_server_store.rs Stop the npm cache from growing without bound (#61750) 2026-07-29 15:16:39 +00:00
bookmark_store.rs Add named bookmark support (#57491) 2026-06-22 20:47:44 +00:00
buffer_store.rs Make opening large files use less peak memory (#62748) 2026-08-18 16:59:08 +00:00
color_extractor.rs
connection_manager.rs
context_server_store.rs project: Refresh MCP settings after worktree changes (#62026) 2026-08-03 20:33:31 +00:00
debounced_delay.rs
debugger.rs
environment.rs
git_store.rs Fix project path handling when connecting from Unix to Windows remotes (#62038) 2026-08-19 12:16:37 +00:00
image_store.rs markdown_preview: Fix images not rendering over remote (#62490) 2026-08-12 10:44:58 +00:00
lsp_command.rs project: Anchor diagnostic related information that points into the buffer (#62805) 2026-08-18 15:06:02 +00:00
lsp_store.rs project: Anchor diagnostic related information that points into the buffer (#62805) 2026-08-18 15:06:02 +00:00
manifest_tree.rs multi_buffer: Don't eagerly clone BufferSnapshot in range_to_buffer_ranges (#59190) 2026-06-12 12:27:28 +00:00
prettier_store.rs Split out RelPath into a separate crate (#61029) 2026-07-15 08:33:25 +00:00
project.rs editor: Keep the cursor before text inserted by on-type formatting (#61823) 2026-08-12 18:14:00 +00:00
project_search.rs Make search much faster (#62658) 2026-08-15 14:09:29 +00:00
project_settings.rs Show error toast on startup for malformed tasks (#62387) 2026-08-10 16:42:30 +00:00
search.rs search: Fix regex replace with lookahead and lookbehind (#61900) 2026-08-19 15:55:24 +00:00
search_history.rs Add preview to pickers and make them resizable (#59604) 2026-06-19 17:43:07 +00:00
task_inventory.rs multi_buffer: Don't eagerly clone BufferSnapshot in range_to_buffer_ranges (#59190) 2026-06-12 12:27:28 +00:00
task_store.rs
telemetry_snapshot.rs
terminals.rs remote: Do not swallow ssh errors (#58780) 2026-06-08 08:48:09 +00:00
toolchain_store.rs Split out RelPath into a separate crate (#61029) 2026-07-15 08:33:25 +00:00
trusted_worktrees.rs
worktree_store.rs Fix project path handling when connecting from Unix to Windows remotes (#62038) 2026-08-19 12:16:37 +00:00
yarn.rs