summaryrefslogtreecommitdiff
path: root/cli/lsp/config.rs
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2022-03-21 12:33:37 +1100
committerGitHub <noreply@github.com>2022-03-21 12:33:37 +1100
commit1414dc503ba4cddcc5fdd5a0417d54678b1ac3fb (patch)
tree5aa4a03505c3c64d1624bca6417a47c84a97b6fd /cli/lsp/config.rs
parentdaa7c6d32ab5a4029f8084e174d621f5562256be (diff)
feat(lsp): support deno.enablePaths setting (#13978)
Ref: denoland/vscode_deno#633
Diffstat (limited to 'cli/lsp/config.rs')
-rw-r--r--cli/lsp/config.rs175
1 files changed, 142 insertions, 33 deletions
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs
index d35451e84..7b4294943 100644
--- a/cli/lsp/config.rs
+++ b/cli/lsp/config.rs
@@ -1,12 +1,14 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+use super::client::Client;
+use super::logging::lsp_log;
+use crate::fs_util;
use deno_core::error::AnyError;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde_json;
use deno_core::serde_json::Value;
use deno_core::ModuleSpecifier;
-use lsp::WorkspaceFolder;
use lspower::lsp;
use std::collections::BTreeMap;
use std::collections::HashMap;
@@ -128,6 +130,10 @@ impl Default for ImportCompletionSettings {
pub struct SpecifierSettings {
/// A flag that indicates if Deno is enabled for this specifier or not.
pub enable: bool,
+ /// A list of paths, using the workspace folder as a base that should be Deno
+ /// enabled.
+ #[serde(default)]
+ pub enable_paths: Vec<String>,
/// Code lens specific settings for the resource.
#[serde(default)]
pub code_lens: CodeLensSpecifierSettings,
@@ -141,6 +147,10 @@ pub struct WorkspaceSettings {
#[serde(default)]
pub enable: bool,
+ /// A list of paths, using the root_uri as a base that should be Deno enabled.
+ #[serde(default)]
+ pub enable_paths: Vec<String>,
+
/// 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>,
@@ -198,14 +208,27 @@ impl WorkspaceSettings {
#[derive(Debug, Clone, Default)]
pub struct ConfigSnapshot {
pub client_capabilities: ClientCapabilities,
+ pub enabled_paths: HashMap<String, Vec<String>>,
pub settings: Settings,
- pub workspace_folders: Option<Vec<lsp::WorkspaceFolder>>,
}
impl ConfigSnapshot {
+ /// Determine if the provided specifier is enabled or not.
pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool {
- if let Some(settings) = self.settings.specifiers.get(specifier) {
- settings.1.enable
+ if !self.enabled_paths.is_empty() {
+ let specifier_str = specifier.to_string();
+ for (workspace, enabled_paths) in self.enabled_paths.iter() {
+ if specifier_str.starts_with(workspace) {
+ return enabled_paths
+ .iter()
+ .any(|path| specifier_str.starts_with(path));
+ }
+ }
+ }
+ if let Some((_, SpecifierSettings { enable, .. })) =
+ self.settings.specifiers.get(specifier)
+ {
+ *enable
} else {
self.settings.workspace.enable
}
@@ -228,14 +251,19 @@ pub struct Settings {
#[derive(Debug)]
pub struct Config {
pub client_capabilities: ClientCapabilities,
+ enabled_paths: HashMap<String, Vec<String>>,
+ pub root_uri: Option<ModuleSpecifier>,
settings: Settings,
- pub workspace_folders: Option<Vec<WorkspaceFolder>>,
+ pub workspace_folders: Option<Vec<(ModuleSpecifier, lsp::WorkspaceFolder)>>,
}
impl Config {
pub fn new() -> Self {
Self {
client_capabilities: ClientCapabilities::default(),
+ enabled_paths: Default::default(),
+ /// Root provided by the initialization parameters.
+ root_uri: None,
settings: Default::default(),
workspace_folders: None,
}
@@ -259,8 +287,8 @@ impl Config {
pub fn snapshot(&self) -> Arc<ConfigSnapshot> {
Arc::new(ConfigSnapshot {
client_capabilities: self.client_capabilities.clone(),
+ enabled_paths: self.enabled_paths.clone(),
settings: self.settings.clone(),
- workspace_folders: self.workspace_folders.clone(),
})
}
@@ -269,6 +297,16 @@ impl Config {
}
pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool {
+ if !self.enabled_paths.is_empty() {
+ let specifier_str = specifier.to_string();
+ for (workspace, enabled_paths) in self.enabled_paths.iter() {
+ if specifier_str.starts_with(workspace) {
+ return enabled_paths
+ .iter()
+ .any(|path| specifier_str.starts_with(path));
+ }
+ }
+ }
self
.settings
.specifiers
@@ -321,6 +359,66 @@ impl Config {
}
}
+ /// Given the configured workspaces or root URI and the their settings,
+ /// update and resolve any paths that should be enabled
+ pub async fn update_enabled_paths(&mut self, client: Client) -> bool {
+ if let Some(workspace_folders) = self.workspace_folders.clone() {
+ let mut touched = false;
+ for (workspace, folder) in workspace_folders {
+ if let Ok(settings) = client.specifier_configuration(&folder.uri).await
+ {
+ if self.update_enabled_paths_entry(&workspace, settings.enable_paths)
+ {
+ touched = true;
+ }
+ }
+ }
+ touched
+ } else if let Some(root_uri) = self.root_uri.clone() {
+ self.update_enabled_paths_entry(
+ &root_uri,
+ self.settings.workspace.enable_paths.clone(),
+ )
+ } else {
+ false
+ }
+ }
+
+ /// Update a specific entry in the enabled paths for a given workspace.
+ fn update_enabled_paths_entry(
+ &mut self,
+ workspace: &ModuleSpecifier,
+ enabled_paths: Vec<String>,
+ ) -> bool {
+ let workspace = fs_util::ensure_directory_specifier(workspace.clone());
+ let key = workspace.to_string();
+ let mut touched = false;
+ if !enabled_paths.is_empty() {
+ if let Ok(workspace_path) = fs_util::specifier_to_file_path(&workspace) {
+ let mut paths = Vec::new();
+ for path in &enabled_paths {
+ let fs_path = workspace_path.join(path);
+ match ModuleSpecifier::from_file_path(fs_path) {
+ Ok(path_uri) => {
+ paths.push(path_uri.to_string());
+ }
+ Err(_) => {
+ lsp_log!("Unable to resolve a file path for `deno.enablePath` from \"{}\" for workspace \"{}\".", path, workspace);
+ }
+ }
+ }
+ if !paths.is_empty() {
+ touched = true;
+ self.enabled_paths.insert(key, paths);
+ }
+ }
+ } else {
+ touched = true;
+ self.enabled_paths.remove(&key);
+ }
+ touched
+ }
+
pub fn get_specifiers_with_client_uris(&self) -> Vec<SpecifierWithClientUri> {
self
.settings
@@ -330,7 +428,7 @@ impl Config {
specifier: s.clone(),
client_uri: u.clone(),
})
- .collect::<Vec<_>>()
+ .collect()
}
pub fn set_specifier_settings(
@@ -352,33 +450,9 @@ mod tests {
use deno_core::resolve_url;
use deno_core::serde_json::json;
- #[derive(Debug, Default)]
- struct MockLanguageServer;
-
- #[lspower::async_trait]
- impl lspower::LanguageServer for MockLanguageServer {
- async fn initialize(
- &self,
- _params: lspower::lsp::InitializeParams,
- ) -> lspower::jsonrpc::Result<lsp::InitializeResult> {
- Ok(lspower::lsp::InitializeResult {
- capabilities: lspower::lsp::ServerCapabilities::default(),
- server_info: None,
- })
- }
-
- async fn shutdown(&self) -> lspower::jsonrpc::Result<()> {
- Ok(())
- }
- }
-
- fn setup() -> Config {
- Config::new()
- }
-
#[test]
fn test_config_specifier_enabled() {
- let mut config = setup();
+ let mut config = Config::new();
let specifier = resolve_url("file:///a.ts").unwrap();
assert!(!config.specifier_enabled(&specifier));
config
@@ -390,8 +464,42 @@ mod tests {
}
#[test]
+ fn test_config_snapshot_specifier_enabled() {
+ let mut config = Config::new();
+ let specifier = resolve_url("file:///a.ts").unwrap();
+ assert!(!config.specifier_enabled(&specifier));
+ config
+ .set_workspace_settings(json!({
+ "enable": true
+ }))
+ .expect("could not update");
+ let config_snapshot = config.snapshot();
+ assert!(config_snapshot.specifier_enabled(&specifier));
+ }
+
+ #[test]
+ fn test_config_specifier_enabled_path() {
+ let mut config = Config::new();
+ let specifier_a = resolve_url("file:///project/worker/a.ts").unwrap();
+ let specifier_b = resolve_url("file:///project/other/b.ts").unwrap();
+ assert!(!config.specifier_enabled(&specifier_a));
+ assert!(!config.specifier_enabled(&specifier_b));
+ let mut enabled_paths = HashMap::new();
+ enabled_paths.insert(
+ "file:///project/".to_string(),
+ vec!["file:///project/worker/".to_string()],
+ );
+ config.enabled_paths = enabled_paths;
+ assert!(config.specifier_enabled(&specifier_a));
+ assert!(!config.specifier_enabled(&specifier_b));
+ let config_snapshot = config.snapshot();
+ assert!(config_snapshot.specifier_enabled(&specifier_a));
+ assert!(!config_snapshot.specifier_enabled(&specifier_b));
+ }
+
+ #[test]
fn test_set_workspace_settings_defaults() {
- let mut config = setup();
+ let mut config = Config::new();
config
.set_workspace_settings(json!({}))
.expect("could not update");
@@ -399,6 +507,7 @@ mod tests {
config.get_workspace_settings(),
WorkspaceSettings {
enable: false,
+ enable_paths: Vec::new(),
cache: None,
certificate_stores: None,
config: None,