diff options
author | Kitson Kelly <me@kitsonkelly.com> | 2021-07-28 07:25:09 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-28 07:25:09 +1000 |
commit | 667b026798b5284e9ec8bf47baba80f343975d2e (patch) | |
tree | 3e2d85160925222b7052645ffb5fa0c8a4aa476e | |
parent | fd0b24b246e3c6ed22e96f67361da654bbff8b48 (diff) |
feat(lsp): ability to set DENO_DIR via settings (#11527)
Ref: denoland/vscode_deno#287
-rw-r--r-- | cli/flags.rs | 3 | ||||
-rw-r--r-- | cli/lsp/README.md | 1 | ||||
-rw-r--r-- | cli/lsp/config.rs | 5 | ||||
-rw-r--r-- | cli/lsp/language_server.rs | 99 | ||||
-rw-r--r-- | cli/lsp/registries.rs | 6 | ||||
-rw-r--r-- | cli/lsp/sources.rs | 10 | ||||
-rw-r--r-- | cli/program_state.rs | 7 | ||||
-rw-r--r-- | cli/specifier_handler.rs | 8 | ||||
-rw-r--r-- | cli/tests/integration/lsp_tests.rs | 90 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params.json | 1 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params_bad_config_option.json | 1 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params_code_lens_test.json | 1 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params_code_lens_test_disabled.json | 1 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params_did_config_change.json | 1 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params_disabled.json | 1 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params_registry.json | 1 | ||||
-rw-r--r-- | cli/tests/lsp/initialize_params_unstable.json | 1 | ||||
-rw-r--r-- | cli/tools/standalone.rs | 1 |
18 files changed, 213 insertions, 25 deletions
diff --git a/cli/flags.rs b/cli/flags.rs index b7e4e84db..086b20e10 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -139,6 +139,9 @@ pub struct Flags { pub allow_write: Option<Vec<PathBuf>>, pub ca_file: Option<String>, pub cache_blocklist: Vec<String>, + /// This is not exposed as an option in the CLI, it is used internally when + /// the language server is configured with an explicit cache option. + pub cache_path: Option<PathBuf>, pub cached_only: bool, pub config_path: Option<String>, pub coverage_dir: Option<String>, diff --git a/cli/lsp/README.md b/cli/lsp/README.md index 764998fb1..2256c4038 100644 --- a/cli/lsp/README.md +++ b/cli/lsp/README.md @@ -19,6 +19,7 @@ methods that the client calls via the Language Server RPC protocol. There are several settings that the language server supports for a workspace: - `deno.enable` +- `deno.cache` - `deno.config` - `deno.importMap` - `deno.codeLens.implementations` diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index aeb0e29b9..a58a8d1ae 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -148,6 +148,10 @@ pub struct WorkspaceSettings { #[serde(default)] pub enable: bool, + /// An option that points to a path string of the path to utilise as the + /// cache/DENO_DIR for the language server. + pub cache: Option<String>, + /// An option that points to a path string of the config file to apply to /// code within the workspace. pub config: Option<String>, @@ -475,6 +479,7 @@ mod tests { config.get_workspace_settings(), WorkspaceSettings { enable: false, + cache: None, config: None, import_map: None, code_lens: CodeLensSettings { diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 27d6e4204..ab17d03fb 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -95,6 +95,9 @@ pub(crate) struct Inner { module_registries: registries::ModuleRegistry, /// The path to the module registries cache module_registries_location: PathBuf, + /// An optional path to the DENO_DIR which has been specified in the client + /// options. + maybe_cache_path: Option<PathBuf>, /// An optional configuration file which has been specified in the client /// options. maybe_config_file: Option<ConfigFile>, @@ -144,10 +147,11 @@ impl Inner { config, diagnostics_server, documents: Default::default(), - maybe_config_file: Default::default(), - maybe_config_uri: Default::default(), - maybe_import_map: Default::default(), - maybe_import_map_uri: Default::default(), + maybe_cache_path: None, + maybe_config_file: None, + maybe_config_uri: None, + maybe_import_map: None, + maybe_import_map_uri: None, module_registries, module_registries_location, performance, @@ -358,7 +362,7 @@ impl Inner { self.maybe_config_uri = None; if let Some(config_str) = maybe_config { if !config_str.is_empty() { - info!("Updating TypeScript configuration from: \"{}\"", config_str); + info!("Setting TypeScript configuration from: \"{}\"", config_str); let config_url = if let Ok(url) = Url::from_file_path(config_str) { Ok(url) } else if let Some(root_uri) = maybe_root_uri { @@ -417,6 +421,62 @@ impl Inner { }) } + pub fn update_cache(&mut self) -> Result<(), AnyError> { + let mark = self.performance.mark("update_cache", None::<()>); + self.performance.measure(mark); + let (maybe_cache, maybe_root_uri) = { + let config = &self.config; + ( + config.get_workspace_settings().cache, + config.root_uri.clone(), + ) + }; + let maybe_cache_path = if let Some(cache_str) = &maybe_cache { + info!("Setting cache path from: \"{}\"", cache_str); + let cache_url = if let Ok(url) = Url::from_file_path(cache_str) { + Ok(url) + } else if let Some(root_uri) = &maybe_root_uri { + let root_path = root_uri + .to_file_path() + .map_err(|_| anyhow!("Bad root_uri: {}", root_uri))?; + let cache_path = root_path.join(cache_str); + Url::from_file_path(cache_path).map_err(|_| { + anyhow!("Bad file path for import path: {:?}", cache_str) + }) + } else { + Err(anyhow!( + "The path to the cache path (\"{}\") is not resolvable.", + cache_str + )) + }?; + let cache_path = cache_url.to_file_path().map_err(|_| { + anyhow!("Cannot convert \"{}\" into a file path.", cache_url) + })?; + info!( + " Resolved cache path: \"{}\"", + cache_path.to_string_lossy() + ); + Some(cache_path) + } else { + None + }; + if self.maybe_cache_path != maybe_cache_path { + let maybe_custom_root = maybe_cache_path + .clone() + .or_else(|| env::var("DENO_DIR").map(String::into).ok()); + let dir = deno_dir::DenoDir::new(maybe_custom_root) + .expect("could not access DENO_DIR"); + let module_registries_location = dir.root.join(REGISTRIES_PATH); + self.module_registries = + registries::ModuleRegistry::new(&module_registries_location); + self.module_registries_location = module_registries_location; + let sources_location = dir.root.join(SOURCES_PATH); + self.sources = Sources::new(&sources_location); + self.maybe_cache_path = maybe_cache_path; + } + Ok(()) + } + pub async fn update_import_map(&mut self) -> Result<(), AnyError> { let mark = self.performance.mark("update_import_map", None::<()>); let (maybe_import_map, maybe_root_uri) = { @@ -427,7 +487,7 @@ impl Inner { ) }; if let Some(import_map_str) = &maybe_import_map { - info!("Updating import map from: \"{}\"", import_map_str); + info!("Setting import map from: \"{}\"", import_map_str); let import_map_url = if let Ok(url) = Url::from_file_path(import_map_str) { Ok(url) @@ -620,8 +680,12 @@ impl Inner { } self.update_debug_flag(); + // Check to see if we need to change the cache path + if let Err(err) = self.update_cache() { + self.client.show_message(MessageType::Warning, err).await; + } if let Err(err) = self.update_tsconfig().await { - warn!("Updating tsconfig has errored: {}", err); + self.client.show_message(MessageType::Warning, err).await; } if capabilities.code_action_provider.is_some() { @@ -636,14 +700,6 @@ impl Inner { self.ts_fixable_diagnostics = fixable_diagnostics; } - self.performance.measure(mark); - Ok(InitializeResult { - capabilities, - server_info: Some(server_info), - }) - } - - async fn initialized(&mut self, _: InitializedParams) { // Check to see if we need to setup the import map if let Err(err) = self.update_import_map().await { self.client.show_message(MessageType::Warning, err).await; @@ -653,6 +709,14 @@ impl Inner { self.client.show_message(MessageType::Warning, err).await; } + self.performance.measure(mark); + Ok(InitializeResult { + capabilities, + server_info: Some(server_info), + }) + } + + async fn initialized(&mut self, _: InitializedParams) { if self .config .client_capabilities @@ -836,6 +900,9 @@ impl Inner { } self.update_debug_flag(); + if let Err(err) = self.update_cache() { + self.client.show_message(MessageType::Warning, err).await; + } if let Err(err) = self.update_import_map().await { self.client.show_message(MessageType::Warning, err).await; } @@ -2413,6 +2480,7 @@ impl Inner { &specifier, &self.maybe_import_map, &self.maybe_config_file, + &self.maybe_cache_path, ) .await .map_err(|err| { @@ -2425,6 +2493,7 @@ impl Inner { &referrer, &self.maybe_import_map, &self.maybe_config_file, + &self.maybe_cache_path, ) .await .map_err(|err| { diff --git a/cli/lsp/registries.rs b/cli/lsp/registries.rs index 96c24b43f..d044927bc 100644 --- a/cli/lsp/registries.rs +++ b/cli/lsp/registries.rs @@ -254,8 +254,10 @@ pub struct ModuleRegistry { impl Default for ModuleRegistry { fn default() -> Self { - let custom_root = std::env::var("DENO_DIR").map(String::into).ok(); - let dir = deno_dir::DenoDir::new(custom_root).unwrap(); + // This only gets used when creating the tsc runtime and for testing, and so + // it shouldn't ever actually access the DenoDir, so it doesn't support a + // custom root. + let dir = deno_dir::DenoDir::new(None).unwrap(); let location = dir.root.join("registries"); let http_cache = HttpCache::new(&location); let cache_setting = CacheSetting::Use; diff --git a/cli/lsp/sources.rs b/cli/lsp/sources.rs index 62c76260c..033a1e9d5 100644 --- a/cli/lsp/sources.rs +++ b/cli/lsp/sources.rs @@ -9,6 +9,7 @@ use crate::config_file::ConfigFile; use crate::file_fetcher::get_source_from_bytes; use crate::file_fetcher::map_content_type; use crate::file_fetcher::SUPPORTED_SCHEMES; +use crate::flags::Flags; use crate::http_cache; use crate::http_cache::HttpCache; use crate::import_map::ImportMap; @@ -36,8 +37,15 @@ pub async fn cache( specifier: &ModuleSpecifier, maybe_import_map: &Option<ImportMap>, maybe_config_file: &Option<ConfigFile>, + maybe_cache_path: &Option<PathBuf>, ) -> Result<(), AnyError> { - let program_state = Arc::new(ProgramState::build(Default::default()).await?); + let program_state = Arc::new( + ProgramState::build(Flags { + cache_path: maybe_cache_path.clone(), + ..Default::default() + }) + .await?, + ); let handler = Arc::new(Mutex::new(FetchHandler::new( &program_state, Permissions::allow_all(), diff --git a/cli/program_state.rs b/cli/program_state.rs index 264b22729..6775b2276 100644 --- a/cli/program_state.rs +++ b/cli/program_state.rs @@ -61,8 +61,11 @@ pub struct ProgramState { impl ProgramState { pub async fn build(flags: flags::Flags) -> Result<Arc<Self>, AnyError> { - let custom_root = env::var("DENO_DIR").map(String::into).ok(); - let dir = deno_dir::DenoDir::new(custom_root)?; + let maybe_custom_root = flags + .cache_path + .clone() + .or_else(|| env::var("DENO_DIR").map(String::into).ok()); + let dir = deno_dir::DenoDir::new(maybe_custom_root)?; let deps_cache_location = dir.root.join("deps"); let http_cache = http_cache::HttpCache::new(&deps_cache_location); let ca_file = flags.ca_file.clone().or_else(|| env::var("DENO_CERT").ok()); diff --git a/cli/specifier_handler.rs b/cli/specifier_handler.rs index 78687ba95..cec1049a3 100644 --- a/cli/specifier_handler.rs +++ b/cli/specifier_handler.rs @@ -1,7 +1,6 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use crate::ast::Location; -use crate::deno_dir::DenoDir; use crate::disk_cache::DiskCache; use crate::file_fetcher::FileFetcher; use crate::media_type::MediaType; @@ -19,7 +18,6 @@ use deno_core::serde_json; use deno_core::ModuleSpecifier; use log::debug; use std::collections::HashMap; -use std::env; use std::fmt; use std::path::PathBuf; use std::pin::Pin; @@ -236,9 +234,7 @@ impl FetchHandler { root_permissions: Permissions, dynamic_permissions: Permissions, ) -> Result<Self, AnyError> { - let custom_root = env::var("DENO_DIR").map(String::into).ok(); - let deno_dir = DenoDir::new(custom_root)?; - let disk_cache = deno_dir.gen_cache; + let disk_cache = program_state.dir.gen_cache.clone(); let file_fetcher = program_state.file_fetcher.clone(); Ok(FetchHandler { @@ -571,10 +567,12 @@ impl SpecifierHandler for MemoryHandler { #[cfg(test)] pub mod tests { use super::*; + use crate::deno_dir::DenoDir; use crate::file_fetcher::CacheSetting; use crate::http_cache::HttpCache; use deno_core::resolve_url_or_path; use deno_runtime::deno_web::BlobStore; + use std::env; use tempfile::TempDir; macro_rules! map ( diff --git a/cli/tests/integration/lsp_tests.rs b/cli/tests/integration/lsp_tests.rs index 7f4f4e591..8bf019aa7 100644 --- a/cli/tests/integration/lsp_tests.rs +++ b/cli/tests/integration/lsp_tests.rs @@ -2526,6 +2526,96 @@ fn lsp_auto_discover_registry() { } #[test] +fn lsp_cache_location() { + let _g = http_server(); + let temp_dir = TempDir::new().expect("could not create temp dir"); + let mut params: lsp::InitializeParams = + serde_json::from_value(load_fixture("initialize_params.json")).unwrap(); + + params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap()); + if let Some(Value::Object(mut map)) = params.initialization_options { + map.insert("cache".to_string(), json!(".cache")); + params.initialization_options = Some(Value::Object(map)); + } + + let deno_exe = deno_exe_path(); + let mut client = LspClient::new(&deno_exe).unwrap(); + client + .write_request::<_, _, Value>("initialize", params) + .unwrap(); + + client.write_notification("initialized", json!({})).unwrap(); + did_open( + &mut client, + json!({ + "textDocument": { + "uri": "file:///a/file_01.ts", + "languageId": "typescript", + "version": 1, + "text": "export const a = \"a\";\n", + } + }), + ); + let diagnostics = did_open( + &mut client, + load_fixture("did_open_params_import_hover.json"), + ); + let diagnostics = diagnostics.into_iter().flat_map(|x| x.diagnostics); + assert_eq!(diagnostics.count(), 12); + let (maybe_res, maybe_err) = client + .write_request::<_, _, Value>( + "deno/cache", + json!({ + "referrer": { + "uri": "file:///a/file.ts", + }, + "uris": [], + }), + ) + .unwrap(); + assert!(maybe_err.is_none()); + assert!(maybe_res.is_some()); + let (maybe_res, maybe_err) = client + .write_request( + "textDocument/hover", + json!({ + "textDocument": { + "uri": "file:///a/file.ts", + }, + "position": { + "line": 0, + "character": 28 + } + }), + ) + .unwrap(); + assert!(maybe_err.is_none()); + assert_eq!( + maybe_res, + Some(json!({ + "contents": { + "kind": "markdown", + "value": "**Resolved Dependency**\n\n**Code**: http​://127.0.0.1:4545/xTypeScriptTypes.js\n" + }, + "range": { + "start": { + "line": 0, + "character": 20 + }, + "end":{ + "line": 0, + "character": 61 + } + } + })) + ); + let cache_path = temp_dir.path().join(".cache"); + assert!(cache_path.is_dir()); + assert!(cache_path.join("gen").is_dir()); + shutdown(&mut client); +} + +#[test] fn lsp_diagnostics_warn() { let _g = http_server(); let mut client = init("initialize_params.json"); diff --git a/cli/tests/lsp/initialize_params.json b/cli/tests/lsp/initialize_params.json index f0b2d1dad..27711efd0 100644 --- a/cli/tests/lsp/initialize_params.json +++ b/cli/tests/lsp/initialize_params.json @@ -7,6 +7,7 @@ "rootUri": null, "initializationOptions": { "enable": true, + "cache": null, "codeLens": { "implementations": true, "references": true, diff --git a/cli/tests/lsp/initialize_params_bad_config_option.json b/cli/tests/lsp/initialize_params_bad_config_option.json index fbff31566..cfe40acec 100644 --- a/cli/tests/lsp/initialize_params_bad_config_option.json +++ b/cli/tests/lsp/initialize_params_bad_config_option.json @@ -7,6 +7,7 @@ "rootUri": null, "initializationOptions": { "enable": true, + "cache": null, "codeLens": { "implementations": true, "references": true, diff --git a/cli/tests/lsp/initialize_params_code_lens_test.json b/cli/tests/lsp/initialize_params_code_lens_test.json index 792928462..fb803c04f 100644 --- a/cli/tests/lsp/initialize_params_code_lens_test.json +++ b/cli/tests/lsp/initialize_params_code_lens_test.json @@ -7,6 +7,7 @@ "rootUri": null, "initializationOptions": { "enable": true, + "cache": null, "importMap": null, "lint": true, "suggest": { diff --git a/cli/tests/lsp/initialize_params_code_lens_test_disabled.json b/cli/tests/lsp/initialize_params_code_lens_test_disabled.json index febec5695..c4d5e42f8 100644 --- a/cli/tests/lsp/initialize_params_code_lens_test_disabled.json +++ b/cli/tests/lsp/initialize_params_code_lens_test_disabled.json @@ -7,6 +7,7 @@ "rootUri": null, "initializationOptions": { "enable": true, + "cache": null, "codeLens": { "implementations": true, "references": true, diff --git a/cli/tests/lsp/initialize_params_did_config_change.json b/cli/tests/lsp/initialize_params_did_config_change.json index 02237c788..b5cec8499 100644 --- a/cli/tests/lsp/initialize_params_did_config_change.json +++ b/cli/tests/lsp/initialize_params_did_config_change.json @@ -7,6 +7,7 @@ "rootUri": null, "initializationOptions": { "enable": true, + "cache": null, "codeLens": { "implementations": true, "references": true diff --git a/cli/tests/lsp/initialize_params_disabled.json b/cli/tests/lsp/initialize_params_disabled.json index d5e59770a..349cc6ae3 100644 --- a/cli/tests/lsp/initialize_params_disabled.json +++ b/cli/tests/lsp/initialize_params_disabled.json @@ -7,6 +7,7 @@ "rootUri": null, "initializationOptions": { "enable": false, + "cache": null, "codeLens": { "implementations": true, "references": true diff --git a/cli/tests/lsp/initialize_params_registry.json b/cli/tests/lsp/initialize_params_registry.json index 0a19c50ec..e98a62f7f 100644 --- a/cli/tests/lsp/initialize_params_registry.json +++ b/cli/tests/lsp/initialize_params_registry.json @@ -7,6 +7,7 @@ "rootUri": null, "initializationOptions": { "enable": true, + "cache": null, "codeLens": { "implementations": true, "references": true diff --git a/cli/tests/lsp/initialize_params_unstable.json b/cli/tests/lsp/initialize_params_unstable.json index 153e3aef1..e18b6ba8b 100644 --- a/cli/tests/lsp/initialize_params_unstable.json +++ b/cli/tests/lsp/initialize_params_unstable.json @@ -7,6 +7,7 @@ "rootUri": null, "initializationOptions": { "enable": true, + "cache": null, "codeLens": { "implementations": true, "references": true diff --git a/cli/tools/standalone.rs b/cli/tools/standalone.rs index 259c61222..dfec6c7dd 100644 --- a/cli/tools/standalone.rs +++ b/cli/tools/standalone.rs @@ -207,6 +207,7 @@ pub fn compile_to_runtime_flags( allow_write: flags.allow_write, ca_file: flags.ca_file, cache_blocklist: vec![], + cache_path: None, cached_only: false, config_path: None, coverage_dir: flags.coverage_dir, |