mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-25 19:03:30 +04:00
Use async hook instead
This commit is contained in:
parent
1e446d57c4
commit
3a56e4858c
@ -2,8 +2,8 @@
|
|||||||
use helix_lsp::{
|
use helix_lsp::{
|
||||||
block_on,
|
block_on,
|
||||||
lsp::{
|
lsp::{
|
||||||
self, CodeAction, CodeActionOrCommand, CodeActionTriggerKind, Diagnostic,
|
self, CodeAction, CodeActionOrCommand, CodeActionTriggerKind, DiagnosticSeverity,
|
||||||
DiagnosticSeverity, NumberOrString,
|
NumberOrString,
|
||||||
},
|
},
|
||||||
util::{diagnostic_to_lsp_diagnostic, lsp_range_to_range, range_to_lsp_range},
|
util::{diagnostic_to_lsp_diagnostic, lsp_range_to_range, range_to_lsp_range},
|
||||||
Client, LanguageServerId, OffsetEncoding,
|
Client, LanguageServerId, OffsetEncoding,
|
||||||
@ -33,10 +33,10 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::{BTreeMap, HashMap, HashSet},
|
collections::{BTreeMap, HashSet},
|
||||||
fmt::{Display, Write},
|
fmt::{Display, Write},
|
||||||
future::Future,
|
future::Future,
|
||||||
path::{Path, PathBuf},
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Gets the first language server that is attached to a document which supports a specific feature.
|
/// Gets the first language server that is attached to a document which supports a specific feature.
|
||||||
@ -1424,92 +1424,3 @@ fn compute_inlay_hints_for_view(
|
|||||||
|
|
||||||
Some(callback)
|
Some(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pull_diagnostic_for_current_doc(editor: &Editor, jobs: &mut crate::job::Jobs) {
|
|
||||||
let doc = doc!(editor);
|
|
||||||
|
|
||||||
for language_server in doc.language_servers_with_feature(LanguageServerFeature::PullDiagnostics)
|
|
||||||
{
|
|
||||||
let future = language_server
|
|
||||||
.text_document_diagnostic(doc.identifier(), doc.previous_diagnostic_id.clone());
|
|
||||||
|
|
||||||
let server_id = language_server.id();
|
|
||||||
let original_path = doc
|
|
||||||
.path()
|
|
||||||
.expect("safety: the file has a path if there is a running language server")
|
|
||||||
.to_owned();
|
|
||||||
|
|
||||||
let callback = super::make_job_callback(
|
|
||||||
future.expect("safety: language server supports pull diagnostics"),
|
|
||||||
move |editor, _compositor, response: Option<lsp::DocumentDiagnosticReport>| {
|
|
||||||
let parse_diagnostic =
|
|
||||||
|editor: &mut Editor,
|
|
||||||
path: PathBuf,
|
|
||||||
report: Vec<lsp::Diagnostic>,
|
|
||||||
result_id: Option<String>| {
|
|
||||||
let uri = helix_core::Uri::try_from(path);
|
|
||||||
let diagnostics: Vec<(Diagnostic, LanguageServerId)> =
|
|
||||||
report.into_iter().map(|d| (d, server_id)).collect();
|
|
||||||
|
|
||||||
if let Ok(uri) = uri {
|
|
||||||
editor.add_diagnostics(diagnostics, server_id, uri, None, result_id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let handle_document_diagnostic_report_kind = |editor: &mut Editor,
|
|
||||||
report: Option<
|
|
||||||
HashMap<lsp::Url, lsp::DocumentDiagnosticReportKind>,
|
|
||||||
>| {
|
|
||||||
for (url, report) in report.into_iter().flatten() {
|
|
||||||
match report {
|
|
||||||
lsp::DocumentDiagnosticReportKind::Full(report) => {
|
|
||||||
let path = url.to_file_path().unwrap();
|
|
||||||
parse_diagnostic(editor, path, report.items, report.result_id);
|
|
||||||
}
|
|
||||||
lsp::DocumentDiagnosticReportKind::Unchanged(report) => {
|
|
||||||
let Some(doc) = editor.document_by_path_mut(url.path()) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
doc.previous_diagnostic_id = Some(report.result_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(response) = response {
|
|
||||||
let doc = match editor.document_by_path_mut(&original_path) {
|
|
||||||
Some(doc) => doc,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
match response {
|
|
||||||
lsp::DocumentDiagnosticReport::Full(report) => {
|
|
||||||
// Original file diagnostic
|
|
||||||
parse_diagnostic(
|
|
||||||
editor,
|
|
||||||
original_path,
|
|
||||||
report.full_document_diagnostic_report.items,
|
|
||||||
report.full_document_diagnostic_report.result_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Related files diagnostic
|
|
||||||
handle_document_diagnostic_report_kind(
|
|
||||||
editor,
|
|
||||||
report.related_documents,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
lsp::DocumentDiagnosticReport::Unchanged(report) => {
|
|
||||||
doc.previous_diagnostic_id =
|
|
||||||
Some(report.unchanged_document_diagnostic_report.result_id);
|
|
||||||
handle_document_diagnostic_report_kind(
|
|
||||||
editor,
|
|
||||||
report.related_documents,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
jobs.callback(callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
pub use completion::trigger_auto_completion;
|
pub use completion::trigger_auto_completion;
|
||||||
pub use helix_view::handlers::Handlers;
|
pub use helix_view::handlers::Handlers;
|
||||||
|
|
||||||
|
use self::diagnostics::PullDiagnosticsHandler;
|
||||||
|
|
||||||
mod auto_save;
|
mod auto_save;
|
||||||
pub mod completion;
|
pub mod completion;
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
@ -23,11 +25,13 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
|
|||||||
let completions = CompletionHandler::new(config).spawn();
|
let completions = CompletionHandler::new(config).spawn();
|
||||||
let signature_hints = SignatureHelpHandler::new().spawn();
|
let signature_hints = SignatureHelpHandler::new().spawn();
|
||||||
let auto_save = AutoSaveHandler::new().spawn();
|
let auto_save = AutoSaveHandler::new().spawn();
|
||||||
|
let pull_diagnostics = PullDiagnosticsHandler::new().spawn();
|
||||||
|
|
||||||
let handlers = Handlers {
|
let handlers = Handlers {
|
||||||
completions,
|
completions,
|
||||||
signature_hints,
|
signature_hints,
|
||||||
auto_save,
|
auto_save,
|
||||||
|
pull_diagnostics,
|
||||||
};
|
};
|
||||||
|
|
||||||
completion::register_hooks(&handlers);
|
completion::register_hooks(&handlers);
|
||||||
|
@ -1,12 +1,157 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use helix_core::syntax::LanguageServerFeature;
|
||||||
use helix_event::{register_hook, send_blocking};
|
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::document::Mode;
|
||||||
use helix_view::events::DiagnosticsDidChange;
|
use helix_view::events::{DiagnosticsDidChange, DocumentDidChange};
|
||||||
use helix_view::handlers::diagnostics::DiagnosticEvent;
|
use helix_view::handlers::diagnostics::DiagnosticEvent;
|
||||||
|
use helix_view::handlers::lsp::PullDiagnosticsEvent;
|
||||||
use helix_view::handlers::Handlers;
|
use helix_view::handlers::Handlers;
|
||||||
|
use helix_view::Editor;
|
||||||
|
use tokio::time::Instant;
|
||||||
|
|
||||||
use crate::events::OnModeSwitch;
|
use crate::events::OnModeSwitch;
|
||||||
|
use crate::job;
|
||||||
|
|
||||||
pub(super) fn register_hooks(_handlers: &Handlers) {
|
const TIMEOUT: u64 = 120;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct PullDiagnosticsHandler {}
|
||||||
|
|
||||||
|
impl PullDiagnosticsHandler {
|
||||||
|
pub fn new() -> PullDiagnosticsHandler {
|
||||||
|
PullDiagnosticsHandler {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl helix_event::AsyncHook for PullDiagnosticsHandler {
|
||||||
|
type Event = PullDiagnosticsEvent;
|
||||||
|
|
||||||
|
fn handle_event(
|
||||||
|
&mut self,
|
||||||
|
event: Self::Event,
|
||||||
|
_: Option<tokio::time::Instant>,
|
||||||
|
) -> Option<tokio::time::Instant> {
|
||||||
|
match event {
|
||||||
|
PullDiagnosticsEvent::Trigger => {}
|
||||||
|
}
|
||||||
|
Some(Instant::now() + Duration::from_millis(TIMEOUT))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_debounce(&mut self) {
|
||||||
|
job::dispatch_blocking(move |editor, _| pull_diagnostic_for_current_doc(editor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pull_diagnostic_for_current_doc(editor: &mut Editor) {
|
||||||
|
let (_, doc) = current!(editor);
|
||||||
|
|
||||||
|
for language_server in doc.language_servers_with_feature(LanguageServerFeature::PullDiagnostics)
|
||||||
|
{
|
||||||
|
let future = language_server
|
||||||
|
.text_document_diagnostic(doc.identifier(), doc.previous_diagnostic_id.clone());
|
||||||
|
|
||||||
|
let original_path = doc
|
||||||
|
.path()
|
||||||
|
.expect("safety: the file has a path if there is a running language server")
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
let Some(future) = future 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,
|
||||||
|
};
|
||||||
|
|
||||||
|
show_pull_diagnostics(editor, parsed_response, server_id, original_path)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Err(err) => log::error!("signature help request failed: {err}"),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_pull_diagnostics(
|
||||||
|
editor: &mut Editor,
|
||||||
|
response: Option<lsp::DocumentDiagnosticReport>,
|
||||||
|
server_id: LanguageServerId,
|
||||||
|
original_path: PathBuf,
|
||||||
|
) {
|
||||||
|
let parse_diagnostic = |editor: &mut Editor,
|
||||||
|
path: PathBuf,
|
||||||
|
report: Vec<lsp::Diagnostic>,
|
||||||
|
result_id: Option<String>| {
|
||||||
|
let uri = helix_core::Uri::try_from(path);
|
||||||
|
let diagnostics: Vec<(Diagnostic, LanguageServerId)> =
|
||||||
|
report.into_iter().map(|d| (d, server_id)).collect();
|
||||||
|
|
||||||
|
if let Ok(uri) = uri {
|
||||||
|
editor.add_diagnostics(diagnostics, server_id, uri, None, result_id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle_document_diagnostic_report_kind =
|
||||||
|
|editor: &mut Editor,
|
||||||
|
report: Option<HashMap<lsp::Url, lsp::DocumentDiagnosticReportKind>>| {
|
||||||
|
for (url, report) in report.into_iter().flatten() {
|
||||||
|
match report {
|
||||||
|
lsp::DocumentDiagnosticReportKind::Full(report) => {
|
||||||
|
let path = url.to_file_path().unwrap();
|
||||||
|
parse_diagnostic(editor, path, report.items, report.result_id);
|
||||||
|
}
|
||||||
|
lsp::DocumentDiagnosticReportKind::Unchanged(report) => {
|
||||||
|
let Some(doc) = editor.document_by_path_mut(url.path()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
doc.previous_diagnostic_id = Some(report.result_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(response) = response {
|
||||||
|
let doc = match editor.document_by_path_mut(&original_path) {
|
||||||
|
Some(doc) => doc,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
match response {
|
||||||
|
lsp::DocumentDiagnosticReport::Full(report) => {
|
||||||
|
// Original file diagnostic
|
||||||
|
parse_diagnostic(
|
||||||
|
editor,
|
||||||
|
original_path,
|
||||||
|
report.full_document_diagnostic_report.items,
|
||||||
|
report.full_document_diagnostic_report.result_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Related files diagnostic
|
||||||
|
handle_document_diagnostic_report_kind(editor, report.related_documents);
|
||||||
|
}
|
||||||
|
lsp::DocumentDiagnosticReport::Unchanged(report) => {
|
||||||
|
doc.previous_diagnostic_id =
|
||||||
|
Some(report.unchanged_document_diagnostic_report.result_id);
|
||||||
|
handle_document_diagnostic_report_kind(editor, report.related_documents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn register_hooks(handlers: &Handlers) {
|
||||||
register_hook!(move |event: &mut DiagnosticsDidChange<'_>| {
|
register_hook!(move |event: &mut DiagnosticsDidChange<'_>| {
|
||||||
if event.editor.mode != Mode::Insert {
|
if event.editor.mode != Mode::Insert {
|
||||||
for (view, _) in event.editor.tree.views_mut() {
|
for (view, _) in event.editor.tree.views_mut() {
|
||||||
@ -21,4 +166,12 @@ pub(super) fn register_hooks(_handlers: &Handlers) {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let tx = handlers.pull_diagnostics.clone();
|
||||||
|
register_hook!(move |event: &mut DocumentDidChange<'_>| {
|
||||||
|
if event.doc.config.load().lsp.auto_signature_help {
|
||||||
|
send_blocking(&tx, PullDiagnosticsEvent::Trigger);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -1071,7 +1071,6 @@ pub fn clear_completion(&mut self, editor: &mut Editor) {
|
|||||||
|
|
||||||
pub fn handle_idle_timeout(&mut self, cx: &mut commands::Context) -> EventResult {
|
pub fn handle_idle_timeout(&mut self, cx: &mut commands::Context) -> EventResult {
|
||||||
commands::compute_inlay_hints_for_all_views(cx.editor, cx.jobs);
|
commands::compute_inlay_hints_for_all_views(cx.editor, cx.jobs);
|
||||||
commands::pull_diagnostic_for_current_doc(cx.editor, cx.jobs);
|
|
||||||
|
|
||||||
EventResult::Ignored(None)
|
EventResult::Ignored(None)
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ pub struct Handlers {
|
|||||||
pub completions: Sender<lsp::CompletionEvent>,
|
pub completions: Sender<lsp::CompletionEvent>,
|
||||||
pub signature_hints: Sender<lsp::SignatureHelpEvent>,
|
pub signature_hints: Sender<lsp::SignatureHelpEvent>,
|
||||||
pub auto_save: Sender<AutoSaveEvent>,
|
pub auto_save: Sender<AutoSaveEvent>,
|
||||||
|
pub pull_diagnostics: Sender<lsp::PullDiagnosticsEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handlers {
|
impl Handlers {
|
||||||
|
@ -47,6 +47,10 @@ pub enum SignatureHelpEvent {
|
|||||||
RequestComplete { open: bool },
|
RequestComplete { open: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum PullDiagnosticsEvent {
|
||||||
|
Trigger,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ApplyEditError {
|
pub struct ApplyEditError {
|
||||||
pub kind: ApplyEditErrorKind,
|
pub kind: ApplyEditErrorKind,
|
||||||
|
Loading…
Reference in New Issue
Block a user