mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
feat(lsp): WorkspaceSettings::disablePaths (#20475)
This commit is contained in:
parent
109a42ab07
commit
022664aab4
7 changed files with 146 additions and 22 deletions
|
@ -239,6 +239,10 @@ pub struct SpecifierSettings {
|
||||||
/// A flag that indicates if Deno is enabled for this specifier or not.
|
/// A flag that indicates if Deno is enabled for this specifier or not.
|
||||||
pub enable: Option<bool>,
|
pub enable: Option<bool>,
|
||||||
/// A list of paths, using the workspace folder as a base that should be Deno
|
/// A list of paths, using the workspace folder as a base that should be Deno
|
||||||
|
/// disabled.
|
||||||
|
#[serde(default)]
|
||||||
|
pub disable_paths: Vec<String>,
|
||||||
|
/// A list of paths, using the workspace folder as a base that should be Deno
|
||||||
/// enabled.
|
/// enabled.
|
||||||
pub enable_paths: Option<Vec<String>>,
|
pub enable_paths: Option<Vec<String>>,
|
||||||
/// Code lens specific settings for the resource.
|
/// Code lens specific settings for the resource.
|
||||||
|
@ -285,6 +289,11 @@ pub struct WorkspaceSettings {
|
||||||
/// A flag that indicates if Deno is enabled for the workspace.
|
/// A flag that indicates if Deno is enabled for the workspace.
|
||||||
pub enable: Option<bool>,
|
pub enable: Option<bool>,
|
||||||
|
|
||||||
|
/// A list of paths, using the root_uri as a base that should be Deno
|
||||||
|
/// disabled.
|
||||||
|
#[serde(default)]
|
||||||
|
pub disable_paths: Vec<String>,
|
||||||
|
|
||||||
/// A list of paths, using the root_uri as a base that should be Deno enabled.
|
/// A list of paths, using the root_uri as a base that should be Deno enabled.
|
||||||
pub enable_paths: Option<Vec<String>>,
|
pub enable_paths: Option<Vec<String>>,
|
||||||
|
|
||||||
|
@ -353,6 +362,7 @@ impl Default for WorkspaceSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
WorkspaceSettings {
|
WorkspaceSettings {
|
||||||
enable: None,
|
enable: None,
|
||||||
|
disable_paths: vec![],
|
||||||
enable_paths: None,
|
enable_paths: None,
|
||||||
cache: None,
|
cache: None,
|
||||||
certificate_stores: None,
|
certificate_stores: None,
|
||||||
|
@ -643,34 +653,96 @@ impl Config {
|
||||||
pub fn enabled_urls(&self) -> Vec<Url> {
|
pub fn enabled_urls(&self) -> Vec<Url> {
|
||||||
let mut urls = vec![];
|
let mut urls = vec![];
|
||||||
for (workspace_uri, _) in &self.workspace_folders {
|
for (workspace_uri, _) in &self.workspace_folders {
|
||||||
|
let Ok(workspace_path) = specifier_to_file_path(workspace_uri) else {
|
||||||
|
lsp_log!("Unable to convert uri \"{}\" to path.", workspace_uri);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let specifier_settings = self.settings.specifiers.get(workspace_uri);
|
let specifier_settings = self.settings.specifiers.get(workspace_uri);
|
||||||
let enable = specifier_settings
|
let enable = specifier_settings
|
||||||
.and_then(|s| s.enable)
|
.and_then(|s| s.enable)
|
||||||
.or(self.settings.workspace.enable)
|
.or(self.settings.workspace.enable)
|
||||||
.unwrap_or(self.has_config_file());
|
.unwrap_or(self.has_config_file());
|
||||||
|
let disable_paths = specifier_settings
|
||||||
|
.map(|s| &s.disable_paths)
|
||||||
|
.unwrap_or(&self.settings.workspace.disable_paths);
|
||||||
|
let resolved_disable_paths = disable_paths
|
||||||
|
.iter()
|
||||||
|
.map(|p| workspace_path.join(p))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let enable_paths = specifier_settings
|
let enable_paths = specifier_settings
|
||||||
.and_then(|s| s.enable_paths.as_ref())
|
.and_then(|s| s.enable_paths.as_ref())
|
||||||
.or(self.settings.workspace.enable_paths.as_ref());
|
.or(self.settings.workspace.enable_paths.as_ref());
|
||||||
if let Some(enable_paths) = enable_paths {
|
if let Some(enable_paths) = enable_paths {
|
||||||
let Ok(scope_path) = specifier_to_file_path(workspace_uri) else {
|
|
||||||
lsp_log!("Unable to convert uri \"{}\" to path.", workspace_uri);
|
|
||||||
return vec![];
|
|
||||||
};
|
|
||||||
for path in enable_paths {
|
for path in enable_paths {
|
||||||
let path = scope_path.join(path);
|
let path = workspace_path.join(path);
|
||||||
let Ok(path_uri) = specifier_from_file_path(&path) else {
|
let Ok(path_uri) = specifier_from_file_path(&path) else {
|
||||||
lsp_log!("Unable to convert path \"{}\" to uri.", path.display());
|
lsp_log!("Unable to convert path \"{}\" to uri.", path.display());
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
urls.push(path_uri);
|
if !resolved_disable_paths.iter().any(|p| path.starts_with(p)) {
|
||||||
|
urls.push(path_uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if enable {
|
} else if enable
|
||||||
|
&& !resolved_disable_paths
|
||||||
|
.iter()
|
||||||
|
.any(|p| workspace_path.starts_with(p))
|
||||||
|
{
|
||||||
urls.push(workspace_uri.clone());
|
urls.push(workspace_uri.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort for determinism
|
// sort for determinism
|
||||||
urls.sort();
|
urls.sort();
|
||||||
|
urls.dedup();
|
||||||
|
urls
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disabled_urls(&self) -> Vec<Url> {
|
||||||
|
let root_enable = self
|
||||||
|
.settings
|
||||||
|
.workspace
|
||||||
|
.enable
|
||||||
|
.unwrap_or(self.has_config_file());
|
||||||
|
let mut urls = vec![];
|
||||||
|
if let Some(cf) = self.maybe_config_file() {
|
||||||
|
if let Some(files) = cf.to_files_config().ok().flatten() {
|
||||||
|
for path in files.exclude {
|
||||||
|
let Ok(path_uri) = specifier_from_file_path(&path) else {
|
||||||
|
lsp_log!("Unable to convert path \"{}\" to uri.", path.display());
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
urls.push(path_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (workspace_uri, _) in &self.workspace_folders {
|
||||||
|
let Ok(workspace_path) = specifier_to_file_path(workspace_uri) else {
|
||||||
|
lsp_log!("Unable to convert uri \"{}\" to path.", workspace_uri);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let specifier_settings = self.settings.specifiers.get(workspace_uri);
|
||||||
|
let enable = specifier_settings
|
||||||
|
.and_then(|s| s.enable)
|
||||||
|
.unwrap_or(root_enable);
|
||||||
|
if enable {
|
||||||
|
let disable_paths = specifier_settings
|
||||||
|
.map(|s| &s.disable_paths)
|
||||||
|
.unwrap_or(&self.settings.workspace.disable_paths);
|
||||||
|
for path in disable_paths {
|
||||||
|
let path = workspace_path.join(path);
|
||||||
|
let Ok(path_uri) = specifier_from_file_path(&path) else {
|
||||||
|
lsp_log!("Unable to convert path \"{}\" to uri.", path.display());
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
urls.push(path_uri);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
urls.push(workspace_uri.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
urls.sort();
|
||||||
|
urls.dedup();
|
||||||
urls
|
urls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -778,9 +850,9 @@ fn specifier_enabled(
|
||||||
|
|
||||||
let root_enable = settings.workspace.enable.unwrap_or(config_file.is_some());
|
let root_enable = settings.workspace.enable.unwrap_or(config_file.is_some());
|
||||||
if let Some(settings) = settings.specifiers.get(specifier) {
|
if let Some(settings) = settings.specifiers.get(specifier) {
|
||||||
// TODO(nayeemrmn): We don't know from where to resolve `enable_paths` in
|
// TODO(nayeemrmn): We don't know from where to resolve path lists in this
|
||||||
// this case. If it's detected, instead defer to workspace scopes.
|
// case. If they're detected, instead defer to workspace scopes.
|
||||||
if settings.enable_paths.is_none() {
|
if settings.enable_paths.is_none() && settings.disable_paths.is_empty() {
|
||||||
return settings.enable.unwrap_or(root_enable);
|
return settings.enable.unwrap_or(root_enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -795,13 +867,22 @@ fn specifier_enabled(
|
||||||
};
|
};
|
||||||
if path.starts_with(&workspace_path) {
|
if path.starts_with(&workspace_path) {
|
||||||
let specifier_settings = settings.specifiers.get(workspace_uri);
|
let specifier_settings = settings.specifiers.get(workspace_uri);
|
||||||
|
let disable_paths = specifier_settings
|
||||||
|
.map(|s| &s.disable_paths)
|
||||||
|
.unwrap_or(&settings.workspace.disable_paths);
|
||||||
|
let resolved_disable_paths = disable_paths
|
||||||
|
.iter()
|
||||||
|
.map(|p| workspace_path.join(p))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let enable_paths = specifier_settings
|
let enable_paths = specifier_settings
|
||||||
.and_then(|s| s.enable_paths.as_ref())
|
.and_then(|s| s.enable_paths.as_ref())
|
||||||
.or(settings.workspace.enable_paths.as_ref());
|
.or(settings.workspace.enable_paths.as_ref());
|
||||||
if let Some(enable_paths) = enable_paths {
|
if let Some(enable_paths) = enable_paths {
|
||||||
for enable_path in enable_paths {
|
for enable_path in enable_paths {
|
||||||
let enable_path = workspace_path.join(enable_path);
|
let enable_path = workspace_path.join(enable_path);
|
||||||
if path.starts_with(&enable_path) {
|
if path.starts_with(&enable_path)
|
||||||
|
&& !resolved_disable_paths.iter().any(|p| path.starts_with(p))
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -809,7 +890,8 @@ fn specifier_enabled(
|
||||||
} else {
|
} else {
|
||||||
return specifier_settings
|
return specifier_settings
|
||||||
.and_then(|s| s.enable)
|
.and_then(|s| s.enable)
|
||||||
.unwrap_or(root_enable);
|
.unwrap_or(root_enable)
|
||||||
|
&& !resolved_disable_paths.iter().any(|p| path.starts_with(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -919,6 +1001,20 @@ mod tests {
|
||||||
assert!(!config_snapshot.specifier_enabled(&specifier_b));
|
assert!(!config_snapshot.specifier_enabled(&specifier_b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_config_specifier_disabled_path() {
|
||||||
|
let root_uri = resolve_url("file:///root/").unwrap();
|
||||||
|
let mut config = Config::new_with_root(root_uri.clone());
|
||||||
|
config.settings.workspace.enable = Some(true);
|
||||||
|
config.settings.workspace.enable_paths =
|
||||||
|
Some(vec!["mod1.ts".to_string(), "mod2.ts".to_string()]);
|
||||||
|
config.settings.workspace.disable_paths = vec!["mod2.ts".to_string()];
|
||||||
|
|
||||||
|
assert!(config.specifier_enabled(&root_uri.join("mod1.ts").unwrap()));
|
||||||
|
assert!(!config.specifier_enabled(&root_uri.join("mod2.ts").unwrap()));
|
||||||
|
assert!(!config.specifier_enabled(&root_uri.join("mod3.ts").unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_set_workspace_settings_defaults() {
|
fn test_set_workspace_settings_defaults() {
|
||||||
let mut config = Config::new();
|
let mut config = Config::new();
|
||||||
|
@ -929,6 +1025,7 @@ mod tests {
|
||||||
config.workspace_settings().clone(),
|
config.workspace_settings().clone(),
|
||||||
WorkspaceSettings {
|
WorkspaceSettings {
|
||||||
enable: None,
|
enable: None,
|
||||||
|
disable_paths: vec![],
|
||||||
enable_paths: None,
|
enable_paths: None,
|
||||||
cache: None,
|
cache: None,
|
||||||
certificate_stores: None,
|
certificate_stores: None,
|
||||||
|
@ -1135,13 +1232,18 @@ mod tests {
|
||||||
let mut config = Config::new_with_root(root_uri.clone());
|
let mut config = Config::new_with_root(root_uri.clone());
|
||||||
config.settings.workspace.enable = Some(true);
|
config.settings.workspace.enable = Some(true);
|
||||||
|
|
||||||
config.settings.workspace.enable_paths = Some(vec!["mod1.ts".to_string()]);
|
config.settings.workspace.enable_paths =
|
||||||
|
Some(vec!["mod1.ts".to_string(), "mod2.ts".to_string()]);
|
||||||
|
config.settings.workspace.disable_paths = vec!["mod2.ts".to_string()];
|
||||||
assert!(
|
assert!(
|
||||||
config.specifier_enabled_for_test(&root_uri.join("mod1.ts").unwrap())
|
config.specifier_enabled_for_test(&root_uri.join("mod1.ts").unwrap())
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!config.specifier_enabled_for_test(&root_uri.join("mod2.ts").unwrap())
|
!config.specifier_enabled_for_test(&root_uri.join("mod2.ts").unwrap())
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
!config.specifier_enabled_for_test(&root_uri.join("mod3.ts").unwrap())
|
||||||
|
);
|
||||||
config.settings.workspace.enable_paths = None;
|
config.settings.workspace.enable_paths = None;
|
||||||
|
|
||||||
config.set_config_file(
|
config.set_config_file(
|
||||||
|
|
|
@ -1477,6 +1477,7 @@ let c: number = "a";
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
SpecifierSettings {
|
SpecifierSettings {
|
||||||
enable: Some(false),
|
enable: Some(false),
|
||||||
|
disable_paths: vec![],
|
||||||
enable_paths: None,
|
enable_paths: None,
|
||||||
code_lens: Default::default(),
|
code_lens: Default::default(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -804,6 +804,7 @@ impl FileSystemDocuments {
|
||||||
|
|
||||||
pub struct UpdateDocumentConfigOptions<'a> {
|
pub struct UpdateDocumentConfigOptions<'a> {
|
||||||
pub enabled_urls: Vec<Url>,
|
pub enabled_urls: Vec<Url>,
|
||||||
|
pub disabled_urls: Vec<Url>,
|
||||||
pub document_preload_limit: usize,
|
pub document_preload_limit: usize,
|
||||||
pub maybe_import_map: Option<Arc<import_map::ImportMap>>,
|
pub maybe_import_map: Option<Arc<import_map::ImportMap>>,
|
||||||
pub maybe_config_file: Option<&'a ConfigFile>,
|
pub maybe_config_file: Option<&'a ConfigFile>,
|
||||||
|
@ -1283,14 +1284,10 @@ impl Documents {
|
||||||
.filter_map(|url| specifier_to_file_path(url).ok())
|
.filter_map(|url| specifier_to_file_path(url).ok())
|
||||||
.collect(),
|
.collect(),
|
||||||
options
|
options
|
||||||
.maybe_config_file
|
.disabled_urls
|
||||||
.and_then(|cf| {
|
.iter()
|
||||||
cf.to_files_config()
|
.filter_map(|url| specifier_to_file_path(url).ok())
|
||||||
.ok()
|
.collect(),
|
||||||
.flatten()
|
|
||||||
.map(|files| files.exclude)
|
|
||||||
})
|
|
||||||
.unwrap_or_default(),
|
|
||||||
options.document_preload_limit,
|
options.document_preload_limit,
|
||||||
);
|
);
|
||||||
self.resolver_config_hash = new_resolver_config_hash;
|
self.resolver_config_hash = new_resolver_config_hash;
|
||||||
|
@ -2032,6 +2029,7 @@ console.log(b, "hello deno");
|
||||||
|
|
||||||
documents.update_config(UpdateDocumentConfigOptions {
|
documents.update_config(UpdateDocumentConfigOptions {
|
||||||
enabled_urls: vec![],
|
enabled_urls: vec![],
|
||||||
|
disabled_urls: vec![],
|
||||||
document_preload_limit: 1_000,
|
document_preload_limit: 1_000,
|
||||||
maybe_import_map: Some(Arc::new(import_map)),
|
maybe_import_map: Some(Arc::new(import_map)),
|
||||||
maybe_config_file: None,
|
maybe_config_file: None,
|
||||||
|
@ -2073,6 +2071,7 @@ console.log(b, "hello deno");
|
||||||
|
|
||||||
documents.update_config(UpdateDocumentConfigOptions {
|
documents.update_config(UpdateDocumentConfigOptions {
|
||||||
enabled_urls: vec![],
|
enabled_urls: vec![],
|
||||||
|
disabled_urls: vec![],
|
||||||
document_preload_limit: 1_000,
|
document_preload_limit: 1_000,
|
||||||
maybe_import_map: Some(Arc::new(import_map)),
|
maybe_import_map: Some(Arc::new(import_map)),
|
||||||
maybe_config_file: None,
|
maybe_config_file: None,
|
||||||
|
|
|
@ -1354,6 +1354,7 @@ impl Inner {
|
||||||
async fn refresh_documents_config(&mut self) {
|
async fn refresh_documents_config(&mut self) {
|
||||||
self.documents.update_config(UpdateDocumentConfigOptions {
|
self.documents.update_config(UpdateDocumentConfigOptions {
|
||||||
enabled_urls: self.config.enabled_urls(),
|
enabled_urls: self.config.enabled_urls(),
|
||||||
|
disabled_urls: self.config.disabled_urls(),
|
||||||
document_preload_limit: self
|
document_preload_limit: self
|
||||||
.config
|
.config
|
||||||
.workspace_settings()
|
.workspace_settings()
|
||||||
|
|
|
@ -285,6 +285,7 @@ fn get_cwd_uri() -> Result<ModuleSpecifier, AnyError> {
|
||||||
pub fn get_repl_workspace_settings() -> WorkspaceSettings {
|
pub fn get_repl_workspace_settings() -> WorkspaceSettings {
|
||||||
WorkspaceSettings {
|
WorkspaceSettings {
|
||||||
enable: Some(true),
|
enable: Some(true),
|
||||||
|
disable_paths: vec![],
|
||||||
enable_paths: None,
|
enable_paths: None,
|
||||||
config: None,
|
config: None,
|
||||||
certificate_stores: None,
|
certificate_stores: None,
|
||||||
|
|
|
@ -1298,13 +1298,14 @@ fn lsp_inlay_hints_not_enabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lsp_workspace_enable_paths() {
|
fn lsp_workspace_disable_enable_paths() {
|
||||||
fn run_test(use_trailing_slash: bool) {
|
fn run_test(use_trailing_slash: bool) {
|
||||||
let context = TestContextBuilder::new().use_temp_cwd().build();
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
let temp_dir = context.temp_dir();
|
let temp_dir = context.temp_dir();
|
||||||
temp_dir.create_dir_all("worker");
|
temp_dir.create_dir_all("worker");
|
||||||
temp_dir.write("worker/shared.ts", "export const a = 1");
|
temp_dir.write("worker/shared.ts", "export const a = 1");
|
||||||
temp_dir.write("worker/other.ts", "import { a } from './shared.ts';\na;");
|
temp_dir.write("worker/other.ts", "import { a } from './shared.ts';\na;");
|
||||||
|
temp_dir.write("worker/node.ts", "Buffer.alloc(1);");
|
||||||
|
|
||||||
let root_specifier = temp_dir.uri();
|
let root_specifier = temp_dir.uri();
|
||||||
|
|
||||||
|
@ -1312,6 +1313,7 @@ fn lsp_workspace_enable_paths() {
|
||||||
client.initialize_with_config(
|
client.initialize_with_config(
|
||||||
|builder| {
|
|builder| {
|
||||||
builder
|
builder
|
||||||
|
.set_disable_paths(vec!["./worker/node.ts".to_string()])
|
||||||
.set_enable_paths(vec!["./worker".to_string()])
|
.set_enable_paths(vec!["./worker".to_string()])
|
||||||
.set_root_uri(root_specifier.clone())
|
.set_root_uri(root_specifier.clone())
|
||||||
.set_workspace_folders(vec![lsp::WorkspaceFolder {
|
.set_workspace_folders(vec![lsp::WorkspaceFolder {
|
||||||
|
@ -1329,6 +1331,7 @@ fn lsp_workspace_enable_paths() {
|
||||||
},
|
},
|
||||||
json!([{
|
json!([{
|
||||||
"enable": false,
|
"enable": false,
|
||||||
|
"disablePaths": ["./worker/node.ts"],
|
||||||
"enablePaths": ["./worker"],
|
"enablePaths": ["./worker"],
|
||||||
}]),
|
}]),
|
||||||
);
|
);
|
||||||
|
@ -1395,6 +1398,17 @@ fn lsp_workspace_enable_paths() {
|
||||||
);
|
);
|
||||||
assert_eq!(res, json!(null));
|
assert_eq!(res, json!(null));
|
||||||
|
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/hover",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": root_specifier.join("./worker/node.ts").unwrap(),
|
||||||
|
},
|
||||||
|
"position": { "line": 0, "character": 0 }
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert_eq!(res, json!(null));
|
||||||
|
|
||||||
let res = client.write_request(
|
let res = client.write_request(
|
||||||
"textDocument/hover",
|
"textDocument/hover",
|
||||||
json!({
|
json!({
|
||||||
|
|
|
@ -388,6 +388,12 @@ impl InitializeParamsBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_disable_paths(&mut self, value: Vec<String>) -> &mut Self {
|
||||||
|
let options = self.initialization_options_mut();
|
||||||
|
options.insert("disablePaths".to_string(), value.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_enable_paths(&mut self, value: Vec<String>) -> &mut Self {
|
pub fn set_enable_paths(&mut self, value: Vec<String>) -> &mut Self {
|
||||||
let options = self.initialization_options_mut();
|
let options = self.initialization_options_mut();
|
||||||
options.insert("enablePaths".to_string(), value.into());
|
options.insert("enablePaths".to_string(), value.into());
|
||||||
|
|
Loading…
Reference in a new issue