mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 20:29:11 +00:00
perf(repl): don't walk workspace in repl language server (#24037)
This commit is contained in:
parent
3c3076a84c
commit
3d3722507e
5 changed files with 90 additions and 81 deletions
|
@ -31,6 +31,7 @@ use deno_runtime::fs_util::specifier_to_file_path;
|
||||||
use deno_runtime::permissions::PermissionsContainer;
|
use deno_runtime::permissions::PermissionsContainer;
|
||||||
use import_map::ImportMap;
|
use import_map::ImportMap;
|
||||||
use lsp::Url;
|
use lsp::Url;
|
||||||
|
use lsp_types::ClientCapabilities;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -40,21 +41,6 @@ use tower_lsp::lsp_types as lsp;
|
||||||
|
|
||||||
pub const SETTINGS_SECTION: &str = "deno";
|
pub const SETTINGS_SECTION: &str = "deno";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct ClientCapabilities {
|
|
||||||
pub code_action_disabled_support: bool,
|
|
||||||
pub line_folding_only: bool,
|
|
||||||
pub snippet_support: bool,
|
|
||||||
pub status_notification: bool,
|
|
||||||
/// The client provides the `experimental.testingApi` capability, which is
|
|
||||||
/// built around VSCode's testing API. It indicates that the server should
|
|
||||||
/// send notifications about tests discovered in modules.
|
|
||||||
pub testing_api: bool,
|
|
||||||
pub workspace_configuration: bool,
|
|
||||||
pub workspace_did_change_watched_files: bool,
|
|
||||||
pub workspace_will_rename_files: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_true() -> bool {
|
fn is_true() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -975,57 +961,73 @@ impl Config {
|
||||||
&self.settings.unscoped.internal_inspect
|
&self.settings.unscoped.internal_inspect
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_capabilities(
|
pub fn set_client_capabilities(
|
||||||
&mut self,
|
&mut self,
|
||||||
capabilities: &lsp::ClientCapabilities,
|
client_capabilities: ClientCapabilities,
|
||||||
) {
|
) {
|
||||||
if let Some(experimental) = &capabilities.experimental {
|
self.client_capabilities = client_capabilities;
|
||||||
self.client_capabilities.status_notification = experimental
|
}
|
||||||
.get("statusNotification")
|
|
||||||
.and_then(|it| it.as_bool())
|
|
||||||
== Some(true);
|
|
||||||
self.client_capabilities.testing_api =
|
|
||||||
experimental.get("testingApi").and_then(|it| it.as_bool())
|
|
||||||
== Some(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(workspace) = &capabilities.workspace {
|
pub fn workspace_capable(&self) -> bool {
|
||||||
self.client_capabilities.workspace_configuration =
|
self.client_capabilities.workspace.is_some()
|
||||||
workspace.configuration.unwrap_or(false);
|
}
|
||||||
self.client_capabilities.workspace_did_change_watched_files = workspace
|
|
||||||
.did_change_watched_files
|
|
||||||
.and_then(|it| it.dynamic_registration)
|
|
||||||
.unwrap_or(false);
|
|
||||||
if let Some(file_operations) = &workspace.file_operations {
|
|
||||||
if let Some(true) = file_operations.dynamic_registration {
|
|
||||||
self.client_capabilities.workspace_will_rename_files =
|
|
||||||
file_operations.will_rename.unwrap_or(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(text_document) = &capabilities.text_document {
|
pub fn workspace_configuration_capable(&self) -> bool {
|
||||||
self.client_capabilities.line_folding_only = text_document
|
(|| self.client_capabilities.workspace.as_ref()?.configuration)()
|
||||||
.folding_range
|
.unwrap_or(false)
|
||||||
.as_ref()
|
}
|
||||||
.and_then(|it| it.line_folding_only)
|
|
||||||
.unwrap_or(false);
|
pub fn did_change_watched_files_capable(&self) -> bool {
|
||||||
self.client_capabilities.code_action_disabled_support = text_document
|
(|| {
|
||||||
.code_action
|
let workspace = self.client_capabilities.workspace.as_ref()?;
|
||||||
.as_ref()
|
let did_change_watched_files =
|
||||||
.and_then(|it| it.disabled_support)
|
workspace.did_change_watched_files.as_ref()?;
|
||||||
.unwrap_or(false);
|
did_change_watched_files.dynamic_registration
|
||||||
self.client_capabilities.snippet_support =
|
})()
|
||||||
if let Some(completion) = &text_document.completion {
|
.unwrap_or(false)
|
||||||
completion
|
}
|
||||||
.completion_item
|
|
||||||
.as_ref()
|
pub fn will_rename_files_capable(&self) -> bool {
|
||||||
.and_then(|it| it.snippet_support)
|
(|| {
|
||||||
.unwrap_or(false)
|
let workspace = self.client_capabilities.workspace.as_ref()?;
|
||||||
} else {
|
let file_operations = workspace.file_operations.as_ref()?;
|
||||||
false
|
file_operations.dynamic_registration.filter(|d| *d)?;
|
||||||
};
|
file_operations.will_rename
|
||||||
}
|
})()
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn line_folding_only_capable(&self) -> bool {
|
||||||
|
(|| {
|
||||||
|
let text_document = self.client_capabilities.text_document.as_ref()?;
|
||||||
|
text_document.folding_range.as_ref()?.line_folding_only
|
||||||
|
})()
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn code_action_disabled_capable(&self) -> bool {
|
||||||
|
(|| {
|
||||||
|
let text_document = self.client_capabilities.text_document.as_ref()?;
|
||||||
|
text_document.code_action.as_ref()?.disabled_support
|
||||||
|
})()
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn snippet_support_capable(&self) -> bool {
|
||||||
|
(|| {
|
||||||
|
let text_document = self.client_capabilities.text_document.as_ref()?;
|
||||||
|
let completion = text_document.completion.as_ref()?;
|
||||||
|
completion.completion_item.as_ref()?.snippet_support
|
||||||
|
})()
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn testing_api_capable(&self) -> bool {
|
||||||
|
(|| {
|
||||||
|
let experimental = self.client_capabilities.experimental.as_ref()?;
|
||||||
|
experimental.get("testingApi")?.as_bool()
|
||||||
|
})()
|
||||||
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ fn get_maybe_test_module_fut(
|
||||||
maybe_parsed_source: Option<&ParsedSourceResult>,
|
maybe_parsed_source: Option<&ParsedSourceResult>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> Option<TestModuleFut> {
|
) -> Option<TestModuleFut> {
|
||||||
if !config.client_capabilities.testing_api {
|
if !config.testing_api_capable() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let parsed_source = maybe_parsed_source?.as_ref().ok()?.clone();
|
let parsed_source = maybe_parsed_source?.as_ref().ok()?.clone();
|
||||||
|
|
|
@ -439,7 +439,7 @@ impl LanguageServer {
|
||||||
(
|
(
|
||||||
inner.client.clone(),
|
inner.client.clone(),
|
||||||
inner.config.workspace_folders.clone(),
|
inner.config.workspace_folders.clone(),
|
||||||
inner.config.client_capabilities.workspace_configuration,
|
inner.config.workspace_configuration_capable(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if capable {
|
if capable {
|
||||||
|
@ -769,7 +769,7 @@ impl Inner {
|
||||||
vec![],
|
vec![],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.config.update_capabilities(¶ms.capabilities);
|
self.config.set_client_capabilities(params.capabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.diagnostics_server.start();
|
self.diagnostics_server.start();
|
||||||
|
@ -802,6 +802,10 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_workspace(config: &Config) -> (BTreeSet<ModuleSpecifier>, bool) {
|
fn walk_workspace(config: &Config) -> (BTreeSet<ModuleSpecifier>, bool) {
|
||||||
|
if !config.workspace_capable() {
|
||||||
|
log::debug!("Skipped workspace walk due to client incapability.");
|
||||||
|
return (Default::default(), false);
|
||||||
|
}
|
||||||
let mut workspace_files = Default::default();
|
let mut workspace_files = Default::default();
|
||||||
let entry_limit = 1000;
|
let entry_limit = 1000;
|
||||||
let mut pending = VecDeque::new();
|
let mut pending = VecDeque::new();
|
||||||
|
@ -1664,10 +1668,10 @@ impl Inner {
|
||||||
.map(CodeActionOrCommand::CodeAction),
|
.map(CodeActionOrCommand::CodeAction),
|
||||||
);
|
);
|
||||||
|
|
||||||
let code_action_disabled_support =
|
let code_action_disabled_capable =
|
||||||
self.config.client_capabilities.code_action_disabled_support;
|
self.config.code_action_disabled_capable();
|
||||||
let actions: Vec<CodeActionOrCommand> = all_actions.into_iter().filter(|ca| {
|
let actions: Vec<CodeActionOrCommand> = all_actions.into_iter().filter(|ca| {
|
||||||
code_action_disabled_support
|
code_action_disabled_capable
|
||||||
|| matches!(ca, CodeActionOrCommand::CodeAction(ca) if ca.disabled.is_none())
|
|| matches!(ca, CodeActionOrCommand::CodeAction(ca) if ca.disabled.is_none())
|
||||||
}).collect();
|
}).collect();
|
||||||
let response = if actions.is_empty() {
|
let response = if actions.is_empty() {
|
||||||
|
@ -2318,7 +2322,7 @@ impl Inner {
|
||||||
span.to_folding_range(
|
span.to_folding_range(
|
||||||
asset_or_doc.line_index(),
|
asset_or_doc.line_index(),
|
||||||
asset_or_doc.text().as_bytes(),
|
asset_or_doc.text().as_bytes(),
|
||||||
self.config.client_capabilities.line_folding_only,
|
self.config.line_folding_only_capable(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<FoldingRange>>(),
|
.collect::<Vec<FoldingRange>>(),
|
||||||
|
@ -2887,11 +2891,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
|
||||||
inner.refresh_documents_config().await;
|
inner.refresh_documents_config().await;
|
||||||
inner.task_queue.start(self.clone());
|
inner.task_queue.start(self.clone());
|
||||||
self.init_flag.raise();
|
self.init_flag.raise();
|
||||||
if inner
|
if inner.config.did_change_watched_files_capable() {
|
||||||
.config
|
|
||||||
.client_capabilities
|
|
||||||
.workspace_did_change_watched_files
|
|
||||||
{
|
|
||||||
// we are going to watch all the JSON files in the workspace, and the
|
// we are going to watch all the JSON files in the workspace, and the
|
||||||
// notification handler will pick up any of the changes of those files we
|
// notification handler will pick up any of the changes of those files we
|
||||||
// are interested in.
|
// are interested in.
|
||||||
|
@ -2909,7 +2909,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
|
||||||
register_options: Some(serde_json::to_value(options).unwrap()),
|
register_options: Some(serde_json::to_value(options).unwrap()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if inner.config.client_capabilities.workspace_will_rename_files {
|
if inner.config.will_rename_files_capable() {
|
||||||
let options = FileOperationRegistrationOptions {
|
let options = FileOperationRegistrationOptions {
|
||||||
filters: vec![FileOperationFilter {
|
filters: vec![FileOperationFilter {
|
||||||
scheme: Some("file".to_string()),
|
scheme: Some("file".to_string()),
|
||||||
|
@ -2927,7 +2927,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if inner.config.client_capabilities.testing_api {
|
if inner.config.testing_api_capable() {
|
||||||
let test_server = testing::TestServer::new(
|
let test_server = testing::TestServer::new(
|
||||||
inner.client.clone(),
|
inner.client.clone(),
|
||||||
inner.performance.clone(),
|
inner.performance.clone(),
|
||||||
|
@ -3051,7 +3051,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
|
||||||
};
|
};
|
||||||
self.refresh_configuration().await;
|
self.refresh_configuration().await;
|
||||||
let mut inner = self.inner.write().await;
|
let mut inner = self.inner.write().await;
|
||||||
if !inner.config.client_capabilities.workspace_configuration {
|
if !inner.config.workspace_configuration_capable() {
|
||||||
let config = params.settings.as_object().map(|settings| {
|
let config = params.settings.as_object().map(|settings| {
|
||||||
let deno =
|
let deno =
|
||||||
serde_json::to_value(settings.get(SETTINGS_SECTION)).unwrap();
|
serde_json::to_value(settings.get(SETTINGS_SECTION)).unwrap();
|
||||||
|
@ -3726,6 +3726,10 @@ mod tests {
|
||||||
temp_dir.uri().join("root2/").unwrap(),
|
temp_dir.uri().join("root2/").unwrap(),
|
||||||
temp_dir.uri().join("root3/").unwrap(),
|
temp_dir.uri().join("root3/").unwrap(),
|
||||||
]);
|
]);
|
||||||
|
config.set_client_capabilities(ClientCapabilities {
|
||||||
|
workspace: Some(Default::default()),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
config.set_workspace_settings(
|
config.set_workspace_settings(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
vec![
|
vec![
|
||||||
|
|
|
@ -4679,7 +4679,7 @@ impl UserPreferences {
|
||||||
// TODO(nayeemrmn): Investigate why we use `Index` here.
|
// TODO(nayeemrmn): Investigate why we use `Index` here.
|
||||||
import_module_specifier_ending: Some(ImportModuleSpecifierEnding::Index),
|
import_module_specifier_ending: Some(ImportModuleSpecifierEnding::Index),
|
||||||
include_completions_with_snippet_text: Some(
|
include_completions_with_snippet_text: Some(
|
||||||
config.client_capabilities.snippet_support,
|
config.snippet_support_capable(),
|
||||||
),
|
),
|
||||||
provide_refactor_not_applicable_reason: Some(true),
|
provide_refactor_not_applicable_reason: Some(true),
|
||||||
quote_preference: Some(fmt_config.into()),
|
quote_preference: Some(fmt_config.into()),
|
||||||
|
@ -4717,7 +4717,7 @@ impl UserPreferences {
|
||||||
include_completions_with_class_member_snippets: Some(
|
include_completions_with_class_member_snippets: Some(
|
||||||
language_settings.suggest.enabled
|
language_settings.suggest.enabled
|
||||||
&& language_settings.suggest.class_member_snippets.enabled
|
&& language_settings.suggest.class_member_snippets.enabled
|
||||||
&& config.client_capabilities.snippet_support,
|
&& config.snippet_support_capable(),
|
||||||
),
|
),
|
||||||
include_completions_with_insert_text: Some(
|
include_completions_with_insert_text: Some(
|
||||||
language_settings.suggest.enabled,
|
language_settings.suggest.enabled,
|
||||||
|
@ -4728,7 +4728,7 @@ impl UserPreferences {
|
||||||
.suggest
|
.suggest
|
||||||
.object_literal_method_snippets
|
.object_literal_method_snippets
|
||||||
.enabled
|
.enabled
|
||||||
&& config.client_capabilities.snippet_support,
|
&& config.snippet_support_capable(),
|
||||||
),
|
),
|
||||||
import_module_specifier_preference: Some(
|
import_module_specifier_preference: Some(
|
||||||
language_settings.preferences.import_module_specifier,
|
language_settings.preferences.import_module_specifier,
|
||||||
|
|
|
@ -1084,7 +1084,10 @@ fn closed_file_pre_load_does_not_occur() {
|
||||||
.new_command()
|
.new_command()
|
||||||
.args_vec(["repl", "-A", "--log-level=debug"])
|
.args_vec(["repl", "-A", "--log-level=debug"])
|
||||||
.with_pty(|console| {
|
.with_pty(|console| {
|
||||||
assert_contains!(console.all_output(), "Skipped document preload.",);
|
assert_contains!(
|
||||||
|
console.all_output(),
|
||||||
|
"Skipped workspace walk due to client incapability.",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue