diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 093f4691f3..3fc70c437d 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -2496,10 +2496,6 @@ impl ToOffset for Anchor { fn to_offset<'a>(&self, content: impl Into>) -> usize { content.into().summary_for_anchor(self).bytes } - - fn to_full_offset<'a>(&self, _: impl Into>, _: Bias) -> usize { - self.full_offset - } } impl<'a> ToOffset for &'a Anchor { diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index 1dbf9700ee..d44e1f85b5 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -476,11 +476,99 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) { } ] ); + assert_eq!( + chunks_with_diagnostics(buffer, 0..buffer.len()), + [ + ("\n\nfn a() { ".to_string(), None), + ("A".to_string(), Some(DiagnosticSeverity::ERROR)), + (" }\nfn b() { ".to_string(), None), + ("BB".to_string(), Some(DiagnosticSeverity::ERROR)), + (" }\nfn c() { ".to_string(), None), + ("CCC".to_string(), Some(DiagnosticSeverity::ERROR)), + (" }\n".to_string(), None), + ] + ); + assert_eq!( + chunks_with_diagnostics(buffer, Point::new(3, 10)..Point::new(4, 11)), + [ + ("B".to_string(), Some(DiagnosticSeverity::ERROR)), + (" }\nfn c() { ".to_string(), None), + ("CC".to_string(), Some(DiagnosticSeverity::ERROR)), + ] + ); - dbg!(buffer - .snapshot() - .highlighted_text_for_range(0..buffer.len()) - .collect::>()); + // Ensure overlapping diagnostics are highlighted correctly. + buffer + .update_diagnostics( + Some(open_notification.text_document.version), + vec![ + lsp::Diagnostic { + range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 10)), + severity: Some(lsp::DiagnosticSeverity::ERROR), + message: "undefined variable 'A'".to_string(), + ..Default::default() + }, + lsp::Diagnostic { + range: lsp::Range::new(lsp::Position::new(0, 9), lsp::Position::new(0, 12)), + severity: Some(lsp::DiagnosticSeverity::WARNING), + message: "unreachable statement".to_string(), + ..Default::default() + }, + ], + cx, + ) + .unwrap(); + assert_eq!( + buffer + .diagnostics_in_range(Point::new(2, 0)..Point::new(3, 0)) + .collect::>(), + &[ + Diagnostic { + range: Point::new(2, 9)..Point::new(2, 12), + severity: DiagnosticSeverity::WARNING, + message: "unreachable statement".to_string() + }, + Diagnostic { + range: Point::new(2, 9)..Point::new(2, 10), + severity: DiagnosticSeverity::ERROR, + message: "undefined variable 'A'".to_string() + }, + ] + ); + assert_eq!( + chunks_with_diagnostics(buffer, Point::new(2, 0)..Point::new(3, 0)), + [ + ("fn a() { ".to_string(), None), + ("A".to_string(), Some(DiagnosticSeverity::ERROR)), + (" }".to_string(), Some(DiagnosticSeverity::WARNING)), + ("\n".to_string(), None), + ] + ); + assert_eq!( + chunks_with_diagnostics(buffer, Point::new(2, 10)..Point::new(3, 0)), + [ + (" }".to_string(), Some(DiagnosticSeverity::WARNING)), + ("\n".to_string(), None), + ] + ); + + fn chunks_with_diagnostics( + buffer: &Buffer, + range: Range, + ) -> Vec<(String, Option)> { + let mut chunks: Vec<(String, Option)> = Vec::new(); + for chunk in buffer.snapshot().highlighted_text_for_range(range) { + if chunks + .last() + .map_or(false, |prev_chunk| prev_chunk.1 == chunk.diagnostic) + { + chunks.last_mut().unwrap().0.push_str(chunk.text); + } else { + chunks.push((chunk.text.to_string(), chunk.diagnostic)); + } + } + chunks + } }); }