diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/lsp/analysis.rs | 40 | ||||
-rw-r--r-- | cli/lsp/language_server.rs | 73 | ||||
-rw-r--r-- | cli/lsp/sources.rs | 87 | ||||
-rw-r--r-- | cli/lsp/tsc.rs | 72 |
4 files changed, 90 insertions, 182 deletions
diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs index ad4396616..7b0f159bb 100644 --- a/cli/lsp/analysis.rs +++ b/cli/lsp/analysis.rs @@ -1,6 +1,6 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use super::text::LineIndex; +use super::language_server; use super::tsc; use crate::ast; @@ -13,7 +13,6 @@ use crate::tools::lint::create_linter; use deno_core::error::custom_error; use deno_core::error::AnyError; -use deno_core::futures::Future; use deno_core::serde::Deserialize; use deno_core::serde::Serialize; use deno_core::serde_json::json; @@ -353,21 +352,14 @@ fn is_preferred( /// Convert changes returned from a TypeScript quick fix action into edits /// for an LSP CodeAction. -pub async fn ts_changes_to_edit<F, Fut, V>( +pub(crate) async fn ts_changes_to_edit( changes: &[tsc::FileTextChanges], - index_provider: &F, - version_provider: &V, -) -> Result<Option<lsp::WorkspaceEdit>, AnyError> -where - F: Fn(ModuleSpecifier) -> Fut + Clone, - Fut: Future<Output = Result<LineIndex, AnyError>>, - V: Fn(ModuleSpecifier) -> Option<i32>, -{ + language_server: &mut language_server::Inner, +) -> Result<Option<lsp::WorkspaceEdit>, AnyError> { let mut text_document_edits = Vec::new(); for change in changes { - let text_document_edit = change - .to_text_document_edit(index_provider, version_provider) - .await?; + let text_document_edit = + change.to_text_document_edit(language_server).await?; text_document_edits.push(text_document_edit); } Ok(Some(lsp::WorkspaceEdit { @@ -392,18 +384,12 @@ pub struct CodeActionCollection { impl CodeActionCollection { /// Add a TypeScript code fix action to the code actions collection. - pub async fn add_ts_fix_action<F, Fut, V>( + pub(crate) async fn add_ts_fix_action( &mut self, action: &tsc::CodeFixAction, diagnostic: &lsp::Diagnostic, - index_provider: &F, - version_provider: &V, - ) -> Result<(), AnyError> - where - F: Fn(ModuleSpecifier) -> Fut + Clone, - Fut: Future<Output = Result<LineIndex, AnyError>>, - V: Fn(ModuleSpecifier) -> Option<i32>, - { + language_server: &mut language_server::Inner, + ) -> Result<(), AnyError> { if action.commands.is_some() { // In theory, tsc can return actions that require "commands" to be applied // back into TypeScript. Currently there is only one command, `install @@ -417,9 +403,7 @@ impl CodeActionCollection { "The action returned from TypeScript is unsupported.", )); } - let edit = - ts_changes_to_edit(&action.changes, index_provider, version_provider) - .await?; + let edit = ts_changes_to_edit(&action.changes, language_server).await?; let code_action = lsp::CodeAction { title: action.description.clone(), kind: Some(lsp::CodeActionKind::QUICKFIX), @@ -502,7 +486,7 @@ impl CodeActionCollection { &self, action: &tsc::CodeFixAction, diagnostic: &lsp::Diagnostic, - file_diagnostics: &[&lsp::Diagnostic], + file_diagnostics: &[lsp::Diagnostic], ) -> bool { // If the action does not have a fix id (indicating it can be "bundled up") // or if the collection already contains a "bundled" action return false @@ -517,7 +501,7 @@ impl CodeActionCollection { // other diagnostics that could be bundled together in a "fix all" code // action file_diagnostics.iter().any(|d| { - if d == &diagnostic || d.code.is_none() || diagnostic.code.is_none() { + if d == diagnostic || d.code.is_none() || diagnostic.code.is_none() { false } else { d.code == diagnostic.code diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 838ca2725..0fa7f9d68 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -66,7 +66,7 @@ pub struct StateSnapshot { } #[derive(Debug)] -struct Inner { +pub(crate) struct Inner { /// Cached versions of "fixed" assets that can either be inlined in Rust or /// are part of the TypeScript snapshot and have to be fetched out. assets: HashMap<ModuleSpecifier, Option<AssetDocument>>, @@ -132,8 +132,8 @@ 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. - async fn get_line_index( - &self, + pub(crate) async fn get_line_index( + &mut self, specifier: ModuleSpecifier, ) -> Result<LineIndex, AnyError> { let mark = self.performance.mark("get_line_index"); @@ -170,7 +170,7 @@ impl Inner { /// Only searches already cached assets and documents for a line index. If /// the line index cannot be found, `None` is returned. fn get_line_index_sync( - &self, + &mut self, specifier: &ModuleSpecifier, ) -> Option<LineIndex> { let mark = self.performance.mark("get_line_index_sync"); @@ -501,6 +501,13 @@ impl Inner { self.performance.measure(mark); Ok(()) } + + pub(crate) fn document_version( + &mut self, + specifier: ModuleSpecifier, + ) -> Option<i32> { + self.documents.version(&specifier) + } } // lspower::LanguageServer methods. This file's LanguageServer delegates to us. @@ -826,7 +833,7 @@ impl Inner { } } - async fn hover(&self, params: HoverParams) -> LspResult<Option<Hover>> { + async fn hover(&mut self, params: HoverParams) -> LspResult<Option<Hover>> { if !self.enabled() { return Ok(None); } @@ -898,9 +905,10 @@ impl Inner { return Ok(None); } let line_index = self.get_line_index_sync(&specifier).unwrap(); - let file_diagnostics: Vec<&Diagnostic> = self + let file_diagnostics: Vec<Diagnostic> = self .diagnostics .diagnostics_for(&specifier, &DiagnosticSource::TypeScript) + .cloned() .collect(); let mut code_actions = CodeActionCollection::default(); for diagnostic in &fixable_diagnostics { @@ -931,12 +939,7 @@ impl Inner { })?; for action in actions { code_actions - .add_ts_fix_action( - &action, - diagnostic, - &|s| self.get_line_index(s), - &|s| self.documents.version(&s), - ) + .add_ts_fix_action(&action, diagnostic, self) .await .map_err(|err| { error!("Unable to convert fix: {}", err); @@ -958,7 +961,7 @@ impl Inner { } async fn code_action_resolve( - &self, + &mut self, params: CodeAction, ) -> LspResult<CodeAction> { let mark = self.performance.mark("code_action_resolve"); @@ -989,16 +992,13 @@ impl Inner { Err(LspError::invalid_request()) } else { let mut code_action = params.clone(); - code_action.edit = ts_changes_to_edit( - &combined_code_actions.changes, - &|s| self.get_line_index(s), - &|s| self.documents.version(&s), - ) - .await - .map_err(|err| { - error!("Unable to convert changes to edits: {}", err); - LspError::internal_error() - })?; + code_action.edit = + ts_changes_to_edit(&combined_code_actions.changes, self) + .await + .map_err(|err| { + error!("Unable to convert changes to edits: {}", err); + LspError::internal_error() + })?; Ok(code_action) } } else { @@ -1214,7 +1214,7 @@ impl Inner { } async fn document_highlight( - &self, + &mut self, params: DocumentHighlightParams, ) -> LspResult<Option<Vec<DocumentHighlight>>> { if !self.enabled() { @@ -1342,9 +1342,7 @@ impl Inner { serde_json::from_value(res).unwrap(); if let Some(definition) = maybe_definition { - let results = definition - .to_definition(&line_index, |s| self.get_line_index(s)) - .await; + let results = definition.to_definition(&line_index, self).await; self.performance.measure(mark); Ok(results) } else { @@ -1354,7 +1352,7 @@ impl Inner { } async fn completion( - &self, + &mut self, params: CompletionParams, ) -> LspResult<Option<CompletionResponse>> { if !self.enabled() { @@ -1399,7 +1397,7 @@ impl Inner { } async fn goto_implementation( - &self, + &mut self, params: GotoImplementationParams, ) -> LspResult<Option<GotoImplementationResponse>> { if !self.enabled() { @@ -1447,10 +1445,7 @@ impl Inner { ModuleSpecifier::resolve_url(&document_span.file_name).unwrap(); let impl_line_index = &self.get_line_index(impl_specifier).await.unwrap(); - if let Some(link) = document_span - .to_link(impl_line_index, |s| self.get_line_index(s)) - .await - { + if let Some(link) = document_span.to_link(impl_line_index, self).await { results.push(link); } } @@ -1463,13 +1458,13 @@ impl Inner { } async fn rename( - &self, + &mut self, params: RenameParams, ) -> LspResult<Option<WorkspaceEdit>> { if !self.enabled() { return Ok(None); } - let mark = self.performance.mark("goto_implementation"); + let mark = self.performance.mark("rename"); let specifier = utils::normalize_url(params.text_document_position.text_document.uri); @@ -1515,11 +1510,7 @@ impl Inner { if let Some(locations) = maybe_locations { let rename_locations = tsc::RenameLocations { locations }; let workspace_edits = rename_locations - .into_workspace_edit( - ¶ms.new_name, - |s| self.get_line_index(s), - |s| self.documents.version(&s), - ) + .into_workspace_edit(¶ms.new_name, self) .await .map_err(|err| { error!("Failed to get workspace edits: {:#?}", err); @@ -1747,7 +1738,7 @@ impl Inner { } async fn virtual_text_document( - &self, + &mut self, params: VirtualTextDocumentParams, ) -> LspResult<Option<String>> { let mark = self.performance.mark("virtual_text_document"); diff --git a/cli/lsp/sources.rs b/cli/lsp/sources.rs index fc09f3f4d..fac1120fb 100644 --- a/cli/lsp/sources.rs +++ b/cli/lsp/sources.rs @@ -51,10 +51,7 @@ struct Metadata { } #[derive(Debug, Clone, Default)] -pub struct Sources(Arc<Mutex<Inner>>); - -#[derive(Debug, Default)] -struct Inner { +pub struct Sources { http_cache: HttpCache, maybe_import_map: Option<ImportMap>, metadata: HashMap<ModuleSpecifier, Metadata>, @@ -64,64 +61,13 @@ struct Inner { impl Sources { pub fn new(location: &Path) -> Self { - Self(Arc::new(Mutex::new(Inner::new(location)))) - } - - pub fn contains(&self, specifier: &ModuleSpecifier) -> bool { - self.0.lock().unwrap().contains(specifier) - } - - /// Provides the length of the source content, calculated in a way that should - /// match the behavior of JavaScript, where strings are stored effectively as - /// `&[u16]` and when counting "chars" we need to represent the string as a - /// UTF-16 string in Rust. - pub fn get_length_utf16(&self, specifier: &ModuleSpecifier) -> Option<usize> { - self.0.lock().unwrap().get_length_utf16(specifier) - } - - pub fn get_line_index( - &self, - specifier: &ModuleSpecifier, - ) -> Option<LineIndex> { - self.0.lock().unwrap().get_line_index(specifier) - } - - pub fn get_media_type( - &self, - specifier: &ModuleSpecifier, - ) -> Option<MediaType> { - self.0.lock().unwrap().get_media_type(specifier) - } - - pub fn get_script_version( - &self, - specifier: &ModuleSpecifier, - ) -> Option<String> { - self.0.lock().unwrap().get_script_version(specifier) - } - - pub fn get_text(&self, specifier: &ModuleSpecifier) -> Option<String> { - self.0.lock().unwrap().get_text(specifier) - } - - pub fn resolve_import( - &self, - specifier: &str, - referrer: &ModuleSpecifier, - ) -> Option<(ModuleSpecifier, MediaType)> { - self.0.lock().unwrap().resolve_import(specifier, referrer) - } -} - -impl Inner { - fn new(location: &Path) -> Self { Self { http_cache: HttpCache::new(location), ..Default::default() } } - fn contains(&mut self, specifier: &ModuleSpecifier) -> bool { + pub fn contains(&mut self, specifier: &ModuleSpecifier) -> bool { if let Some(specifier) = self.resolve_specifier(specifier) { if self.get_metadata(&specifier).is_some() { return true; @@ -130,13 +76,20 @@ impl Inner { false } - fn get_length_utf16(&mut self, specifier: &ModuleSpecifier) -> Option<usize> { + /// Provides the length of the source content, calculated in a way that should + /// match the behavior of JavaScript, where strings are stored effectively as + /// `&[u16]` and when counting "chars" we need to represent the string as a + /// UTF-16 string in Rust. + pub fn get_length_utf16( + &mut self, + specifier: &ModuleSpecifier, + ) -> Option<usize> { let specifier = self.resolve_specifier(specifier)?; let metadata = self.get_metadata(&specifier)?; Some(metadata.source.encode_utf16().count()) } - fn get_line_index( + pub fn get_line_index( &mut self, specifier: &ModuleSpecifier, ) -> Option<LineIndex> { @@ -145,7 +98,7 @@ impl Inner { Some(metadata.line_index) } - fn get_media_type( + pub fn get_media_type( &mut self, specifier: &ModuleSpecifier, ) -> Option<MediaType> { @@ -283,7 +236,7 @@ impl Inner { None } - fn get_script_version( + pub fn get_script_version( &mut self, specifier: &ModuleSpecifier, ) -> Option<String> { @@ -304,7 +257,7 @@ impl Inner { None } - fn get_text(&mut self, specifier: &ModuleSpecifier) -> Option<String> { + pub fn get_text(&mut self, specifier: &ModuleSpecifier) -> Option<String> { let specifier = self.resolve_specifier(specifier)?; let metadata = self.get_metadata(&specifier)?; Some(metadata.source) @@ -324,7 +277,7 @@ impl Inner { Some((resolved_specifier, media_type)) } - fn resolve_import( + pub fn resolve_import( &mut self, specifier: &str, referrer: &ModuleSpecifier, @@ -420,7 +373,7 @@ mod tests { #[test] fn test_sources_get_script_version() { - let (sources, _) = setup(); + let (mut sources, _) = setup(); let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); let tests = c.join("tests"); let specifier = ModuleSpecifier::resolve_path( @@ -433,7 +386,7 @@ mod tests { #[test] fn test_sources_get_text() { - let (sources, _) = setup(); + let (mut sources, _) = setup(); let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); let tests = c.join("tests"); let specifier = ModuleSpecifier::resolve_path( @@ -448,7 +401,7 @@ mod tests { #[test] fn test_sources_get_length_utf16() { - let (sources, _) = setup(); + let (mut sources, _) = setup(); let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); let tests = c.join("tests"); let specifier = ModuleSpecifier::resolve_path( @@ -463,10 +416,10 @@ mod tests { #[test] fn test_sources_resolve_specifier_non_supported_schema() { - let (sources, _) = setup(); + let (mut sources, _) = setup(); let specifier = ModuleSpecifier::resolve_url("foo://a/b/c.ts") .expect("could not create specifier"); - let actual = sources.0.lock().unwrap().resolve_specifier(&specifier); + let actual = sources.resolve_specifier(&specifier); assert!(actual.is_none()); } } diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index 579979b06..67286e288 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -2,6 +2,7 @@ use super::analysis::CodeLensSource; use super::analysis::ResolvedDependency; +use super::language_server; use super::language_server::StateSnapshot; use super::text; use super::text::LineIndex; @@ -16,7 +17,6 @@ use crate::tsc_config::TsConfig; use deno_core::error::anyhow; use deno_core::error::custom_error; use deno_core::error::AnyError; -use deno_core::futures::Future; use deno_core::json_op_sync; use deno_core::serde::Deserialize; use deno_core::serde::Serialize; @@ -443,18 +443,16 @@ pub struct DocumentSpan { } impl DocumentSpan { - pub async fn to_link<F, Fut>( + pub(crate) async fn to_link( &self, line_index: &LineIndex, - index_provider: F, - ) -> Option<lsp::LocationLink> - where - F: Fn(ModuleSpecifier) -> Fut, - Fut: Future<Output = Result<LineIndex, AnyError>>, - { + language_server: &mut language_server::Inner, + ) -> Option<lsp::LocationLink> { let target_specifier = ModuleSpecifier::resolve_url(&self.file_name).unwrap(); - if let Ok(target_line_index) = index_provider(target_specifier).await { + if let Ok(target_line_index) = + language_server.get_line_index(target_specifier).await + { let target_uri = utils::normalize_file_name(&self.file_name).unwrap(); let (target_range, target_selection_range) = if let Some(context_span) = &self.context_span { @@ -559,17 +557,11 @@ pub struct RenameLocations { } impl RenameLocations { - pub async fn into_workspace_edit<F, Fut, V>( + pub(crate) async fn into_workspace_edit( self, new_name: &str, - index_provider: F, - version_provider: V, - ) -> Result<lsp::WorkspaceEdit, AnyError> - where - F: Fn(ModuleSpecifier) -> Fut, - Fut: Future<Output = Result<LineIndex, AnyError>>, - V: Fn(ModuleSpecifier) -> Option<i32>, - { + language_server: &mut language_server::Inner, + ) -> Result<lsp::WorkspaceEdit, AnyError> { let mut text_document_edit_map: HashMap<Url, lsp::TextDocumentEdit> = HashMap::new(); for location in self.locations.iter() { @@ -584,7 +576,7 @@ impl RenameLocations { lsp::TextDocumentEdit { text_document: lsp::OptionalVersionedTextDocumentIdentifier { uri: uri.clone(), - version: version_provider(specifier.clone()), + version: language_server.document_version(specifier.clone()), }, edits: Vec::<lsp::OneOf<lsp::TextEdit, lsp::AnnotatedTextEdit>>::new(), @@ -598,7 +590,7 @@ impl RenameLocations { range: location .document_span .text_span - .to_range(&index_provider(specifier.clone()).await?), + .to_range(&language_server.get_line_index(specifier.clone()).await?), new_text: new_name.to_string(), })); } @@ -655,22 +647,16 @@ pub struct DefinitionInfoAndBoundSpan { } impl DefinitionInfoAndBoundSpan { - pub async fn to_definition<F, Fut>( + pub(crate) async fn to_definition( &self, line_index: &LineIndex, - index_provider: F, - ) -> Option<lsp::GotoDefinitionResponse> - where - F: Fn(ModuleSpecifier) -> Fut + Clone, - Fut: Future<Output = Result<LineIndex, AnyError>>, - { + language_server: &mut language_server::Inner, + ) -> Option<lsp::GotoDefinitionResponse> { if let Some(definitions) = &self.definitions { let mut location_links = Vec::<lsp::LocationLink>::new(); for di in definitions { - if let Some(link) = di - .document_span - .to_link(line_index, index_provider.clone()) - .await + if let Some(link) = + di.document_span.to_link(line_index, language_server).await { location_links.push(link); } @@ -739,18 +725,12 @@ pub struct FileTextChanges { } impl FileTextChanges { - pub async fn to_text_document_edit<F, Fut, V>( + pub(crate) async fn to_text_document_edit( &self, - index_provider: &F, - version_provider: &V, - ) -> Result<lsp::TextDocumentEdit, AnyError> - where - F: Fn(ModuleSpecifier) -> Fut + Clone, - Fut: Future<Output = Result<LineIndex, AnyError>>, - V: Fn(ModuleSpecifier) -> Option<i32>, - { + language_server: &mut language_server::Inner, + ) -> Result<lsp::TextDocumentEdit, AnyError> { let specifier = ModuleSpecifier::resolve_url(&self.file_name)?; - let line_index = index_provider(specifier.clone()).await?; + let line_index = language_server.get_line_index(specifier.clone()).await?; let edits = self .text_changes .iter() @@ -759,7 +739,7 @@ impl FileTextChanges { Ok(lsp::TextDocumentEdit { text_document: lsp::OptionalVersionedTextDocumentIdentifier { uri: specifier.as_url().clone(), - version: version_provider(specifier), + version: language_server.document_version(specifier), }, edits, }) @@ -1043,7 +1023,7 @@ fn get_length(state: &mut State, args: Value) -> Result<Value, AnyError> { .unwrap(); Ok(json!(content.encode_utf16().count())) } else { - let sources = &state.state_snapshot.sources; + let sources = &mut state.state_snapshot.sources; Ok(json!(sources.get_length_utf16(&specifier).unwrap())) } } @@ -1068,7 +1048,7 @@ fn get_text(state: &mut State, args: Value) -> Result<Value, AnyError> { .unwrap() .clone() } else { - let sources = &state.state_snapshot.sources; + let sources = &mut state.state_snapshot.sources; sources.get_text(&specifier).unwrap() }; Ok(json!(text::slice(&content, v.start..v.end))) @@ -1078,7 +1058,7 @@ fn resolve(state: &mut State, args: Value) -> Result<Value, AnyError> { let v: ResolveArgs = serde_json::from_value(args)?; let mut resolved = Vec::<Option<(String, String)>>::new(); let referrer = ModuleSpecifier::resolve_url(&v.base)?; - let sources = &state.state_snapshot.sources; + let sources = &mut state.state_snapshot.sources; if state.state_snapshot.documents.contains(&referrer) { if let Some(dependencies) = @@ -1172,7 +1152,7 @@ fn script_version(state: &mut State, args: Value) -> Result<Value, AnyError> { if let Some(version) = state.state_snapshot.documents.version(&specifier) { return Ok(json!(version.to_string())); } else { - let sources = &state.state_snapshot.sources; + let sources = &mut state.state_snapshot.sources; if let Some(version) = sources.get_script_version(&specifier) { return Ok(json!(version)); } |