summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/bench/fixtures/initialize_params.json4
-rw-r--r--cli/bench/lsp.rs48
-rw-r--r--cli/lsp/README.md53
-rw-r--r--cli/lsp/capabilities.rs10
-rw-r--r--cli/lsp/config.rs109
-rw-r--r--cli/lsp/diagnostics.rs115
-rw-r--r--cli/lsp/language_server.rs296
-rw-r--r--cli/lsp/urls.rs2
8 files changed, 443 insertions, 194 deletions
diff --git a/cli/bench/fixtures/initialize_params.json b/cli/bench/fixtures/initialize_params.json
index c4eb19c70..d8a396b90 100644
--- a/cli/bench/fixtures/initialize_params.json
+++ b/cli/bench/fixtures/initialize_params.json
@@ -39,6 +39,10 @@
"willSaveWaitUntil": true,
"didSave": true
}
+ },
+ "workspace": {
+ "configuration": true,
+ "workspaceFolders": true
}
}
}
diff --git a/cli/bench/lsp.rs b/cli/bench/lsp.rs
index aea238441..173c52774 100644
--- a/cli/bench/lsp.rs
+++ b/cli/bench/lsp.rs
@@ -184,6 +184,22 @@ impl LspClient {
}
}
+ fn read_request<R>(&mut self) -> Result<(u64, String, Option<R>), AnyError>
+ where
+ R: de::DeserializeOwned,
+ {
+ loop {
+ if let LspMessage::Request(id, method, maybe_params) = self.read()? {
+ if let Some(p) = maybe_params {
+ let params = serde_json::from_value(p)?;
+ return Ok((id, method, Some(params)));
+ } else {
+ return Ok((id, method, None));
+ }
+ }
+ }
+ }
+
fn write(&mut self, value: Value) -> Result<(), AnyError> {
let value_str = value.to_string();
let msg = format!(
@@ -222,6 +238,18 @@ impl LspClient {
}
}
+ fn write_response<V>(&mut self, id: u64, result: V) -> Result<(), AnyError>
+ where
+ V: Serialize,
+ {
+ let value = json!({
+ "jsonrpc": "2.0",
+ "id": id,
+ "result": result
+ });
+ self.write(value)
+ }
+
fn write_notification<S, V>(
&mut self,
method: S,
@@ -266,6 +294,16 @@ fn bench_big_file_edits(deno_exe: &Path) -> Result<Duration, AnyError> {
}),
)?;
+ let (id, method, _): (u64, String, Option<Value>) = client.read_request()?;
+ assert_eq!(method, "workspace/configuration");
+
+ client.write_response(
+ id,
+ json!({
+ "enable": true
+ }),
+ )?;
+
let (method, _): (String, Option<Value>) = client.read_notification()?;
assert_eq!(method, "textDocument/publishDiagnostics");
let (method, _): (String, Option<Value>) = client.read_notification()?;
@@ -328,6 +366,16 @@ fn bench_startup_shutdown(deno_exe: &Path) -> Result<Duration, AnyError> {
}),
)?;
+ let (id, method, _): (u64, String, Option<Value>) = client.read_request()?;
+ assert_eq!(method, "workspace/configuration");
+
+ client.write_response(
+ id,
+ json!({
+ "enable": true
+ }),
+ )?;
+
let (method, _): (String, Option<Value>) = client.read_notification()?;
assert_eq!(method, "textDocument/publishDiagnostics");
let (method, _): (String, Option<Value>) = client.read_notification()?;
diff --git a/cli/lsp/README.md b/cli/lsp/README.md
index 11464efd2..d480e3133 100644
--- a/cli/lsp/README.md
+++ b/cli/lsp/README.md
@@ -61,3 +61,56 @@ with Deno:
textDocument: TextDocumentIdentifier;
}
```
+
+## Settings
+
+There are several settings that the language server supports for a workspace:
+
+- `deno.enable`
+- `deno.config`
+- `deno.import_map`
+- `deno.code_lens.implementations`
+- `deno.code_lens.references`
+- `deno.code_lens.references_all_functions`
+- `deno.suggest.complete_function_calls`
+- `deno.suggest.names`
+- `deno.suggest.paths`
+- `deno.suggest.auto_imports`
+- `deno.imports.hosts`
+- `deno.lint`
+- `deno.unstable`
+
+There are settings that are support on a per resource basis by the language
+server:
+
+- `deno.enable`
+
+There are several points in the process where Deno analyzes these settings.
+First, when the `initialize` request from the client, the
+`initializationOptions` will be assumed to be an object that represents the
+`deno` namespace of options. For example, the following value:
+
+```json
+{
+ "enable": true,
+ "unstable": true
+}
+```
+
+Would enable Deno with the unstable APIs for this instance of the language
+server.
+
+When the language server receives a `workspace/didChangeConfiguration`
+notification, it will assess if the client has indicated if it has a
+`workspaceConfiguration` capability. If it does, it will send a
+`workspace/configuration` request which will include a request for the workspace
+configuration as well as the configuration of all URIs that the language server
+is currently tracking.
+
+If the client has the `workspaceConfiguration` capability, the language server
+will send a configuration request for the URI when it received the
+`textDocument/didOpen` notification in order to get the resources specific
+settings.
+
+If the client does not have the `workspaceConfiguration` capability, the
+language server will assume the workspace setting applies to all resources.
diff --git a/cli/lsp/capabilities.rs b/cli/lsp/capabilities.rs
index 677e3921e..89400d108 100644
--- a/cli/lsp/capabilities.rs
+++ b/cli/lsp/capabilities.rs
@@ -27,6 +27,8 @@ use lspower::lsp::TextDocumentSyncCapability;
use lspower::lsp::TextDocumentSyncKind;
use lspower::lsp::TextDocumentSyncOptions;
use lspower::lsp::WorkDoneProgressOptions;
+use lspower::lsp::WorkspaceFoldersServerCapabilities;
+use lspower::lsp::WorkspaceServerCapabilities;
use super::semantic_tokens::get_legend;
@@ -132,7 +134,13 @@ pub fn server_capabilities(
},
),
),
- workspace: None,
+ workspace: Some(WorkspaceServerCapabilities {
+ workspace_folders: Some(WorkspaceFoldersServerCapabilities {
+ supported: Some(true),
+ change_notifications: None,
+ }),
+ file_operations: None,
+ }),
experimental: None,
linked_editing_range_provider: None,
moniker_provider: None,
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs
index 63f04e3cf..7aca52a9b 100644
--- a/cli/lsp/config.rs
+++ b/cli/lsp/config.rs
@@ -4,11 +4,14 @@ use deno_core::serde::Deserialize;
use deno_core::serde_json;
use deno_core::serde_json::Value;
use deno_core::url::Url;
+use deno_core::ModuleSpecifier;
use lspower::jsonrpc::Error as LSPError;
use lspower::jsonrpc::Result as LSPResult;
use lspower::lsp;
use std::collections::HashMap;
+pub const SETTINGS_SECTION: &str = "deno";
+
#[derive(Debug, Clone, Default)]
pub struct ClientCapabilities {
pub status_notification: bool,
@@ -84,19 +87,43 @@ impl Default for ImportCompletionSettings {
}
}
+/// Deno language server specific settings that can be applied uniquely to a
+/// specifier.
+#[derive(Debug, Default, Clone, Deserialize)]
+pub struct SpecifierSettings {
+ /// A flag that indicates if Deno is enabled for this specifier or not.
+ pub enable: bool,
+}
+
+/// Deno language server specific settings that are applied to a workspace.
#[derive(Debug, Default, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WorkspaceSettings {
+ /// A flag that indicates if Deno is enabled for the workspace.
pub enable: bool,
+
+ /// An option that points to a path string of the tsconfig file to apply to
+ /// code within the workspace.
pub config: Option<String>,
+
+ /// An option that points to a path string of the import map to apply to the
+ /// code within the workspace.
pub import_map: Option<String>,
+
+ /// Code lens specific settings for the workspace.
#[serde(default)]
pub code_lens: CodeLensSettings,
#[serde(default)]
+
+ /// Suggestion (auto-completion) settings for the workspace.
pub suggest: CompletionSettings,
+ /// A flag that indicates if linting is enabled for the workspace.
#[serde(default)]
pub lint: bool,
+
+ /// A flag that indicates if Dene should validate code against the unstable
+ /// APIs for the workspace.
#[serde(default)]
pub unstable: bool,
}
@@ -113,15 +140,21 @@ impl WorkspaceSettings {
pub struct Config {
pub client_capabilities: ClientCapabilities,
pub root_uri: Option<Url>,
- pub settings: WorkspaceSettings,
+ pub specifier_settings: HashMap<ModuleSpecifier, SpecifierSettings>,
+ pub workspace_settings: WorkspaceSettings,
}
impl Config {
- pub fn update(&mut self, value: Value) -> LSPResult<()> {
- let settings: WorkspaceSettings = serde_json::from_value(value)
- .map_err(|err| LSPError::invalid_params(err.to_string()))?;
- self.settings = settings;
- Ok(())
+ pub fn contains(&self, specifier: &ModuleSpecifier) -> bool {
+ self.specifier_settings.contains_key(specifier)
+ }
+
+ pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool {
+ if let Some(settings) = self.specifier_settings.get(specifier) {
+ settings.enable
+ } else {
+ self.workspace_settings.enable
+ }
}
#[allow(clippy::redundant_closure_call)]
@@ -154,4 +187,68 @@ impl Config {
.unwrap_or(false);
}
}
+
+ pub fn update_specifier(
+ &mut self,
+ specifier: ModuleSpecifier,
+ value: Value,
+ ) -> LSPResult<()> {
+ let settings: SpecifierSettings = serde_json::from_value(value)
+ .map_err(|err| LSPError::invalid_params(err.to_string()))?;
+ self.specifier_settings.insert(specifier, settings);
+ Ok(())
+ }
+
+ pub fn update_workspace(&mut self, value: Value) -> LSPResult<()> {
+ let settings: WorkspaceSettings = serde_json::from_value(value)
+ .map_err(|err| LSPError::invalid_params(err.to_string()))?;
+ self.workspace_settings = settings;
+ self.specifier_settings = HashMap::new();
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use deno_core::resolve_url;
+ use deno_core::serde_json::json;
+
+ #[test]
+ fn test_config_contains() {
+ let mut config = Config::default();
+ let specifier = resolve_url("https://deno.land/x/a.ts").unwrap();
+ assert!(!config.contains(&specifier));
+ config
+ .update_specifier(
+ specifier.clone(),
+ json!({
+ "enable": true
+ }),
+ )
+ .expect("could not update specifier");
+ assert!(config.contains(&specifier));
+ }
+
+ #[test]
+ fn test_config_specifier_enabled() {
+ let mut config = Config::default();
+ let specifier = resolve_url("file:///a.ts").unwrap();
+ assert!(!config.specifier_enabled(&specifier));
+ config
+ .update_workspace(json!({
+ "enable": true
+ }))
+ .expect("could not update");
+ assert!(config.specifier_enabled(&specifier));
+ config
+ .update_specifier(
+ specifier.clone(),
+ json!({
+ "enable": false
+ }),
+ )
+ .expect("could not update");
+ assert!(!config.specifier_enabled(&specifier));
+ }
}
diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs
index 4fcf2959a..b03a32059 100644
--- a/cli/lsp/diagnostics.rs
+++ b/cli/lsp/diagnostics.rs
@@ -65,7 +65,7 @@ async fn publish_diagnostics(
// disabled, otherwise the client will not clear down previous
// diagnostics
let mut diagnostics: Vec<lsp::Diagnostic> =
- if snapshot.config.settings.lint {
+ if snapshot.config.workspace_settings.lint {
collection
.diagnostics_for(&specifier, &DiagnosticSource::Lint)
.cloned()
@@ -73,7 +73,7 @@ async fn publish_diagnostics(
} else {
vec![]
};
- if snapshot.config.settings.enable {
+ if snapshot.config.specifier_enabled(&specifier) {
diagnostics.extend(
collection
.diagnostics_for(&specifier, &DiagnosticSource::TypeScript)
@@ -98,12 +98,8 @@ async fn update_diagnostics(
snapshot: &language_server::StateSnapshot,
ts_server: &tsc::TsServer,
) {
- let (enabled, lint_enabled) = {
- let config = &snapshot.config;
- (config.settings.enable, config.settings.lint)
- };
-
let mark = snapshot.performance.mark("update_diagnostics");
+ let lint_enabled = snapshot.config.workspace_settings.lint;
let lint = async {
let collection = collection.clone();
@@ -128,62 +124,50 @@ async fn update_diagnostics(
};
let ts = async {
- if enabled {
- let collection = collection.clone();
- let mark = snapshot.performance.mark("update_diagnostics_ts");
- let diagnostics = generate_ts_diagnostics(
- snapshot.clone(),
- collection.clone(),
- ts_server,
- )
- .await
- .map_err(|err| {
- error!("Error generating TypeScript diagnostics: {}", err);
- err
- })
- .unwrap_or_default();
- {
- let mut collection = collection.lock().unwrap();
- for (specifier, version, diagnostics) in diagnostics {
- collection.set(
- specifier,
- DiagnosticSource::TypeScript,
- version,
- diagnostics,
- );
- }
+ let collection = collection.clone();
+ let mark = snapshot.performance.mark("update_diagnostics_ts");
+ let diagnostics =
+ generate_ts_diagnostics(snapshot.clone(), collection.clone(), ts_server)
+ .await
+ .map_err(|err| {
+ error!("Error generating TypeScript diagnostics: {}", err);
+ err
+ })
+ .unwrap_or_default();
+ {
+ let mut collection = collection.lock().unwrap();
+ for (specifier, version, diagnostics) in diagnostics {
+ collection.set(
+ specifier,
+ DiagnosticSource::TypeScript,
+ version,
+ diagnostics,
+ );
}
- publish_diagnostics(client, collection, snapshot).await;
- snapshot.performance.measure(mark);
- };
+ }
+ publish_diagnostics(client, collection, snapshot).await;
+ snapshot.performance.measure(mark);
};
let deps = async {
- if enabled {
- let collection = collection.clone();
- let mark = snapshot.performance.mark("update_diagnostics_deps");
- let diagnostics =
- generate_dependency_diagnostics(snapshot.clone(), collection.clone())
- .await
- .map_err(|err| {
- error!("Error generating dependency diagnostics: {}", err);
- err
- })
- .unwrap_or_default();
- {
- let mut collection = collection.lock().unwrap();
- for (specifier, version, diagnostics) in diagnostics {
- collection.set(
- specifier,
- DiagnosticSource::Deno,
- version,
- diagnostics,
- );
- }
+ let collection = collection.clone();
+ let mark = snapshot.performance.mark("update_diagnostics_deps");
+ let diagnostics =
+ generate_dependency_diagnostics(snapshot.clone(), collection.clone())
+ .await
+ .map_err(|err| {
+ error!("Error generating dependency diagnostics: {}", err);
+ err
+ })
+ .unwrap_or_default();
+ {
+ let mut collection = collection.lock().unwrap();
+ for (specifier, version, diagnostics) in diagnostics {
+ collection.set(specifier, DiagnosticSource::Deno, version, diagnostics);
}
- publish_diagnostics(client, collection, snapshot).await;
- snapshot.performance.measure(mark);
- };
+ }
+ publish_diagnostics(client, collection, snapshot).await;
+ snapshot.performance.measure(mark);
};
tokio::join!(lint, ts, deps);
@@ -534,11 +518,13 @@ async fn generate_ts_diagnostics(
{
let collection = collection.lock().unwrap();
for specifier in state_snapshot.documents.open_specifiers() {
- let version = state_snapshot.documents.version(specifier);
- let current_version =
- collection.get_version(specifier, &DiagnosticSource::TypeScript);
- if version != current_version {
- specifiers.push(specifier.clone());
+ if state_snapshot.config.specifier_enabled(specifier) {
+ let version = state_snapshot.documents.version(specifier);
+ let current_version =
+ collection.get_version(specifier, &DiagnosticSource::TypeScript);
+ if version != current_version {
+ specifiers.push(specifier.clone());
+ }
}
}
}
@@ -568,6 +554,9 @@ async fn generate_dependency_diagnostics(
let sources = &mut state_snapshot.sources;
for specifier in state_snapshot.documents.open_specifiers() {
+ if !state_snapshot.config.specifier_enabled(specifier) {
+ continue;
+ }
let version = state_snapshot.documents.version(specifier);
let current_version = collection.lock().unwrap().get_version(specifier, &DiagnosticSource::Deno);
if version != current_version {
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 12fc70c8c..2fbc41b03 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -44,6 +44,7 @@ use super::analysis::ResolvedDependency;
use super::capabilities;
use super::completions;
use super::config::Config;
+use super::config::SETTINGS_SECTION;
use super::diagnostics;
use super::diagnostics::DiagnosticSource;
use super::documents::DocumentCache;
@@ -78,6 +79,7 @@ pub struct StateSnapshot {
pub module_registries: registries::ModuleRegistry,
pub performance: Performance,
pub sources: Sources,
+ pub url_map: urls::LspUrlMap,
}
#[derive(Debug)]
@@ -188,10 +190,6 @@ impl Inner {
}
}
- fn enabled(&self) -> bool {
- self.config.settings.enable
- }
-
/// Searches assets, open documents and external sources for a line_index,
/// which might be performed asynchronously, hydrating in memory caches for
/// subsequent requests.
@@ -293,6 +291,7 @@ impl Inner {
module_registries: self.module_registries.clone(),
performance: self.performance.clone(),
sources: self.sources.clone(),
+ url_map: self.url_map.clone(),
}
}
@@ -300,7 +299,10 @@ impl Inner {
let mark = self.performance.mark("update_import_map");
let (maybe_import_map, maybe_root_uri) = {
let config = &self.config;
- (config.settings.import_map.clone(), config.root_uri.clone())
+ (
+ config.workspace_settings.import_map.clone(),
+ config.root_uri.clone(),
+ )
};
if let Some(import_map_str) = &maybe_import_map {
info!("Updating import map from: \"{}\"", import_map_str);
@@ -345,7 +347,8 @@ impl Inner {
async fn update_registries(&mut self) -> Result<(), AnyError> {
let mark = self.performance.mark("update_registries");
- for (registry, enabled) in self.config.settings.suggest.imports.hosts.iter()
+ for (registry, enabled) in
+ self.config.workspace_settings.suggest.imports.hosts.iter()
{
if *enabled {
info!("Enabling auto complete registry for: {}", registry);
@@ -376,13 +379,16 @@ impl Inner {
}));
let (maybe_config, maybe_root_uri) = {
let config = &self.config;
- if config.settings.unstable {
+ if config.workspace_settings.unstable {
let unstable_libs = json!({
"lib": ["deno.ns", "deno.window", "deno.unstable"]
});
tsconfig.merge(&unstable_libs);
}
- (config.settings.config.clone(), config.root_uri.clone())
+ (
+ config.workspace_settings.config.clone(),
+ config.root_uri.clone(),
+ )
};
if let Some(config_str) = &maybe_config {
info!("Updating TypeScript configuration from: \"{}\"", config_str);
@@ -491,7 +497,7 @@ impl Inner {
let config = &mut self.config;
config.root_uri = params.root_uri;
if let Some(value) = params.initialization_options {
- config.update(value)?;
+ config.update_workspace(value)?;
}
config.update_capabilities(&params.capabilities);
}
@@ -573,13 +579,35 @@ impl Inner {
async fn did_open(&mut self, params: DidOpenTextDocumentParams) {
let mark = self.performance.mark("did_open");
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+
+ // we only query the individual resource file if the client supports it
+ if self.config.client_capabilities.workspace_configuration
+ && !self.config.contains(&specifier)
+ {
+ if let Ok(value) = self
+ .client
+ .configuration(vec![ConfigurationItem {
+ scope_uri: Some(params.text_document.uri.clone()),
+ section: Some(SETTINGS_SECTION.to_string()),
+ }])
+ .await
+ {
+ if let Err(err) = self
+ .config
+ .update_specifier(specifier.clone(), value[0].clone())
+ {
+ warn!("Error updating specifier configuration: {}", err);
+ }
+ }
+ }
+
if params.text_document.uri.scheme() == "deno" {
// we can ignore virtual text documents opening, as they don't need to
// be tracked in memory, as they are static assets that won't change
// already managed by the language service
return;
}
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
self.documents.open(
specifier.clone(),
params.text_document.version,
@@ -635,56 +663,69 @@ impl Inner {
params: DidChangeConfigurationParams,
) {
let mark = self.performance.mark("did_change_configuration");
- let config = if self.config.client_capabilities.workspace_configuration {
- self
- .client
- .configuration(vec![ConfigurationItem {
- scope_uri: None,
- section: Some("deno".to_string()),
- }])
- .await
- .map(|vec| vec.get(0).cloned())
- .unwrap_or_else(|err| {
- error!("failed to fetch the extension settings {}", err);
- None
- })
- } else {
- params
- .settings
- .as_object()
- .map(|settings| settings.get("deno"))
- .flatten()
- .cloned()
- };
- if let Some(config) = config {
- if let Err(err) = self.config.update(config) {
- error!("failed to update settings: {}", err);
- }
- if let Err(err) = self.update_import_map().await {
- self
- .client
- .show_message(MessageType::Warning, err.to_string())
- .await;
- }
- if let Err(err) = self.update_registries().await {
- self
- .client
- .show_message(MessageType::Warning, err.to_string())
- .await;
- }
- if let Err(err) = self.update_tsconfig().await {
- self
- .client
- .show_message(MessageType::Warning, err.to_string())
- .await;
+ if self.config.client_capabilities.workspace_configuration {
+ let specifiers: Vec<ModuleSpecifier> =
+ self.config.specifier_settings.keys().cloned().collect();
+ let mut snapshot = self.snapshot();
+ let mut config_items = specifiers
+ .iter()
+ .map(|s| ConfigurationItem {
+ scope_uri: Some(snapshot.url_map.normalize_specifier(s).unwrap()),
+ section: Some(SETTINGS_SECTION.to_string()),
+ })
+ .collect();
+ let mut items = vec![ConfigurationItem {
+ scope_uri: None,
+ section: Some(SETTINGS_SECTION.to_string()),
+ }];
+ items.append(&mut config_items);
+ if let Ok(configs) = self.client.configuration(items).await {
+ for (i, value) in configs.into_iter().enumerate() {
+ if let Err(err) = match i {
+ 0 => self.config.update_workspace(value),
+ _ => self
+ .config
+ .update_specifier(specifiers[i - 1].clone(), value),
+ } {
+ error!("failed to update settings: {}", err);
+ }
+ }
}
- if let Err(err) = self.diagnostics_server.update() {
- error!("{}", err);
+ } else if let Some(config) = params
+ .settings
+ .as_object()
+ .map(|settings| settings.get(SETTINGS_SECTION))
+ .flatten()
+ .cloned()
+ {
+ if let Err(err) = self.config.update_workspace(config) {
+ error!("failed to update settings: {}", err);
}
- } else {
- error!("received empty extension settings from the client");
}
+
+ if let Err(err) = self.update_import_map().await {
+ self
+ .client
+ .show_message(MessageType::Warning, err.to_string())
+ .await;
+ }
+ if let Err(err) = self.update_registries().await {
+ self
+ .client
+ .show_message(MessageType::Warning, err.to_string())
+ .await;
+ }
+ if let Err(err) = self.update_tsconfig().await {
+ self
+ .client
+ .show_message(MessageType::Warning, err.to_string())
+ .await;
+ }
+ if let Err(err) = self.diagnostics_server.update() {
+ error!("{}", err);
+ }
+
self.performance.measure(mark);
}
@@ -719,14 +760,14 @@ impl Inner {
}
async fn document_symbol(
- &self,
+ &mut self,
params: DocumentSymbolParams,
) -> LspResult<Option<DocumentSymbolResponse>> {
- if !self.enabled() {
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
return Ok(None);
}
let mark = self.performance.mark("document_symbol");
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -817,14 +858,15 @@ impl Inner {
}
}
- async fn hover(&self, params: HoverParams) -> LspResult<Option<Hover>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("hover");
+ async fn hover(&mut self, params: HoverParams) -> LspResult<Option<Hover>> {
let specifier = self
.url_map
.normalize_url(&params.text_document_position_params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+ let mark = self.performance.mark("hover");
+
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
line_index
@@ -860,12 +902,12 @@ impl Inner {
&mut self,
params: CodeActionParams,
) -> LspResult<Option<CodeActionResponse>> {
- if !self.enabled() {
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
return Ok(None);
}
let mark = self.performance.mark("code_action");
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
let fixable_diagnostics: Vec<&Diagnostic> = params
.context
.diagnostics
@@ -1016,12 +1058,14 @@ impl Inner {
&mut self,
params: CodeLensParams,
) -> LspResult<Option<Vec<CodeLens>>> {
- if !self.enabled() || !self.config.settings.enabled_code_lens() {
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier)
+ || !self.config.workspace_settings.enabled_code_lens()
+ {
return Ok(None);
}
let mark = self.performance.mark("code_lens");
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
let line_index = self.get_line_index_sync(&specifier).unwrap();
let navigation_tree =
self.get_navigation_tree(&specifier).await.map_err(|err| {
@@ -1037,7 +1081,7 @@ impl Inner {
let mut code_lenses = cl.borrow_mut();
// TSC Implementations Code Lens
- if self.config.settings.code_lens.implementations {
+ if self.config.workspace_settings.code_lens.implementations {
let source = CodeLensSource::Implementations;
match i.kind {
tsc::ScriptElementKind::InterfaceElement => {
@@ -1061,7 +1105,7 @@ impl Inner {
}
// TSC References Code Lens
- if self.config.settings.code_lens.references {
+ if self.config.workspace_settings.code_lens.references {
let source = CodeLensSource::References;
if let Some(parent) = &mp {
if parent.kind == tsc::ScriptElementKind::EnumElement {
@@ -1070,7 +1114,12 @@ impl Inner {
}
match i.kind {
tsc::ScriptElementKind::FunctionElement => {
- if self.config.settings.code_lens.references_all_functions {
+ if self
+ .config
+ .workspace_settings
+ .code_lens
+ .references_all_functions
+ {
code_lenses.push(i.to_code_lens(
&line_index,
&specifier,
@@ -1317,16 +1366,17 @@ impl Inner {
}
async fn document_highlight(
- &self,
+ &mut self,
params: DocumentHighlightParams,
) -> LspResult<Option<Vec<DocumentHighlight>>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("document_highlight");
let specifier = self
.url_map
.normalize_url(&params.text_document_position_params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+
+ let mark = self.performance.mark("document_highlight");
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
line_index
@@ -1369,13 +1419,13 @@ impl Inner {
&mut self,
params: ReferenceParams,
) -> LspResult<Option<Vec<Location>>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("references");
let specifier = self
.url_map
.normalize_url(&params.text_document_position.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+ let mark = self.performance.mark("references");
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
line_index
@@ -1424,13 +1474,13 @@ impl Inner {
&mut self,
params: GotoDefinitionParams,
) -> LspResult<Option<GotoDefinitionResponse>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("goto_definition");
let specifier = self
.url_map
.normalize_url(&params.text_document_position_params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+ let mark = self.performance.mark("goto_definition");
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
line_index
@@ -1464,16 +1514,16 @@ impl Inner {
}
async fn completion(
- &self,
+ &mut self,
params: CompletionParams,
) -> LspResult<Option<CompletionResponse>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("completion");
let specifier = self
.url_map
.normalize_url(&params.text_document_position.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+ let mark = self.performance.mark("completion");
// Import specifiers are something wholly internal to Deno, so for
// completions, we will use internal logic and if there are completions
// for imports, we will return those and not send a message into tsc, where
@@ -1526,7 +1576,7 @@ impl Inner {
if let Some(completions) = maybe_completion_info {
let results = completions.as_completion_response(
&line_index,
- &self.config.settings.suggest,
+ &self.config.workspace_settings.suggest,
&specifier,
position,
);
@@ -1583,13 +1633,13 @@ impl Inner {
&mut self,
params: GotoImplementationParams,
) -> LspResult<Option<GotoImplementationResponse>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("goto_implementation");
let specifier = self
.url_map
.normalize_url(&params.text_document_position_params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+ let mark = self.performance.mark("goto_implementation");
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
line_index
@@ -1630,14 +1680,14 @@ impl Inner {
}
async fn folding_range(
- &self,
+ &mut self,
params: FoldingRangeParams,
) -> LspResult<Option<Vec<FoldingRange>>> {
- if !self.enabled() {
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
return Ok(None);
}
let mark = self.performance.mark("folding_range");
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -1690,11 +1740,11 @@ impl Inner {
&mut self,
params: CallHierarchyIncomingCallsParams,
) -> LspResult<Option<Vec<CallHierarchyIncomingCall>>> {
- if !self.enabled() {
+ let specifier = self.url_map.normalize_url(&params.item.uri);
+ if !self.config.specifier_enabled(&specifier) {
return Ok(None);
}
let mark = self.performance.mark("incoming_calls");
- let specifier = self.url_map.normalize_url(&params.item.uri);
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -1744,11 +1794,11 @@ impl Inner {
&mut self,
params: CallHierarchyOutgoingCallsParams,
) -> LspResult<Option<Vec<CallHierarchyOutgoingCall>>> {
- if !self.enabled() {
+ let specifier = self.url_map.normalize_url(&params.item.uri);
+ if !self.config.specifier_enabled(&specifier) {
return Ok(None);
}
let mark = self.performance.mark("outgoing_calls");
- let specifier = self.url_map.normalize_url(&params.item.uri);
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -1799,13 +1849,13 @@ impl Inner {
&mut self,
params: CallHierarchyPrepareParams,
) -> LspResult<Option<Vec<CallHierarchyItem>>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("prepare_call_hierarchy");
let specifier = self
.url_map
.normalize_url(&params.text_document_position_params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+ let mark = self.performance.mark("prepare_call_hierarchy");
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -1876,13 +1926,13 @@ impl Inner {
&mut self,
params: RenameParams,
) -> LspResult<Option<WorkspaceEdit>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("rename");
let specifier = self
.url_map
.normalize_url(&params.text_document_position.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+ let mark = self.performance.mark("rename");
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -1963,14 +2013,14 @@ impl Inner {
}
async fn selection_range(
- &self,
+ &mut self,
params: SelectionRangeParams,
) -> LspResult<Option<Vec<SelectionRange>>> {
- if !self.enabled() {
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
return Ok(None);
}
let mark = self.performance.mark("selection_range");
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -2005,14 +2055,14 @@ impl Inner {
}
async fn semantic_tokens_full(
- &self,
+ &mut self,
params: SemanticTokensParams,
) -> LspResult<Option<SemanticTokensResult>> {
- if !self.enabled() {
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
return Ok(None);
}
let mark = self.performance.mark("semantic_tokens_full");
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -2052,14 +2102,14 @@ impl Inner {
}
async fn semantic_tokens_range(
- &self,
+ &mut self,
params: SemanticTokensRangeParams,
) -> LspResult<Option<SemanticTokensRangeResult>> {
- if !self.enabled() {
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
return Ok(None);
}
let mark = self.performance.mark("semantic_tokens_range");
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
@@ -2098,16 +2148,16 @@ impl Inner {
}
async fn signature_help(
- &self,
+ &mut self,
params: SignatureHelpParams,
) -> LspResult<Option<SignatureHelp>> {
- if !self.enabled() {
- return Ok(None);
- }
- let mark = self.performance.mark("signature_help");
let specifier = self
.url_map
.normalize_url(&params.text_document_position_params.text_document.uri);
+ if !self.config.specifier_enabled(&specifier) {
+ return Ok(None);
+ }
+ let mark = self.performance.mark("signature_help");
let line_index =
if let Some(line_index) = self.get_line_index_sync(&specifier) {
line_index
diff --git a/cli/lsp/urls.rs b/cli/lsp/urls.rs
index 559f1652a..49049b535 100644
--- a/cli/lsp/urls.rs
+++ b/cli/lsp/urls.rs
@@ -54,7 +54,7 @@ fn hash_data_specifier(specifier: &ModuleSpecifier) -> String {
/// A bi-directional map of URLs sent to the LSP client and internal module
/// specifiers. We need to map internal specifiers into `deno:` schema URLs
/// to allow the Deno language server to manage these as virtual documents.
-#[derive(Debug, Default)]
+#[derive(Debug, Default, Clone)]
pub struct LspUrlMap {
specifier_to_url: HashMap<ModuleSpecifier, Url>,
url_to_specifier: HashMap<Url, ModuleSpecifier>,