diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 3d28ce19a8..10deb5c9ca 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -2067,7 +2067,7 @@ impl Default for Diagnostic { message: Default::default(), group_id: Default::default(), is_primary: Default::default(), - is_valid: Default::default(), + is_valid: true, } } } diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index e18589cbc9..04e33d9acc 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -750,6 +750,107 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) { }); } +#[gpui::test] +async fn test_preserving_disk_based_diagnostics(mut cx: gpui::TestAppContext) { + let buffer = cx.add_model(|cx| { + let text = " + use a::*; + const b: i32 = c::; + const c: i32 = d; + const e: i32 = f +; + " + .unindent(); + + let mut rust_lang = rust_lang(); + rust_lang.config.language_server = Some(LanguageServerConfig { + disk_based_diagnostic_sources: HashSet::from_iter(["disk".to_string()]), + ..Default::default() + }); + + let mut buffer = Buffer::new(0, text, cx); + buffer.set_language(Some(Arc::new(rust_lang)), None, cx); + buffer + }); + + // Initially, there are three errors. The second one is disk-based. + let diagnostics = vec![ + DiagnosticEntry { + range: PointUtf16::new(1, 16)..PointUtf16::new(1, 18), + diagnostic: Diagnostic { + severity: DiagnosticSeverity::ERROR, + message: "syntax error 1".to_string(), + group_id: 0, + is_primary: true, + is_valid: true, + ..Default::default() + }, + }, + DiagnosticEntry { + range: PointUtf16::new(2, 15)..PointUtf16::new(2, 16), + diagnostic: Diagnostic { + severity: DiagnosticSeverity::ERROR, + message: "cannot find value `d` in this scope".to_string(), + source: Some("disk".to_string()), + group_id: 1, + is_primary: true, + is_valid: true, + ..Default::default() + }, + }, + DiagnosticEntry { + range: PointUtf16::new(3, 17)..PointUtf16::new(3, 18), + diagnostic: Diagnostic { + severity: DiagnosticSeverity::ERROR, + message: "syntax error 2".to_string(), + group_id: 2, + is_primary: true, + is_valid: true, + ..Default::default() + }, + }, + ]; + buffer.update(&mut cx, |buffer, cx| { + buffer + .update_diagnostics(None, diagnostics.clone(), cx) + .unwrap(); + assert_eq!( + buffer + .snapshot() + .diagnostics_in_range::<_, PointUtf16>(PointUtf16::new(0, 0)..PointUtf16::new(4, 0)) + .collect::>(), + diagnostics.as_slice(), + ); + }); + + // The diagnostics are updated, and the disk-based diagnostic is omitted from this message. + let mut new_diagnostics = vec![diagnostics[0].clone(), diagnostics[2].clone()]; + new_diagnostics[0].diagnostic.message = "another syntax error".to_string(); + new_diagnostics[1].diagnostic.message = "yet another syntax error".to_string(); + + buffer.update(&mut cx, |buffer, cx| { + buffer + .update_diagnostics(None, new_diagnostics.clone(), cx) + .unwrap(); + assert_eq!( + buffer + .snapshot() + .diagnostics_in_range::<_, PointUtf16>(PointUtf16::new(0, 0)..PointUtf16::new(4, 0)) + .collect::>(), + &[ + new_diagnostics[0].clone(), + DiagnosticEntry { + range: diagnostics[1].range.clone(), + diagnostic: Diagnostic { + is_valid: false, + ..diagnostics[1].diagnostic.clone() + }, + }, + new_diagnostics[1].clone(), + ], + ); + }); +} + #[gpui::test] async fn test_empty_diagnostic_ranges(mut cx: gpui::TestAppContext) { cx.add_model(|cx| { diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 055e80b29a..eec52d2fa5 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -2057,12 +2057,18 @@ pub trait FromAnchor { impl FromAnchor for Point { fn from_anchor(anchor: &Anchor, snapshot: &BufferSnapshot) -> Self { - anchor.to_point(snapshot) + snapshot.summary_for_anchor(anchor) + } +} + +impl FromAnchor for PointUtf16 { + fn from_anchor(anchor: &Anchor, snapshot: &BufferSnapshot) -> Self { + snapshot.summary_for_anchor(anchor) } } impl FromAnchor for usize { fn from_anchor(anchor: &Anchor, snapshot: &BufferSnapshot) -> Self { - anchor.to_offset(snapshot) + snapshot.summary_for_anchor(anchor) } }