From 9e667bdd8d789401477833a9e9bf7b4d8138dca8 Mon Sep 17 00:00:00 2001 From: Sofus Addington Date: Wed, 14 Aug 2024 22:22:55 +0200 Subject: [PATCH] Pull diagnostics on open --- helix-term/src/events.rs | 5 +- helix-term/src/handlers.rs | 4 + helix-term/src/handlers/diagnostics.rs | 154 ++++++++++++++++++++----- helix-view/src/editor.rs | 3 + helix-view/src/events.rs | 1 + helix-view/src/handlers.rs | 3 +- helix-view/src/handlers/lsp.rs | 9 +- 7 files changed, 147 insertions(+), 32 deletions(-) diff --git a/helix-term/src/events.rs b/helix-term/src/events.rs index 415213c2245e5..95e0b34e20c79 100644 --- a/helix-term/src/events.rs +++ b/helix-term/src/events.rs @@ -1,6 +1,8 @@ use helix_event::{events, register_event}; use helix_view::document::Mode; -use helix_view::events::{DiagnosticsDidChange, DocumentDidChange, SelectionDidChange}; +use helix_view::events::{ + DiagnosticsDidChange, DocumentDidChange, DocumentDidOpen, SelectionDidChange, +}; use crate::commands; use crate::keymap::MappableCommand; @@ -16,6 +18,7 @@ pub fn register() { register_event::(); register_event::(); register_event::(); + register_event::(); register_event::(); register_event::(); } diff --git a/helix-term/src/handlers.rs b/helix-term/src/handlers.rs index b32b9e2ffdb02..b737eb409e4f8 100644 --- a/helix-term/src/handlers.rs +++ b/helix-term/src/handlers.rs @@ -14,6 +14,8 @@ use crate::handlers::signature_help::SignatureHelpHandler; pub use completion::trigger_auto_completion; pub use helix_view::handlers::Handlers; +use self::diagnostics::PullDiagnosticsForDocumentsHandler; + mod auto_save; pub mod completion; mod diagnostics; @@ -26,12 +28,14 @@ pub fn setup(config: Arc>) -> Handlers { let signature_hints = SignatureHelpHandler::new().spawn(); let auto_save = AutoSaveHandler::new().spawn(); let pull_diagnostics = PullDiagnosticsHandler::new().spawn(); + let pull_diagnostics_document = PullDiagnosticsForDocumentsHandler::new().spawn(); let handlers = Handlers { completions, signature_hints, auto_save, pull_diagnostics, + pull_diagnostics_document, }; completion::register_hooks(&handlers); diff --git a/helix-term/src/handlers/diagnostics.rs b/helix-term/src/handlers/diagnostics.rs index 9db591fbde740..74478f25abc66 100644 --- a/helix-term/src/handlers/diagnostics.rs +++ b/helix-term/src/handlers/diagnostics.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::time::Duration; use helix_core::syntax::LanguageServerFeature; @@ -7,11 +7,13 @@ use helix_event::{register_hook, send_blocking}; use helix_lsp::lsp::{self, Diagnostic}; use helix_lsp::LanguageServerId; use helix_view::document::Mode; -use helix_view::events::{DiagnosticsDidChange, DocumentDidChange}; +use helix_view::events::{DiagnosticsDidChange, DocumentDidChange, DocumentDidOpen}; use helix_view::handlers::diagnostics::DiagnosticEvent; -use helix_view::handlers::lsp::PullDiagnosticsEvent; +use helix_view::handlers::lsp::{ + PullDiagnosticsForDocumentsEvent, PullDiagnosticsForLanguageServersEvent, +}; use helix_view::handlers::Handlers; -use helix_view::Editor; +use helix_view::{DocumentId, Editor}; use tokio::time::Instant; use crate::events::OnModeSwitch; @@ -47,32 +49,53 @@ pub(super) fn register_hooks(handlers: &Handlers) { send_blocking( &tx, - PullDiagnosticsEvent { + PullDiagnosticsForLanguageServersEvent { language_server_ids, }, ); } Ok(()) }); -} -const TIMEOUT: u64 = 120; + let tx = handlers.pull_diagnostics_document.clone(); + register_hook!(move |event: &mut DocumentDidOpen| { + send_blocking( + &tx, + PullDiagnosticsForDocumentsEvent { + document_id: event.doc, + }, + ); + + Ok(()) + }); +} #[derive(Debug)] pub(super) struct PullDiagnosticsHandler { - language_server_ids: Vec, + language_server_ids: HashSet, } impl PullDiagnosticsHandler { pub fn new() -> PullDiagnosticsHandler { PullDiagnosticsHandler { - language_server_ids: vec![], + language_server_ids: [].into(), + } + } +} +pub(super) struct PullDiagnosticsForDocumentsHandler { + document_ids: HashSet, +} + +impl PullDiagnosticsForDocumentsHandler { + pub fn new() -> PullDiagnosticsForDocumentsHandler { + PullDiagnosticsForDocumentsHandler { + document_ids: [].into(), } } } impl helix_event::AsyncHook for PullDiagnosticsHandler { - type Event = PullDiagnosticsEvent; + type Event = PullDiagnosticsForLanguageServersEvent; fn handle_event( &mut self, @@ -80,27 +103,98 @@ impl helix_event::AsyncHook for PullDiagnosticsHandler { _: Option, ) -> Option { self.language_server_ids = event.language_server_ids; - Some(Instant::now() + Duration::from_millis(TIMEOUT)) + Some(Instant::now() + Duration::from_millis(120)) } fn finish_debounce(&mut self) { let language_servers = self.language_server_ids.clone(); job::dispatch_blocking(move |editor, _| { - pull_diagnostic_for_document( - editor, - language_servers, - editor.documents().map(|x| x.id()).collect(), - ) + pull_diagnostic_for_language_servers(editor, language_servers) + }) + } +} + +impl helix_event::AsyncHook for PullDiagnosticsForDocumentsHandler { + type Event = PullDiagnosticsForDocumentsEvent; + + fn handle_event( + &mut self, + event: Self::Event, + _: Option, + ) -> Option { + self.document_ids.insert(event.document_id); + + Some(Instant::now() + Duration::from_millis(50)) + } + + fn finish_debounce(&mut self) { + let document_ids = self.document_ids.clone(); + job::dispatch_blocking(move |editor, _| { + pull_diagnostics_for_documents(editor, document_ids) }) } } -fn pull_diagnostic_for_document( +fn pull_diagnostics_for_documents(editor: &mut Editor, document_ids: HashSet) { + for document_id in document_ids { + let doc = doc_mut!(editor, &document_id); + + log::error!("Pulling for {:?}", doc.path()); + + let language_servers = + doc.language_servers_with_feature(LanguageServerFeature::PullDiagnostics); + + for language_server in language_servers { + let Some(future) = language_server + .text_document_diagnostic(doc.identifier(), doc.previous_diagnostic_id.clone()) + else { + return; + }; + + let Some(uri) = doc.uri() else { + return; + }; + + let server_id = language_server.id(); + + tokio::spawn(async move { + match future.await { + Ok(res) => { + job::dispatch(move |editor, _| { + let parsed_response: Option = + match serde_json::from_value(res) { + Ok(result) => Some(result), + Err(_) => None, + }; + + let Some(response) = parsed_response else { + return; + }; + + handle_pull_diagnostics_response( + editor, + response, + server_id, + uri, + &document_id, + ) + }) + .await + } + Err(err) => log::error!("Pull diagnostic request failed: {err}"), + } + }); + } + } +} + +fn pull_diagnostic_for_language_servers( editor: &mut Editor, - language_server_ids: Vec, - document_ids: Vec, + language_server_ids: HashSet, ) { - for document_id in document_ids.clone() { + let document_ids: Vec<_> = editor.documents().map(|x| x.id()).collect(); + + for document_id in document_ids { let doc = doc_mut!(editor, &document_id); let language_servers = doc .language_servers() @@ -123,8 +217,6 @@ fn pull_diagnostic_for_document( match future.await { Ok(res) => { job::dispatch(move |editor, _| { - log::error!("{}", res); - let parsed_response: Option = match serde_json::from_value(res) { Ok(result) => Some(result), @@ -135,18 +227,24 @@ fn pull_diagnostic_for_document( return; }; - show_pull_diagnostics(editor, response, server_id, uri, &document_id) + handle_pull_diagnostics_response( + editor, + response, + server_id, + uri, + &document_id, + ) }) .await } - Err(err) => log::error!("signature help request failed: {err}"), + Err(err) => log::error!("Pull diagnostic request failed: {err}"), } }); } } } -fn show_pull_diagnostics( +fn handle_pull_diagnostics_response( editor: &mut Editor, response: lsp::DocumentDiagnosticReport, server_id: LanguageServerId, @@ -157,7 +255,7 @@ fn show_pull_diagnostics( match response { lsp::DocumentDiagnosticReport::Full(report) => { // Original file diagnostic - parse_diagnostic( + add_diagnostic( editor, uri, report.full_document_diagnostic_report.items, @@ -187,7 +285,7 @@ fn show_pull_diagnostics( } } -fn parse_diagnostic( +fn add_diagnostic( editor: &mut Editor, uri: Uri, report: Vec, @@ -213,7 +311,7 @@ fn handle_document_diagnostic_report_kind( return; }; - parse_diagnostic(editor, uri, report.items, report.result_id, server_id); + add_diagnostic(editor, uri, report.items, report.result_id, server_id); } lsp::DocumentDiagnosticReportKind::Unchanged(report) => { let doc = doc_mut!(editor, &document_id); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 691c762b59b55..39122672e1e1b 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -3,6 +3,7 @@ use crate::{ document::{ DocumentOpenError, DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint, }, + events::DocumentDidOpen, graphics::{CursorKind, Rect}, handlers::Handlers, info::Info, @@ -1717,6 +1718,8 @@ impl Editor { let id = self.new_document(doc); self.launch_language_servers(id); + helix_event::dispatch(DocumentDidOpen { doc: id }); + id }; diff --git a/helix-view/src/events.rs b/helix-view/src/events.rs index 881412495464b..3ee4beb9ee817 100644 --- a/helix-view/src/events.rs +++ b/helix-view/src/events.rs @@ -5,6 +5,7 @@ use crate::{Document, DocumentId, Editor, ViewId}; events! { DocumentDidChange<'a> { doc: &'a mut Document, view: ViewId, old_text: &'a Rope } + DocumentDidOpen { doc: DocumentId} SelectionDidChange<'a> { doc: &'a mut Document, view: ViewId } DiagnosticsDidChange<'a> { editor: &'a mut Editor, doc: DocumentId } } diff --git a/helix-view/src/handlers.rs b/helix-view/src/handlers.rs index 519ccca8abd1f..1dedf1bcef044 100644 --- a/helix-view/src/handlers.rs +++ b/helix-view/src/handlers.rs @@ -19,7 +19,8 @@ pub struct Handlers { pub completions: Sender, pub signature_hints: Sender, pub auto_save: Sender, - pub pull_diagnostics: Sender, + pub pull_diagnostics: Sender, + pub pull_diagnostics_document: Sender, } impl Handlers { diff --git a/helix-view/src/handlers/lsp.rs b/helix-view/src/handlers/lsp.rs index ff540fd0f6e4b..bd0aba74fe14a 100644 --- a/helix-view/src/handlers/lsp.rs +++ b/helix-view/src/handlers/lsp.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::fmt::Display; use crate::editor::Action; @@ -47,8 +48,12 @@ pub enum SignatureHelpEvent { RequestComplete { open: bool }, } -pub struct PullDiagnosticsEvent { - pub language_server_ids: Vec, +pub struct PullDiagnosticsForLanguageServersEvent { + pub language_server_ids: HashSet, +} + +pub struct PullDiagnosticsForDocumentsEvent { + pub document_id: DocumentId, } #[derive(Debug)]