Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--helix-term/src/application.rs105
-rw-r--r--helix-view/src/handlers/lsp.rs92
2 files changed, 99 insertions, 98 deletions
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index ba74a817..242cce1b 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -11,7 +11,6 @@ use helix_view::{
align_view,
document::{DocumentOpenError, DocumentSavedEventResult},
editor::{ConfigEvent, EditorEvent},
- events::DiagnosticsDidChange,
graphics::Rect,
theme,
tree::Layout,
@@ -33,7 +32,7 @@ use crate::{
use log::{debug, error, info, warn};
#[cfg(not(feature = "integration"))]
use std::io::stdout;
-use std::{collections::btree_map::Entry, io::stdin, path::Path, sync::Arc};
+use std::{io::stdin, path::Path, sync::Arc};
#[cfg(not(windows))]
use anyhow::Context;
@@ -748,7 +747,7 @@ impl Application {
);
}
}
- Notification::PublishDiagnostics(mut params) => {
+ Notification::PublishDiagnostics(params) => {
let uri = match helix_core::Uri::try_from(params.uri) {
Ok(uri) => uri,
Err(err) => {
@@ -761,100 +760,12 @@ impl Application {
log::error!("Discarding publishDiagnostic notification sent by an uninitialized server: {}", language_server.name());
return;
}
- // have to inline the function because of borrow checking...
- let doc = self.editor.documents.values_mut()
- .find(|doc| doc.uri().is_some_and(|u| u == uri))
- .filter(|doc| {
- if let Some(version) = params.version {
- if version != doc.version() {
- log::info!("Version ({version}) is out of date for {uri:?} (expected ({}), dropping PublishDiagnostic notification", doc.version());
- return false;
- }
- }
- true
- });
-
- let mut unchanged_diag_sources = Vec::new();
- if let Some(doc) = &doc {
- let lang_conf = doc.language.clone();
-
- if let Some(lang_conf) = &lang_conf {
- if let Some(old_diagnostics) = self.editor.diagnostics.get(&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_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) {
- unchanged_diag_sources.push(source.clone())
- }
- }
- }
- }
- }
-
- 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.
- let diagnostics = match self.editor.diagnostics.entry(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.extend(diagnostics);
- current_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_by_key(|(d, server_id)| (d.severity, d.range.start, *server_id));
-
- if let Some(doc) = doc {
- let diagnostic_of_language_server_and_not_in_unchanged_sources =
- |diagnostic: &lsp::Diagnostic, ls_id| {
- ls_id == server_id
- && diagnostic.source.as_ref().map_or(true, |source| {
- !unchanged_diag_sources.contains(source)
- })
- };
- let diagnostics = Editor::doc_diagnostics_with_filter(
- &self.editor.language_servers,
- &self.editor.diagnostics,
- doc,
- diagnostic_of_language_server_and_not_in_unchanged_sources,
- );
- doc.replace_diagnostics(
- diagnostics,
- &unchanged_diag_sources,
- Some(server_id),
- );
-
- let doc = doc.id();
- helix_event::dispatch(DiagnosticsDidChange {
- editor: &mut self.editor,
- doc,
- });
- }
+ self.editor.handle_lsp_diagnostics(
+ language_server.id(),
+ uri,
+ params.version,
+ params.diagnostics,
+ );
}
Notification::ShowMessage(params) => {
if self.config.load().editor.lsp.display_messages {
diff --git a/helix-view/src/handlers/lsp.rs b/helix-view/src/handlers/lsp.rs
index 39e7dba9..3f0cfbfc 100644
--- a/helix-view/src/handlers/lsp.rs
+++ b/helix-view/src/handlers/lsp.rs
@@ -1,10 +1,12 @@
+use std::collections::btree_map::Entry;
use std::fmt::Display;
use crate::editor::Action;
+use crate::events::DiagnosticsDidChange;
use crate::Editor;
use helix_core::Uri;
use helix_lsp::util::generate_transaction_from_edits;
-use helix_lsp::{lsp, OffsetEncoding};
+use helix_lsp::{lsp, LanguageServerId, OffsetEncoding};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SignatureHelpInvoked {
@@ -271,4 +273,92 @@ impl Editor {
}
Ok(())
}
+
+ pub fn handle_lsp_diagnostics(
+ &mut self,
+ server_id: LanguageServerId,
+ uri: Uri,
+ version: Option<i32>,
+ mut diagnostics: Vec<lsp::Diagnostic>,
+ ) {
+ let doc = self.documents.values_mut()
+ .find(|doc| doc.uri().is_some_and(|u| u == uri))
+ .filter(|doc| {
+ if let Some(version) = version {
+ if version != doc.version() {
+ log::info!("Version ({version}) is out of date for {uri:?} (expected ({}), dropping PublishDiagnostic notification", doc.version());
+ return false;
+ }
+ }
+ true
+ });
+
+ let mut unchanged_diag_sources = Vec::new();
+ if let Some((lang_conf, old_diagnostics)) = doc
+ .as_ref()
+ .and_then(|doc| Some((doc.language_config()?, self.diagnostics.get(&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
+ diagnostics.sort_by_key(|d| (d.severity, d.range.start));
+ }
+ for source in &lang_conf.persistent_diagnostic_sources {
+ let new_diagnostics = 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) {
+ unchanged_diag_sources.push(source.clone())
+ }
+ }
+ }
+
+ let diagnostics = diagnostics.into_iter().map(|d| (d, server_id));
+
+ // Insert the original lsp::Diagnostics here because we may have no open document
+ // for diagnostic message and so we can't calculate the exact position.
+ // When using them later in the diagnostics picker, we calculate them on-demand.
+ let diagnostics = match self.diagnostics.entry(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.extend(diagnostics);
+ current_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_by_key(|(d, server_id)| (d.severity, d.range.start, *server_id));
+
+ if let Some(doc) = doc {
+ let diagnostic_of_language_server_and_not_in_unchanged_sources =
+ |diagnostic: &lsp::Diagnostic, ls_id| {
+ ls_id == server_id
+ && diagnostic
+ .source
+ .as_ref()
+ .map_or(true, |source| !unchanged_diag_sources.contains(source))
+ };
+ let diagnostics = Self::doc_diagnostics_with_filter(
+ &self.language_servers,
+ &self.diagnostics,
+ doc,
+ diagnostic_of_language_server_and_not_in_unchanged_sources,
+ );
+ doc.replace_diagnostics(diagnostics, &unchanged_diag_sources, Some(server_id));
+
+ let doc = doc.id();
+ helix_event::dispatch(DiagnosticsDidChange { editor: self, doc });
+ }
+ }
}