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