From 99772489263c18b973452c41b80078983cbc8ca4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 27 Oct 2021 18:58:07 -0600 Subject: [PATCH] Adjust disk-based diagnostics based on edits since the last save Still need to add tests... not sure if this is right yet. Co-Authored-By: Max Brunsfeld --- crates/buffer/src/lib.rs | 3 +++ crates/language/src/language.rs | 8 +++---- crates/language/src/lib.rs | 42 +++++++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 00fe10ad337747db222ef1007eb06b32155e2ea0..40610fcbc3fd1293937c0097679503666d2a3e54 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -332,6 +332,7 @@ pub struct Edit { pub old_bytes: Range, pub new_bytes: Range, pub old_lines: Range, + pub new_lines: Range, } impl Edit { @@ -2014,6 +2015,7 @@ impl<'a, F: FnMut(&FragmentSummary) -> bool> Iterator for Edits<'a, F> { old_bytes: self.old_offset..self.old_offset, new_bytes: self.new_offset..self.new_offset + fragment.len, old_lines: self.old_point..self.old_point, + new_lines: self.new_point..self.new_point + fragment_lines, }); } @@ -2035,6 +2037,7 @@ impl<'a, F: FnMut(&FragmentSummary) -> bool> Iterator for Edits<'a, F> { old_bytes: self.old_offset..self.old_offset + fragment.len, new_bytes: self.new_offset..self.new_offset, old_lines: self.old_point..self.old_point + &fragment_lines, + new_lines: self.new_point..self.new_point, }); } diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index b6ff132881c0df34cc4543617b88f834332d3012..8517f3c2a0adec661e18ad50d2efd612e0d31d96 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -3,7 +3,7 @@ use anyhow::Result; use gpui::AppContext; use parking_lot::Mutex; use serde::Deserialize; -use std::{path::Path, str, sync::Arc}; +use std::{collections::HashSet, path::Path, str, sync::Arc}; use theme::SyntaxTheme; use tree_sitter::{Language as Grammar, Query}; pub use tree_sitter::{Parser, Tree}; @@ -19,7 +19,7 @@ pub struct LanguageConfig { #[derive(Deserialize)] pub struct LanguageServerConfig { pub binary: String, - pub disk_based_diagnostic_sources: Vec, + pub disk_based_diagnostic_sources: HashSet, } #[derive(Clone, Debug, Deserialize)] @@ -130,11 +130,11 @@ impl Language { } } - pub fn disk_based_diagnostic_sources(&self) -> &[String] { + pub fn disk_based_diagnostic_sources(&self) -> Option<&HashSet> { self.config .language_server .as_ref() - .map_or(&[], |config| &config.disk_based_diagnostic_sources) + .map(|config| &config.disk_based_diagnostic_sources) } pub fn brackets(&self) -> &[BracketPair] { diff --git a/crates/language/src/lib.rs b/crates/language/src/lib.rs index 866e182af3411749608a98ba6cf6716f16e3d2a3..cae05b983b5f339821b3076a5b7c052116c0db62 100644 --- a/crates/language/src/lib.rs +++ b/crates/language/src/lib.rs @@ -661,18 +661,52 @@ impl Buffer { } else { self.content() }; + + let empty_set = HashSet::new(); + let disk_based_sources = self + .language + .as_ref() + .and_then(|language| language.disk_based_diagnostic_sources()) + .unwrap_or(&empty_set); + + let mut edits_since_save = self.text.edits_since(self.saved_version.clone()).peekable(); + let mut last_edit_old_end = Point::zero(); + let mut last_edit_new_end = Point::zero(); + self.diagnostics = content.anchor_range_multimap( Bias::Left, Bias::Right, - diagnostics.into_iter().map(|diagnostic| { + diagnostics.into_iter().filter_map(|diagnostic| { // TODO: Use UTF-16 positions. - let start = Point::new( + let mut start = Point::new( diagnostic.range.start.line, diagnostic.range.start.character, ); - let end = Point::new(diagnostic.range.end.line, diagnostic.range.end.character); + let mut end = Point::new(diagnostic.range.end.line, diagnostic.range.end.character); let severity = diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR); - (start..end, (severity, diagnostic.message)) + + 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_lines.end <= start { + last_edit_old_end = edit.old_lines.end; + last_edit_new_end = edit.new_lines.end; + edits_since_save.next(); + } else if edit.old_lines.start <= end && edit.old_lines.end >= start { + return None; + } else { + break; + } + } + + start = last_edit_new_end + (start - last_edit_old_end); + end = last_edit_new_end + (end - last_edit_old_end); + } + + Some((start..end, (severity, diagnostic.message))) }), );