mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 15:24:46 -05:00
parent
33b1a6ed61
commit
84733d90c7
9 changed files with 456 additions and 194 deletions
|
@ -39,6 +39,10 @@
|
||||||
"willSaveWaitUntil": true,
|
"willSaveWaitUntil": true,
|
||||||
"didSave": true
|
"didSave": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"configuration": true,
|
||||||
|
"workspaceFolders": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
fn write(&mut self, value: Value) -> Result<(), AnyError> {
|
||||||
let value_str = value.to_string();
|
let value_str = value.to_string();
|
||||||
let msg = format!(
|
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>(
|
fn write_notification<S, V>(
|
||||||
&mut self,
|
&mut self,
|
||||||
method: S,
|
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()?;
|
let (method, _): (String, Option<Value>) = client.read_notification()?;
|
||||||
assert_eq!(method, "textDocument/publishDiagnostics");
|
assert_eq!(method, "textDocument/publishDiagnostics");
|
||||||
let (method, _): (String, Option<Value>) = client.read_notification()?;
|
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()?;
|
let (method, _): (String, Option<Value>) = client.read_notification()?;
|
||||||
assert_eq!(method, "textDocument/publishDiagnostics");
|
assert_eq!(method, "textDocument/publishDiagnostics");
|
||||||
let (method, _): (String, Option<Value>) = client.read_notification()?;
|
let (method, _): (String, Option<Value>) = client.read_notification()?;
|
||||||
|
|
|
@ -61,3 +61,56 @@ with Deno:
|
||||||
textDocument: TextDocumentIdentifier;
|
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.
|
||||||
|
|
|
@ -27,6 +27,8 @@ use lspower::lsp::TextDocumentSyncCapability;
|
||||||
use lspower::lsp::TextDocumentSyncKind;
|
use lspower::lsp::TextDocumentSyncKind;
|
||||||
use lspower::lsp::TextDocumentSyncOptions;
|
use lspower::lsp::TextDocumentSyncOptions;
|
||||||
use lspower::lsp::WorkDoneProgressOptions;
|
use lspower::lsp::WorkDoneProgressOptions;
|
||||||
|
use lspower::lsp::WorkspaceFoldersServerCapabilities;
|
||||||
|
use lspower::lsp::WorkspaceServerCapabilities;
|
||||||
|
|
||||||
use super::semantic_tokens::get_legend;
|
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,
|
experimental: None,
|
||||||
linked_editing_range_provider: None,
|
linked_editing_range_provider: None,
|
||||||
moniker_provider: None,
|
moniker_provider: None,
|
||||||
|
|
|
@ -4,11 +4,14 @@ use deno_core::serde::Deserialize;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::serde_json::Value;
|
use deno_core::serde_json::Value;
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
|
use deno_core::ModuleSpecifier;
|
||||||
use lspower::jsonrpc::Error as LSPError;
|
use lspower::jsonrpc::Error as LSPError;
|
||||||
use lspower::jsonrpc::Result as LSPResult;
|
use lspower::jsonrpc::Result as LSPResult;
|
||||||
use lspower::lsp;
|
use lspower::lsp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub const SETTINGS_SECTION: &str = "deno";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct ClientCapabilities {
|
pub struct ClientCapabilities {
|
||||||
pub status_notification: bool,
|
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)]
|
#[derive(Debug, Default, Clone, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct WorkspaceSettings {
|
pub struct WorkspaceSettings {
|
||||||
|
/// A flag that indicates if Deno is enabled for the workspace.
|
||||||
pub enable: bool,
|
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>,
|
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>,
|
pub import_map: Option<String>,
|
||||||
|
|
||||||
|
/// Code lens specific settings for the workspace.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub code_lens: CodeLensSettings,
|
pub code_lens: CodeLensSettings,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
||||||
|
/// Suggestion (auto-completion) settings for the workspace.
|
||||||
pub suggest: CompletionSettings,
|
pub suggest: CompletionSettings,
|
||||||
|
|
||||||
|
/// A flag that indicates if linting is enabled for the workspace.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub lint: bool,
|
pub lint: bool,
|
||||||
|
|
||||||
|
/// A flag that indicates if Dene should validate code against the unstable
|
||||||
|
/// APIs for the workspace.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub unstable: bool,
|
pub unstable: bool,
|
||||||
}
|
}
|
||||||
|
@ -113,15 +140,21 @@ impl WorkspaceSettings {
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub client_capabilities: ClientCapabilities,
|
pub client_capabilities: ClientCapabilities,
|
||||||
pub root_uri: Option<Url>,
|
pub root_uri: Option<Url>,
|
||||||
pub settings: WorkspaceSettings,
|
pub specifier_settings: HashMap<ModuleSpecifier, SpecifierSettings>,
|
||||||
|
pub workspace_settings: WorkspaceSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn update(&mut self, value: Value) -> LSPResult<()> {
|
pub fn contains(&self, specifier: &ModuleSpecifier) -> bool {
|
||||||
let settings: WorkspaceSettings = serde_json::from_value(value)
|
self.specifier_settings.contains_key(specifier)
|
||||||
.map_err(|err| LSPError::invalid_params(err.to_string()))?;
|
}
|
||||||
self.settings = settings;
|
|
||||||
Ok(())
|
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)]
|
#[allow(clippy::redundant_closure_call)]
|
||||||
|
@ -154,4 +187,68 @@ impl Config {
|
||||||
.unwrap_or(false);
|
.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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ async fn publish_diagnostics(
|
||||||
// disabled, otherwise the client will not clear down previous
|
// disabled, otherwise the client will not clear down previous
|
||||||
// diagnostics
|
// diagnostics
|
||||||
let mut diagnostics: Vec<lsp::Diagnostic> =
|
let mut diagnostics: Vec<lsp::Diagnostic> =
|
||||||
if snapshot.config.settings.lint {
|
if snapshot.config.workspace_settings.lint {
|
||||||
collection
|
collection
|
||||||
.diagnostics_for(&specifier, &DiagnosticSource::Lint)
|
.diagnostics_for(&specifier, &DiagnosticSource::Lint)
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -73,7 +73,7 @@ async fn publish_diagnostics(
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
if snapshot.config.settings.enable {
|
if snapshot.config.specifier_enabled(&specifier) {
|
||||||
diagnostics.extend(
|
diagnostics.extend(
|
||||||
collection
|
collection
|
||||||
.diagnostics_for(&specifier, &DiagnosticSource::TypeScript)
|
.diagnostics_for(&specifier, &DiagnosticSource::TypeScript)
|
||||||
|
@ -98,12 +98,8 @@ async fn update_diagnostics(
|
||||||
snapshot: &language_server::StateSnapshot,
|
snapshot: &language_server::StateSnapshot,
|
||||||
ts_server: &tsc::TsServer,
|
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 mark = snapshot.performance.mark("update_diagnostics");
|
||||||
|
let lint_enabled = snapshot.config.workspace_settings.lint;
|
||||||
|
|
||||||
let lint = async {
|
let lint = async {
|
||||||
let collection = collection.clone();
|
let collection = collection.clone();
|
||||||
|
@ -128,14 +124,10 @@ async fn update_diagnostics(
|
||||||
};
|
};
|
||||||
|
|
||||||
let ts = async {
|
let ts = async {
|
||||||
if enabled {
|
|
||||||
let collection = collection.clone();
|
let collection = collection.clone();
|
||||||
let mark = snapshot.performance.mark("update_diagnostics_ts");
|
let mark = snapshot.performance.mark("update_diagnostics_ts");
|
||||||
let diagnostics = generate_ts_diagnostics(
|
let diagnostics =
|
||||||
snapshot.clone(),
|
generate_ts_diagnostics(snapshot.clone(), collection.clone(), ts_server)
|
||||||
collection.clone(),
|
|
||||||
ts_server,
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
error!("Error generating TypeScript diagnostics: {}", err);
|
error!("Error generating TypeScript diagnostics: {}", err);
|
||||||
|
@ -156,10 +148,8 @@ async fn update_diagnostics(
|
||||||
publish_diagnostics(client, collection, snapshot).await;
|
publish_diagnostics(client, collection, snapshot).await;
|
||||||
snapshot.performance.measure(mark);
|
snapshot.performance.measure(mark);
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let deps = async {
|
let deps = async {
|
||||||
if enabled {
|
|
||||||
let collection = collection.clone();
|
let collection = collection.clone();
|
||||||
let mark = snapshot.performance.mark("update_diagnostics_deps");
|
let mark = snapshot.performance.mark("update_diagnostics_deps");
|
||||||
let diagnostics =
|
let diagnostics =
|
||||||
|
@ -173,18 +163,12 @@ async fn update_diagnostics(
|
||||||
{
|
{
|
||||||
let mut collection = collection.lock().unwrap();
|
let mut collection = collection.lock().unwrap();
|
||||||
for (specifier, version, diagnostics) in diagnostics {
|
for (specifier, version, diagnostics) in diagnostics {
|
||||||
collection.set(
|
collection.set(specifier, DiagnosticSource::Deno, version, diagnostics);
|
||||||
specifier,
|
|
||||||
DiagnosticSource::Deno,
|
|
||||||
version,
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
publish_diagnostics(client, collection, snapshot).await;
|
publish_diagnostics(client, collection, snapshot).await;
|
||||||
snapshot.performance.measure(mark);
|
snapshot.performance.measure(mark);
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
tokio::join!(lint, ts, deps);
|
tokio::join!(lint, ts, deps);
|
||||||
|
|
||||||
|
@ -534,6 +518,7 @@ async fn generate_ts_diagnostics(
|
||||||
{
|
{
|
||||||
let collection = collection.lock().unwrap();
|
let collection = collection.lock().unwrap();
|
||||||
for specifier in state_snapshot.documents.open_specifiers() {
|
for specifier in state_snapshot.documents.open_specifiers() {
|
||||||
|
if state_snapshot.config.specifier_enabled(specifier) {
|
||||||
let version = state_snapshot.documents.version(specifier);
|
let version = state_snapshot.documents.version(specifier);
|
||||||
let current_version =
|
let current_version =
|
||||||
collection.get_version(specifier, &DiagnosticSource::TypeScript);
|
collection.get_version(specifier, &DiagnosticSource::TypeScript);
|
||||||
|
@ -542,6 +527,7 @@ async fn generate_ts_diagnostics(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if !specifiers.is_empty() {
|
if !specifiers.is_empty() {
|
||||||
let req = tsc::RequestMethod::GetDiagnostics(specifiers);
|
let req = tsc::RequestMethod::GetDiagnostics(specifiers);
|
||||||
let res = ts_server.request(state_snapshot.clone(), req).await?;
|
let res = ts_server.request(state_snapshot.clone(), req).await?;
|
||||||
|
@ -568,6 +554,9 @@ async fn generate_dependency_diagnostics(
|
||||||
|
|
||||||
let sources = &mut state_snapshot.sources;
|
let sources = &mut state_snapshot.sources;
|
||||||
for specifier in state_snapshot.documents.open_specifiers() {
|
for specifier in state_snapshot.documents.open_specifiers() {
|
||||||
|
if !state_snapshot.config.specifier_enabled(specifier) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let version = state_snapshot.documents.version(specifier);
|
let version = state_snapshot.documents.version(specifier);
|
||||||
let current_version = collection.lock().unwrap().get_version(specifier, &DiagnosticSource::Deno);
|
let current_version = collection.lock().unwrap().get_version(specifier, &DiagnosticSource::Deno);
|
||||||
if version != current_version {
|
if version != current_version {
|
||||||
|
|
|
@ -44,6 +44,7 @@ use super::analysis::ResolvedDependency;
|
||||||
use super::capabilities;
|
use super::capabilities;
|
||||||
use super::completions;
|
use super::completions;
|
||||||
use super::config::Config;
|
use super::config::Config;
|
||||||
|
use super::config::SETTINGS_SECTION;
|
||||||
use super::diagnostics;
|
use super::diagnostics;
|
||||||
use super::diagnostics::DiagnosticSource;
|
use super::diagnostics::DiagnosticSource;
|
||||||
use super::documents::DocumentCache;
|
use super::documents::DocumentCache;
|
||||||
|
@ -78,6 +79,7 @@ pub struct StateSnapshot {
|
||||||
pub module_registries: registries::ModuleRegistry,
|
pub module_registries: registries::ModuleRegistry,
|
||||||
pub performance: Performance,
|
pub performance: Performance,
|
||||||
pub sources: Sources,
|
pub sources: Sources,
|
||||||
|
pub url_map: urls::LspUrlMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[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,
|
/// Searches assets, open documents and external sources for a line_index,
|
||||||
/// which might be performed asynchronously, hydrating in memory caches for
|
/// which might be performed asynchronously, hydrating in memory caches for
|
||||||
/// subsequent requests.
|
/// subsequent requests.
|
||||||
|
@ -293,6 +291,7 @@ impl Inner {
|
||||||
module_registries: self.module_registries.clone(),
|
module_registries: self.module_registries.clone(),
|
||||||
performance: self.performance.clone(),
|
performance: self.performance.clone(),
|
||||||
sources: self.sources.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 mark = self.performance.mark("update_import_map");
|
||||||
let (maybe_import_map, maybe_root_uri) = {
|
let (maybe_import_map, maybe_root_uri) = {
|
||||||
let config = &self.config;
|
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 {
|
if let Some(import_map_str) = &maybe_import_map {
|
||||||
info!("Updating import map from: \"{}\"", import_map_str);
|
info!("Updating import map from: \"{}\"", import_map_str);
|
||||||
|
@ -345,7 +347,8 @@ impl Inner {
|
||||||
|
|
||||||
async fn update_registries(&mut self) -> Result<(), AnyError> {
|
async fn update_registries(&mut self) -> Result<(), AnyError> {
|
||||||
let mark = self.performance.mark("update_registries");
|
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 {
|
if *enabled {
|
||||||
info!("Enabling auto complete registry for: {}", registry);
|
info!("Enabling auto complete registry for: {}", registry);
|
||||||
|
@ -376,13 +379,16 @@ impl Inner {
|
||||||
}));
|
}));
|
||||||
let (maybe_config, maybe_root_uri) = {
|
let (maybe_config, maybe_root_uri) = {
|
||||||
let config = &self.config;
|
let config = &self.config;
|
||||||
if config.settings.unstable {
|
if config.workspace_settings.unstable {
|
||||||
let unstable_libs = json!({
|
let unstable_libs = json!({
|
||||||
"lib": ["deno.ns", "deno.window", "deno.unstable"]
|
"lib": ["deno.ns", "deno.window", "deno.unstable"]
|
||||||
});
|
});
|
||||||
tsconfig.merge(&unstable_libs);
|
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 {
|
if let Some(config_str) = &maybe_config {
|
||||||
info!("Updating TypeScript configuration from: \"{}\"", config_str);
|
info!("Updating TypeScript configuration from: \"{}\"", config_str);
|
||||||
|
@ -491,7 +497,7 @@ impl Inner {
|
||||||
let config = &mut self.config;
|
let config = &mut self.config;
|
||||||
config.root_uri = params.root_uri;
|
config.root_uri = params.root_uri;
|
||||||
if let Some(value) = params.initialization_options {
|
if let Some(value) = params.initialization_options {
|
||||||
config.update(value)?;
|
config.update_workspace(value)?;
|
||||||
}
|
}
|
||||||
config.update_capabilities(¶ms.capabilities);
|
config.update_capabilities(¶ms.capabilities);
|
||||||
}
|
}
|
||||||
|
@ -573,13 +579,35 @@ impl Inner {
|
||||||
|
|
||||||
async fn did_open(&mut self, params: DidOpenTextDocumentParams) {
|
async fn did_open(&mut self, params: DidOpenTextDocumentParams) {
|
||||||
let mark = self.performance.mark("did_open");
|
let mark = self.performance.mark("did_open");
|
||||||
|
let specifier = self.url_map.normalize_url(¶ms.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" {
|
if params.text_document.uri.scheme() == "deno" {
|
||||||
// we can ignore virtual text documents opening, as they don't need to
|
// 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
|
// be tracked in memory, as they are static assets that won't change
|
||||||
// already managed by the language service
|
// already managed by the language service
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
|
||||||
self.documents.open(
|
self.documents.open(
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
params.text_document.version,
|
params.text_document.version,
|
||||||
|
@ -635,32 +663,47 @@ impl Inner {
|
||||||
params: DidChangeConfigurationParams,
|
params: DidChangeConfigurationParams,
|
||||||
) {
|
) {
|
||||||
let mark = self.performance.mark("did_change_configuration");
|
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 self.config.client_capabilities.workspace_configuration {
|
||||||
if let Err(err) = self.config.update(config) {
|
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);
|
error!("failed to update settings: {}", 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(err) = self.update_import_map().await {
|
if let Err(err) = self.update_import_map().await {
|
||||||
self
|
self
|
||||||
.client
|
.client
|
||||||
|
@ -682,9 +725,7 @@ impl Inner {
|
||||||
if let Err(err) = self.diagnostics_server.update() {
|
if let Err(err) = self.diagnostics_server.update() {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
error!("received empty extension settings from the client");
|
|
||||||
}
|
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,14 +760,14 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn document_symbol(
|
async fn document_symbol(
|
||||||
&self,
|
&mut self,
|
||||||
params: DocumentSymbolParams,
|
params: DocumentSymbolParams,
|
||||||
) -> LspResult<Option<DocumentSymbolResponse>> {
|
) -> LspResult<Option<DocumentSymbolResponse>> {
|
||||||
if !self.enabled() {
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let mark = self.performance.mark("document_symbol");
|
let mark = self.performance.mark("document_symbol");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
|
||||||
|
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
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>> {
|
async fn hover(&mut self, params: HoverParams) -> LspResult<Option<Hover>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("hover");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
.normalize_url(¶ms.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 =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
line_index
|
line_index
|
||||||
|
@ -860,12 +902,12 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: CodeActionParams,
|
params: CodeActionParams,
|
||||||
) -> LspResult<Option<CodeActionResponse>> {
|
) -> LspResult<Option<CodeActionResponse>> {
|
||||||
if !self.enabled() {
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("code_action");
|
let mark = self.performance.mark("code_action");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
|
||||||
let fixable_diagnostics: Vec<&Diagnostic> = params
|
let fixable_diagnostics: Vec<&Diagnostic> = params
|
||||||
.context
|
.context
|
||||||
.diagnostics
|
.diagnostics
|
||||||
|
@ -1016,12 +1058,14 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: CodeLensParams,
|
params: CodeLensParams,
|
||||||
) -> LspResult<Option<Vec<CodeLens>>> {
|
) -> LspResult<Option<Vec<CodeLens>>> {
|
||||||
if !self.enabled() || !self.config.settings.enabled_code_lens() {
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier)
|
||||||
|
|| !self.config.workspace_settings.enabled_code_lens()
|
||||||
|
{
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("code_lens");
|
let mark = self.performance.mark("code_lens");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
|
||||||
let line_index = self.get_line_index_sync(&specifier).unwrap();
|
let line_index = self.get_line_index_sync(&specifier).unwrap();
|
||||||
let navigation_tree =
|
let navigation_tree =
|
||||||
self.get_navigation_tree(&specifier).await.map_err(|err| {
|
self.get_navigation_tree(&specifier).await.map_err(|err| {
|
||||||
|
@ -1037,7 +1081,7 @@ impl Inner {
|
||||||
let mut code_lenses = cl.borrow_mut();
|
let mut code_lenses = cl.borrow_mut();
|
||||||
|
|
||||||
// TSC Implementations Code Lens
|
// TSC Implementations Code Lens
|
||||||
if self.config.settings.code_lens.implementations {
|
if self.config.workspace_settings.code_lens.implementations {
|
||||||
let source = CodeLensSource::Implementations;
|
let source = CodeLensSource::Implementations;
|
||||||
match i.kind {
|
match i.kind {
|
||||||
tsc::ScriptElementKind::InterfaceElement => {
|
tsc::ScriptElementKind::InterfaceElement => {
|
||||||
|
@ -1061,7 +1105,7 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TSC References Code Lens
|
// TSC References Code Lens
|
||||||
if self.config.settings.code_lens.references {
|
if self.config.workspace_settings.code_lens.references {
|
||||||
let source = CodeLensSource::References;
|
let source = CodeLensSource::References;
|
||||||
if let Some(parent) = &mp {
|
if let Some(parent) = &mp {
|
||||||
if parent.kind == tsc::ScriptElementKind::EnumElement {
|
if parent.kind == tsc::ScriptElementKind::EnumElement {
|
||||||
|
@ -1070,7 +1114,12 @@ impl Inner {
|
||||||
}
|
}
|
||||||
match i.kind {
|
match i.kind {
|
||||||
tsc::ScriptElementKind::FunctionElement => {
|
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(
|
code_lenses.push(i.to_code_lens(
|
||||||
&line_index,
|
&line_index,
|
||||||
&specifier,
|
&specifier,
|
||||||
|
@ -1317,16 +1366,17 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn document_highlight(
|
async fn document_highlight(
|
||||||
&self,
|
&mut self,
|
||||||
params: DocumentHighlightParams,
|
params: DocumentHighlightParams,
|
||||||
) -> LspResult<Option<Vec<DocumentHighlight>>> {
|
) -> LspResult<Option<Vec<DocumentHighlight>>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("document_highlight");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
.normalize_url(¶ms.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 =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
line_index
|
line_index
|
||||||
|
@ -1369,13 +1419,13 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: ReferenceParams,
|
params: ReferenceParams,
|
||||||
) -> LspResult<Option<Vec<Location>>> {
|
) -> LspResult<Option<Vec<Location>>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("references");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position.text_document.uri);
|
.normalize_url(¶ms.text_document_position.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let mark = self.performance.mark("references");
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
line_index
|
line_index
|
||||||
|
@ -1424,13 +1474,13 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: GotoDefinitionParams,
|
params: GotoDefinitionParams,
|
||||||
) -> LspResult<Option<GotoDefinitionResponse>> {
|
) -> LspResult<Option<GotoDefinitionResponse>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("goto_definition");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
.normalize_url(¶ms.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 =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
line_index
|
line_index
|
||||||
|
@ -1464,16 +1514,16 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn completion(
|
async fn completion(
|
||||||
&self,
|
&mut self,
|
||||||
params: CompletionParams,
|
params: CompletionParams,
|
||||||
) -> LspResult<Option<CompletionResponse>> {
|
) -> LspResult<Option<CompletionResponse>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("completion");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position.text_document.uri);
|
.normalize_url(¶ms.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
|
// Import specifiers are something wholly internal to Deno, so for
|
||||||
// completions, we will use internal logic and if there are completions
|
// 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
|
// 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 {
|
if let Some(completions) = maybe_completion_info {
|
||||||
let results = completions.as_completion_response(
|
let results = completions.as_completion_response(
|
||||||
&line_index,
|
&line_index,
|
||||||
&self.config.settings.suggest,
|
&self.config.workspace_settings.suggest,
|
||||||
&specifier,
|
&specifier,
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
|
@ -1583,13 +1633,13 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: GotoImplementationParams,
|
params: GotoImplementationParams,
|
||||||
) -> LspResult<Option<GotoImplementationResponse>> {
|
) -> LspResult<Option<GotoImplementationResponse>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("goto_implementation");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
.normalize_url(¶ms.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 =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
line_index
|
line_index
|
||||||
|
@ -1630,14 +1680,14 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn folding_range(
|
async fn folding_range(
|
||||||
&self,
|
&mut self,
|
||||||
params: FoldingRangeParams,
|
params: FoldingRangeParams,
|
||||||
) -> LspResult<Option<Vec<FoldingRange>>> {
|
) -> LspResult<Option<Vec<FoldingRange>>> {
|
||||||
if !self.enabled() {
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let mark = self.performance.mark("folding_range");
|
let mark = self.performance.mark("folding_range");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
|
||||||
|
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
|
@ -1690,11 +1740,11 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: CallHierarchyIncomingCallsParams,
|
params: CallHierarchyIncomingCallsParams,
|
||||||
) -> LspResult<Option<Vec<CallHierarchyIncomingCall>>> {
|
) -> LspResult<Option<Vec<CallHierarchyIncomingCall>>> {
|
||||||
if !self.enabled() {
|
let specifier = self.url_map.normalize_url(¶ms.item.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let mark = self.performance.mark("incoming_calls");
|
let mark = self.performance.mark("incoming_calls");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.item.uri);
|
|
||||||
|
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
|
@ -1744,11 +1794,11 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: CallHierarchyOutgoingCallsParams,
|
params: CallHierarchyOutgoingCallsParams,
|
||||||
) -> LspResult<Option<Vec<CallHierarchyOutgoingCall>>> {
|
) -> LspResult<Option<Vec<CallHierarchyOutgoingCall>>> {
|
||||||
if !self.enabled() {
|
let specifier = self.url_map.normalize_url(¶ms.item.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let mark = self.performance.mark("outgoing_calls");
|
let mark = self.performance.mark("outgoing_calls");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.item.uri);
|
|
||||||
|
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
|
@ -1799,13 +1849,13 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: CallHierarchyPrepareParams,
|
params: CallHierarchyPrepareParams,
|
||||||
) -> LspResult<Option<Vec<CallHierarchyItem>>> {
|
) -> LspResult<Option<Vec<CallHierarchyItem>>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("prepare_call_hierarchy");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
.normalize_url(¶ms.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 =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
|
@ -1876,13 +1926,13 @@ impl Inner {
|
||||||
&mut self,
|
&mut self,
|
||||||
params: RenameParams,
|
params: RenameParams,
|
||||||
) -> LspResult<Option<WorkspaceEdit>> {
|
) -> LspResult<Option<WorkspaceEdit>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("rename");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position.text_document.uri);
|
.normalize_url(¶ms.text_document_position.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let mark = self.performance.mark("rename");
|
||||||
|
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
|
@ -1963,14 +2013,14 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn selection_range(
|
async fn selection_range(
|
||||||
&self,
|
&mut self,
|
||||||
params: SelectionRangeParams,
|
params: SelectionRangeParams,
|
||||||
) -> LspResult<Option<Vec<SelectionRange>>> {
|
) -> LspResult<Option<Vec<SelectionRange>>> {
|
||||||
if !self.enabled() {
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let mark = self.performance.mark("selection_range");
|
let mark = self.performance.mark("selection_range");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
|
||||||
|
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
|
@ -2005,14 +2055,14 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn semantic_tokens_full(
|
async fn semantic_tokens_full(
|
||||||
&self,
|
&mut self,
|
||||||
params: SemanticTokensParams,
|
params: SemanticTokensParams,
|
||||||
) -> LspResult<Option<SemanticTokensResult>> {
|
) -> LspResult<Option<SemanticTokensResult>> {
|
||||||
if !self.enabled() {
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let mark = self.performance.mark("semantic_tokens_full");
|
let mark = self.performance.mark("semantic_tokens_full");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
|
||||||
|
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
|
@ -2052,14 +2102,14 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn semantic_tokens_range(
|
async fn semantic_tokens_range(
|
||||||
&self,
|
&mut self,
|
||||||
params: SemanticTokensRangeParams,
|
params: SemanticTokensRangeParams,
|
||||||
) -> LspResult<Option<SemanticTokensRangeResult>> {
|
) -> LspResult<Option<SemanticTokensRangeResult>> {
|
||||||
if !self.enabled() {
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
|
if !self.config.specifier_enabled(&specifier) {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let mark = self.performance.mark("semantic_tokens_range");
|
let mark = self.performance.mark("semantic_tokens_range");
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
|
||||||
|
|
||||||
let line_index =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
|
@ -2098,16 +2148,16 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn signature_help(
|
async fn signature_help(
|
||||||
&self,
|
&mut self,
|
||||||
params: SignatureHelpParams,
|
params: SignatureHelpParams,
|
||||||
) -> LspResult<Option<SignatureHelp>> {
|
) -> LspResult<Option<SignatureHelp>> {
|
||||||
if !self.enabled() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mark = self.performance.mark("signature_help");
|
|
||||||
let specifier = self
|
let specifier = self
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
.normalize_url(¶ms.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 =
|
let line_index =
|
||||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||||
line_index
|
line_index
|
||||||
|
|
|
@ -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
|
/// 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
|
/// specifiers. We need to map internal specifiers into `deno:` schema URLs
|
||||||
/// to allow the Deno language server to manage these as virtual documents.
|
/// to allow the Deno language server to manage these as virtual documents.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct LspUrlMap {
|
pub struct LspUrlMap {
|
||||||
specifier_to_url: HashMap<ModuleSpecifier, Url>,
|
specifier_to_url: HashMap<ModuleSpecifier, Url>,
|
||||||
url_to_specifier: HashMap<Url, ModuleSpecifier>,
|
url_to_specifier: HashMap<Url, ModuleSpecifier>,
|
||||||
|
|
|
@ -114,3 +114,16 @@ compiler. Its main purpose is to ensure that TypeScript and JavaScript can run
|
||||||
under Deno. The secondary ability to do TypeScript and JavaScript emitting via
|
under Deno. The secondary ability to do TypeScript and JavaScript emitting via
|
||||||
the runtime API `Deno.emit()` is intended to be simple and straight forward and
|
the runtime API `Deno.emit()` is intended to be simple and straight forward and
|
||||||
support a certain set of use cases.
|
support a certain set of use cases.
|
||||||
|
|
||||||
|
### How do I combine Deno code with non-Deno code in my IDE?
|
||||||
|
|
||||||
|
The Deno language server supports the ability to have a "per-resource"
|
||||||
|
configuration of enabling Deno or not. This also requires a client IDE to
|
||||||
|
support this ability. For Visual Studio Code the official
|
||||||
|
[Deno extension](https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno)
|
||||||
|
supports the vscode concept of
|
||||||
|
[multi-root workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces).
|
||||||
|
This means you just need to add folders to the workspace and set the
|
||||||
|
`deno.enable` setting as required on each folder.
|
||||||
|
|
||||||
|
For other IDEs, the client extensions needs to support the similar IDE concepts.
|
||||||
|
|
Loading…
Reference in a new issue