From 41ca46cf8ca65dbd98df7e038fc12a272f0c9e2a Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Tue, 9 Jan 2024 02:01:04 +0100 Subject: Initialize diagnostics when opening a document (#8873) --- helix-term/src/application.rs | 160 ++++++++++----------------------------- helix-term/src/commands.rs | 26 ++++--- helix-term/src/commands/typed.rs | 6 +- helix-term/src/ui/editor.rs | 4 +- helix-term/src/ui/picker.rs | 13 +++- helix-term/src/ui/statusline.rs | 3 +- 6 files changed, 76 insertions(+), 136 deletions(-) (limited to 'helix-term/src') diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 3abe9cae..4eda8097 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1,14 +1,8 @@ use arc_swap::{access::Map, ArcSwap}; use futures_util::Stream; -use helix_core::{ - chars::char_is_word, - diagnostic::{DiagnosticTag, NumberOrString}, - path::get_relative_path, - pos_at_coords, syntax, Selection, -}; +use helix_core::{path::get_relative_path, pos_at_coords, syntax, Selection}; use helix_lsp::{ lsp::{self, notification::Notification}, - util::lsp_pos_to_pos, LspProgressMap, }; use helix_view::{ @@ -392,6 +386,12 @@ impl Application { self.editor.syn_loader = self.syn_loader.clone(); for document in self.editor.documents.values_mut() { document.detect_language(self.syn_loader.clone()); + let diagnostics = Editor::doc_diagnostics( + &self.editor.language_servers, + &self.editor.diagnostics, + document, + ); + document.replace_diagnostics(diagnostics, &[], None); } Ok(()) @@ -567,6 +567,14 @@ impl Application { let id = doc.id(); doc.detect_language(loader); self.editor.refresh_language_servers(id); + // and again a borrow checker workaround... + let doc = doc_mut!(self.editor, &doc_save_event.doc_id); + let diagnostics = Editor::doc_diagnostics( + &self.editor.language_servers, + &self.editor.diagnostics, + doc, + ); + doc.replace_diagnostics(diagnostics, &[], None); } // TODO: fix being overwritten by lsp @@ -731,7 +739,6 @@ impl Application { log::error!("Discarding publishDiagnostic notification sent by an uninitialized server: {}", language_server.name()); return; } - let offset_encoding = language_server.offset_encoding(); // 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)) @@ -745,11 +752,10 @@ impl Application { true }); - if let Some(doc) = doc { + let mut unchanged_diag_sources = Vec::new(); + if let Some(doc) = &doc { 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) @@ -774,118 +780,11 @@ impl Application { }) .map(|(d, _)| d); if new_diagnostics.eq(old_diagnostics) { - unchaged_diag_sources_.push(source.clone()) + unchanged_diag_sources.push(source.clone()) } } } } - - 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, - diagnostic.range.start, - offset_encoding, - ) { - start - } else { - log::warn!("lsp position out of bounds - {:?}", diagnostic); - return None; - }; - - let end = if let Some(end) = - lsp_pos_to_pos(&text, diagnostic.range.end, offset_encoding) - { - end - } else { - log::warn!("lsp position out of bounds - {:?}", diagnostic); - return None; - }; - let severity = - diagnostic.severity.map(|severity| match severity { - DiagnosticSeverity::ERROR => Error, - DiagnosticSeverity::WARNING => Warning, - DiagnosticSeverity::INFORMATION => Info, - DiagnosticSeverity::HINT => Hint, - severity => unreachable!( - "unrecognized diagnostic severity: {:?}", - severity - ), - }); - - if let Some(lang_conf) = &lang_conf { - if let Some(severity) = severity { - if severity < lang_conf.diagnostic_severity { - return None; - } - } - }; - - let code = match diagnostic.code.clone() { - Some(x) => match x { - lsp::NumberOrString::Number(x) => { - Some(NumberOrString::Number(x)) - } - lsp::NumberOrString::String(x) => { - Some(NumberOrString::String(x)) - } - }, - None => None, - }; - - let tags = if let Some(tags) = &diagnostic.tags { - let new_tags = tags - .iter() - .filter_map(|tag| match *tag { - lsp::DiagnosticTag::DEPRECATED => { - Some(DiagnosticTag::Deprecated) - } - lsp::DiagnosticTag::UNNECESSARY => { - Some(DiagnosticTag::Unnecessary) - } - _ => None, - }) - .collect(); - - new_tags - } else { - Vec::new() - }; - - let ends_at_word = start != end - && end != 0 - && text.get_char(end - 1).map_or(false, char_is_word); - let starts_at_word = start != end - && text.get_char(start).map_or(false, char_is_word); - - Some(Diagnostic { - range: Range { start, end }, - ends_at_word, - starts_at_word, - zero_width: start == end, - line: diagnostic.range.start.line as usize, - message: diagnostic.message.clone(), - severity, - code, - tags, - source: diagnostic.source.clone(), - data: diagnostic.data.clone(), - language_server_id: server_id, - }) - }); - - doc.replace_diagnostics(diagnostics, unchaged_diag_sources, server_id); } let diagnostics = params.diagnostics.into_iter().map(|d| (d, server_id)); @@ -910,6 +809,27 @@ impl Application { diagnostics.sort_unstable_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), + ); + } } Notification::ShowMessage(params) => { log::warn!("unhandled window/showMessage: {:?}", params); @@ -1017,7 +937,7 @@ impl Application { // Clear any diagnostics for documents with this server open. for doc in self.editor.documents_mut() { - doc.clear_diagnostics(server_id); + doc.clear_diagnostics(Some(server_id)); } // Remove the language server from the registry. diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ff0849f2..c9593380 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3350,7 +3350,7 @@ fn exit_select_mode(cx: &mut Context) { fn goto_first_diag(cx: &mut Context) { let (view, doc) = current!(cx.editor); - let selection = match doc.shown_diagnostics().next() { + let selection = match doc.diagnostics().first() { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; @@ -3359,7 +3359,7 @@ fn goto_first_diag(cx: &mut Context) { fn goto_last_diag(cx: &mut Context) { let (view, doc) = current!(cx.editor); - let selection = match doc.shown_diagnostics().last() { + let selection = match doc.diagnostics().last() { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; @@ -3375,9 +3375,10 @@ fn goto_next_diag(cx: &mut Context) { .cursor(doc.text().slice(..)); let diag = doc - .shown_diagnostics() + .diagnostics() + .iter() .find(|diag| diag.range.start > cursor_pos) - .or_else(|| doc.shown_diagnostics().next()); + .or_else(|| doc.diagnostics().first()); let selection = match diag { Some(diag) => Selection::single(diag.range.start, diag.range.end), @@ -3395,10 +3396,11 @@ fn goto_prev_diag(cx: &mut Context) { .cursor(doc.text().slice(..)); let diag = doc - .shown_diagnostics() + .diagnostics() + .iter() .rev() .find(|diag| diag.range.start < cursor_pos) - .or_else(|| doc.shown_diagnostics().last()); + .or_else(|| doc.diagnostics().last()); let selection = match diag { // NOTE: the selection is reversed because we're jumping to the @@ -4185,9 +4187,13 @@ fn replace_with_yanked(cx: &mut Context) { } fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) { - let Some(values) = editor.registers + let Some(values) = editor + .registers .read(register, editor) - .filter(|values| values.len() > 0) else { return }; + .filter(|values| values.len() > 0) + else { + return; + }; let values: Vec<_> = values.map(|value| value.to_string()).collect(); let (view, doc) = current!(editor); @@ -4224,7 +4230,9 @@ fn replace_selections_with_primary_clipboard(cx: &mut Context) { } fn paste(editor: &mut Editor, register: char, pos: Paste, count: usize) { - let Some(values) = editor.registers.read(register, editor) else { return }; + let Some(values) = editor.registers.read(register, editor) else { + return; + }; let values: Vec<_> = values.map(|value| value.to_string()).collect(); let (view, doc) = current!(editor); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index f530ce10..208854e8 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1502,7 +1502,7 @@ fn lsp_stop( for doc in cx.editor.documents_mut() { if let Some(client) = doc.remove_language_server_by_name(ls_name) { - doc.clear_diagnostics(client.id()); + doc.clear_diagnostics(Some(client.id())); } } } @@ -2008,6 +2008,10 @@ fn language( let id = doc.id(); cx.editor.refresh_language_servers(id); + let doc = doc_mut!(cx.editor); + let diagnostics = + Editor::doc_diagnostics(&cx.editor.language_servers, &cx.editor.diagnostics, doc); + doc.replace_diagnostics(diagnostics, &[], None); Ok(()) } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index ff267e42..24fcdb01 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -386,7 +386,7 @@ impl EditorView { let mut warning_vec = Vec::new(); let mut error_vec = Vec::new(); - for diagnostic in doc.shown_diagnostics() { + for diagnostic in doc.diagnostics() { // Separate diagnostics into different Vecs by severity. let (vec, scope) = match diagnostic.severity { Some(Severity::Info) => (&mut info_vec, info), @@ -684,7 +684,7 @@ impl EditorView { .primary() .cursor(doc.text().slice(..)); - let diagnostics = doc.shown_diagnostics().filter(|diagnostic| { + let diagnostics = doc.diagnostics().iter().filter(|diagnostic| { diagnostic.range.start <= cursor && diagnostic.range.end >= cursor }); diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 9ba45335..08a367ba 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -480,8 +480,7 @@ impl Picker { .find::>>() .map(|overlay| &mut overlay.content.file_picker), }; - let Some(picker) = picker - else { + let Some(picker) = picker else { log::info!("picker closed before syntax highlighting finished"); return; }; @@ -489,7 +488,15 @@ impl Picker { let doc = match current_file { PathOrId::Id(doc_id) => doc_mut!(editor, &doc_id), PathOrId::Path(path) => match picker.preview_cache.get_mut(&path) { - Some(CachedPreview::Document(ref mut doc)) => doc, + Some(CachedPreview::Document(ref mut doc)) => { + let diagnostics = Editor::doc_diagnostics( + &editor.language_servers, + &editor.diagnostics, + doc, + ); + doc.replace_diagnostics(diagnostics, &[], None); + doc + } _ => return, }, }; diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index 52dd49f9..9871828e 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -227,7 +227,8 @@ where { let (warnings, errors) = context .doc - .shown_diagnostics() + .diagnostics() + .iter() .fold((0, 0), |mut counts, diag| { use helix_core::diagnostic::Severity; match diag.severity { -- cgit v1.2.3-70-g09d2