editor: Improve find_matches and replace_all perf (#51941)
Helps with https://github.com/zed-industries/zed/issues/38927 - **editor: Add a benchmark for find/replace** - **text: batch fragment insertions before turning them into a SumTree** ## Context <!-- What does this PR do, and why? How is it expected to impact users? Not just what changed, but what motivated it and why this approach. Link to Linear issue (e.g., ENG-123) or GitHub issue (e.g., Closes #456) if one exists — helps with traceability. --> ## How to Review <!-- Help reviewers focus their attention: - For small PRs: note what to focus on (e.g., "error handling in foo.rs") - For large PRs (>400 LOC): provide a guided tour — numbered list of files/commits to read in order. (The `large-pr` label is applied automatically.) - See the review process guidelines for comment conventions --> ## Self-Review Checklist <!-- Check before requesting review: --> - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [ ] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Improved performance of "Replace All" in buffer search --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
This commit is contained in:
1 parent
156a47d0d0
commit
cd67c9f84d
8 files changed
+506
-39
No files matched your search
@@ -5258,6 +5258,16 @@ impl MultiBufferSnapshot {
|
||||
Some(Anchor::in_buffer(path_key_index, anchor))
|
||||
}
|
||||
|
||||
/// Lifts a buffer anchor range to a multibuffer anchor range without checking against excerpt boundaries. Returns `None` if there are no excerpts for the buffer.
|
||||
pub fn anchor_range_in_buffer(&self, range: Range<text::Anchor>) -> Option<Range<Anchor>> {
|
||||
if range.start.buffer_id != range.end.buffer_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
let path_key_index = self.path_key_index_for_buffer(range.start.buffer_id)?;
|
||||
Some(Anchor::range_in_buffer(path_key_index, range))
|
||||
}
|
||||
|
||||
/// Creates a multibuffer anchor for the given buffer anchor, if it is contained in any excerpt.
|
||||
pub fn anchor_in_excerpt(&self, text_anchor: text::Anchor) -> Option<Anchor> {
|
||||
let excerpts = {
|
||||
@@ -5295,6 +5305,19 @@ impl MultiBufferSnapshot {
|
||||
&self,
|
||||
text_anchor: Range<text::Anchor>,
|
||||
) -> Option<Range<Anchor>> {
|
||||
if self.is_singleton() {
|
||||
let excerpt = self.excerpts.first()?;
|
||||
let buffer_snapshot = excerpt.buffer_snapshot(self);
|
||||
if excerpt.range.contains(&text_anchor.start, &buffer_snapshot)
|
||||
&& excerpt.range.contains(&text_anchor.end, &buffer_snapshot)
|
||||
{
|
||||
return Some(Anchor::range_in_buffer(excerpt.path_key_index, text_anchor));
|
||||
}
|
||||
}
|
||||
|
||||
// for each search match
|
||||
|
||||
let mut buffer_snapshot = None;
|
||||
for excerpt in {
|
||||
let this = &self;
|
||||
let buffer_id = text_anchor.start.buffer_id;
|
||||
@@ -5316,7 +5339,8 @@ impl MultiBufferSnapshot {
|
||||
.into_iter()
|
||||
.flatten()
|
||||
} {
|
||||
let buffer_snapshot = excerpt.buffer_snapshot(self);
|
||||
let buffer_snapshot =
|
||||
buffer_snapshot.get_or_insert_with(|| excerpt.buffer_snapshot(self));
|
||||
if excerpt.range.contains(&text_anchor.start, &buffer_snapshot)
|
||||
&& excerpt.range.contains(&text_anchor.end, &buffer_snapshot)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user