Skip to content

Commit 618184e

Browse files
committed
feat(language_server): support textDocument/diagnostic
1 parent 7e88451 commit 618184e

File tree

9 files changed

+324
-118
lines changed

9 files changed

+324
-118
lines changed

crates/oxc_language_server/src/capabilities.rs

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,40 @@
11
use tower_lsp_server::lsp_types::{
22
ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability,
3-
ExecuteCommandOptions, OneOf, SaveOptions, ServerCapabilities, TextDocumentSyncCapability,
4-
TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions,
5-
WorkDoneProgressOptions, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
3+
DiagnosticOptions, DiagnosticServerCapabilities, ExecuteCommandOptions, OneOf, SaveOptions,
4+
ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
5+
TextDocumentSyncSaveOptions, WorkDoneProgressOptions, WorkspaceFoldersServerCapabilities,
6+
WorkspaceServerCapabilities,
67
};
78

89
use crate::{code_actions::CODE_ACTION_KIND_SOURCE_FIX_ALL_OXC, commands::FIX_ALL_COMMAND_ID};
910

10-
#[derive(Clone, Default)]
11+
/// Represents the capabilities of the client that the server can use to determine
12+
/// which features to enable or disable.
13+
#[derive(Clone, Default, Debug)]
1114
pub struct Capabilities {
1215
pub code_action_provider: bool,
1316
pub workspace_apply_edit: bool,
1417
pub workspace_execute_command: bool,
1518
pub workspace_configuration: bool,
19+
/// Whether the client supports dynamic registration of file watchers.
1620
pub dynamic_watchers: bool,
21+
/// Whether the client supports pull diagnostics.
22+
pull_diagnostics: bool,
23+
/// Whether the client supports the `workspace/diagnostic/refresh` request.
24+
refresh_diagnostics: bool,
1725
}
1826

19-
impl From<ClientCapabilities> for Capabilities {
20-
fn from(value: ClientCapabilities) -> Self {
27+
impl Capabilities {
28+
/// The server supports pull and push diagnostics.
29+
/// Only use push diagnostics if the client does not support pull diagnostics,
30+
/// or we can not the client to refresh diagnostics.
31+
pub fn use_push_diagnostics(&self) -> bool {
32+
!self.pull_diagnostics || !self.refresh_diagnostics
33+
}
34+
}
35+
36+
impl From<&ClientCapabilities> for Capabilities {
37+
fn from(value: &ClientCapabilities) -> Self {
2138
// check if the client support some code action literal support
2239
let code_action_provider = value.text_document.as_ref().is_some_and(|capability| {
2340
capability.code_action.as_ref().is_some_and(|code_action| {
@@ -34,18 +51,33 @@ impl From<ClientCapabilities> for Capabilities {
3451
.workspace
3552
.as_ref()
3653
.is_some_and(|workspace| workspace.configuration.is_some_and(|config| config));
37-
let dynamic_watchers = value.workspace.is_some_and(|workspace| {
38-
workspace.did_change_watched_files.is_some_and(|watched_files| {
39-
watched_files.dynamic_registration.is_some_and(|dynamic| dynamic)
54+
let dynamic_watchers = value.workspace.as_ref().is_some_and(|workspace| {
55+
workspace.did_change_watched_files.as_ref().is_some_and(|watched_files| {
56+
watched_files.dynamic_registration.as_ref().is_some_and(|dynamic| *dynamic)
4057
})
4158
});
4259

60+
let pull_diagnostics = value
61+
.text_document
62+
.as_ref()
63+
.is_some_and(|text_document| text_document.diagnostic.is_some());
64+
65+
// BUG: see https://github.com/tower-lsp-community/tower-lsp-server/issues/50
66+
// let refresh_diagnostics = value.workspace.as_ref().is_some_and(|workspace| {
67+
// workspace
68+
// .diagnostic
69+
// .as_ref()
70+
// .is_some_and(|diagnostic| diagnostic.refresh_support.is_some_and(|refresh| refresh))
71+
// });
72+
4373
Self {
4474
code_action_provider,
4575
workspace_apply_edit,
4676
workspace_execute_command,
4777
workspace_configuration,
4878
dynamic_watchers,
79+
pull_diagnostics,
80+
refresh_diagnostics: true,
4981
}
5082
}
5183
}
@@ -92,6 +124,11 @@ impl From<Capabilities> for ServerCapabilities {
92124
} else {
93125
None
94126
},
127+
diagnostic_provider: if value.use_push_diagnostics() {
128+
None
129+
} else {
130+
Some(DiagnosticServerCapabilities::Options(DiagnosticOptions::default()))
131+
},
95132
..ServerCapabilities::default()
96133
}
97134
}
@@ -108,6 +145,37 @@ mod test {
108145

109146
use super::Capabilities;
110147

148+
#[test]
149+
fn test_use_push_diagnostics() {
150+
let capabilities = Capabilities {
151+
pull_diagnostics: true,
152+
refresh_diagnostics: true,
153+
..Default::default()
154+
};
155+
assert!(!capabilities.use_push_diagnostics());
156+
157+
let capabilities = Capabilities {
158+
pull_diagnostics: false,
159+
refresh_diagnostics: true,
160+
..Default::default()
161+
};
162+
assert!(capabilities.use_push_diagnostics());
163+
164+
let capabilities = Capabilities {
165+
pull_diagnostics: true,
166+
refresh_diagnostics: false,
167+
..Default::default()
168+
};
169+
assert!(capabilities.use_push_diagnostics());
170+
171+
let capabilities = Capabilities {
172+
pull_diagnostics: false,
173+
refresh_diagnostics: false,
174+
..Default::default()
175+
};
176+
assert!(capabilities.use_push_diagnostics());
177+
}
178+
111179
#[test]
112180
fn test_code_action_provider_vscode() {
113181
let client_capabilities = ClientCapabilities {
@@ -138,7 +206,7 @@ mod test {
138206
..ClientCapabilities::default()
139207
};
140208

141-
let capabilities = Capabilities::from(client_capabilities);
209+
let capabilities = Capabilities::from(&client_capabilities);
142210

143211
assert!(capabilities.code_action_provider);
144212
}
@@ -168,7 +236,7 @@ mod test {
168236
..ClientCapabilities::default()
169237
};
170238

171-
let capabilities = Capabilities::from(client_capabilities);
239+
let capabilities = Capabilities::from(&client_capabilities);
172240

173241
assert!(capabilities.code_action_provider);
174242
}
@@ -201,7 +269,7 @@ mod test {
201269
..ClientCapabilities::default()
202270
};
203271

204-
let capabilities = Capabilities::from(client_capabilities);
272+
let capabilities = Capabilities::from(&client_capabilities);
205273

206274
assert!(capabilities.code_action_provider);
207275
}
@@ -219,7 +287,7 @@ mod test {
219287
..ClientCapabilities::default()
220288
};
221289

222-
let capabilities = Capabilities::from(client_capabilities);
290+
let capabilities = Capabilities::from(&client_capabilities);
223291

224292
assert!(capabilities.workspace_execute_command);
225293
}
@@ -235,7 +303,7 @@ mod test {
235303
..ClientCapabilities::default()
236304
};
237305

238-
let capabilities = Capabilities::from(client_capabilities);
306+
let capabilities = Capabilities::from(&client_capabilities);
239307

240308
assert!(capabilities.workspace_apply_edit);
241309
}
@@ -253,7 +321,7 @@ mod test {
253321
..Default::default()
254322
};
255323

256-
let capabilities = Capabilities::from(client_capabilities);
324+
let capabilities = Capabilities::from(&client_capabilities);
257325
assert!(capabilities.dynamic_watchers);
258326
}
259327

@@ -270,7 +338,7 @@ mod test {
270338
..Default::default()
271339
};
272340

273-
let capabilities = Capabilities::from(client_capabilities);
341+
let capabilities = Capabilities::from(&client_capabilities);
274342
assert!(capabilities.dynamic_watchers);
275343
}
276344
}

0 commit comments

Comments
 (0)