diff options
-rw-r--r-- | cli/lsp/config.rs | 66 | ||||
-rw-r--r-- | cli/lsp/language_server.rs | 42 | ||||
-rw-r--r-- | cli/tests/integration_tests_lsp.rs | 90 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params_did_config_change.json | 62 |
4 files changed, 203 insertions, 57 deletions
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index 3e1b9fe85..33f9122da 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -165,8 +165,8 @@ impl ConfigSnapshot { } enum ConfigRequest { + All, Specifier(ModuleSpecifier, ModuleSpecifier), - Workspace, } #[derive(Debug, Default, Clone)] @@ -197,12 +197,8 @@ impl Config { loop { match rx.recv().await { None => break, - Some(ConfigRequest::Workspace) => { - let mut items = vec![lsp::ConfigurationItem { - scope_uri: None, - section: Some(SETTINGS_SECTION.to_string()), - }]; - let (specifier_uri_map, mut specifier_items): ( + Some(ConfigRequest::All) => { + let (specifier_uri_map, items): ( Vec<(ModuleSpecifier, ModuleSpecifier)>, Vec<lsp::ConfigurationItem>, ) = { @@ -223,40 +219,18 @@ impl Config { .collect(), ) }; - items.append(&mut specifier_items); if let Ok(configs) = client.configuration(items).await { let mut settings = settings_ref.write().unwrap(); for (i, value) in configs.into_iter().enumerate() { - match i { - 0 => { - match serde_json::from_value::<WorkspaceSettings>(value) { - Ok(workspace_settings) => { - settings.workspace = workspace_settings; - } - Err(err) => { - error!( - "Error converting workspace settings: {}", - err - ); - } - } + match serde_json::from_value::<SpecifierSettings>(value) { + Ok(specifier_settings) => { + let (specifier, uri) = specifier_uri_map[i].clone(); + settings + .specifiers + .insert(specifier, (uri, specifier_settings)); } - _ => { - match serde_json::from_value::<SpecifierSettings>(value) { - Ok(specifier_settings) => { - let (specifier, uri) = - specifier_uri_map[i - 1].clone(); - settings - .specifiers - .insert(specifier, (uri, specifier_settings)); - } - Err(err) => { - error!( - "Error converting specifier settings: {}", - err - ); - } - } + Err(err) => { + error!("Error converting specifier settings: {}", err); } } } @@ -376,22 +350,24 @@ impl Config { } } - pub async fn update_specifier_settings( - &self, - specifier: &ModuleSpecifier, - uri: &ModuleSpecifier, - ) -> Result<(), AnyError> { + /// Update all currently cached specifier settings + pub async fn update_all_settings(&self) -> Result<(), AnyError> { self .tx - .send(ConfigRequest::Specifier(specifier.clone(), uri.clone())) + .send(ConfigRequest::All) .await .map_err(|_| anyhow!("Error sending config update task.")) } - pub async fn update_workspace_settings(&self) -> Result<(), AnyError> { + /// Update a specific specifiers settings from the client. + pub async fn update_specifier_settings( + &self, + specifier: &ModuleSpecifier, + uri: &ModuleSpecifier, + ) -> Result<(), AnyError> { self .tx - .send(ConfigRequest::Workspace) + .send(ConfigRequest::Specifier(specifier.clone(), uri.clone())) .await .map_err(|_| anyhow!("Error sending config update task.")) } diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index ebcb6b9e3..c8b959596 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -677,18 +677,36 @@ impl Inner { .performance .mark("did_change_configuration", Some(¶ms)); - if self.config.client_capabilities.workspace_configuration { - if let Err(err) = self.config.update_workspace_settings().await { - error!("Error updating workspace settings: {}", err); - } - } else if let Some(config) = params - .settings - .as_object() - .map(|settings| settings.get(SETTINGS_SECTION)) - .flatten() - .cloned() - { - if let Err(err) = self.config.set_workspace_settings(config) { + let maybe_config = + if self.config.client_capabilities.workspace_configuration { + let config_response = self + .client + .configuration(vec![ConfigurationItem { + scope_uri: None, + section: Some(SETTINGS_SECTION.to_string()), + }]) + .await; + if let Err(err) = self.config.update_all_settings().await { + error!("Cannot request updating all settings: {}", err); + } + match config_response { + Ok(value_vec) => value_vec.get(0).cloned(), + Err(err) => { + error!("Error getting workspace configuration: {}", err); + None + } + } + } else { + params + .settings + .as_object() + .map(|settings| settings.get(SETTINGS_SECTION)) + .flatten() + .cloned() + }; + + if let Some(value) = maybe_config { + if let Err(err) = self.config.set_workspace_settings(value) { error!("failed to update settings: {}", err); } } diff --git a/cli/tests/integration_tests_lsp.rs b/cli/tests/integration_tests_lsp.rs index 744b8d387..999d2de71 100644 --- a/cli/tests/integration_tests_lsp.rs +++ b/cli/tests/integration_tests_lsp.rs @@ -2125,3 +2125,93 @@ fn lsp_format_markdown() { ); shutdown(&mut client); } + +#[test] +fn lsp_configuration_did_change() { + let _g = http_server(); + let mut client = init("initialize_params_did_config_change.json"); + did_open( + &mut client, + json!({ + "textDocument": { + "uri": "file:///a/file.ts", + "languageId": "typescript", + "version": 1, + "text": "import * as a from \"http://localhost:4545/x/a@\"" + } + }), + ); + client + .write_notification( + "workspace/didChangeConfiguration", + json!({ + "settings": {} + }), + ) + .unwrap(); + let (id, method, _) = client.read_request::<Value>().unwrap(); + assert_eq!(method, "workspace/configuration"); + client + .write_response( + id, + json!([{ + "enable": true, + "codeLens": { + "implementations": true, + "references": true + }, + "importMap": null, + "lint": true, + "suggest": { + "autoImports": true, + "completeFunctionCalls": false, + "names": true, + "paths": true, + "imports": { + "hosts": { + "http://localhost:4545/": true + } + } + }, + "unstable": false + }]), + ) + .unwrap(); + let (maybe_res, maybe_err) = client + .write_request( + "textDocument/completion", + json!({ + "textDocument": { + "uri": "file:///a/file.ts" + }, + "position": { + "line": 0, + "character": 46 + }, + "context": { + "triggerKind": 2, + "triggerCharacter": "@" + } + }), + ) + .unwrap(); + assert!(maybe_err.is_none()); + if let Some(lsp::CompletionResponse::List(list)) = maybe_res { + assert!(!list.is_incomplete); + assert_eq!(list.items.len(), 3); + } else { + panic!("unexpected response"); + } + let (maybe_res, maybe_err) = client + .write_request( + "completionItem/resolve", + load_fixture("completion_resolve_params_registry.json"), + ) + .unwrap(); + assert!(maybe_err.is_none()); + assert_eq!( + maybe_res, + Some(load_fixture("completion_resolve_response_registry.json")) + ); + shutdown(&mut client); +} diff --git a/cli/tests/lsp/initialize_params_did_config_change.json b/cli/tests/lsp/initialize_params_did_config_change.json new file mode 100644 index 000000000..02237c788 --- /dev/null +++ b/cli/tests/lsp/initialize_params_did_config_change.json @@ -0,0 +1,62 @@ +{ + "processId": 0, + "clientInfo": { + "name": "test-harness", + "version": "1.0.0" + }, + "rootUri": null, + "initializationOptions": { + "enable": true, + "codeLens": { + "implementations": true, + "references": true + }, + "importMap": null, + "lint": true, + "suggest": { + "autoImports": true, + "completeFunctionCalls": false, + "names": true, + "paths": true, + "imports": { + "hosts": { + "http://localhost:4545/": false + } + } + }, + "unstable": false + }, + "capabilities": { + "textDocument": { + "codeAction": { + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "quickfix" + ] + } + }, + "isPreferredSupport": true, + "dataSupport": true, + "resolveSupport": { + "properties": [ + "edit" + ] + } + }, + "foldingRange": { + "lineFoldingOnly": true + }, + "synchronization": { + "dynamicRegistration": true, + "willSave": true, + "willSaveWaitUntil": true, + "didSave": true + } + }, + "workspace": { + "configuration": true, + "workspaceFolders": true + } + } +} |