project search: Fix search results not being highlighted (#18273)

Closes #18254
Closes #18219
Closes #17690

This fixes the project search not highlighting all results.

The problem was relatively simple, even though it took a while to find
it: we inserted multiple excerpts concurrently and the order in the
multi-buffer ended up being wrong. Sorting the resulting `match_ranges`
fixed the problem, but as it turns out, we can do a better job by moving
the concurrency into the method on the MultiBuffer.

Performance is the same, but now the problem is fixed.

Release Notes:

- Fixed search results in project-wide search not being highlighted
consistently and navigation sometimes being broken (#18254, #18219,
#17690)

---------

Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Thorsten Ball 2024-09-24 15:03:22 +02:00 committed by GitHub
parent f019ad563f
commit 93a4295f66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 163 additions and 130 deletions

View file

@ -263,54 +263,35 @@ impl ProjectSearch {
let mut limit_reached = false;
while let Some(results) = matches.next().await {
let tasks = results
.into_iter()
.map(|result| {
let this = this.clone();
cx.spawn(|mut cx| async move {
match result {
project::search::SearchResult::Buffer { buffer, ranges } => {
let mut match_ranges_rx =
this.update(&mut cx, |this, cx| {
this.excerpts.update(cx, |excerpts, cx| {
excerpts.stream_excerpts_with_context_lines(
buffer,
ranges,
editor::DEFAULT_MULTIBUFFER_CONTEXT,
cx,
)
})
})?;
let mut match_ranges = vec![];
while let Some(range) = match_ranges_rx.next().await {
match_ranges.push(range);
}
anyhow::Ok((match_ranges, false))
}
project::search::SearchResult::LimitReached => {
anyhow::Ok((vec![], true))
}
}
})
})
.collect::<Vec<_>>();
let result_ranges = futures::future::join_all(tasks).await;
let mut combined_ranges = vec![];
for (ranges, result_limit_reached) in result_ranges.into_iter().flatten() {
combined_ranges.extend(ranges);
if result_limit_reached {
limit_reached = result_limit_reached;
let mut buffers_with_ranges = Vec::with_capacity(results.len());
for result in results {
match result {
project::search::SearchResult::Buffer { buffer, ranges } => {
buffers_with_ranges.push((buffer, ranges));
}
project::search::SearchResult::LimitReached => {
limit_reached = true;
}
}
}
let match_ranges = this
.update(&mut cx, |this, cx| {
this.excerpts.update(cx, |excerpts, cx| {
excerpts.push_multiple_excerpts_with_context_lines(
buffers_with_ranges,
editor::DEFAULT_MULTIBUFFER_CONTEXT,
cx,
)
})
})
.ok()?
.await;
this.update(&mut cx, |this, cx| {
if !combined_ranges.is_empty() {
this.no_results = Some(false);
this.match_ranges.extend(combined_ranges);
cx.notify();
}
this.no_results = Some(false);
this.match_ranges.extend(match_ranges);
cx.notify();
})
.ok()?;
}
@ -2745,7 +2726,7 @@ pub mod tests {
search_view
.results_editor
.update(cx, |editor, cx| editor.display_text(cx)),
"\n\n\nconst TWO: usize = one::ONE + one::ONE;\n\n\n\n\nconst ONE: usize = 1;\n",
"\n\n\nconst ONE: usize = 1;\n\n\n\n\nconst TWO: usize = one::ONE + one::ONE;\n",
"New search in directory should have a filter that matches a certain directory"
);
})