diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index ffaf5e6cf7..f518253733 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -2205,7 +2205,7 @@ impl Editor { } pub fn show_next_diagnostic(&mut self, _: &ShowNextDiagnostic, cx: &mut ViewContext) { - let selection = self.selections::(cx).last().unwrap(); + let selection = self.newest_selection(cx); let buffer = self.buffer.read(cx.as_ref()); let diagnostic_group_id = dbg!(buffer .diagnostics_in_range::<_, usize>(selection.head()..buffer.len()) diff --git a/crates/language/src/lib.rs b/crates/language/src/lib.rs index e2747504b9..f810c75cc4 100644 --- a/crates/language/src/lib.rs +++ b/crates/language/src/lib.rs @@ -86,6 +86,7 @@ pub struct Diagnostic { pub severity: DiagnosticSeverity, pub message: String, pub group_id: usize, + pub is_primary: bool, } struct LanguageServerState { @@ -717,68 +718,82 @@ impl Buffer { .peekable(); let mut last_edit_old_end = PointUtf16::zero(); let mut last_edit_new_end = PointUtf16::zero(); - let mut groups = HashMap::new(); + let mut group_ids_by_diagnostic_range = HashMap::new(); + let mut diagnostics_by_group_id = HashMap::new(); let mut next_group_id = 0; - - content.anchor_range_multimap( - Bias::Left, - Bias::Right, - diagnostics.iter().filter_map(|diagnostic| { - let mut start = diagnostic.range.start.to_point_utf16(); - let mut end = diagnostic.range.end.to_point_utf16(); - let source = diagnostic.source.as_ref(); - let code = diagnostic.code.as_ref(); - let group_id = diagnostic_ranges(&diagnostic, abs_path.as_deref()) - .find_map(|range| groups.get(&(source, code, range))) - .copied() - .unwrap_or_else(|| { - let group_id = post_inc(&mut next_group_id); - for range in diagnostic_ranges(&diagnostic, abs_path.as_deref()) { - groups.insert((source, code, range), group_id); - } - group_id - }); - - if diagnostic - .source - .as_ref() - .map_or(false, |source| disk_based_sources.contains(source)) - { - while let Some(edit) = edits_since_save.peek() { - if edit.old.end <= start { - last_edit_old_end = edit.old.end; - last_edit_new_end = edit.new.end; - edits_since_save.next(); - } else if edit.old.start <= end && edit.old.end >= start { - return None; - } else { - break; - } + 'outer: for diagnostic in &diagnostics { + let mut start = diagnostic.range.start.to_point_utf16(); + let mut end = diagnostic.range.end.to_point_utf16(); + let source = diagnostic.source.as_ref(); + let code = diagnostic.code.as_ref(); + let group_id = diagnostic_ranges(&diagnostic, abs_path.as_deref()) + .find_map(|range| group_ids_by_diagnostic_range.get(&(source, code, range))) + .copied() + .unwrap_or_else(|| { + let group_id = post_inc(&mut next_group_id); + for range in diagnostic_ranges(&diagnostic, abs_path.as_deref()) { + group_ids_by_diagnostic_range.insert((source, code, range), group_id); } + group_id + }); - start = last_edit_new_end + (start - last_edit_old_end); - end = last_edit_new_end + (end - last_edit_old_end); - } - - let mut range = content.clip_point_utf16(start, Bias::Left) - ..content.clip_point_utf16(end, Bias::Right); - if range.start == range.end { - range.end.column += 1; - range.end = content.clip_point_utf16(range.end, Bias::Right); - if range.start == range.end && range.end.column > 0 { - range.start.column -= 1; - range.start = content.clip_point_utf16(range.start, Bias::Left); + if diagnostic + .source + .as_ref() + .map_or(false, |source| disk_based_sources.contains(source)) + { + while let Some(edit) = edits_since_save.peek() { + if edit.old.end <= start { + last_edit_old_end = edit.old.end; + last_edit_new_end = edit.new.end; + edits_since_save.next(); + } else if edit.old.start <= end && edit.old.end >= start { + continue 'outer; + } else { + break; } } - Some(( + + start = last_edit_new_end + (start - last_edit_old_end); + end = last_edit_new_end + (end - last_edit_old_end); + } + + let mut range = content.clip_point_utf16(start, Bias::Left) + ..content.clip_point_utf16(end, Bias::Right); + if range.start == range.end { + range.end.column += 1; + range.end = content.clip_point_utf16(range.end, Bias::Right); + if range.start == range.end && range.end.column > 0 { + range.start.column -= 1; + range.start = content.clip_point_utf16(range.start, Bias::Left); + } + } + + diagnostics_by_group_id + .entry(group_id) + .or_insert(Vec::new()) + .push(( range, Diagnostic { severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR), message: diagnostic.message.clone(), group_id, + is_primary: false, }, - )) - }), + )); + } + + content.anchor_range_multimap( + Bias::Left, + Bias::Right, + diagnostics_by_group_id + .into_values() + .flat_map(|mut diagnostics| { + let primary_diagnostic = + diagnostics.iter_mut().min_by_key(|d| d.1.severity).unwrap(); + primary_diagnostic.1.is_primary = true; + diagnostics + }), ) }; diff --git a/crates/language/src/proto.rs b/crates/language/src/proto.rs index bccb965a55..6a259e0726 100644 --- a/crates/language/src/proto.rs +++ b/crates/language/src/proto.rs @@ -142,6 +142,7 @@ pub fn serialize_diagnostics(map: &AnchorRangeMultimap) -> proto::Di _ => proto::diagnostic::Severity::None, } as i32, group_id: diagnostic.group_id as u64, + is_primary: diagnostic.is_primary, }) .collect(), } @@ -310,6 +311,7 @@ pub fn deserialize_diagnostics(message: proto::DiagnosticSet) -> AnchorRangeMult }, message: diagnostic.message, group_id: diagnostic.group_id as usize, + is_primary: diagnostic.is_primary, }, )) }), diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index c73b29224f..671755195d 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -484,6 +484,7 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) { severity: DiagnosticSeverity::ERROR, message: "undefined variable 'BB'".to_string(), group_id: 1, + is_primary: true, }, ), ( @@ -492,6 +493,7 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) { severity: DiagnosticSeverity::ERROR, message: "undefined variable 'CCC'".to_string(), group_id: 2, + is_primary: true, } ) ] @@ -549,6 +551,7 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) { severity: DiagnosticSeverity::WARNING, message: "unreachable statement".to_string(), group_id: 1, + is_primary: true, } ), ( @@ -557,6 +560,7 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) { severity: DiagnosticSeverity::ERROR, message: "undefined variable 'A'".to_string(), group_id: 0, + is_primary: true, }, ) ] @@ -626,6 +630,7 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) { severity: DiagnosticSeverity::ERROR, message: "undefined variable 'A'".to_string(), group_id: 0, + is_primary: true, } ), ( @@ -634,6 +639,7 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) { severity: DiagnosticSeverity::ERROR, message: "undefined variable 'BB'".to_string(), group_id: 1, + is_primary: true, }, ) ] @@ -808,7 +814,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::WARNING, message: "error 1".to_string(), - group_id: 0 + group_id: 0, + is_primary: true, } ), ( @@ -816,7 +823,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::HINT, message: "error 1 hint 1".to_string(), - group_id: 0 + group_id: 0, + is_primary: false, } ), ( @@ -824,7 +832,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::HINT, message: "error 2 hint 1".to_string(), - group_id: 1 + group_id: 1, + is_primary: false, } ), ( @@ -832,7 +841,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::HINT, message: "error 2 hint 2".to_string(), - group_id: 1 + group_id: 1, + is_primary: false, } ), ( @@ -840,7 +850,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::ERROR, message: "error 2".to_string(), - group_id: 1 + group_id: 1, + is_primary: true, } ) ] @@ -854,7 +865,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::WARNING, message: "error 1".to_string(), - group_id: 0 + group_id: 0, + is_primary: true, } ), ( @@ -862,7 +874,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::HINT, message: "error 1 hint 1".to_string(), - group_id: 0 + group_id: 0, + is_primary: false, } ), ] @@ -875,7 +888,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::HINT, message: "error 2 hint 1".to_string(), - group_id: 1 + group_id: 1, + is_primary: false, } ), ( @@ -883,7 +897,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::HINT, message: "error 2 hint 2".to_string(), - group_id: 1 + group_id: 1, + is_primary: false, } ), ( @@ -891,7 +906,8 @@ async fn test_grouped_diagnostics(mut cx: gpui::TestAppContext) { &Diagnostic { severity: DiagnosticSeverity::ERROR, message: "error 2".to_string(), - group_id: 1 + group_id: 1, + is_primary: true, } ) ] diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 5a9b7d205e..e6b444b548 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -3635,6 +3635,7 @@ mod tests { severity: lsp::DiagnosticSeverity::ERROR, message: "undefined variable 'A'".to_string(), group_id: 0, + is_primary: true } )] ) diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index f826c4b03f..950178be34 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -257,6 +257,7 @@ message Diagnostic { Severity severity = 3; string message = 4; uint64 group_id = 5; + bool is_primary = 6; enum Severity { None = 0; Error = 1; diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index d9d45207d0..0c60ba3cbd 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -1716,6 +1716,7 @@ mod tests { group_id: 0, message: "message 1".to_string(), severity: lsp::DiagnosticSeverity::ERROR, + is_primary: true } ), ( @@ -1723,7 +1724,8 @@ mod tests { &Diagnostic { group_id: 1, severity: lsp::DiagnosticSeverity::WARNING, - message: "message 2".to_string() + message: "message 2".to_string(), + is_primary: true } ) ]