Skip to content

Commit 4177ba6

Browse files
committed
Pull diagnostics on open
1 parent 96a984c commit 4177ba6

File tree

7 files changed

+164
-77
lines changed

7 files changed

+164
-77
lines changed

helix-term/src/events.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use helix_event::{events, register_event};
22
use helix_view::document::Mode;
3-
use helix_view::events::{DiagnosticsDidChange, DocumentDidChange, SelectionDidChange};
3+
use helix_view::events::{
4+
DiagnosticsDidChange, DocumentDidChange, DocumentDidOpen, SelectionDidChange,
5+
};
46

57
use crate::commands;
68
use crate::keymap::MappableCommand;
@@ -16,6 +18,7 @@ pub fn register() {
1618
register_event::<PostInsertChar>();
1719
register_event::<PostCommand>();
1820
register_event::<DocumentDidChange>();
21+
register_event::<DocumentDidOpen>();
1922
register_event::<SelectionDidChange>();
2023
register_event::<DiagnosticsDidChange>();
2124
}

helix-term/src/handlers.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ use crate::config::Config;
88
use crate::events;
99
use crate::handlers::auto_save::AutoSaveHandler;
1010
use crate::handlers::completion::CompletionHandler;
11-
use crate::handlers::diagnostics::PullDiagnosticsHandler;
11+
use crate::handlers::diagnostics::PullDiagnosticsForLanguageServersHandler;
1212
use crate::handlers::signature_help::SignatureHelpHandler;
1313

1414
pub use completion::trigger_auto_completion;
1515
pub use helix_view::handlers::Handlers;
1616

17+
use self::diagnostics::PullDiagnosticsForDocumentsHandler;
18+
1719
mod auto_save;
1820
pub mod completion;
1921
mod diagnostics;
@@ -25,13 +27,16 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
2527
let completions = CompletionHandler::new(config).spawn();
2628
let signature_hints = SignatureHelpHandler::new().spawn();
2729
let auto_save = AutoSaveHandler::new().spawn();
28-
let pull_diagnostics = PullDiagnosticsHandler::new().spawn();
30+
let pull_diagnostics_for_language_servers =
31+
PullDiagnosticsForLanguageServersHandler::new().spawn();
32+
let pull_diagnostics_for_documents = PullDiagnosticsForDocumentsHandler::new().spawn();
2933

3034
let handlers = Handlers {
3135
completions,
3236
signature_hints,
3337
auto_save,
34-
pull_diagnostics,
38+
pull_diagnostics_for_language_servers,
39+
pull_diagnostics_for_documents,
3540
};
3641

3742
completion::register_hooks(&handlers);

helix-term/src/handlers/diagnostics.rs

Lines changed: 136 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::HashMap;
1+
use std::collections::{HashMap, HashSet};
22
use std::time::Duration;
33

44
use helix_core::syntax::LanguageServerFeature;
@@ -7,11 +7,13 @@ use helix_event::{register_hook, send_blocking};
77
use helix_lsp::lsp::{self, Diagnostic};
88
use helix_lsp::LanguageServerId;
99
use helix_view::document::Mode;
10-
use helix_view::events::{DiagnosticsDidChange, DocumentDidChange};
10+
use helix_view::events::{DiagnosticsDidChange, DocumentDidChange, DocumentDidOpen};
1111
use helix_view::handlers::diagnostics::DiagnosticEvent;
12-
use helix_view::handlers::lsp::PullDiagnosticsEvent;
12+
use helix_view::handlers::lsp::{
13+
PullDiagnosticsForDocumentsEvent, PullDiagnosticsForLanguageServersEvent,
14+
};
1315
use helix_view::handlers::Handlers;
14-
use helix_view::Editor;
16+
use helix_view::{DocumentId, Editor};
1517
use tokio::time::Instant;
1618

1719
use crate::events::OnModeSwitch;
@@ -33,7 +35,7 @@ pub(super) fn register_hooks(handlers: &Handlers) {
3335
Ok(())
3436
});
3537

36-
let tx = handlers.pull_diagnostics.clone();
38+
let tx = handlers.pull_diagnostics_for_language_servers.clone();
3739
register_hook!(move |event: &mut DocumentDidChange<'_>| {
3840
if event
3941
.doc
@@ -47,117 +49,179 @@ pub(super) fn register_hooks(handlers: &Handlers) {
4749

4850
send_blocking(
4951
&tx,
50-
PullDiagnosticsEvent {
52+
PullDiagnosticsForLanguageServersEvent {
5153
language_server_ids,
5254
},
5355
);
5456
}
5557
Ok(())
5658
});
57-
}
5859

59-
const TIMEOUT: u64 = 120;
60+
let tx = handlers.pull_diagnostics_for_documents.clone();
61+
register_hook!(move |event: &mut DocumentDidOpen<'_>| {
62+
if event
63+
.doc
64+
.has_language_server_with_feature(LanguageServerFeature::PullDiagnostics)
65+
{
66+
send_blocking(
67+
&tx,
68+
PullDiagnosticsForDocumentsEvent {
69+
document_id: event.doc.id(),
70+
},
71+
);
72+
}
73+
74+
Ok(())
75+
});
76+
}
6077

6178
#[derive(Debug)]
62-
pub(super) struct PullDiagnosticsHandler {
63-
language_server_ids: Vec<LanguageServerId>,
79+
pub(super) struct PullDiagnosticsForLanguageServersHandler {
80+
language_server_ids: HashSet<LanguageServerId>,
6481
}
6582

66-
impl PullDiagnosticsHandler {
67-
pub fn new() -> PullDiagnosticsHandler {
68-
PullDiagnosticsHandler {
69-
language_server_ids: vec![],
83+
impl PullDiagnosticsForLanguageServersHandler {
84+
pub fn new() -> PullDiagnosticsForLanguageServersHandler {
85+
PullDiagnosticsForLanguageServersHandler {
86+
language_server_ids: [].into(),
7087
}
7188
}
7289
}
90+
pub(super) struct PullDiagnosticsForDocumentsHandler {
91+
document_ids: HashSet<DocumentId>,
92+
}
7393

74-
impl helix_event::AsyncHook for PullDiagnosticsHandler {
75-
type Event = PullDiagnosticsEvent;
94+
impl PullDiagnosticsForDocumentsHandler {
95+
pub fn new() -> PullDiagnosticsForDocumentsHandler {
96+
PullDiagnosticsForDocumentsHandler {
97+
document_ids: [].into(),
98+
}
99+
}
100+
}
101+
102+
impl helix_event::AsyncHook for PullDiagnosticsForLanguageServersHandler {
103+
type Event = PullDiagnosticsForLanguageServersEvent;
76104

77105
fn handle_event(
78106
&mut self,
79107
event: Self::Event,
80108
_: Option<tokio::time::Instant>,
81109
) -> Option<tokio::time::Instant> {
82110
self.language_server_ids = event.language_server_ids;
83-
Some(Instant::now() + Duration::from_millis(TIMEOUT))
111+
Some(Instant::now() + Duration::from_millis(120))
84112
}
85113

86114
fn finish_debounce(&mut self) {
87115
let language_servers = self.language_server_ids.clone();
88116
job::dispatch_blocking(move |editor, _| {
89-
pull_diagnostic_for_document(
90-
editor,
91-
language_servers,
92-
editor.documents().map(|x| x.id()).collect(),
93-
)
117+
pull_diagnostic_for_language_servers(editor, language_servers)
94118
})
95119
}
96120
}
97121

98-
fn pull_diagnostic_for_document(
122+
impl helix_event::AsyncHook for PullDiagnosticsForDocumentsHandler {
123+
type Event = PullDiagnosticsForDocumentsEvent;
124+
125+
fn handle_event(
126+
&mut self,
127+
event: Self::Event,
128+
_: Option<tokio::time::Instant>,
129+
) -> Option<tokio::time::Instant> {
130+
self.document_ids.insert(event.document_id);
131+
Some(Instant::now() + Duration::from_millis(50))
132+
}
133+
134+
fn finish_debounce(&mut self) {
135+
let document_ids = self.document_ids.clone();
136+
job::dispatch_blocking(move |editor, _| {
137+
pull_diagnostics_for_documents(editor, document_ids)
138+
})
139+
}
140+
}
141+
142+
fn pull_diagnostics_for_documents(editor: &mut Editor, document_ids: HashSet<DocumentId>) {
143+
for document_id in document_ids {
144+
let Some(doc) = editor.document_mut(document_id) else {
145+
return;
146+
};
147+
148+
let language_servers =
149+
doc.language_servers_with_feature(LanguageServerFeature::PullDiagnostics);
150+
151+
for language_server in language_servers {
152+
pull_diagnostics_for_document(doc, language_server);
153+
}
154+
}
155+
}
156+
157+
fn pull_diagnostic_for_language_servers(
99158
editor: &mut Editor,
100-
language_server_ids: Vec<LanguageServerId>,
101-
document_ids: Vec<helix_view::DocumentId>,
159+
language_server_ids: HashSet<LanguageServerId>,
102160
) {
103-
for document_id in document_ids.clone() {
104-
let doc = doc_mut!(editor, &document_id);
161+
let document_ids: Vec<_> = editor.documents().map(|x| x.id()).collect();
162+
163+
for document_id in document_ids {
164+
let Some(doc) = editor.document_mut(document_id) else {
165+
return;
166+
};
167+
105168
let language_servers = doc
106169
.language_servers()
107170
.filter(|x| language_server_ids.contains(&x.id()));
108171

109172
for language_server in language_servers {
110-
let Some(future) = language_server
111-
.text_document_diagnostic(doc.identifier(), doc.previous_diagnostic_id.clone())
112-
else {
113-
return;
114-
};
115-
116-
let Some(uri) = doc.uri() else {
117-
return;
118-
};
119-
120-
let server_id = language_server.id();
121-
122-
tokio::spawn(async move {
123-
match future.await {
124-
Ok(res) => {
125-
job::dispatch(move |editor, _| {
126-
log::error!("{}", res);
127-
128-
let parsed_response: Option<lsp::DocumentDiagnosticReport> =
129-
match serde_json::from_value(res) {
130-
Ok(result) => Some(result),
131-
Err(_) => None,
132-
};
133-
134-
let Some(response) = parsed_response else {
135-
return;
136-
};
137-
138-
show_pull_diagnostics(editor, response, server_id, uri, &document_id)
139-
})
140-
.await
141-
}
142-
Err(err) => log::error!("signature help request failed: {err}"),
143-
}
144-
});
173+
pull_diagnostics_for_document(doc, language_server);
145174
}
146175
}
147176
}
148177

149-
fn show_pull_diagnostics(
178+
fn pull_diagnostics_for_document(doc: &helix_view::Document, language_server: &helix_lsp::Client) {
179+
let Some(future) = language_server
180+
.text_document_diagnostic(doc.identifier(), doc.previous_diagnostic_id.clone())
181+
else {
182+
return;
183+
};
184+
185+
let Some(uri) = doc.uri() else {
186+
return;
187+
};
188+
189+
let server_id = language_server.id();
190+
let document_id = doc.id();
191+
192+
tokio::spawn(async move {
193+
match future.await {
194+
Ok(res) => {
195+
job::dispatch(move |editor, _| {
196+
let response = match serde_json::from_value(res) {
197+
Ok(result) => result,
198+
Err(_) => return,
199+
};
200+
201+
handle_pull_diagnostics_response(editor, response, server_id, uri, document_id)
202+
})
203+
.await
204+
}
205+
Err(err) => log::error!("Pull diagnostic request failed: {err}"),
206+
}
207+
});
208+
}
209+
210+
fn handle_pull_diagnostics_response(
150211
editor: &mut Editor,
151212
response: lsp::DocumentDiagnosticReport,
152213
server_id: LanguageServerId,
153214
uri: Uri,
154-
document_id: &helix_view::DocumentId,
215+
document_id: helix_view::DocumentId,
155216
) {
156-
let doc = doc_mut!(editor, document_id);
217+
let Some(doc) = editor.document_mut(document_id) else {
218+
return;
219+
};
220+
157221
match response {
158222
lsp::DocumentDiagnosticReport::Full(report) => {
159223
// Original file diagnostic
160-
parse_diagnostic(
224+
add_diagnostics_to_editor(
161225
editor,
162226
uri,
163227
report.full_document_diagnostic_report.items,
@@ -187,7 +251,7 @@ fn show_pull_diagnostics(
187251
}
188252
}
189253

190-
fn parse_diagnostic(
254+
fn add_diagnostics_to_editor(
191255
editor: &mut Editor,
192256
uri: Uri,
193257
report: Vec<lsp::Diagnostic>,
@@ -202,7 +266,7 @@ fn parse_diagnostic(
202266

203267
fn handle_document_diagnostic_report_kind(
204268
editor: &mut Editor,
205-
document_id: &helix_view::DocumentId,
269+
document_id: helix_view::DocumentId,
206270
report: Option<HashMap<lsp::Url, lsp::DocumentDiagnosticReportKind>>,
207271
server_id: LanguageServerId,
208272
) {
@@ -213,10 +277,12 @@ fn handle_document_diagnostic_report_kind(
213277
return;
214278
};
215279

216-
parse_diagnostic(editor, uri, report.items, report.result_id, server_id);
280+
add_diagnostics_to_editor(editor, uri, report.items, report.result_id, server_id);
217281
}
218282
lsp::DocumentDiagnosticReportKind::Unchanged(report) => {
219-
let doc = doc_mut!(editor, &document_id);
283+
let Some(doc) = editor.document_mut(document_id) else {
284+
return;
285+
};
220286
doc.previous_diagnostic_id = Some(report.result_id);
221287
}
222288
}

helix-view/src/editor.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::{
33
document::{
44
DocumentOpenError, DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint,
55
},
6+
events::DocumentDidOpen,
67
graphics::{CursorKind, Rect},
78
handlers::Handlers,
89
info::Info,
@@ -1721,6 +1722,11 @@ impl Editor {
17211722
};
17221723

17231724
self.switch(id, action);
1725+
1726+
if let Some(doc) = self.document_mut(id) {
1727+
helix_event::dispatch(DocumentDidOpen { doc });
1728+
};
1729+
17241730
Ok(id)
17251731
}
17261732

helix-view/src/events.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{Document, DocumentId, Editor, ViewId};
55

66
events! {
77
DocumentDidChange<'a> { doc: &'a mut Document, view: ViewId, old_text: &'a Rope }
8+
DocumentDidOpen<'a> { doc: &'a mut Document}
89
SelectionDidChange<'a> { doc: &'a mut Document, view: ViewId }
910
DiagnosticsDidChange<'a> { editor: &'a mut Editor, doc: DocumentId }
1011
}

helix-view/src/handlers.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ pub struct Handlers {
1919
pub completions: Sender<lsp::CompletionEvent>,
2020
pub signature_hints: Sender<lsp::SignatureHelpEvent>,
2121
pub auto_save: Sender<AutoSaveEvent>,
22-
pub pull_diagnostics: Sender<lsp::PullDiagnosticsEvent>,
22+
pub pull_diagnostics_for_language_servers: Sender<lsp::PullDiagnosticsForLanguageServersEvent>,
23+
pub pull_diagnostics_for_documents: Sender<lsp::PullDiagnosticsForDocumentsEvent>,
2324
}
2425

2526
impl Handlers {

0 commit comments

Comments
 (0)