mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-03 17:44:30 +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::{
|
use language::{
|
||||||
language_settings::{self, all_language_settings, language_settings, InlayHintSettings},
|
language_settings::{self, all_language_settings, language_settings, InlayHintSettings},
|
||||||
markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
|
markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
|
||||||
CursorShape, Diagnostic, DiagnosticEntry, Documentation, IndentKind, IndentSize, Language,
|
CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
|
||||||
OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId,
|
Point, Selection, SelectionGoal, TransactionId,
|
||||||
};
|
};
|
||||||
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
|
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
|
||||||
use linked_editing_ranges::refresh_linked_ranges;
|
use linked_editing_ranges::refresh_linked_ranges;
|
||||||
|
@ -9272,41 +9272,35 @@ impl Editor {
|
||||||
let snapshot = self.snapshot(cx);
|
let snapshot = self.snapshot(cx);
|
||||||
loop {
|
loop {
|
||||||
let diagnostics = if direction == Direction::Prev {
|
let diagnostics = if direction == Direction::Prev {
|
||||||
buffer
|
buffer.diagnostics_in_range(0..search_start, true)
|
||||||
.diagnostics_in_range(0..search_start, true)
|
|
||||||
.map(|DiagnosticEntry { diagnostic, range }| DiagnosticEntry {
|
|
||||||
diagnostic,
|
|
||||||
range: range.to_offset(&buffer),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
} else {
|
} else {
|
||||||
buffer
|
buffer.diagnostics_in_range(search_start..buffer.len(), false)
|
||||||
.diagnostics_in_range(search_start..buffer.len(), false)
|
|
||||||
.map(|DiagnosticEntry { diagnostic, range }| DiagnosticEntry {
|
|
||||||
diagnostic,
|
|
||||||
range: range.to_offset(&buffer),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
}
|
||||||
.into_iter()
|
|
||||||
.filter(|diagnostic| !snapshot.intersects_fold(diagnostic.range.start));
|
.filter(|diagnostic| !snapshot.intersects_fold(diagnostic.range.start));
|
||||||
|
let search_start_anchor = buffer.anchor_after(search_start);
|
||||||
let group = diagnostics
|
let group = diagnostics
|
||||||
// relies on diagnostics_in_range to return diagnostics with the same starting range to
|
// relies on diagnostics_in_range to return diagnostics with the same starting range to
|
||||||
// be sorted in a stable way
|
// be sorted in a stable way
|
||||||
// skip until we are at current active diagnostic, if it exists
|
// skip until we are at current active diagnostic, if it exists
|
||||||
.skip_while(|entry| {
|
.skip_while(|entry| {
|
||||||
(match direction {
|
let is_in_range = match direction {
|
||||||
Direction::Prev => entry.range.start >= search_start,
|
Direction::Prev => {
|
||||||
Direction::Next => entry.range.start <= search_start,
|
entry.range.start.cmp(&search_start_anchor, &buffer).is_ge()
|
||||||
}) && self
|
}
|
||||||
.active_diagnostics
|
Direction::Next => {
|
||||||
.as_ref()
|
entry.range.start.cmp(&search_start_anchor, &buffer).is_le()
|
||||||
.is_some_and(|a| a.group_id != entry.diagnostic.group_id)
|
}
|
||||||
|
};
|
||||||
|
is_in_range
|
||||||
|
&& self
|
||||||
|
.active_diagnostics
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|a| a.group_id != entry.diagnostic.group_id)
|
||||||
})
|
})
|
||||||
.find_map(|entry| {
|
.find_map(|entry| {
|
||||||
if entry.diagnostic.is_primary
|
if entry.diagnostic.is_primary
|
||||||
&& entry.diagnostic.severity <= DiagnosticSeverity::WARNING
|
&& entry.diagnostic.severity <= DiagnosticSeverity::WARNING
|
||||||
&& !entry.range.is_empty()
|
&& !(entry.range.start == entry.range.end)
|
||||||
// if we match with the active diagnostic, skip it
|
// if we match with the active diagnostic, skip it
|
||||||
&& Some(entry.diagnostic.group_id)
|
&& Some(entry.diagnostic.group_id)
|
||||||
!= self.active_diagnostics.as_ref().map(|d| d.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 {
|
if let Some((primary_range, group_id)) = group {
|
||||||
self.activate_diagnostics(group_id, cx);
|
self.activate_diagnostics(group_id, cx);
|
||||||
|
let primary_range = primary_range.to_offset(&buffer);
|
||||||
if self.active_diagnostics.is_some() {
|
if self.active_diagnostics.is_some() {
|
||||||
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
s.select(vec![Selection {
|
s.select(vec![Selection {
|
||||||
|
|
Loading…
Reference in a new issue