mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
refactor(lsp): prefer using document instead of documents collection (#12720)
This commit is contained in:
parent
fdf890a68d
commit
28dbb4a95e
7 changed files with 728 additions and 897 deletions
|
@ -220,9 +220,9 @@ async fn resolve_implementation_code_lens(
|
||||||
data: CodeLensData,
|
data: CodeLensData,
|
||||||
language_server: &mut language_server::Inner,
|
language_server: &mut language_server::Inner,
|
||||||
) -> Result<lsp::CodeLens, AnyError> {
|
) -> Result<lsp::CodeLens, AnyError> {
|
||||||
let line_index = language_server
|
let asset_or_doc =
|
||||||
.get_line_index_sync(&data.specifier)
|
language_server.get_cached_asset_or_document(&data.specifier)?;
|
||||||
.unwrap();
|
let line_index = asset_or_doc.line_index();
|
||||||
let req = tsc::RequestMethod::GetImplementation((
|
let req = tsc::RequestMethod::GetImplementation((
|
||||||
data.specifier.clone(),
|
data.specifier.clone(),
|
||||||
line_index.offset_tsc(code_lens.range.start)?,
|
line_index.offset_tsc(code_lens.range.start)?,
|
||||||
|
@ -289,9 +289,9 @@ async fn resolve_references_code_lens(
|
||||||
data: CodeLensData,
|
data: CodeLensData,
|
||||||
language_server: &mut language_server::Inner,
|
language_server: &mut language_server::Inner,
|
||||||
) -> Result<lsp::CodeLens, AnyError> {
|
) -> Result<lsp::CodeLens, AnyError> {
|
||||||
let line_index = language_server
|
let asset_or_document =
|
||||||
.get_line_index_sync(&data.specifier)
|
language_server.get_cached_asset_or_document(&data.specifier)?;
|
||||||
.unwrap();
|
let line_index = asset_or_document.line_index();
|
||||||
let req = tsc::RequestMethod::GetReferences((
|
let req = tsc::RequestMethod::GetReferences((
|
||||||
data.specifier.clone(),
|
data.specifier.clone(),
|
||||||
line_index.offset_tsc(code_lens.range.start)?,
|
line_index.offset_tsc(code_lens.range.start)?,
|
||||||
|
@ -307,9 +307,12 @@ async fn resolve_references_code_lens(
|
||||||
}
|
}
|
||||||
let reference_specifier =
|
let reference_specifier =
|
||||||
resolve_url(&reference.document_span.file_name)?;
|
resolve_url(&reference.document_span.file_name)?;
|
||||||
let line_index =
|
let asset_or_doc = language_server
|
||||||
language_server.get_line_index(reference_specifier).await?;
|
.get_asset_or_document(&reference_specifier)
|
||||||
locations.push(reference.to_location(line_index, language_server));
|
.await?;
|
||||||
|
locations.push(
|
||||||
|
reference.to_location(asset_or_doc.line_index(), language_server),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let command = if !locations.is_empty() {
|
let command = if !locations.is_empty() {
|
||||||
let title = if locations.len() > 1 {
|
let title = if locations.len() > 1 {
|
||||||
|
|
|
@ -114,9 +114,8 @@ pub(crate) async fn get_import_completions(
|
||||||
state_snapshot: &language_server::StateSnapshot,
|
state_snapshot: &language_server::StateSnapshot,
|
||||||
client: lspower::Client,
|
client: lspower::Client,
|
||||||
) -> Option<lsp::CompletionResponse> {
|
) -> Option<lsp::CompletionResponse> {
|
||||||
let (text, _, range) = state_snapshot
|
let document = state_snapshot.documents.get(specifier)?;
|
||||||
.documents
|
let (text, _, range) = document.get_maybe_dependency(position)?;
|
||||||
.get_maybe_dependency(specifier, position)?;
|
|
||||||
let range = to_narrow_lsp_range(&range);
|
let range = to_narrow_lsp_range(&range);
|
||||||
// completions for local relative modules
|
// completions for local relative modules
|
||||||
if text.starts_with("./") || text.starts_with("../") {
|
if text.starts_with("./") || text.starts_with("../") {
|
||||||
|
@ -134,7 +133,9 @@ pub(crate) async fn get_import_completions(
|
||||||
};
|
};
|
||||||
let maybe_items = state_snapshot
|
let maybe_items = state_snapshot
|
||||||
.module_registries
|
.module_registries
|
||||||
.get_completions(&text, offset, &range, state_snapshot)
|
.get_completions(&text, offset, &range, |specifier| {
|
||||||
|
state_snapshot.documents.contains_specifier(specifier)
|
||||||
|
})
|
||||||
.await;
|
.await;
|
||||||
let items = maybe_items.unwrap_or_else(|| {
|
let items = maybe_items.unwrap_or_else(|| {
|
||||||
get_workspace_completions(specifier, &text, &range, state_snapshot)
|
get_workspace_completions(specifier, &text, &range, state_snapshot)
|
||||||
|
@ -276,7 +277,12 @@ fn get_workspace_completions(
|
||||||
range: &lsp::Range,
|
range: &lsp::Range,
|
||||||
state_snapshot: &language_server::StateSnapshot,
|
state_snapshot: &language_server::StateSnapshot,
|
||||||
) -> Vec<lsp::CompletionItem> {
|
) -> Vec<lsp::CompletionItem> {
|
||||||
let workspace_specifiers = state_snapshot.documents.specifiers(false, true);
|
let workspace_specifiers = state_snapshot
|
||||||
|
.documents
|
||||||
|
.documents(false, true)
|
||||||
|
.into_iter()
|
||||||
|
.map(|d| d.specifier().clone())
|
||||||
|
.collect();
|
||||||
let specifier_strings =
|
let specifier_strings =
|
||||||
get_relative_specifiers(specifier, workspace_specifiers);
|
get_relative_specifiers(specifier, workspace_specifiers);
|
||||||
specifier_strings
|
specifier_strings
|
||||||
|
@ -449,7 +455,7 @@ mod tests {
|
||||||
.set(&specifier, HashMap::default(), source.as_bytes())
|
.set(&specifier, HashMap::default(), source.as_bytes())
|
||||||
.expect("could not cache file");
|
.expect("could not cache file");
|
||||||
assert!(
|
assert!(
|
||||||
documents.content(&specifier).is_some(),
|
documents.get(&specifier).is_some(),
|
||||||
"source could not be setup"
|
"source could not be setup"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,20 +303,20 @@ async fn generate_lint_diagnostics(
|
||||||
snapshot: &language_server::StateSnapshot,
|
snapshot: &language_server::StateSnapshot,
|
||||||
collection: Arc<Mutex<DiagnosticCollection>>,
|
collection: Arc<Mutex<DiagnosticCollection>>,
|
||||||
) -> Result<DiagnosticVec, AnyError> {
|
) -> Result<DiagnosticVec, AnyError> {
|
||||||
let documents = snapshot.documents.clone();
|
let documents = snapshot.documents.documents(true, true);
|
||||||
let workspace_settings = snapshot.config.settings.workspace.clone();
|
let workspace_settings = snapshot.config.settings.workspace.clone();
|
||||||
let maybe_lint_config = snapshot.maybe_lint_config.clone();
|
let maybe_lint_config = snapshot.maybe_lint_config.clone();
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
let mut diagnostics_vec = Vec::new();
|
let mut diagnostics_vec = Vec::new();
|
||||||
if workspace_settings.lint {
|
if workspace_settings.lint {
|
||||||
for specifier in documents.specifiers(true, true) {
|
for document in documents {
|
||||||
let version = documents.lsp_version(&specifier);
|
let version = document.maybe_lsp_version();
|
||||||
let current_version = collection
|
let current_version = collection
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.get_version(&specifier, &DiagnosticSource::DenoLint);
|
.get_version(document.specifier(), &DiagnosticSource::DenoLint);
|
||||||
if version != current_version {
|
if version != current_version {
|
||||||
let diagnostics = match documents.parsed_source(&specifier) {
|
let diagnostics = match document.maybe_parsed_source() {
|
||||||
Some(Ok(parsed_source)) => {
|
Some(Ok(parsed_source)) => {
|
||||||
if let Ok(references) = analysis::get_lint_references(
|
if let Ok(references) = analysis::get_lint_references(
|
||||||
&parsed_source,
|
&parsed_source,
|
||||||
|
@ -332,11 +332,15 @@ async fn generate_lint_diagnostics(
|
||||||
}
|
}
|
||||||
Some(Err(_)) => Vec::new(),
|
Some(Err(_)) => Vec::new(),
|
||||||
None => {
|
None => {
|
||||||
error!("Missing file contents for: {}", specifier);
|
error!("Missing file contents for: {}", document.specifier());
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
diagnostics_vec.push((specifier.clone(), version, diagnostics));
|
diagnostics_vec.push((
|
||||||
|
document.specifier().clone(),
|
||||||
|
version,
|
||||||
|
diagnostics,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,14 +360,14 @@ async fn generate_ts_diagnostics(
|
||||||
let collection = collection.lock().await;
|
let collection = collection.lock().await;
|
||||||
snapshot
|
snapshot
|
||||||
.documents
|
.documents
|
||||||
.specifiers(true, true)
|
.documents(true, true)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|s| {
|
.filter_map(|d| {
|
||||||
let version = snapshot.documents.lsp_version(s);
|
let version = d.maybe_lsp_version();
|
||||||
let current_version =
|
let current_version =
|
||||||
collection.get_version(s, &DiagnosticSource::TypeScript);
|
collection.get_version(d.specifier(), &DiagnosticSource::TypeScript);
|
||||||
if version != current_version {
|
if version != current_version {
|
||||||
Some(s.clone())
|
Some(d.specifier().clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -376,7 +380,11 @@ async fn generate_ts_diagnostics(
|
||||||
ts_server.request(snapshot.clone(), req).await?;
|
ts_server.request(snapshot.clone(), req).await?;
|
||||||
for (specifier_str, ts_diagnostics) in ts_diagnostics_map {
|
for (specifier_str, ts_diagnostics) in ts_diagnostics_map {
|
||||||
let specifier = resolve_url(&specifier_str)?;
|
let specifier = resolve_url(&specifier_str)?;
|
||||||
let version = snapshot.documents.lsp_version(&specifier);
|
let version = snapshot
|
||||||
|
.documents
|
||||||
|
.get(&specifier)
|
||||||
|
.map(|d| d.maybe_lsp_version())
|
||||||
|
.flatten();
|
||||||
diagnostics_vec.push((
|
diagnostics_vec.push((
|
||||||
specifier,
|
specifier,
|
||||||
version,
|
version,
|
||||||
|
@ -421,7 +429,18 @@ fn diagnose_dependency(
|
||||||
) {
|
) {
|
||||||
match resolved {
|
match resolved {
|
||||||
Some(Ok((specifier, range))) => {
|
Some(Ok((specifier, range))) => {
|
||||||
if !documents.contains_specifier(specifier) {
|
if let Some(doc) = documents.get(specifier) {
|
||||||
|
if let Some(message) = doc.maybe_warning() {
|
||||||
|
diagnostics.push(lsp::Diagnostic {
|
||||||
|
range: documents::to_lsp_range(range),
|
||||||
|
severity: Some(lsp::DiagnosticSeverity::Warning),
|
||||||
|
code: Some(lsp::NumberOrString::String("deno-warn".to_string())),
|
||||||
|
source: Some("deno".to_string()),
|
||||||
|
message,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let (code, message) = match specifier.scheme() {
|
let (code, message) = match specifier.scheme() {
|
||||||
"file" => (Some(lsp::NumberOrString::String("no-local".to_string())), format!("Unable to load a local module: \"{}\".\n Please check the file path.", specifier)),
|
"file" => (Some(lsp::NumberOrString::String("no-local".to_string())), format!("Unable to load a local module: \"{}\".\n Please check the file path.", specifier)),
|
||||||
"data" => (Some(lsp::NumberOrString::String("no-cache-data".to_string())), "Uncached data URL.".to_string()),
|
"data" => (Some(lsp::NumberOrString::String("no-cache-data".to_string())), "Uncached data URL.".to_string()),
|
||||||
|
@ -437,15 +456,6 @@ fn diagnose_dependency(
|
||||||
data: Some(json!({ "specifier": specifier })),
|
data: Some(json!({ "specifier": specifier })),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
} else if let Some(message) = documents.maybe_warning(specifier) {
|
|
||||||
diagnostics.push(lsp::Diagnostic {
|
|
||||||
range: documents::to_lsp_range(range),
|
|
||||||
severity: Some(lsp::DiagnosticSeverity::Warning),
|
|
||||||
code: Some(lsp::NumberOrString::String("deno-warn".to_string())),
|
|
||||||
source: Some("deno".to_string()),
|
|
||||||
message,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Err(err)) => diagnostics.push(lsp::Diagnostic {
|
Some(Err(err)) => diagnostics.push(lsp::Diagnostic {
|
||||||
|
@ -471,18 +481,18 @@ async fn generate_deps_diagnostics(
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
let mut diagnostics_vec = Vec::new();
|
let mut diagnostics_vec = Vec::new();
|
||||||
|
|
||||||
for specifier in documents.specifiers(true, true) {
|
for document in documents.documents(true, true) {
|
||||||
if !config.specifier_enabled(&specifier) {
|
if !config.specifier_enabled(document.specifier()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let version = documents.lsp_version(&specifier);
|
let version = document.maybe_lsp_version();
|
||||||
let current_version = collection
|
let current_version = collection
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.get_version(&specifier, &DiagnosticSource::Deno);
|
.get_version(document.specifier(), &DiagnosticSource::Deno);
|
||||||
if version != current_version {
|
if version != current_version {
|
||||||
let mut diagnostics = Vec::new();
|
let mut diagnostics = Vec::new();
|
||||||
if let Some(dependencies) = documents.dependencies(&specifier) {
|
if let Some(dependencies) = document.dependencies() {
|
||||||
for (_, dependency) in dependencies {
|
for (_, dependency) in dependencies {
|
||||||
diagnose_dependency(
|
diagnose_dependency(
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
|
@ -496,7 +506,11 @@ async fn generate_deps_diagnostics(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
diagnostics_vec.push((specifier.clone(), version, diagnostics));
|
diagnostics_vec.push((
|
||||||
|
document.specifier().clone(),
|
||||||
|
version,
|
||||||
|
diagnostics,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,9 +547,14 @@ async fn publish_diagnostics(
|
||||||
diagnostics
|
diagnostics
|
||||||
.extend(collection.get(&specifier, DiagnosticSource::Deno).cloned());
|
.extend(collection.get(&specifier, DiagnosticSource::Deno).cloned());
|
||||||
}
|
}
|
||||||
let uri = specifier.clone();
|
let version = snapshot
|
||||||
let version = snapshot.documents.lsp_version(&specifier);
|
.documents
|
||||||
client.publish_diagnostics(uri, diagnostics, version).await;
|
.get(&specifier)
|
||||||
|
.map(|d| d.maybe_lsp_version())
|
||||||
|
.flatten();
|
||||||
|
client
|
||||||
|
.publish_diagnostics(specifier.clone(), diagnostics, version)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -678,7 +697,7 @@ mod tests {
|
||||||
let (snapshot, collection, _) = setup(&[(
|
let (snapshot, collection, _) = setup(&[(
|
||||||
"file:///a.ts",
|
"file:///a.ts",
|
||||||
r#"import * as b from "./b.ts";
|
r#"import * as b from "./b.ts";
|
||||||
|
|
||||||
let a = "a";
|
let a = "a";
|
||||||
console.log(a);
|
console.log(a);
|
||||||
"#,
|
"#,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -39,6 +39,7 @@ use super::diagnostics;
|
||||||
use super::diagnostics::DiagnosticSource;
|
use super::diagnostics::DiagnosticSource;
|
||||||
use super::documents::to_hover_text;
|
use super::documents::to_hover_text;
|
||||||
use super::documents::to_lsp_range;
|
use super::documents::to_lsp_range;
|
||||||
|
use super::documents::AssetOrDocument;
|
||||||
use super::documents::Documents;
|
use super::documents::Documents;
|
||||||
use super::documents::LanguageId;
|
use super::documents::LanguageId;
|
||||||
use super::lsp_custom;
|
use super::lsp_custom;
|
||||||
|
@ -47,7 +48,6 @@ use super::performance::Performance;
|
||||||
use super::refactor;
|
use super::refactor;
|
||||||
use super::registries;
|
use super::registries;
|
||||||
use super::text;
|
use super::text;
|
||||||
use super::text::LineIndex;
|
|
||||||
use super::tsc;
|
use super::tsc;
|
||||||
use super::tsc::AssetDocument;
|
use super::tsc::AssetDocument;
|
||||||
use super::tsc::Assets;
|
use super::tsc::Assets;
|
||||||
|
@ -171,71 +171,82 @@ impl Inner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Searches assets, open documents and external sources for a line_index,
|
/// Searches assets and open documents which might be performed asynchronously,
|
||||||
/// which might be performed asynchronously, hydrating in memory caches for
|
/// hydrating in memory caches for subsequent requests.
|
||||||
/// subsequent requests.
|
pub(crate) async fn get_asset_or_document(
|
||||||
pub(crate) async fn get_line_index(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
specifier: ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Result<Arc<LineIndex>, AnyError> {
|
) -> LspResult<AssetOrDocument> {
|
||||||
let mark = self
|
self
|
||||||
.performance
|
.get_maybe_asset_or_document(specifier)
|
||||||
.mark("get_line_index", Some(json!({ "specifier": specifier })));
|
.await?
|
||||||
let result = if specifier.scheme() == "asset" {
|
.map_or_else(
|
||||||
if let Some(asset) = self.get_asset(&specifier).await? {
|
|| {
|
||||||
Ok(asset.line_index)
|
Err(LspError::invalid_params(format!(
|
||||||
} else {
|
"Unable to find asset or document for: {}",
|
||||||
Err(anyhow!("asset is missing: {}", specifier))
|
specifier
|
||||||
}
|
)))
|
||||||
} else if let Some(line_index) = self.documents.line_index(&specifier) {
|
},
|
||||||
Ok(line_index)
|
Ok,
|
||||||
} else {
|
)
|
||||||
Err(anyhow!("Unable to find line index for: {}", specifier))
|
|
||||||
};
|
|
||||||
self.performance.measure(mark);
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only searches already cached assets and documents for a line index. If
|
/// Searches assets and open documents which might be performed asynchronously,
|
||||||
/// the line index cannot be found, `None` is returned.
|
/// hydrating in memory caches for subsequent requests.
|
||||||
pub fn get_line_index_sync(
|
pub(crate) async fn get_maybe_asset_or_document(
|
||||||
&self,
|
&mut self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Option<Arc<LineIndex>> {
|
) -> LspResult<Option<AssetOrDocument>> {
|
||||||
let mark = self.performance.mark(
|
let mark = self.performance.mark(
|
||||||
"get_line_index_sync",
|
"get_maybe_asset_or_document",
|
||||||
Some(json!({ "specifier": specifier })),
|
Some(json!({ "specifier": specifier })),
|
||||||
);
|
);
|
||||||
let maybe_line_index = if specifier.scheme() == "asset" {
|
let result = if specifier.scheme() == "asset" {
|
||||||
if let Some(Some(asset)) = self.assets.get(specifier) {
|
self.get_asset(specifier).await?.map(AssetOrDocument::Asset)
|
||||||
Some(asset.line_index.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.documents.line_index(specifier)
|
self.documents.get(specifier).map(AssetOrDocument::Document)
|
||||||
};
|
};
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
maybe_line_index
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(@kitsonk) we really should find a better way to just return the
|
/// Only searches already cached assets and documents. If
|
||||||
// content as a `&str`, or be able to get the byte at a particular offset
|
/// the asset or document cannot be found an error is returned.
|
||||||
// which is all that this API that is consuming it is trying to do at the
|
pub(crate) fn get_cached_asset_or_document(
|
||||||
// moment
|
|
||||||
/// Searches already cached assets and documents and returns its text
|
|
||||||
/// content. If not found, `None` is returned.
|
|
||||||
pub(crate) fn get_text_content(
|
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Option<Arc<String>> {
|
) -> LspResult<AssetOrDocument> {
|
||||||
|
self
|
||||||
|
.get_maybe_cached_asset_or_document(specifier)
|
||||||
|
.map_or_else(
|
||||||
|
|| {
|
||||||
|
Err(LspError::invalid_params(format!(
|
||||||
|
"An unexpected specifier ({}) was provided.",
|
||||||
|
specifier
|
||||||
|
)))
|
||||||
|
},
|
||||||
|
Ok,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only searches already cached assets and documents. If
|
||||||
|
/// the asset or document cannot be found, `None` is returned.
|
||||||
|
pub(crate) fn get_maybe_cached_asset_or_document(
|
||||||
|
&self,
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
) -> Option<AssetOrDocument> {
|
||||||
if specifier.scheme() == "asset" {
|
if specifier.scheme() == "asset" {
|
||||||
self
|
self
|
||||||
.assets
|
.assets
|
||||||
.get(specifier)
|
.get(specifier)
|
||||||
.map(|o| o.clone().map(|a| a.text))?
|
.map(|maybe_asset| {
|
||||||
|
maybe_asset
|
||||||
|
.as_ref()
|
||||||
|
.map(|asset| AssetOrDocument::Asset(asset.clone()))
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
} else {
|
} else {
|
||||||
self.documents.content(specifier)
|
self.documents.get(specifier).map(AssetOrDocument::Document)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,33 +258,30 @@ impl Inner {
|
||||||
"get_navigation_tree",
|
"get_navigation_tree",
|
||||||
Some(json!({ "specifier": specifier })),
|
Some(json!({ "specifier": specifier })),
|
||||||
);
|
);
|
||||||
let maybe_navigation_tree = if specifier.scheme() == "asset" {
|
let asset_or_doc = self.get_cached_asset_or_document(specifier)?;
|
||||||
self.assets.get_navigation_tree(specifier)
|
let navigation_tree =
|
||||||
} else {
|
if let Some(navigation_tree) = asset_or_doc.maybe_navigation_tree() {
|
||||||
self.documents.get_navigation_tree(specifier)
|
navigation_tree
|
||||||
};
|
|
||||||
let navigation_tree = if let Some(navigation_tree) = maybe_navigation_tree {
|
|
||||||
navigation_tree
|
|
||||||
} else {
|
|
||||||
let navigation_tree: tsc::NavigationTree = self
|
|
||||||
.ts_server
|
|
||||||
.request(
|
|
||||||
self.snapshot()?,
|
|
||||||
tsc::RequestMethod::GetNavigationTree(specifier.clone()),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let navigation_tree = Arc::new(navigation_tree);
|
|
||||||
if specifier.scheme() == "asset" {
|
|
||||||
self
|
|
||||||
.assets
|
|
||||||
.set_navigation_tree(specifier, navigation_tree.clone())?;
|
|
||||||
} else {
|
} else {
|
||||||
self
|
let navigation_tree: tsc::NavigationTree = self
|
||||||
.documents
|
.ts_server
|
||||||
.set_navigation_tree(specifier, navigation_tree.clone())?;
|
.request(
|
||||||
}
|
self.snapshot()?,
|
||||||
navigation_tree
|
tsc::RequestMethod::GetNavigationTree(specifier.clone()),
|
||||||
};
|
)
|
||||||
|
.await?;
|
||||||
|
let navigation_tree = Arc::new(navigation_tree);
|
||||||
|
if specifier.scheme() == "asset" {
|
||||||
|
self
|
||||||
|
.assets
|
||||||
|
.set_navigation_tree(specifier, navigation_tree.clone())?;
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
.documents
|
||||||
|
.set_navigation_tree(specifier, navigation_tree.clone())?;
|
||||||
|
}
|
||||||
|
navigation_tree
|
||||||
|
};
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
Ok(navigation_tree)
|
Ok(navigation_tree)
|
||||||
}
|
}
|
||||||
|
@ -335,7 +343,11 @@ impl Inner {
|
||||||
| MediaType::Dts
|
| MediaType::Dts
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.documents.is_diagnosable(specifier)
|
self
|
||||||
|
.documents
|
||||||
|
.get(specifier)
|
||||||
|
.map(|d| d.is_diagnosable())
|
||||||
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,22 +606,20 @@ impl Inner {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn document_version(
|
|
||||||
&self,
|
|
||||||
specifier: &ModuleSpecifier,
|
|
||||||
) -> Option<i32> {
|
|
||||||
self.documents.lsp_version(specifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_asset(
|
async fn get_asset(
|
||||||
&mut self,
|
&mut self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Result<Option<AssetDocument>, AnyError> {
|
) -> LspResult<Option<AssetDocument>> {
|
||||||
if let Some(maybe_asset) = self.assets.get(specifier) {
|
if let Some(maybe_asset) = self.assets.get(specifier) {
|
||||||
Ok(maybe_asset.clone())
|
Ok(maybe_asset.clone())
|
||||||
} else {
|
} else {
|
||||||
let maybe_asset =
|
let maybe_asset =
|
||||||
tsc::get_asset(specifier, &self.ts_server, self.snapshot()?).await?;
|
tsc::get_asset(specifier, &self.ts_server, self.snapshot()?)
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
error!("Error getting asset {}: {}", specifier, err);
|
||||||
|
LspError::internal_error()
|
||||||
|
})?;
|
||||||
self.assets.insert(specifier.clone(), maybe_asset.clone());
|
self.assets.insert(specifier.clone(), maybe_asset.clone());
|
||||||
Ok(maybe_asset)
|
Ok(maybe_asset)
|
||||||
}
|
}
|
||||||
|
@ -783,14 +793,14 @@ impl Inner {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let content = Arc::new(params.text_document.text);
|
let content = Arc::new(params.text_document.text);
|
||||||
self.documents.open(
|
let document = self.documents.open(
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
params.text_document.version,
|
params.text_document.version,
|
||||||
params.text_document.language_id.parse().unwrap(),
|
params.text_document.language_id.parse().unwrap(),
|
||||||
content,
|
content,
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.is_diagnosable(&specifier) {
|
if document.is_diagnosable() {
|
||||||
self
|
self
|
||||||
.diagnostics_server
|
.diagnostics_server
|
||||||
.invalidate(self.documents.dependents(&specifier))
|
.invalidate(self.documents.dependents(&specifier))
|
||||||
|
@ -811,8 +821,8 @@ impl Inner {
|
||||||
params.text_document.version,
|
params.text_document.version,
|
||||||
params.content_changes,
|
params.content_changes,
|
||||||
) {
|
) {
|
||||||
Ok(()) => {
|
Ok(document) => {
|
||||||
if self.is_diagnosable(&specifier) {
|
if document.is_diagnosable() {
|
||||||
self
|
self
|
||||||
.diagnostics_server
|
.diagnostics_server
|
||||||
.invalidate(self.documents.dependents(&specifier))
|
.invalidate(self.documents.dependents(&specifier))
|
||||||
|
@ -974,16 +984,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("document_symbol", Some(¶ms));
|
let mark = self.performance.mark("document_symbol", Some(¶ms));
|
||||||
|
let asset_or_document = self.get_cached_asset_or_document(&specifier)?;
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let line_index = asset_or_document.line_index();
|
||||||
|| {
|
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let req = tsc::RequestMethod::GetNavigationTree(specifier);
|
let req = tsc::RequestMethod::GetNavigationTree(specifier);
|
||||||
let navigation_tree: tsc::NavigationTree = self
|
let navigation_tree: tsc::NavigationTree = self
|
||||||
|
@ -1014,9 +1016,10 @@ impl Inner {
|
||||||
params: DocumentFormattingParams,
|
params: DocumentFormattingParams,
|
||||||
) -> LspResult<Option<Vec<TextEdit>>> {
|
) -> LspResult<Option<Vec<TextEdit>>> {
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
if !self.documents.is_formattable(&specifier) {
|
let document = match self.documents.get(&specifier) {
|
||||||
return Ok(None);
|
Some(doc) if doc.is_open() => doc,
|
||||||
}
|
_ => return Ok(None),
|
||||||
|
};
|
||||||
let mark = self.performance.mark("formatting", Some(¶ms));
|
let mark = self.performance.mark("formatting", Some(¶ms));
|
||||||
let file_path =
|
let file_path =
|
||||||
if let Ok(file_path) = params.text_document.uri.to_file_path() {
|
if let Ok(file_path) = params.text_document.uri.to_file_path() {
|
||||||
|
@ -1031,34 +1034,23 @@ impl Inner {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let content = self.documents.content(&specifier).map_or_else(
|
|
||||||
|| {
|
|
||||||
Err(LspError::invalid_params(
|
|
||||||
"The specified file could not be found in memory.",
|
|
||||||
))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
let line_index = self.documents.line_index(&specifier).unwrap();
|
|
||||||
let maybe_parsed_source = self.documents.parsed_source(&specifier);
|
|
||||||
|
|
||||||
let text_edits = tokio::task::spawn_blocking(move || {
|
let text_edits = tokio::task::spawn_blocking(move || {
|
||||||
let format_result = match maybe_parsed_source {
|
let format_result = match document.maybe_parsed_source() {
|
||||||
Some(Ok(parsed_source)) => {
|
Some(Ok(parsed_source)) => {
|
||||||
format_parsed_source(&parsed_source, fmt_options)
|
format_parsed_source(&parsed_source, fmt_options)
|
||||||
}
|
}
|
||||||
Some(Err(err)) => Err(err.to_string()),
|
Some(Err(err)) => Err(err.to_string()),
|
||||||
None => {
|
None => {
|
||||||
// it's not a js/ts file, so attempt to format its contents
|
// it's not a js/ts file, so attempt to format its contents
|
||||||
format_file(&file_path, content.as_str(), fmt_options)
|
format_file(&file_path, document.content().as_str(), fmt_options)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match format_result {
|
match format_result {
|
||||||
Ok(new_text) => Some(text::get_edits(
|
Ok(new_text) => Some(text::get_edits(
|
||||||
content.as_str(),
|
document.content().as_str(),
|
||||||
&new_text,
|
&new_text,
|
||||||
line_index.as_ref(),
|
document.line_index().as_ref(),
|
||||||
)),
|
)),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// TODO(lucacasonato): handle error properly
|
// TODO(lucacasonato): handle error properly
|
||||||
|
@ -1094,14 +1086,17 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("hover", Some(¶ms));
|
let mark = self.performance.mark("hover", Some(¶ms));
|
||||||
let hover = if let Some((_, dep, range)) =
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
self.documents.get_maybe_dependency(
|
let hover = if let Some((_, dep, range)) = asset_or_doc
|
||||||
&specifier,
|
.get_maybe_dependency(¶ms.text_document_position_params.position)
|
||||||
¶ms.text_document_position_params.position,
|
{
|
||||||
) {
|
let dep_maybe_types_dependency = dep
|
||||||
let maybe_types_dependency =
|
.get_code()
|
||||||
self.documents.get_maybe_types_for_dependency(&dep);
|
.map(|s| self.documents.get(s))
|
||||||
let value = match (&dep.maybe_code, &dep.maybe_type, &maybe_types_dependency) {
|
.flatten()
|
||||||
|
.map(|d| d.maybe_types_dependency())
|
||||||
|
.flatten();
|
||||||
|
let value = match (&dep.maybe_code, &dep.maybe_type, &dep_maybe_types_dependency) {
|
||||||
(Some(code_dep), Some(type_dep), None) => format!(
|
(Some(code_dep), Some(type_dep), None) => format!(
|
||||||
"**Resolved Dependency**\n\n**Code**: {}\n\n**Types**: {}\n",
|
"**Resolved Dependency**\n\n**Code**: {}\n\n**Types**: {}\n",
|
||||||
to_hover_text(code_dep),
|
to_hover_text(code_dep),
|
||||||
|
@ -1136,15 +1131,7 @@ impl Inner {
|
||||||
range: Some(to_lsp_range(&range)),
|
range: Some(to_lsp_range(&range)),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let line_index = asset_or_doc.line_index();
|
||||||
|| {
|
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
let req = tsc::RequestMethod::GetQuickInfo((
|
let req = tsc::RequestMethod::GetQuickInfo((
|
||||||
specifier,
|
specifier,
|
||||||
line_index.offset_tsc(params.text_document_position_params.position)?,
|
line_index.offset_tsc(params.text_document_position_params.position)?,
|
||||||
|
@ -1176,7 +1163,8 @@ impl Inner {
|
||||||
|
|
||||||
let mark = self.performance.mark("code_action", Some(¶ms));
|
let mark = self.performance.mark("code_action", Some(¶ms));
|
||||||
let mut all_actions = CodeActionResponse::new();
|
let mut all_actions = CodeActionResponse::new();
|
||||||
let line_index = self.get_line_index_sync(&specifier).unwrap();
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|
let line_index = asset_or_doc.line_index();
|
||||||
|
|
||||||
// QuickFix
|
// QuickFix
|
||||||
let fixable_diagnostics: Vec<&Diagnostic> = params
|
let fixable_diagnostics: Vec<&Diagnostic> = params
|
||||||
|
@ -1266,12 +1254,8 @@ impl Inner {
|
||||||
.add_deno_lint_ignore_action(
|
.add_deno_lint_ignore_action(
|
||||||
&specifier,
|
&specifier,
|
||||||
diagnostic,
|
diagnostic,
|
||||||
self.documents.text_info(&specifier),
|
asset_or_doc.document().map(|d| d.text_info()),
|
||||||
self
|
asset_or_doc.maybe_parsed_source().map(|r| r.ok()).flatten(),
|
||||||
.documents
|
|
||||||
.parsed_source(&specifier)
|
|
||||||
.map(|r| r.ok())
|
|
||||||
.flatten(),
|
|
||||||
)
|
)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
error!("Unable to fix lint error: {}", err);
|
error!("Unable to fix lint error: {}", err);
|
||||||
|
@ -1400,8 +1384,9 @@ impl Inner {
|
||||||
error!("Unable to decode code action data: {}", err);
|
error!("Unable to decode code action data: {}", err);
|
||||||
LspError::invalid_params("The CodeAction's data is invalid.")
|
LspError::invalid_params("The CodeAction's data is invalid.")
|
||||||
})?;
|
})?;
|
||||||
let line_index =
|
let asset_or_doc =
|
||||||
self.get_line_index_sync(&action_data.specifier).unwrap();
|
self.get_cached_asset_or_document(&action_data.specifier)?;
|
||||||
|
let line_index = asset_or_doc.line_index();
|
||||||
let start = line_index.offset_tsc(action_data.range.start)?;
|
let start = line_index.offset_tsc(action_data.range.start)?;
|
||||||
let length = line_index.offset_tsc(action_data.range.end)? - start;
|
let length = line_index.offset_tsc(action_data.range.end)? - start;
|
||||||
let req = tsc::RequestMethod::GetEditsForRefactor((
|
let req = tsc::RequestMethod::GetEditsForRefactor((
|
||||||
|
@ -1449,25 +1434,15 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("code_lens", Some(¶ms));
|
let mark = self.performance.mark("code_lens", Some(¶ms));
|
||||||
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
let navigation_tree =
|
let navigation_tree =
|
||||||
self.get_navigation_tree(&specifier).await.map_err(|err| {
|
self.get_navigation_tree(&specifier).await.map_err(|err| {
|
||||||
error!("Error getting code lenses for \"{}\": {}", specifier, err);
|
error!("Error getting code lenses for \"{}\": {}", specifier, err);
|
||||||
LspError::internal_error()
|
LspError::internal_error()
|
||||||
})?;
|
})?;
|
||||||
let parsed_source = self
|
let parsed_source =
|
||||||
.documents
|
asset_or_doc.maybe_parsed_source().map(|r| r.ok()).flatten();
|
||||||
.parsed_source(&specifier)
|
let line_index = asset_or_doc.line_index();
|
||||||
.map(|r| r.ok())
|
|
||||||
.flatten();
|
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
|
||||||
|| {
|
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
let code_lenses = code_lens::collect(
|
let code_lenses = code_lens::collect(
|
||||||
&specifier,
|
&specifier,
|
||||||
parsed_source,
|
parsed_source,
|
||||||
|
@ -1520,15 +1495,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("document_highlight", Some(¶ms));
|
let mark = self.performance.mark("document_highlight", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
let files_to_search = vec![specifier.clone()];
|
let files_to_search = vec![specifier.clone()];
|
||||||
let req = tsc::RequestMethod::GetDocumentHighlights((
|
let req = tsc::RequestMethod::GetDocumentHighlights((
|
||||||
specifier,
|
specifier,
|
||||||
|
@ -1572,15 +1540,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("references", Some(¶ms));
|
let mark = self.performance.mark("references", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
let req = tsc::RequestMethod::GetReferences((
|
let req = tsc::RequestMethod::GetReferences((
|
||||||
specifier,
|
specifier,
|
||||||
line_index.offset_tsc(params.text_document_position.position)?,
|
line_index.offset_tsc(params.text_document_position.position)?,
|
||||||
|
@ -1602,10 +1563,9 @@ impl Inner {
|
||||||
}
|
}
|
||||||
let reference_specifier =
|
let reference_specifier =
|
||||||
resolve_url(&reference.document_span.file_name).unwrap();
|
resolve_url(&reference.document_span.file_name).unwrap();
|
||||||
// TODO(lucacasonato): handle error correctly
|
let asset_or_doc =
|
||||||
let line_index =
|
self.get_asset_or_document(&reference_specifier).await?;
|
||||||
self.get_line_index(reference_specifier).await.unwrap();
|
results.push(reference.to_location(asset_or_doc.line_index(), self));
|
||||||
results.push(reference.to_location(line_index, self));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
|
@ -1630,15 +1590,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("goto_definition", Some(¶ms));
|
let mark = self.performance.mark("goto_definition", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
let req = tsc::RequestMethod::GetDefinition((
|
let req = tsc::RequestMethod::GetDefinition((
|
||||||
specifier,
|
specifier,
|
||||||
line_index.offset_tsc(params.text_document_position_params.position)?,
|
line_index.offset_tsc(params.text_document_position_params.position)?,
|
||||||
|
@ -1676,6 +1629,7 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("completion", Some(¶ms));
|
let mark = self.performance.mark("completion", Some(¶ms));
|
||||||
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
// 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
|
||||||
|
@ -1690,15 +1644,7 @@ impl Inner {
|
||||||
{
|
{
|
||||||
Some(response)
|
Some(response)
|
||||||
} else {
|
} else {
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let line_index = asset_or_doc.line_index();
|
||||||
|| {
|
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
let trigger_character = if let Some(context) = ¶ms.context {
|
let trigger_character = if let Some(context) = ¶ms.context {
|
||||||
context.trigger_character.clone()
|
context.trigger_character.clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -1801,15 +1747,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("goto_implementation", Some(¶ms));
|
let mark = self.performance.mark("goto_implementation", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let req = tsc::RequestMethod::GetImplementation((
|
let req = tsc::RequestMethod::GetImplementation((
|
||||||
specifier,
|
specifier,
|
||||||
|
@ -1854,15 +1793,7 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("folding_range", Some(¶ms));
|
let mark = self.performance.mark("folding_range", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let req = tsc::RequestMethod::GetOutliningSpans(specifier.clone());
|
let req = tsc::RequestMethod::GetOutliningSpans(specifier.clone());
|
||||||
let outlining_spans: Vec<tsc::OutliningSpan> = self
|
let outlining_spans: Vec<tsc::OutliningSpan> = self
|
||||||
|
@ -1875,20 +1806,13 @@ impl Inner {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let response = if !outlining_spans.is_empty() {
|
let response = if !outlining_spans.is_empty() {
|
||||||
let text_content =
|
|
||||||
self.get_text_content(&specifier).ok_or_else(|| {
|
|
||||||
LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
Some(
|
Some(
|
||||||
outlining_spans
|
outlining_spans
|
||||||
.iter()
|
.iter()
|
||||||
.map(|span| {
|
.map(|span| {
|
||||||
span.to_folding_range(
|
span.to_folding_range(
|
||||||
line_index.clone(),
|
asset_or_doc.line_index(),
|
||||||
text_content.as_str().as_bytes(),
|
asset_or_doc.text().as_str().as_bytes(),
|
||||||
self.config.client_capabilities.line_folding_only,
|
self.config.client_capabilities.line_folding_only,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -1913,15 +1837,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("incoming_calls", Some(¶ms));
|
let mark = self.performance.mark("incoming_calls", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let req = tsc::RequestMethod::ProvideCallHierarchyIncomingCalls((
|
let req = tsc::RequestMethod::ProvideCallHierarchyIncomingCalls((
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
|
@ -1969,15 +1886,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("outgoing_calls", Some(¶ms));
|
let mark = self.performance.mark("outgoing_calls", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let req = tsc::RequestMethod::ProvideCallHierarchyOutgoingCalls((
|
let req = tsc::RequestMethod::ProvideCallHierarchyOutgoingCalls((
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
|
@ -2030,15 +1940,8 @@ impl Inner {
|
||||||
let mark = self
|
let mark = self
|
||||||
.performance
|
.performance
|
||||||
.mark("prepare_call_hierarchy", Some(¶ms));
|
.mark("prepare_call_hierarchy", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let req = tsc::RequestMethod::PrepareCallHierarchy((
|
let req = tsc::RequestMethod::PrepareCallHierarchy((
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
|
@ -2109,15 +2012,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("rename", Some(¶ms));
|
let mark = self.performance.mark("rename", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let req = tsc::RequestMethod::FindRenameLocations {
|
let req = tsc::RequestMethod::FindRenameLocations {
|
||||||
specifier,
|
specifier,
|
||||||
|
@ -2204,15 +2100,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("selection_range", Some(¶ms));
|
let mark = self.performance.mark("selection_range", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut selection_ranges = Vec::<SelectionRange>::new();
|
let mut selection_ranges = Vec::<SelectionRange>::new();
|
||||||
for position in params.positions {
|
for position in params.positions {
|
||||||
|
@ -2249,15 +2138,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("semantic_tokens_full", Some(¶ms));
|
let mark = self.performance.mark("semantic_tokens_full", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let req = tsc::RequestMethod::GetEncodedSemanticClassifications((
|
let req = tsc::RequestMethod::GetEncodedSemanticClassifications((
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
|
@ -2300,15 +2182,8 @@ impl Inner {
|
||||||
let mark = self
|
let mark = self
|
||||||
.performance
|
.performance
|
||||||
.mark("semantic_tokens_range", Some(¶ms));
|
.mark("semantic_tokens_range", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let start = line_index.offset_tsc(params.range.start)?;
|
let start = line_index.offset_tsc(params.range.start)?;
|
||||||
let length = line_index.offset_tsc(params.range.end)? - start;
|
let length = line_index.offset_tsc(params.range.end)? - start;
|
||||||
|
@ -2350,15 +2225,8 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark("signature_help", Some(¶ms));
|
let mark = self.performance.mark("signature_help", Some(¶ms));
|
||||||
let line_index = self.get_line_index_sync(&specifier).map_or_else(
|
let asset_or_doc = self.get_cached_asset_or_document(&specifier)?;
|
||||||
|| {
|
let line_index = asset_or_doc.line_index();
|
||||||
Err(LspError::invalid_params(format!(
|
|
||||||
"An unexpected specifier ({}) was provided.",
|
|
||||||
specifier
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Ok,
|
|
||||||
)?;
|
|
||||||
let options = if let Some(context) = params.context {
|
let options = if let Some(context) = params.context {
|
||||||
tsc::SignatureHelpItemsOptions {
|
tsc::SignatureHelpItemsOptions {
|
||||||
trigger_reason: Some(tsc::SignatureHelpTriggerReason {
|
trigger_reason: Some(tsc::SignatureHelpTriggerReason {
|
||||||
|
@ -2689,7 +2557,12 @@ impl Inner {
|
||||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||||
let contents = if specifier.as_str() == "deno:/status.md" {
|
let contents = if specifier.as_str() == "deno:/status.md" {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
let mut documents_specifiers = self.documents.specifiers(false, false);
|
let mut documents_specifiers = self
|
||||||
|
.documents
|
||||||
|
.documents(false, false)
|
||||||
|
.into_iter()
|
||||||
|
.map(|d| d.specifier().clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
documents_specifiers.sort();
|
documents_specifiers.sort();
|
||||||
let measures = self.performance.to_vec();
|
let measures = self.performance.to_vec();
|
||||||
let workspace_settings = self.config.get_workspace_settings();
|
let workspace_settings = self.config.get_workspace_settings();
|
||||||
|
@ -2743,27 +2616,15 @@ impl Inner {
|
||||||
}
|
}
|
||||||
Some(contents)
|
Some(contents)
|
||||||
} else {
|
} else {
|
||||||
match specifier.scheme() {
|
let asset_or_doc = self
|
||||||
"asset" => {
|
.get_maybe_asset_or_document(&specifier)
|
||||||
if let Some(asset) = self
|
.await
|
||||||
.get_asset(&specifier)
|
.map_err(|_| LspError::internal_error())?;
|
||||||
.await
|
if let Some(asset_or_doc) = asset_or_doc {
|
||||||
.map_err(|_| LspError::internal_error())?
|
Some(asset_or_doc.text().to_string())
|
||||||
{
|
} else {
|
||||||
Some(asset.text.to_string())
|
error!("The source was not found: {}", specifier);
|
||||||
} else {
|
None
|
||||||
error!("Missing asset: {}", specifier);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if let Some(source) = self.documents.content(&specifier) {
|
|
||||||
Some(source.to_string())
|
|
||||||
} else {
|
|
||||||
error!("The cached source was not found: {}", specifier);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use super::language_server;
|
|
||||||
use super::path_to_regex::parse;
|
use super::path_to_regex::parse;
|
||||||
use super::path_to_regex::string_to_regex;
|
use super::path_to_regex::string_to_regex;
|
||||||
use super::path_to_regex::Compiler;
|
use super::path_to_regex::Compiler;
|
||||||
|
@ -439,7 +438,7 @@ impl ModuleRegistry {
|
||||||
current_specifier: &str,
|
current_specifier: &str,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
range: &lsp::Range,
|
range: &lsp::Range,
|
||||||
state_snapshot: &language_server::StateSnapshot,
|
specifier_exists: impl Fn(&ModuleSpecifier) -> bool,
|
||||||
) -> Option<Vec<lsp::CompletionItem>> {
|
) -> Option<Vec<lsp::CompletionItem>> {
|
||||||
if let Ok(specifier) = Url::parse(current_specifier) {
|
if let Ok(specifier) = Url::parse(current_specifier) {
|
||||||
let origin = base_url(&specifier);
|
let origin = base_url(&specifier);
|
||||||
|
@ -529,9 +528,7 @@ impl ModuleRegistry {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let command = if key.name == last_key_name
|
let command = if key.name == last_key_name
|
||||||
&& !state_snapshot
|
&& !specifier_exists(&item_specifier)
|
||||||
.documents
|
|
||||||
.contains_specifier(&item_specifier)
|
|
||||||
{
|
{
|
||||||
Some(lsp::Command {
|
Some(lsp::Command {
|
||||||
title: "".to_string(),
|
title: "".to_string(),
|
||||||
|
@ -619,9 +616,7 @@ impl ModuleRegistry {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
let command = if k.name == last_key_name
|
let command = if k.name == last_key_name
|
||||||
&& !state_snapshot
|
&& !specifier_exists(&item_specifier)
|
||||||
.documents
|
|
||||||
.contains_specifier(&item_specifier)
|
|
||||||
{
|
{
|
||||||
Some(lsp::Command {
|
Some(lsp::Command {
|
||||||
title: "".to_string(),
|
title: "".to_string(),
|
||||||
|
@ -771,38 +766,8 @@ impl ModuleRegistry {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::lsp::documents::Documents;
|
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
fn mock_state_snapshot(
|
|
||||||
source_fixtures: &[(&str, &str)],
|
|
||||||
location: &Path,
|
|
||||||
) -> language_server::StateSnapshot {
|
|
||||||
let documents = Documents::new(location);
|
|
||||||
let http_cache = HttpCache::new(location);
|
|
||||||
for (specifier, source) in source_fixtures {
|
|
||||||
let specifier =
|
|
||||||
resolve_url(specifier).expect("failed to create specifier");
|
|
||||||
http_cache
|
|
||||||
.set(&specifier, HashMap::default(), source.as_bytes())
|
|
||||||
.expect("could not cache file");
|
|
||||||
assert!(
|
|
||||||
documents.content(&specifier).is_some(),
|
|
||||||
"source could not be setup"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
language_server::StateSnapshot {
|
|
||||||
documents,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(sources: &[(&str, &str)]) -> language_server::StateSnapshot {
|
|
||||||
let temp_dir = TempDir::new().expect("could not create temp dir");
|
|
||||||
let location = temp_dir.path().join("deps");
|
|
||||||
mock_state_snapshot(sources, &location)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validate_registry_configuration() {
|
fn test_validate_registry_configuration() {
|
||||||
assert!(validate_config(&RegistryConfigurationJson {
|
assert!(validate_config(&RegistryConfigurationJson {
|
||||||
|
@ -920,9 +885,8 @@ mod tests {
|
||||||
character: 21,
|
character: 21,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let state_snapshot = setup(&[]);
|
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions("h", 1, &range, &state_snapshot)
|
.get_completions("h", 1, &range, |_| false)
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -946,7 +910,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions("http://localhost", 16, &range, &state_snapshot)
|
.get_completions("http://localhost", 16, &range, |_| false)
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -971,7 +935,6 @@ mod tests {
|
||||||
.enable("http://localhost:4545/")
|
.enable("http://localhost:4545/")
|
||||||
.await
|
.await
|
||||||
.expect("could not enable");
|
.expect("could not enable");
|
||||||
let state_snapshot = setup(&[]);
|
|
||||||
let range = lsp::Range {
|
let range = lsp::Range {
|
||||||
start: lsp::Position {
|
start: lsp::Position {
|
||||||
line: 0,
|
line: 0,
|
||||||
|
@ -983,7 +946,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions("http://localhost:4545", 21, &range, &state_snapshot)
|
.get_completions("http://localhost:4545", 21, &range, |_| false)
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -1007,7 +970,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions("http://localhost:4545/", 22, &range, &state_snapshot)
|
.get_completions("http://localhost:4545/", 22, &range, |_| false)
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -1031,7 +994,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions("http://localhost:4545/x/", 24, &range, &state_snapshot)
|
.get_completions("http://localhost:4545/x/", 24, &range, |_| false)
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -1049,12 +1012,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions(
|
.get_completions("http://localhost:4545/x/a@", 26, &range, |_| false)
|
||||||
"http://localhost:4545/x/a@",
|
|
||||||
26,
|
|
||||||
&range,
|
|
||||||
&state_snapshot,
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -1070,12 +1028,9 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions(
|
.get_completions("http://localhost:4545/x/a@v1.0.0/", 33, &range, |_| {
|
||||||
"http://localhost:4545/x/a@v1.0.0/",
|
false
|
||||||
33,
|
})
|
||||||
&range,
|
|
||||||
&state_snapshot,
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -1098,7 +1053,6 @@ mod tests {
|
||||||
.enable_custom("http://localhost:4545/lsp/registries/deno-import-intellisense-key-first.json")
|
.enable_custom("http://localhost:4545/lsp/registries/deno-import-intellisense-key-first.json")
|
||||||
.await
|
.await
|
||||||
.expect("could not enable");
|
.expect("could not enable");
|
||||||
let state_snapshot = setup(&[]);
|
|
||||||
let range = lsp::Range {
|
let range = lsp::Range {
|
||||||
start: lsp::Position {
|
start: lsp::Position {
|
||||||
line: 0,
|
line: 0,
|
||||||
|
@ -1110,7 +1064,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions("http://localhost:4545/", 22, &range, &state_snapshot)
|
.get_completions("http://localhost:4545/", 22, &range, |_| false)
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -1139,12 +1093,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions(
|
.get_completions("http://localhost:4545/cde@", 26, &range, |_| false)
|
||||||
"http://localhost:4545/cde@",
|
|
||||||
26,
|
|
||||||
&range,
|
|
||||||
&state_snapshot,
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
@ -1173,7 +1122,6 @@ mod tests {
|
||||||
.enable_custom("http://localhost:4545/lsp/registries/deno-import-intellisense-complex.json")
|
.enable_custom("http://localhost:4545/lsp/registries/deno-import-intellisense-complex.json")
|
||||||
.await
|
.await
|
||||||
.expect("could not enable");
|
.expect("could not enable");
|
||||||
let state_snapshot = setup(&[]);
|
|
||||||
let range = lsp::Range {
|
let range = lsp::Range {
|
||||||
start: lsp::Position {
|
start: lsp::Position {
|
||||||
line: 0,
|
line: 0,
|
||||||
|
@ -1185,7 +1133,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let completions = module_registry
|
let completions = module_registry
|
||||||
.get_completions("http://localhost:4545/", 22, &range, &state_snapshot)
|
.get_completions("http://localhost:4545/", 22, &range, |_| false)
|
||||||
.await;
|
.await;
|
||||||
assert!(completions.is_some());
|
assert!(completions.is_some());
|
||||||
let completions = completions.unwrap();
|
let completions = completions.unwrap();
|
||||||
|
|
147
cli/lsp/tsc.rs
147
cli/lsp/tsc.rs
|
@ -119,25 +119,58 @@ impl TsServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct AssetDocumentInner {
|
||||||
|
text: Arc<String>,
|
||||||
|
length: usize,
|
||||||
|
line_index: Arc<LineIndex>,
|
||||||
|
maybe_navigation_tree: Option<Arc<NavigationTree>>,
|
||||||
|
}
|
||||||
|
|
||||||
/// An lsp representation of an asset in memory, that has either been retrieved
|
/// An lsp representation of an asset in memory, that has either been retrieved
|
||||||
/// from static assets built into Rust, or static assets built into tsc.
|
/// from static assets built into Rust, or static assets built into tsc.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AssetDocument {
|
pub struct AssetDocument(Arc<AssetDocumentInner>);
|
||||||
pub text: Arc<String>,
|
|
||||||
pub length: usize,
|
|
||||||
pub line_index: Arc<LineIndex>,
|
|
||||||
pub maybe_navigation_tree: Option<Arc<NavigationTree>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AssetDocument {
|
impl AssetDocument {
|
||||||
pub fn new<T: AsRef<str>>(text: T) -> Self {
|
pub fn new(text: impl AsRef<str>) -> Self {
|
||||||
let text = text.as_ref();
|
let text = text.as_ref();
|
||||||
Self {
|
Self(Arc::new(AssetDocumentInner {
|
||||||
text: Arc::new(text.to_string()),
|
text: Arc::new(text.to_string()),
|
||||||
length: text.encode_utf16().count(),
|
length: text.encode_utf16().count(),
|
||||||
line_index: Arc::new(LineIndex::new(text)),
|
line_index: Arc::new(LineIndex::new(text)),
|
||||||
maybe_navigation_tree: None,
|
maybe_navigation_tree: None,
|
||||||
}
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_navigation_tree(
|
||||||
|
&self,
|
||||||
|
tree: Arc<NavigationTree>,
|
||||||
|
) -> AssetDocument {
|
||||||
|
AssetDocument(Arc::new(AssetDocumentInner {
|
||||||
|
maybe_navigation_tree: Some(tree),
|
||||||
|
..(*self.0).clone()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text(&self) -> Arc<String> {
|
||||||
|
self.0.text.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_str(&self) -> &str {
|
||||||
|
self.0.text.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length(&self) -> usize {
|
||||||
|
self.0.length
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn line_index(&self) -> Arc<LineIndex> {
|
||||||
|
self.0.line_index.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maybe_navigation_tree(&self) -> Option<Arc<NavigationTree>> {
|
||||||
|
self.0.maybe_navigation_tree.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,14 +209,6 @@ impl Assets {
|
||||||
self.0.insert(k, v)
|
self.0.insert(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_navigation_tree(
|
|
||||||
&self,
|
|
||||||
specifier: &ModuleSpecifier,
|
|
||||||
) -> Option<Arc<NavigationTree>> {
|
|
||||||
let doc = self.0.get(specifier).map(|v| v.as_ref()).flatten()?;
|
|
||||||
doc.maybe_navigation_tree.as_ref().cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_navigation_tree(
|
pub fn set_navigation_tree(
|
||||||
&mut self,
|
&mut self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
|
@ -196,7 +221,7 @@ impl Assets {
|
||||||
let doc = maybe_doc
|
let doc = maybe_doc
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.ok_or_else(|| anyhow!("Cannot get doc mutable"))?;
|
.ok_or_else(|| anyhow!("Cannot get doc mutable"))?;
|
||||||
doc.maybe_navigation_tree = Some(navigation_tree);
|
*doc = doc.with_navigation_tree(navigation_tree);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -605,10 +630,11 @@ impl DocumentSpan {
|
||||||
language_server: &mut language_server::Inner,
|
language_server: &mut language_server::Inner,
|
||||||
) -> Option<lsp::LocationLink> {
|
) -> Option<lsp::LocationLink> {
|
||||||
let target_specifier = normalize_specifier(&self.file_name).ok()?;
|
let target_specifier = normalize_specifier(&self.file_name).ok()?;
|
||||||
let target_line_index = language_server
|
let target_asset_or_doc = language_server
|
||||||
.get_line_index(target_specifier.clone())
|
.get_asset_or_document(&target_specifier)
|
||||||
.await
|
.await
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
let target_line_index = target_asset_or_doc.line_index();
|
||||||
let target_uri = language_server
|
let target_uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&target_specifier)
|
.normalize_specifier(&target_specifier)
|
||||||
|
@ -854,6 +880,8 @@ impl RenameLocations {
|
||||||
for location in self.locations.iter() {
|
for location in self.locations.iter() {
|
||||||
let specifier = normalize_specifier(&location.document_span.file_name)?;
|
let specifier = normalize_specifier(&location.document_span.file_name)?;
|
||||||
let uri = language_server.url_map.normalize_specifier(&specifier)?;
|
let uri = language_server.url_map.normalize_specifier(&specifier)?;
|
||||||
|
let asset_or_doc =
|
||||||
|
language_server.get_asset_or_document(&specifier).await?;
|
||||||
|
|
||||||
// ensure TextDocumentEdit for `location.file_name`.
|
// ensure TextDocumentEdit for `location.file_name`.
|
||||||
if text_document_edit_map.get(&uri).is_none() {
|
if text_document_edit_map.get(&uri).is_none() {
|
||||||
|
@ -862,7 +890,7 @@ impl RenameLocations {
|
||||||
lsp::TextDocumentEdit {
|
lsp::TextDocumentEdit {
|
||||||
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
||||||
uri: uri.clone(),
|
uri: uri.clone(),
|
||||||
version: language_server.document_version(&specifier),
|
version: asset_or_doc.document_version(),
|
||||||
},
|
},
|
||||||
edits:
|
edits:
|
||||||
Vec::<lsp::OneOf<lsp::TextEdit, lsp::AnnotatedTextEdit>>::new(),
|
Vec::<lsp::OneOf<lsp::TextEdit, lsp::AnnotatedTextEdit>>::new(),
|
||||||
|
@ -876,7 +904,7 @@ impl RenameLocations {
|
||||||
range: location
|
range: location
|
||||||
.document_span
|
.document_span
|
||||||
.text_span
|
.text_span
|
||||||
.to_range(language_server.get_line_index(specifier.clone()).await?),
|
.to_range(asset_or_doc.line_index()),
|
||||||
new_text: new_name.to_string(),
|
new_text: new_name.to_string(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -1018,16 +1046,17 @@ impl FileTextChanges {
|
||||||
language_server: &mut language_server::Inner,
|
language_server: &mut language_server::Inner,
|
||||||
) -> Result<lsp::TextDocumentEdit, AnyError> {
|
) -> Result<lsp::TextDocumentEdit, AnyError> {
|
||||||
let specifier = normalize_specifier(&self.file_name)?;
|
let specifier = normalize_specifier(&self.file_name)?;
|
||||||
let line_index = language_server.get_line_index(specifier.clone()).await?;
|
let asset_or_doc =
|
||||||
|
language_server.get_asset_or_document(&specifier).await?;
|
||||||
let edits = self
|
let edits = self
|
||||||
.text_changes
|
.text_changes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|tc| tc.as_text_edit(line_index.clone()))
|
.map(|tc| tc.as_text_edit(asset_or_doc.line_index()))
|
||||||
.collect();
|
.collect();
|
||||||
Ok(lsp::TextDocumentEdit {
|
Ok(lsp::TextDocumentEdit {
|
||||||
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
||||||
uri: specifier.clone(),
|
uri: specifier.clone(),
|
||||||
version: language_server.document_version(&specifier),
|
version: asset_or_doc.document_version(),
|
||||||
},
|
},
|
||||||
edits,
|
edits,
|
||||||
})
|
})
|
||||||
|
@ -1039,11 +1068,17 @@ impl FileTextChanges {
|
||||||
) -> Result<Vec<lsp::DocumentChangeOperation>, AnyError> {
|
) -> Result<Vec<lsp::DocumentChangeOperation>, AnyError> {
|
||||||
let mut ops = Vec::<lsp::DocumentChangeOperation>::new();
|
let mut ops = Vec::<lsp::DocumentChangeOperation>::new();
|
||||||
let specifier = normalize_specifier(&self.file_name)?;
|
let specifier = normalize_specifier(&self.file_name)?;
|
||||||
let line_index = if !self.is_new_file.unwrap_or(false) {
|
let maybe_asset_or_document = if !self.is_new_file.unwrap_or(false) {
|
||||||
language_server.get_line_index(specifier.clone()).await?
|
let asset_or_doc =
|
||||||
|
language_server.get_asset_or_document(&specifier).await?;
|
||||||
|
Some(asset_or_doc)
|
||||||
} else {
|
} else {
|
||||||
Arc::new(LineIndex::new(""))
|
None
|
||||||
};
|
};
|
||||||
|
let line_index = maybe_asset_or_document
|
||||||
|
.as_ref()
|
||||||
|
.map(|d| d.line_index())
|
||||||
|
.unwrap_or_else(|| Arc::new(LineIndex::new("")));
|
||||||
|
|
||||||
if self.is_new_file.unwrap_or(false) {
|
if self.is_new_file.unwrap_or(false) {
|
||||||
ops.push(lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(
|
ops.push(lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(
|
||||||
|
@ -1066,7 +1101,9 @@ impl FileTextChanges {
|
||||||
ops.push(lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
|
ops.push(lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
|
||||||
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
text_document: lsp::OptionalVersionedTextDocumentIdentifier {
|
||||||
uri: specifier.clone(),
|
uri: specifier.clone(),
|
||||||
version: language_server.document_version(&specifier),
|
version: maybe_asset_or_document
|
||||||
|
.map(|d| d.document_version())
|
||||||
|
.flatten(),
|
||||||
},
|
},
|
||||||
edits,
|
edits,
|
||||||
}));
|
}));
|
||||||
|
@ -1354,13 +1391,13 @@ impl CallHierarchyItem {
|
||||||
maybe_root_path: Option<&Path>,
|
maybe_root_path: Option<&Path>,
|
||||||
) -> Option<lsp::CallHierarchyItem> {
|
) -> Option<lsp::CallHierarchyItem> {
|
||||||
let target_specifier = normalize_specifier(&self.file).ok()?;
|
let target_specifier = normalize_specifier(&self.file).ok()?;
|
||||||
let target_line_index = language_server
|
let target_asset_or_doc = language_server
|
||||||
.get_line_index(target_specifier)
|
.get_asset_or_document(&target_specifier)
|
||||||
.await
|
.await
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
Some(self.to_call_hierarchy_item(
|
Some(self.to_call_hierarchy_item(
|
||||||
target_line_index,
|
target_asset_or_doc.line_index(),
|
||||||
language_server,
|
language_server,
|
||||||
maybe_root_path,
|
maybe_root_path,
|
||||||
))
|
))
|
||||||
|
@ -1455,21 +1492,21 @@ impl CallHierarchyIncomingCall {
|
||||||
maybe_root_path: Option<&Path>,
|
maybe_root_path: Option<&Path>,
|
||||||
) -> Option<lsp::CallHierarchyIncomingCall> {
|
) -> Option<lsp::CallHierarchyIncomingCall> {
|
||||||
let target_specifier = normalize_specifier(&self.from.file).ok()?;
|
let target_specifier = normalize_specifier(&self.from.file).ok()?;
|
||||||
let target_line_index = language_server
|
let target_asset_or_doc = language_server
|
||||||
.get_line_index(target_specifier)
|
.get_asset_or_document(&target_specifier)
|
||||||
.await
|
.await
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
Some(lsp::CallHierarchyIncomingCall {
|
Some(lsp::CallHierarchyIncomingCall {
|
||||||
from: self.from.to_call_hierarchy_item(
|
from: self.from.to_call_hierarchy_item(
|
||||||
target_line_index.clone(),
|
target_asset_or_doc.line_index(),
|
||||||
language_server,
|
language_server,
|
||||||
maybe_root_path,
|
maybe_root_path,
|
||||||
),
|
),
|
||||||
from_ranges: self
|
from_ranges: self
|
||||||
.from_spans
|
.from_spans
|
||||||
.iter()
|
.iter()
|
||||||
.map(|span| span.to_range(target_line_index.clone()))
|
.map(|span| span.to_range(target_asset_or_doc.line_index()))
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1490,14 +1527,14 @@ impl CallHierarchyOutgoingCall {
|
||||||
maybe_root_path: Option<&Path>,
|
maybe_root_path: Option<&Path>,
|
||||||
) -> Option<lsp::CallHierarchyOutgoingCall> {
|
) -> Option<lsp::CallHierarchyOutgoingCall> {
|
||||||
let target_specifier = normalize_specifier(&self.to.file).ok()?;
|
let target_specifier = normalize_specifier(&self.to.file).ok()?;
|
||||||
let target_line_index = language_server
|
let target_asset_or_doc = language_server
|
||||||
.get_line_index(target_specifier)
|
.get_asset_or_document(&target_specifier)
|
||||||
.await
|
.await
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
Some(lsp::CallHierarchyOutgoingCall {
|
Some(lsp::CallHierarchyOutgoingCall {
|
||||||
to: self.to.to_call_hierarchy_item(
|
to: self.to.to_call_hierarchy_item(
|
||||||
target_line_index,
|
target_asset_or_doc.line_index(),
|
||||||
language_server,
|
language_server,
|
||||||
maybe_root_path,
|
maybe_root_path,
|
||||||
),
|
),
|
||||||
|
@ -2099,10 +2136,11 @@ fn cache_snapshot(
|
||||||
let content = state
|
let content = state
|
||||||
.state_snapshot
|
.state_snapshot
|
||||||
.documents
|
.documents
|
||||||
.content(specifier)
|
.get(specifier)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
anyhow!("Specifier unexpectedly doesn't have content: {}", specifier)
|
anyhow!("Specifier unexpectedly doesn't exist: {}", specifier)
|
||||||
})?;
|
})?
|
||||||
|
.content();
|
||||||
state
|
state
|
||||||
.snapshots
|
.snapshots
|
||||||
.insert((specifier.clone(), version.into()), content.to_string());
|
.insert((specifier.clone(), version.into()), content.to_string());
|
||||||
|
@ -2242,7 +2280,7 @@ fn op_get_length(
|
||||||
let specifier = state.normalize_specifier(args.specifier)?;
|
let specifier = state.normalize_specifier(args.specifier)?;
|
||||||
let r = if let Some(Some(asset)) = state.state_snapshot.assets.get(&specifier)
|
let r = if let Some(Some(asset)) = state.state_snapshot.assets.get(&specifier)
|
||||||
{
|
{
|
||||||
Ok(asset.length)
|
Ok(asset.length())
|
||||||
} else {
|
} else {
|
||||||
cache_snapshot(state, &specifier, args.version.clone())?;
|
cache_snapshot(state, &specifier, args.version.clone())?;
|
||||||
let content = state
|
let content = state
|
||||||
|
@ -2275,7 +2313,7 @@ fn op_get_text(
|
||||||
let specifier = state.normalize_specifier(args.specifier)?;
|
let specifier = state.normalize_specifier(args.specifier)?;
|
||||||
let content =
|
let content =
|
||||||
if let Some(Some(content)) = state.state_snapshot.assets.get(&specifier) {
|
if let Some(Some(content)) = state.state_snapshot.assets.get(&specifier) {
|
||||||
content.text.as_str()
|
content.text_str()
|
||||||
} else {
|
} else {
|
||||||
cache_snapshot(state, &specifier, args.version.clone())?;
|
cache_snapshot(state, &specifier, args.version.clone())?;
|
||||||
state
|
state
|
||||||
|
@ -2296,9 +2334,9 @@ fn op_load(
|
||||||
.performance
|
.performance
|
||||||
.mark("op_load", Some(&args));
|
.mark("op_load", Some(&args));
|
||||||
let specifier = state.normalize_specifier(args.specifier)?;
|
let specifier = state.normalize_specifier(args.specifier)?;
|
||||||
let result = state.state_snapshot.documents.content(&specifier);
|
let document = state.state_snapshot.documents.get(&specifier);
|
||||||
state.state_snapshot.performance.measure(mark);
|
state.state_snapshot.performance.measure(mark);
|
||||||
Ok(result.map(|t| t.to_string()))
|
Ok(document.map(|d| d.content().to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_resolve(
|
fn op_resolve(
|
||||||
|
@ -2347,7 +2385,15 @@ fn op_script_names(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
_args: Value,
|
_args: Value,
|
||||||
) -> Result<Vec<ModuleSpecifier>, AnyError> {
|
) -> Result<Vec<ModuleSpecifier>, AnyError> {
|
||||||
Ok(state.state_snapshot.documents.specifiers(true, true))
|
Ok(
|
||||||
|
state
|
||||||
|
.state_snapshot
|
||||||
|
.documents
|
||||||
|
.documents(true, true)
|
||||||
|
.into_iter()
|
||||||
|
.map(|d| d.specifier().clone())
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
@ -2372,7 +2418,12 @@ fn op_script_version(
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(state.state_snapshot.documents.version(&specifier))
|
let script_version = state
|
||||||
|
.state_snapshot
|
||||||
|
.documents
|
||||||
|
.get(&specifier)
|
||||||
|
.map(|d| d.script_version());
|
||||||
|
Ok(script_version)
|
||||||
};
|
};
|
||||||
|
|
||||||
state.state_snapshot.performance.measure(mark);
|
state.state_snapshot.performance.measure(mark);
|
||||||
|
|
Loading…
Reference in a new issue