Skip to content

Commit 913d8d1

Browse files
committed
Cancel ongoing pull diagnostic events
1 parent 0a0e8ca commit 913d8d1

File tree

3 files changed

+75
-74
lines changed

3 files changed

+75
-74
lines changed

helix-lsp/src/client.rs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub struct Client {
6262
initialize_notify: Arc<Notify>,
6363
/// workspace folders added while the server is still initializing
6464
req_timeout: u64,
65+
ongoing_work: Mutex<Vec<(lsp::TextDocumentIdentifier, lsp::ProgressToken)>>,
6566
}
6667

6768
impl Client {
@@ -258,6 +259,7 @@ impl Client {
258259
root_uri,
259260
workspace_folders: Mutex::new(workspace_folders),
260261
initialize_notify: initialize_notify.clone(),
262+
ongoing_work: Mutex::new(Default::default()),
261263
};
262264

263265
Ok((client, server_rx, initialize_notify))
@@ -1237,13 +1239,41 @@ impl Client {
12371239
Some(self.call::<lsp::request::RangeFormatting>(params))
12381240
}
12391241

1242+
pub fn mark_work_as_done(&self, id: lsp::ProgressToken) {
1243+
self.ongoing_work.lock().retain(|x| x.1 != id);
1244+
}
1245+
1246+
fn cancel_ongoing_work(&self, id: lsp::ProgressToken) {
1247+
self.notify::<lsp::notification::Cancel>(lsp::CancelParams { id: id.clone() });
1248+
self.mark_work_as_done(id);
1249+
}
1250+
12401251
pub fn text_document_diagnostic(
12411252
&self,
12421253
text_document: lsp::TextDocumentIdentifier,
12431254
previous_result_id: Option<String>,
1244-
) -> Option<impl Future<Output = Result<lsp::DocumentDiagnosticReportResult>>> {
1255+
) -> Option<(
1256+
impl Future<Output = Result<lsp::DocumentDiagnosticReportResult>>,
1257+
lsp::ProgressToken,
1258+
)> {
12451259
let capabilities = self.capabilities();
12461260

1261+
let ongoing_work = {
1262+
let ongoing_work_lock = self.ongoing_work.lock();
1263+
1264+
ongoing_work_lock
1265+
.iter()
1266+
.filter(|x| x.0 == text_document)
1267+
.cloned()
1268+
.collect::<Vec<_>>()
1269+
};
1270+
1271+
if !ongoing_work.is_empty() {
1272+
for id in ongoing_work.into_iter().map(|x| x.1) {
1273+
self.cancel_ongoing_work(id.clone());
1274+
}
1275+
}
1276+
12471277
// Return early if the server does not support pull diagnostic.
12481278
let identifier = match capabilities.diagnostic_provider.as_ref()? {
12491279
lsp::DiagnosticServerCapabilities::Options(cap) => cap.identifier.clone(),
@@ -1252,15 +1282,30 @@ impl Client {
12521282
}
12531283
};
12541284

1285+
let request_id = match self.next_request_id() {
1286+
jsonrpc::Id::Null => lsp::ProgressToken::Number(1),
1287+
jsonrpc::Id::Num(num) => lsp::ProgressToken::Number(num as i32),
1288+
jsonrpc::Id::Str(str) => lsp::ProgressToken::String(str),
1289+
};
1290+
12551291
let params = lsp::DocumentDiagnosticParams {
1256-
text_document,
1292+
text_document: text_document.clone(),
12571293
identifier,
12581294
previous_result_id,
1259-
work_done_progress_params: lsp::WorkDoneProgressParams::default(),
1295+
work_done_progress_params: lsp::WorkDoneProgressParams {
1296+
work_done_token: Some(request_id.clone()),
1297+
},
12601298
partial_result_params: lsp::PartialResultParams::default(),
12611299
};
12621300

1263-
Some(self.call::<lsp::request::DocumentDiagnosticRequest>(params))
1301+
self.ongoing_work
1302+
.lock()
1303+
.push((text_document, request_id.clone()));
1304+
1305+
Some((
1306+
self.call::<lsp::request::DocumentDiagnosticRequest>(params),
1307+
request_id,
1308+
))
12641309
}
12651310

12661311
pub fn text_document_document_highlight(

helix-term/src/application.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,10 +1020,15 @@ impl Application {
10201020
Ok(MethodCall::WorkspaceDiagnosticRefresh) => {
10211021
for document in self.editor.documents() {
10221022
let language_server = language_server!();
1023-
handlers::diagnostics::pull_diagnostics_for_document(
1024-
document,
1025-
language_server,
1026-
);
1023+
if language_server.supports_feature(
1024+
syntax::config::LanguageServerFeature::PullDiagnostics,
1025+
) && document.supports_language_server(language_server.id())
1026+
{
1027+
handlers::diagnostics::pull_diagnostics_for_document(
1028+
document,
1029+
language_server,
1030+
);
1031+
}
10271032
}
10281033
Ok(serde_json::Value::Null)
10291034
}

helix-term/src/handlers/diagnostics.rs

Lines changed: 17 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::time::Duration;
2+
use tokio::time::Instant;
23

34
use helix_core::diagnostic::DiagnosticProvider;
45
use helix_core::syntax::config::LanguageServerFeature;
@@ -13,7 +14,6 @@ use helix_view::handlers::diagnostics::DiagnosticEvent;
1314
use helix_view::handlers::lsp::PullDiagnosticsEvent;
1415
use helix_view::handlers::Handlers;
1516
use helix_view::{DocumentId, Editor};
16-
use tokio::time::Instant;
1717

1818
use crate::events::OnModeSwitch;
1919
use crate::job;
@@ -74,87 +74,30 @@ pub(super) fn register_hooks(handlers: &Handlers) {
7474
}
7575

7676
#[derive(Debug)]
77-
pub(super) struct PullDiagnosticsHandler {
78-
no_inter_file_dependency_timeout: Option<tokio::time::Instant>,
79-
}
77+
pub(super) struct PullDiagnosticsHandler {}
8078

8179
impl PullDiagnosticsHandler {
82-
pub fn new() -> PullDiagnosticsHandler {
83-
PullDiagnosticsHandler {
84-
no_inter_file_dependency_timeout: None,
85-
}
80+
pub fn new() -> Self {
81+
PullDiagnosticsHandler {}
8682
}
8783
}
8884

89-
const TIMEOUT: Duration = Duration::from_millis(500);
90-
const TIMEOUT_NO_INTER_FILE_DEPENDENCY: Duration = Duration::from_millis(125);
91-
9285
impl helix_event::AsyncHook for PullDiagnosticsHandler {
9386
type Event = PullDiagnosticsEvent;
9487

9588
fn handle_event(
9689
&mut self,
97-
event: Self::Event,
98-
timeout: Option<tokio::time::Instant>,
90+
_event: Self::Event,
91+
_timeout: Option<tokio::time::Instant>,
9992
) -> Option<tokio::time::Instant> {
100-
if timeout.is_none() {
101-
dispatch_pull_diagnostic_for_document(event.document_id, false);
102-
self.no_inter_file_dependency_timeout = Some(Instant::now());
103-
}
104-
105-
if self
106-
.no_inter_file_dependency_timeout
107-
.is_some_and(|nifd_timeout| {
108-
nifd_timeout.duration_since(Instant::now()) > TIMEOUT_NO_INTER_FILE_DEPENDENCY
109-
})
110-
{
111-
dispatch_pull_diagnostic_for_document(event.document_id, true);
112-
self.no_inter_file_dependency_timeout = Some(Instant::now());
113-
};
114-
115-
Some(Instant::now() + TIMEOUT)
93+
Some(Instant::now() + Duration::from_millis(125))
11694
}
11795

11896
fn finish_debounce(&mut self) {
11997
dispatch_pull_diagnostic_for_open_documents();
12098
}
12199
}
122100

123-
fn dispatch_pull_diagnostic_for_document(
124-
document_id: DocumentId,
125-
exclude_language_servers_without_inter_file_dependency: bool,
126-
) {
127-
job::dispatch_blocking(move |editor, _| {
128-
let Some(doc) = editor.document(document_id) else {
129-
return;
130-
};
131-
132-
let language_servers = doc
133-
.language_servers_with_feature(LanguageServerFeature::PullDiagnostics)
134-
.filter(|ls| ls.is_initialized())
135-
.filter(|ls| {
136-
if !exclude_language_servers_without_inter_file_dependency {
137-
return true;
138-
};
139-
ls.capabilities()
140-
.diagnostic_provider
141-
.as_ref()
142-
.is_some_and(|dp| match dp {
143-
lsp::DiagnosticServerCapabilities::Options(options) => {
144-
options.inter_file_dependencies
145-
}
146-
lsp::DiagnosticServerCapabilities::RegistrationOptions(options) => {
147-
options.diagnostic_options.inter_file_dependencies
148-
}
149-
})
150-
});
151-
152-
for language_server in language_servers {
153-
pull_diagnostics_for_document(doc, language_server);
154-
}
155-
})
156-
}
157-
158101
fn dispatch_pull_diagnostic_for_open_documents() {
159102
job::dispatch_blocking(move |editor, _| {
160103
let documents = editor.documents.values();
@@ -204,9 +147,14 @@ pub fn pull_diagnostics_for_document(
204147
let document_id = doc.id();
205148

206149
tokio::spawn(async move {
207-
match future.await {
150+
match future.0.await {
208151
Ok(result) => {
209152
job::dispatch(move |editor, _| {
153+
if let Some(language_server) = editor.language_server_by_id(language_server_id)
154+
{
155+
language_server.mark_work_as_done(future.1);
156+
};
157+
210158
handle_pull_diagnostics_response(editor, result, provider, uri, document_id)
211159
})
212160
.await
@@ -230,7 +178,10 @@ pub fn pull_diagnostics_for_document(
230178
editor.document(document_id),
231179
editor.language_server_by_id(language_server_id),
232180
) {
233-
pull_diagnostics_for_document(doc, language_server);
181+
language_server.mark_work_as_done(future.1);
182+
if doc.supports_language_server(language_server_id) {
183+
pull_diagnostics_for_document(doc, language_server);
184+
}
234185
}
235186
})
236187
.await;

0 commit comments

Comments
 (0)