Pull diagnostics on open

This commit is contained in:
Sofus Addington 2024-08-14 22:22:55 +02:00
parent 96a984c6a4
commit a8f1b9ecd7
7 changed files with 145 additions and 32 deletions

View File

@ -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::<PostInsertChar>();
register_event::<PostCommand>();
register_event::<DocumentDidChange>();
register_event::<DocumentDidOpen>();
register_event::<SelectionDidChange>();
register_event::<DiagnosticsDidChange>();
}

View File

@ -14,6 +14,8 @@
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<ArcSwap<Config>>) -> 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);

View File

@ -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_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<LanguageServerId>,
language_server_ids: HashSet<LanguageServerId>,
}
impl PullDiagnosticsHandler {
pub fn new() -> PullDiagnosticsHandler {
PullDiagnosticsHandler {
language_server_ids: vec![],
language_server_ids: [].into(),
}
}
}
pub(super) struct PullDiagnosticsForDocumentsHandler {
document_ids: HashSet<DocumentId>,
}
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,96 @@ fn handle_event(
_: Option<tokio::time::Instant>,
) -> Option<tokio::time::Instant> {
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)
})
}
}
fn pull_diagnostic_for_document(
impl helix_event::AsyncHook for PullDiagnosticsForDocumentsHandler {
type Event = PullDiagnosticsForDocumentsEvent;
fn handle_event(
&mut self,
event: Self::Event,
_: Option<tokio::time::Instant>,
) -> Option<tokio::time::Instant> {
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_diagnostics_for_documents(editor: &mut Editor, document_ids: HashSet<DocumentId>) {
for document_id in document_ids {
let doc = doc_mut!(editor, &document_id);
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<lsp::DocumentDiagnosticReport> =
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<LanguageServerId>,
document_ids: Vec<helix_view::DocumentId>,
language_server_ids: HashSet<LanguageServerId>,
) {
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 +215,6 @@ fn pull_diagnostic_for_document(
match future.await {
Ok(res) => {
job::dispatch(move |editor, _| {
log::error!("{}", res);
let parsed_response: Option<lsp::DocumentDiagnosticReport> =
match serde_json::from_value(res) {
Ok(result) => Some(result),
@ -135,18 +225,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 +253,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 +283,7 @@ fn show_pull_diagnostics(
}
}
fn parse_diagnostic(
fn add_diagnostic(
editor: &mut Editor,
uri: Uri,
report: Vec<lsp::Diagnostic>,
@ -213,7 +309,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);

View File

@ -3,6 +3,7 @@
document::{
DocumentOpenError, DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint,
},
events::DocumentDidOpen,
graphics::{CursorKind, Rect},
handlers::Handlers,
info::Info,
@ -1717,6 +1718,8 @@ pub fn open(&mut self, path: &Path, action: Action) -> Result<DocumentId, Docume
let id = self.new_document(doc);
self.launch_language_servers(id);
helix_event::dispatch(DocumentDidOpen { doc: id });
id
};

View File

@ -5,6 +5,7 @@
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 }
}

View File

@ -19,7 +19,8 @@ pub struct Handlers {
pub completions: Sender<lsp::CompletionEvent>,
pub signature_hints: Sender<lsp::SignatureHelpEvent>,
pub auto_save: Sender<AutoSaveEvent>,
pub pull_diagnostics: Sender<lsp::PullDiagnosticsEvent>,
pub pull_diagnostics: Sender<lsp::PullDiagnosticsForLanguageServersEvent>,
pub pull_diagnostics_document: Sender<lsp::PullDiagnosticsForDocumentsEvent>,
}
impl Handlers {

View File

@ -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<helix_lsp::LanguageServerId>,
pub struct PullDiagnosticsForLanguageServersEvent {
pub language_server_ids: HashSet<helix_lsp::LanguageServerId>,
}
pub struct PullDiagnosticsForDocumentsEvent {
pub document_id: DocumentId,
}
#[derive(Debug)]