From f959297dcd382b25bdedd0ff6aa27e8fb40e7ecd Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Wed, 11 Sep 2024 00:20:03 +0100 Subject: [PATCH] feat(lsp): unstable setting as list (#25552) --- cli/lsp/config.rs | 56 ++++++++++++++++++++++++++++++++-- cli/lsp/language_server.rs | 6 +++- cli/lsp/repl.rs | 2 +- cli/lsp/testing/execution.rs | 41 ++++++++++++++----------- tests/integration/lsp_tests.rs | 14 +++++++-- 5 files changed, 94 insertions(+), 25 deletions(-) diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index c9729a5e5d..c5d0642855 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -43,6 +43,8 @@ use indexmap::IndexSet; use lsp_types::ClientCapabilities; use std::collections::BTreeMap; use std::collections::HashMap; +use std::ops::Deref; +use std::ops::DerefMut; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; @@ -70,6 +72,54 @@ fn is_true() -> bool { true } +/// Wrapper that defaults if it fails to deserialize. Good for individual +/// settings. +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct SafeValue { + inner: T, +} + +impl<'de, T: Default + for<'de2> Deserialize<'de2>> Deserialize<'de> + for SafeValue +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(Self { + inner: Deserialize::deserialize(deserializer).unwrap_or_default(), + }) + } +} + +impl Serialize for SafeValue { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.inner.serialize(serializer) + } +} + +impl Deref for SafeValue { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for SafeValue { + fn deref_mut(&mut self) -> &mut T { + &mut self.inner + } +} + +impl SafeValue { + pub fn as_deref(&self) -> &T { + &self.inner + } +} + #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct CodeLensSettings { @@ -538,7 +588,7 @@ pub struct WorkspaceSettings { pub unsafely_ignore_certificate_errors: Option>, #[serde(default)] - pub unstable: bool, + pub unstable: SafeValue>, #[serde(default)] pub javascript: LanguageWorkspaceSettings, @@ -568,7 +618,7 @@ impl Default for WorkspaceSettings { testing: Default::default(), tls_certificate: None, unsafely_ignore_certificate_errors: None, - unstable: false, + unstable: Default::default(), javascript: Default::default(), typescript: Default::default(), } @@ -2141,7 +2191,7 @@ mod tests { }, tls_certificate: None, unsafely_ignore_certificate_errors: None, - unstable: false, + unstable: Default::default(), javascript: LanguageWorkspaceSettings { inlay_hints: InlayHintsSettings { parameter_names: InlayHintsParamNamesOptions { diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 2bb13e5e4c..d025d35a8d 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -3859,7 +3859,11 @@ impl Inner { "#, - serde_json::to_string_pretty(&workspace_settings).unwrap(), + serde_json::to_string_pretty(&workspace_settings) + .inspect_err(|e| { + dbg!(e); + }) + .unwrap(), documents_specifiers.len(), documents_specifiers .into_iter() diff --git a/cli/lsp/repl.rs b/cli/lsp/repl.rs index 85d3a022e6..a238a22ccd 100644 --- a/cli/lsp/repl.rs +++ b/cli/lsp/repl.rs @@ -311,7 +311,7 @@ pub fn get_repl_workspace_settings() -> WorkspaceSettings { document_preload_limit: 0, // don't pre-load any modules as it's expensive and not useful for the repl tls_certificate: None, unsafely_ignore_certificate_errors: None, - unstable: false, + unstable: Default::default(), suggest: DenoCompletionSettings { imports: ImportCompletionSettings { auto_discover: false, diff --git a/cli/lsp/testing/execution.rs b/cli/lsp/testing/execution.rs index 4ac565aa0b..a952f2c490 100644 --- a/cli/lsp/testing/execution.rs +++ b/cli/lsp/testing/execution.rs @@ -33,6 +33,7 @@ use deno_runtime::deno_permissions::Permissions; use deno_runtime::tokio_util::create_and_run_current_thread; use indexmap::IndexMap; use lsp_types::Uri; +use std::borrow::Cow; use std::collections::HashMap; use std::collections::HashSet; use std::num::NonZeroUsize; @@ -219,8 +220,9 @@ impl TestRun { ) -> Result<(), AnyError> { let args = self.get_args(); lsp_log!("Executing test run with arguments: {}", args.join(" ")); - let flags = - Arc::new(flags_from_vec(args.into_iter().map(From::from).collect())?); + let flags = Arc::new(flags_from_vec( + args.into_iter().map(|s| From::from(s.as_ref())).collect(), + )?); let factory = CliFactory::from_flags(flags); let cli_options = factory.cli_options()?; // Various test files should not share the same permissions in terms of @@ -452,37 +454,42 @@ impl TestRun { Ok(()) } - fn get_args(&self) -> Vec<&str> { - let mut args = vec!["deno", "test"]; + fn get_args(&self) -> Vec> { + let mut args = vec![Cow::Borrowed("deno"), Cow::Borrowed("test")]; args.extend( self .workspace_settings .testing .args .iter() - .map(|s| s.as_str()), + .map(|s| Cow::Borrowed(s.as_str())), ); - args.push("--trace-leaks"); - if self.workspace_settings.unstable && !args.contains(&"--unstable") { - args.push("--unstable"); + args.push(Cow::Borrowed("--trace-leaks")); + for unstable_feature in self.workspace_settings.unstable.as_deref() { + let flag = format!("--unstable-{unstable_feature}"); + if !args.contains(&Cow::Borrowed(&flag)) { + args.push(Cow::Owned(flag)); + } } if let Some(config) = &self.workspace_settings.config { - if !args.contains(&"--config") && !args.contains(&"-c") { - args.push("--config"); - args.push(config.as_str()); + if !args.contains(&Cow::Borrowed("--config")) + && !args.contains(&Cow::Borrowed("-c")) + { + args.push(Cow::Borrowed("--config")); + args.push(Cow::Borrowed(config.as_str())); } } if let Some(import_map) = &self.workspace_settings.import_map { - if !args.contains(&"--import-map") { - args.push("--import-map"); - args.push(import_map.as_str()); + if !args.contains(&Cow::Borrowed("--import-map")) { + args.push(Cow::Borrowed("--import-map")); + args.push(Cow::Borrowed(import_map.as_str())); } } if self.kind == lsp_custom::TestRunKind::Debug - && !args.contains(&"--inspect") - && !args.contains(&"--inspect-brk") + && !args.contains(&Cow::Borrowed("--inspect")) + && !args.contains(&Cow::Borrowed("--inspect-brk")) { - args.push("--inspect"); + args.push(Cow::Borrowed("--inspect")); } args } diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index f0d0a2d8d5..4c8372df6e 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -10907,7 +10907,7 @@ fn lsp_configuration_did_change() { }, }, }, - "unstable": false, + "unstable": [], } })); let list = client.get_completion_list( @@ -11851,6 +11851,8 @@ Deno.test({ async fn(t) { console.log("test a"); await t.step("step of test a", () => {}); + const kv = await Deno.openKv(); + kv.close(); } }); "#; @@ -11860,6 +11862,12 @@ Deno.test({ let mut client = context.new_lsp_command().build(); client.initialize_default(); + client.change_configuration(json!({ + "deno": { + "enable": true, + "unstable": ["kv"], + }, + })); client.did_open(json!({ "textDocument": { @@ -12380,7 +12388,7 @@ fn lsp_node_modules_dir() { "paths": true, "imports": {}, }, - "unstable": false, + "unstable": [], } })); }; refresh_config(&mut client); @@ -12498,7 +12506,7 @@ fn lsp_vendor_dir() { "paths": true, "imports": {}, }, - "unstable": false, + "unstable": [], } })); let diagnostics = client.read_diagnostics();