diff options
Diffstat (limited to 'helix-term')
-rw-r--r-- | helix-term/src/application.rs | 105 |
1 files changed, 68 insertions, 37 deletions
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index ed085749..35111ca5 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -717,7 +717,7 @@ impl Application { )); } } - Notification::PublishDiagnostics(params) => { + Notification::PublishDiagnostics(mut params) => { let path = match params.uri.to_file_path() { Ok(path) => path, Err(_) => { @@ -731,31 +731,69 @@ impl Application { return; } let offset_encoding = language_server.offset_encoding(); - let doc = self.editor.document_by_path_mut(&path).filter(|doc| { - if let Some(version) = params.version { - if version != doc.version() { - log::info!("Version ({version}) is out of date for {path:?} (expected ({}), dropping PublishDiagnostic notification", doc.version()); - return false; + // have to inline the function because of borrow checking... + let doc = self.editor.documents.values_mut() + .find(|doc| doc.path().map(|p| p == &path).unwrap_or(false)) + .filter(|doc| { + if let Some(version) = params.version { + if version != doc.version() { + log::info!("Version ({version}) is out of date for {path:?} (expected ({}), dropping PublishDiagnostic notification", doc.version()); + return false; + } } - } - - true - }); + true + }); if let Some(doc) = doc { - let lang_conf = doc.language_config(); - let text = doc.text(); + let lang_conf = doc.language.clone(); + let text = doc.text().clone(); + + let mut unchaged_diag_sources_ = Vec::new(); + if let Some(lang_conf) = &lang_conf { + if let Some(old_diagnostics) = + self.editor.diagnostics.get(¶ms.uri) + { + if !lang_conf.persistent_diagnostic_sources.is_empty() { + // Sort diagnostics first by severity and then by line numbers. + // Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order + params + .diagnostics + .sort_unstable_by_key(|d| (d.severity, d.range.start)); + } + for source in &lang_conf.persistent_diagnostic_sources { + let new_diagnostics = params + .diagnostics + .iter() + .filter(|d| d.source.as_ref() == Some(source)); + let old_diagnostics = old_diagnostics + .iter() + .filter(|(d, d_server)| { + *d_server == server_id + && d.source.as_ref() == Some(source) + }) + .map(|(d, _)| d); + if new_diagnostics.eq(old_diagnostics) { + unchaged_diag_sources_.push(source.clone()) + } + } + } + } - let diagnostics = params - .diagnostics - .iter() - .filter_map(|diagnostic| { + let unchaged_diag_sources = &unchaged_diag_sources_; + let diagnostics = + params.diagnostics.iter().filter_map(move |diagnostic| { use helix_core::diagnostic::{Diagnostic, Range, Severity::*}; use lsp::DiagnosticSeverity; + if diagnostic.source.as_ref().map_or(false, |source| { + unchaged_diag_sources.contains(source) + }) { + return None; + } + // TODO: convert inside server let start = if let Some(start) = lsp_pos_to_pos( - text, + &text, diagnostic.range.start, offset_encoding, ) { @@ -766,7 +804,7 @@ impl Application { }; let end = if let Some(end) = - lsp_pos_to_pos(text, diagnostic.range.end, offset_encoding) + lsp_pos_to_pos(&text, diagnostic.range.end, offset_encoding) { end } else { @@ -786,7 +824,7 @@ impl Application { ), }); - if let Some(lang_conf) = lang_conf { + if let Some(lang_conf) = &lang_conf { if let Some(severity) = severity { if severity < lang_conf.diagnostic_severity { return None; @@ -836,38 +874,31 @@ impl Application { data: diagnostic.data.clone(), language_server_id: server_id, }) - }) - .collect(); + }); - doc.replace_diagnostics(diagnostics, server_id); + doc.replace_diagnostics(diagnostics, unchaged_diag_sources, server_id); } - let mut diagnostics = params - .diagnostics - .into_iter() - .map(|d| (d, server_id)) - .collect(); + let diagnostics = params.diagnostics.into_iter().map(|d| (d, server_id)); // Insert the original lsp::Diagnostics here because we may have no open document // for diagnosic message and so we can't calculate the exact position. // When using them later in the diagnostics picker, we calculate them on-demand. - match self.editor.diagnostics.entry(params.uri) { + let diagnostics = match self.editor.diagnostics.entry(params.uri) { Entry::Occupied(o) => { let current_diagnostics = o.into_mut(); // there may entries of other language servers, which is why we can't overwrite the whole entry current_diagnostics.retain(|(_, lsp_id)| *lsp_id != server_id); - current_diagnostics.append(&mut diagnostics); - // Sort diagnostics first by severity and then by line numbers. - // Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order + current_diagnostics.extend(diagnostics); current_diagnostics - .sort_unstable_by_key(|(d, _)| (d.severity, d.range.start)); - } - Entry::Vacant(v) => { - diagnostics - .sort_unstable_by_key(|(d, _)| (d.severity, d.range.start)); - v.insert(diagnostics); + // Sort diagnostics first by severity and then by line numbers. } + Entry::Vacant(v) => v.insert(diagnostics.collect()), }; + + // Sort diagnostics first by severity and then by line numbers. + // Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order + diagnostics.sort_unstable_by_key(|(d, _)| (d.severity, d.range.start)); } Notification::ShowMessage(params) => { log::warn!("unhandled window/showMessage: {:?}", params); |