Skip to content

Commit f3cc3a2

Browse files
committed
fix(language_server): request client for configuration when no configuration is passed in workspace/didChangeConfiguration (#10871)
1 parent 5645684 commit f3cc3a2

File tree

2 files changed

+35
-54
lines changed

2 files changed

+35
-54
lines changed

crates/oxc_language_server/src/main.rs

Lines changed: 33 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use futures::future::join_all;
2-
use log::{debug, info};
2+
use log::{debug, info, warn};
33
use oxc_linter::FixKind;
44
use rustc_hash::{FxBuildHasher, FxHashMap};
55
use serde::{Deserialize, Serialize};
@@ -172,50 +172,12 @@ impl LanguageServer for Backend {
172172
let workers = self.workspace_workers.lock().await;
173173
let new_diagnostics: papaya::HashMap<String, Vec<Diagnostic>, FxBuildHasher> =
174174
ConcurrentHashMap::default();
175+
let options = serde_json::from_value::<Options>(params.settings).ok();
175176

176-
// when we have only workspace folder, apply to it
177-
// ToDo: check if this is really safe because the client could still pass an empty settings
178-
if workers.len() == 1 {
179-
let worker = workers.first().unwrap();
180-
let Some(diagnostics) = worker.did_change_configuration(params.settings).await else {
181-
return;
182-
};
183-
for (uri, reports) in &diagnostics.pin() {
184-
new_diagnostics
185-
.pin()
186-
.insert(uri.clone(), reports.iter().map(|d| d.diagnostic.clone()).collect());
187-
}
188-
189-
// else check if the client support workspace configuration requests so we can only restart only the needed workers
190-
} else if self
191-
.capabilities
192-
.get()
193-
.is_some_and(|capabilities| capabilities.workspace_configuration)
194-
{
195-
let mut config_items = vec![];
177+
// the client passed valid options.
178+
if let Some(options) = options {
196179
for worker in workers.iter() {
197-
let Some(uri) = worker.get_root_uri() else {
198-
continue;
199-
};
200-
// ToDo: this is broken in VSCode. Check how we can get the language server configuration from the client
201-
// changing `section` to `oxc` will return the client configuration.
202-
config_items.push(ConfigurationItem {
203-
scope_uri: Some(uri),
204-
section: Some("oxc_language_server".into()),
205-
});
206-
}
207-
208-
let Ok(configs) = self.client.configuration(config_items).await else {
209-
debug!("failed to get configuration");
210-
return;
211-
};
212-
213-
// we expect that the client is sending all the configuration items in order and completed
214-
// this is a LSP specification and errors should be reported on the client side
215-
for (index, worker) in workers.iter().enumerate() {
216-
let config = &configs[index];
217-
let Some(diagnostics) = worker.did_change_configuration(config.clone()).await
218-
else {
180+
let Some(diagnostics) = worker.did_change_configuration(&options).await else {
219181
continue;
220182
};
221183

@@ -226,14 +188,30 @@ impl LanguageServer for Backend {
226188
);
227189
}
228190
}
191+
// else check if the client support workspace configuration requests
192+
} else if self
193+
.capabilities
194+
.get()
195+
.is_some_and(|capabilities| capabilities.workspace_configuration)
196+
{
197+
let configs = self
198+
.request_workspace_configuration(
199+
workers
200+
.iter()
201+
.map(|worker| worker.get_root_uri().unwrap())
202+
.collect::<Vec<_>>()
203+
.iter()
204+
.collect(),
205+
)
206+
.await;
229207

230-
// we have multiple workspace folders and the client does not support workspace configuration requests
231-
// we assume that every workspace is under effect
232-
} else {
233-
for worker in workers.iter() {
234-
let Some(diagnostics) =
235-
worker.did_change_configuration(params.settings.clone()).await
236-
else {
208+
// we expect that the client is sending all the configuration items in order and completed
209+
// this is a LSP specification and errors should be reported on the client side
210+
for (index, worker) in workers.iter().enumerate() {
211+
let Some(config) = &configs[index] else {
212+
continue;
213+
};
214+
let Some(diagnostics) = worker.did_change_configuration(config).await else {
237215
continue;
238216
};
239217

@@ -244,6 +222,11 @@ impl LanguageServer for Backend {
244222
);
245223
}
246224
}
225+
} else {
226+
warn!(
227+
"could not update the configuration for a worker. Send a custom configuration with `workspace/didChangeConfiguration` or support `workspace/configuration`."
228+
);
229+
return;
247230
}
248231

249232
if new_diagnostics.is_empty() {

crates/oxc_language_server/src/worker.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,8 @@ impl WorkspaceWorker {
233233

234234
pub async fn did_change_configuration(
235235
&self,
236-
options: serde_json::value::Value,
236+
changed_options: &Options,
237237
) -> Option<ConcurrentHashMap<String, Vec<DiagnosticReport>>> {
238-
let changed_options = serde_json::from_value::<Options>(options).unwrap_or_default();
239-
240238
let current_option = &self.options.lock().await.clone();
241239

242240
debug!(
@@ -249,7 +247,7 @@ impl WorkspaceWorker {
249247

250248
*self.options.lock().await = changed_options.clone();
251249

252-
if Self::needs_linter_restart(current_option, &changed_options) {
250+
if Self::needs_linter_restart(current_option, changed_options) {
253251
self.refresh_server_linter().await;
254252
return Some(self.revalidate_diagnostics().await);
255253
}

0 commit comments

Comments
 (0)