Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lsp): include all diagnosable documents on initialize #17979

Merged
merged 37 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6125671
fix(lsp): add all documents to the lsp on initialize
dsherret Feb 28, 2023
f08a5bf
Fix
dsherret Feb 28, 2023
ef6475c
Take into account enabled_paths
dsherret Mar 1, 2023
17b1f0b
Another one.
dsherret Mar 1, 2023
67439dd
More work.
dsherret Mar 4, 2023
abedfff
Merge branch 'main' into fix_lsp_open_docs_root
dsherret Mar 15, 2023
459ce44
Fix inverted logic.
dsherret Mar 15, 2023
72bfa94
Compile
dsherret Mar 15, 2023
cdc4af0
Ignore minified files
dsherret Mar 15, 2023
0129cf9
Merge branch 'main' into fix_lsp_open_docs_root
dsherret Mar 29, 2023
8688718
Handle files in enabled paths
dsherret Mar 29, 2023
8b0ab70
Consolidate code
dsherret Mar 29, 2023
4c9e102
refactor(lsp): remove boolean parameters on `documents.documents(...)`
dsherret Mar 29, 2023
d9c5e91
Remove word "And"
dsherret Mar 29, 2023
fc4d027
Merge branch 'refactor_lsp_documents_bool_param' into fix_lsp_open_do…
dsherret Mar 29, 2023
08ef6af
Working.
dsherret Mar 29, 2023
2dc17b0
Failing test because our textDocument/references implementation is br…
dsherret Mar 29, 2023
bab99d7
fix(lsp): `textDocument/references` should respect `includeDeclaration`
dsherret Mar 29, 2023
b7dee99
Small refactor.
dsherret Mar 29, 2023
a8cb329
Fix codelens test
dsherret Mar 29, 2023
5894f85
Merge branch 'main' into fix_lsp_find_references_respect_include_decl…
dsherret Mar 29, 2023
c5cfb24
Merge branch 'main' into fix_lsp_find_references_respect_include_decl…
dsherret Mar 30, 2023
b7d7541
Add test and improve code
dsherret Mar 30, 2023
41b3004
Merge branch 'main' into fix_lsp_find_references_respect_include_decl…
dsherret Mar 30, 2023
8dec2d3
Oops... Fix test
dsherret Mar 30, 2023
5a55a7e
Reduce flakiness of package_json_uncached_no_error
dsherret Mar 30, 2023
74fb03f
Merge branch 'main' into fix_lsp_open_docs_root
dsherret Mar 30, 2023
818811e
Merge branch 'fix_lsp_find_references_respect_include_declaration' in…
dsherret Mar 30, 2023
7b96f00
Add enabled_root_urls tests
dsherret Mar 30, 2023
bc3c42e
Merge branch 'main' into fix_lsp_open_docs_root
dsherret Mar 30, 2023
697ace6
Refactor document finder to be more easily unit testable
dsherret Mar 30, 2023
2216402
Another test.
dsherret Mar 30, 2023
8fe2597
Merge branch 'main' into fix_lsp_open_docs_root
dsherret Mar 30, 2023
4d8a9b0
Fix tests
dsherret Mar 30, 2023
b416267
Merge branch 'main' into fix_lsp_open_docs_root
dsherret Mar 30, 2023
055f94d
Fix two failing tests.
dsherret Mar 30, 2023
6cc5a97
Update lsp tests to use a temp cwd
dsherret Mar 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 95 additions & 51 deletions cli/lsp/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

use super::client::Client;
use super::logging::lsp_log;
use crate::util::path::ensure_directory_specifier;
use crate::util::path::specifier_to_file_path;
Expand All @@ -10,6 +9,7 @@ use deno_core::serde::Serialize;
use deno_core::serde_json;
use deno_core::serde_json::Value;
use deno_core::ModuleSpecifier;
use lsp::Url;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::sync::Arc;
Expand Down Expand Up @@ -226,7 +226,7 @@ impl Default for ImportCompletionSettings {

/// Deno language server specific settings that can be applied uniquely to a
/// specifier.
#[derive(Debug, Default, Clone, Deserialize)]
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct SpecifierSettings {
/// A flag that indicates if Deno is enabled for this specifier or not.
Expand Down Expand Up @@ -388,50 +388,41 @@ impl WorkspaceSettings {
#[derive(Debug, Clone, Default)]
pub struct ConfigSnapshot {
pub client_capabilities: ClientCapabilities,
pub enabled_paths: HashMap<String, Vec<String>>,
pub enabled_paths: HashMap<Url, Vec<Url>>,
pub settings: Settings,
}

impl ConfigSnapshot {
/// Determine if the provided specifier is enabled or not.
pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool {
if !self.enabled_paths.is_empty() {
let specifier_str = specifier.to_string();
let specifier_str = specifier.as_str();
for (workspace, enabled_paths) in self.enabled_paths.iter() {
if specifier_str.starts_with(workspace) {
if specifier_str.starts_with(workspace.as_str()) {
return enabled_paths
.iter()
.any(|path| specifier_str.starts_with(path));
.any(|path| specifier_str.starts_with(path.as_str()));
}
}
}
if let Some((_, SpecifierSettings { enable, .. })) =
self.settings.specifiers.get(specifier)
{
*enable
if let Some(settings) = self.settings.specifiers.get(specifier) {
settings.enable
} else {
self.settings.workspace.enable
}
}
}

#[derive(Debug, Clone)]
pub struct SpecifierWithClientUri {
pub specifier: ModuleSpecifier,
pub client_uri: ModuleSpecifier,
}

#[derive(Debug, Default, Clone)]
pub struct Settings {
pub specifiers:
BTreeMap<ModuleSpecifier, (ModuleSpecifier, SpecifierSettings)>,
pub specifiers: BTreeMap<ModuleSpecifier, SpecifierSettings>,
pub workspace: WorkspaceSettings,
}

#[derive(Debug)]
pub struct Config {
pub client_capabilities: ClientCapabilities,
enabled_paths: HashMap<String, Vec<String>>,
enabled_paths: HashMap<Url, Vec<Url>>,
pub root_uri: Option<ModuleSpecifier>,
settings: Settings,
pub workspace_folders: Option<Vec<(ModuleSpecifier, lsp::WorkspaceFolder)>>,
Expand Down Expand Up @@ -478,29 +469,47 @@ impl Config {

pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool {
if !self.enabled_paths.is_empty() {
let specifier_str = specifier.to_string();
let specifier_str = specifier.as_str();
for (workspace, enabled_paths) in self.enabled_paths.iter() {
if specifier_str.starts_with(workspace) {
if specifier_str.starts_with(workspace.as_str()) {
return enabled_paths
.iter()
.any(|path| specifier_str.starts_with(path));
.any(|path| specifier_str.starts_with(path.as_str()));
}
}
}
self
.settings
.specifiers
.get(specifier)
.map(|(_, s)| s.enable)
.map(|settings| settings.enable)
.unwrap_or_else(|| self.settings.workspace.enable)
}

pub fn root_dirs(&self) -> Vec<Url> {
let mut dirs: Vec<Url> = Vec::new();
for (workspace, enabled_paths) in &self.enabled_paths {
if enabled_paths.is_empty() {
dsherret marked this conversation as resolved.
Show resolved Hide resolved
dirs.extend(enabled_paths.iter().cloned());
dsherret marked this conversation as resolved.
Show resolved Hide resolved
} else {
dirs.push(workspace.clone());
}
}
if dirs.is_empty() {
if let Some(root_dir) = &self.root_uri {
dirs.push(root_dir.clone())
}
}
sort_and_remove_child_dirs(&mut dirs);
dirs
}

pub fn specifier_code_lens_test(&self, specifier: &ModuleSpecifier) -> bool {
let value = self
.settings
.specifiers
.get(specifier)
.map(|(_, s)| s.code_lens.test)
.map(|settings| settings.code_lens.test)
.unwrap_or_else(|| self.settings.workspace.code_lens.test);
value
}
Expand Down Expand Up @@ -554,13 +563,15 @@ 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 {
pub fn update_enabled_paths(&mut self) -> 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) {
for (workspace, _) in workspace_folders {
if let Some(settings) = self.settings.specifiers.get(&workspace) {
if self.update_enabled_paths_entry(
workspace,
settings.enable_paths.clone(),
) {
touched = true;
}
}
Expand All @@ -583,7 +594,6 @@ impl Config {
enabled_paths: Vec<String>,
) -> bool {
let workspace = ensure_directory_specifier(workspace);
let key = workspace.to_string();
let mut touched = false;
if !enabled_paths.is_empty() {
if let Ok(workspace_path) = specifier_to_file_path(&workspace) {
Expand All @@ -592,7 +602,7 @@ impl Config {
let fs_path = workspace_path.join(path);
match ModuleSpecifier::from_file_path(fs_path) {
Ok(path_uri) => {
paths.push(path_uri.to_string());
paths.push(path_uri);
}
Err(_) => {
lsp_log!("Unable to resolve a file path for `deno.enablePath` from \"{}\" for workspace \"{}\".", path, workspace);
Expand All @@ -601,38 +611,47 @@ impl Config {
}
if !paths.is_empty() {
touched = true;
self.enabled_paths.insert(key, paths);
self.enabled_paths.insert(workspace.clone(), paths);
}
}
} else {
touched = true;
self.enabled_paths.remove(&key);
self.enabled_paths.remove(&workspace);
}
touched
}

pub fn get_specifiers_with_client_uris(&self) -> Vec<SpecifierWithClientUri> {
self
.settings
.specifiers
.iter()
.map(|(s, (u, _))| SpecifierWithClientUri {
specifier: s.clone(),
client_uri: u.clone(),
})
.collect()
pub fn get_specifiers(&self) -> Vec<ModuleSpecifier> {
self.settings.specifiers.keys().cloned().collect()
}

pub fn set_specifier_settings(
&mut self,
specifier: ModuleSpecifier,
client_uri: ModuleSpecifier,
settings: SpecifierSettings,
) {
self
.settings
.specifiers
.insert(specifier, (client_uri, settings));
) -> bool {
if let Some(existing) = self.settings.specifiers.get(&specifier) {
if *existing == settings {
return false;
}
}

self.settings.specifiers.insert(specifier, settings);
true
}
}

fn sort_and_remove_child_dirs(dirs: &mut Vec<Url>) {
if dirs.is_empty() {
return;
}

dirs.sort();
for i in (0..dirs.len() - 1).rev() {
let prev = &dirs[i + 1];
if prev.as_str().starts_with(dirs[i].as_str()) {
dirs.remove(i + 1);
}
}
}

Expand Down Expand Up @@ -678,8 +697,8 @@ mod tests {
assert!(!config.specifier_enabled(&specifier_b));
let mut enabled_paths = HashMap::new();
enabled_paths.insert(
"file:https:///project/".to_string(),
vec!["file:https:///project/worker/".to_string()],
Url::parse("file:https:///project/").unwrap(),
vec![Url::parse("file:https:///project/worker/").unwrap()],
);
config.enabled_paths = enabled_paths;
assert!(config.specifier_enabled(&specifier_a));
Expand Down Expand Up @@ -800,4 +819,29 @@ mod tests {
WorkspaceSettings::default()
);
}

#[test]
fn test_sort_and_remove_child_dirs() {
fn run_test(dirs: Vec<&str>, expected_output: Vec<&str>) {
let mut dirs = dirs
.into_iter()
.map(|dir| Url::parse(dir).unwrap())
.collect();
sort_and_remove_child_dirs(&mut dirs);
let dirs: Vec<_> = dirs.iter().map(|dir| dir.as_str()).collect();
assert_eq!(dirs, expected_output);
}

run_test(
vec![
"file:https:///test/asdf/test/asdf/",
"file:https:///test/asdf/",
"file:https:///test/asdf/",
"file:https:///testing/456/893/",
"file:https:///testing/456/893/test/",
],
vec!["file:https:///test/asdf/", "file:https:///testing/456/893/"],
);
run_test(vec![], vec![]);
}
}
13 changes: 5 additions & 8 deletions cli/lsp/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1179,14 +1179,11 @@ let c: number = "a";
let mut disabled_config = mock_config();
disabled_config.settings.specifiers.insert(
specifier.clone(),
(
specifier.clone(),
SpecifierSettings {
enable: false,
enable_paths: Vec::new(),
code_lens: Default::default(),
},
),
SpecifierSettings {
enable: false,
enable_paths: Vec::new(),
code_lens: Default::default(),
},
);

let diagnostics = generate_lint_diagnostics(
Expand Down
Loading