mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
Improve performance of go-to-diagnostic when many diagnostics are present (#23166)
Instead of eagerly calling `to_offset` on the anchor ranges for each diagnostic in the direction of the search, work lazily in terms of anchors and convert to offsets at the very end. Release Notes: - N/A
This commit is contained in:
parent
9d3a0594f9
commit
74620e611e
1 changed files with 20 additions and 25 deletions
|
@ -99,8 +99,8 @@ use itertools::Itertools;
|
|||
use language::{
|
||||
language_settings::{self, all_language_settings, language_settings, InlayHintSettings},
|
||||
markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
|
||||
CursorShape, Diagnostic, DiagnosticEntry, Documentation, IndentKind, IndentSize, Language,
|
||||
OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId,
|
||||
CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
|
||||
Point, Selection, SelectionGoal, TransactionId,
|
||||
};
|
||||
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
|
||||
use linked_editing_ranges::refresh_linked_ranges;
|
||||
|
@ -9272,41 +9272,35 @@ impl Editor {
|
|||
let snapshot = self.snapshot(cx);
|
||||
loop {
|
||||
let diagnostics = if direction == Direction::Prev {
|
||||
buffer
|
||||
.diagnostics_in_range(0..search_start, true)
|
||||
.map(|DiagnosticEntry { diagnostic, range }| DiagnosticEntry {
|
||||
diagnostic,
|
||||
range: range.to_offset(&buffer),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
buffer.diagnostics_in_range(0..search_start, true)
|
||||
} else {
|
||||
buffer
|
||||
.diagnostics_in_range(search_start..buffer.len(), false)
|
||||
.map(|DiagnosticEntry { diagnostic, range }| DiagnosticEntry {
|
||||
diagnostic,
|
||||
range: range.to_offset(&buffer),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
buffer.diagnostics_in_range(search_start..buffer.len(), false)
|
||||
}
|
||||
.into_iter()
|
||||
.filter(|diagnostic| !snapshot.intersects_fold(diagnostic.range.start));
|
||||
let search_start_anchor = buffer.anchor_after(search_start);
|
||||
let group = diagnostics
|
||||
// relies on diagnostics_in_range to return diagnostics with the same starting range to
|
||||
// be sorted in a stable way
|
||||
// skip until we are at current active diagnostic, if it exists
|
||||
.skip_while(|entry| {
|
||||
(match direction {
|
||||
Direction::Prev => entry.range.start >= search_start,
|
||||
Direction::Next => entry.range.start <= search_start,
|
||||
}) && self
|
||||
.active_diagnostics
|
||||
.as_ref()
|
||||
.is_some_and(|a| a.group_id != entry.diagnostic.group_id)
|
||||
let is_in_range = match direction {
|
||||
Direction::Prev => {
|
||||
entry.range.start.cmp(&search_start_anchor, &buffer).is_ge()
|
||||
}
|
||||
Direction::Next => {
|
||||
entry.range.start.cmp(&search_start_anchor, &buffer).is_le()
|
||||
}
|
||||
};
|
||||
is_in_range
|
||||
&& self
|
||||
.active_diagnostics
|
||||
.as_ref()
|
||||
.is_some_and(|a| a.group_id != entry.diagnostic.group_id)
|
||||
})
|
||||
.find_map(|entry| {
|
||||
if entry.diagnostic.is_primary
|
||||
&& entry.diagnostic.severity <= DiagnosticSeverity::WARNING
|
||||
&& !entry.range.is_empty()
|
||||
&& !(entry.range.start == entry.range.end)
|
||||
// if we match with the active diagnostic, skip it
|
||||
&& Some(entry.diagnostic.group_id)
|
||||
!= self.active_diagnostics.as_ref().map(|d| d.group_id)
|
||||
|
@ -9319,6 +9313,7 @@ impl Editor {
|
|||
|
||||
if let Some((primary_range, group_id)) = group {
|
||||
self.activate_diagnostics(group_id, cx);
|
||||
let primary_range = primary_range.to_offset(&buffer);
|
||||
if self.active_diagnostics.is_some() {
|
||||
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.select(vec![Selection {
|
||||
|
|
Loading…
Reference in a new issue