diff options
Diffstat (limited to 'cli/lsp/tsc.rs')
-rw-r--r-- | cli/lsp/tsc.rs | 294 |
1 files changed, 105 insertions, 189 deletions
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index 9899fad72..8f3db6131 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -1,7 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use super::analysis::ResolvedDependency; -use super::analysis::ResolvedDependencyErr; use super::code_lens; use super::config; use super::language_server; @@ -22,7 +20,6 @@ use crate::tokio_util::create_basic_runtime; use crate::tsc; use crate::tsc::ResolveArgs; -use deno_ast::MediaType; use deno_core::error::anyhow; use deno_core::error::custom_error; use deno_core::error::AnyError; @@ -106,7 +103,7 @@ impl TsServer { Self(tx) } - pub async fn request<R>( + pub(crate) async fn request<R>( &self, snapshot: StateSnapshot, req: RequestMethod, @@ -128,8 +125,8 @@ impl TsServer { pub struct AssetDocument { pub text: Arc<String>, pub length: usize, - pub line_index: LineIndex, - pub maybe_navigation_tree: Option<NavigationTree>, + pub line_index: Arc<LineIndex>, + pub maybe_navigation_tree: Option<Arc<NavigationTree>>, } impl AssetDocument { @@ -138,7 +135,7 @@ impl AssetDocument { Self { text: Arc::new(text.to_string()), length: text.encode_utf16().count(), - line_index: LineIndex::new(text), + line_index: Arc::new(LineIndex::new(text)), maybe_navigation_tree: None, } } @@ -179,10 +176,18 @@ 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, - navigation_tree: NavigationTree, + navigation_tree: Arc<NavigationTree>, ) -> Result<(), AnyError> { let maybe_doc = self .0 @@ -199,7 +204,7 @@ impl Assets { /// Optionally returns an internal asset, first checking for any static assets /// in Rust, then checking any previously retrieved static assets from the /// isolate, and then finally, the tsc isolate itself. -pub async fn get_asset( +pub(crate) async fn get_asset( specifier: &ModuleSpecifier, ts_server: &TsServer, state_snapshot: StateSnapshot, @@ -498,7 +503,7 @@ pub struct TextSpan { } impl TextSpan { - pub fn to_range(&self, line_index: &LineIndex) -> lsp::Range { + pub fn to_range(&self, line_index: Arc<LineIndex>) -> lsp::Range { lsp::Range { start: line_index.position_tsc(self.start.into()), end: line_index.position_tsc(TextSize::from(self.start + self.length)), @@ -532,7 +537,7 @@ pub struct QuickInfo { } impl QuickInfo { - pub fn to_hover(&self, line_index: &LineIndex) -> lsp::Hover { + pub fn to_hover(&self, line_index: Arc<LineIndex>) -> lsp::Hover { let mut contents = Vec::<lsp::MarkedString>::new(); if let Some(display_string) = self .display_parts @@ -585,7 +590,7 @@ pub struct DocumentSpan { impl DocumentSpan { pub(crate) async fn to_link( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, language_server: &mut language_server::Inner, ) -> Option<lsp::LocationLink> { let target_specifier = normalize_specifier(&self.file_name).ok()?; @@ -600,13 +605,13 @@ impl DocumentSpan { let (target_range, target_selection_range) = if let Some(context_span) = &self.context_span { ( - context_span.to_range(&target_line_index), - self.text_span.to_range(&target_line_index), + context_span.to_range(target_line_index.clone()), + self.text_span.to_range(target_line_index), ) } else { ( - self.text_span.to_range(&target_line_index), - self.text_span.to_range(&target_line_index), + self.text_span.to_range(target_line_index.clone()), + self.text_span.to_range(target_line_index), ) }; let origin_selection_range = @@ -642,7 +647,7 @@ pub struct NavigationTree { impl NavigationTree { pub fn to_code_lens( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, specifier: &ModuleSpecifier, source: &code_lens::CodeLensSource, ) -> lsp::CodeLens { @@ -666,7 +671,7 @@ impl NavigationTree { pub fn collect_document_symbols( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, document_symbols: &mut Vec<lsp::DocumentSymbol>, ) -> bool { let mut should_include = self.should_include_entry(); @@ -692,8 +697,8 @@ impl NavigationTree { }) .any(|child_range| range.intersect(child_range).is_some()); if should_traverse_child { - let included_child = - child.collect_document_symbols(line_index, &mut symbol_children); + let included_child = child + .collect_document_symbols(line_index.clone(), &mut symbol_children); should_include = should_include || included_child; } } @@ -727,8 +732,8 @@ impl NavigationTree { document_symbols.push(lsp::DocumentSymbol { name: self.text.clone(), kind: self.kind.clone().into(), - range: span.to_range(line_index), - selection_range: selection_span.to_range(line_index), + range: span.to_range(line_index.clone()), + selection_range: selection_span.to_range(line_index.clone()), tags, children, detail: None, @@ -786,7 +791,7 @@ pub struct ImplementationLocation { impl ImplementationLocation { pub(crate) fn to_location( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, language_server: &mut language_server::Inner, ) -> lsp::Location { let specifier = normalize_specifier(&self.document_span.file_name) @@ -803,7 +808,7 @@ impl ImplementationLocation { pub(crate) async fn to_link( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, language_server: &mut language_server::Inner, ) -> Option<lsp::LocationLink> { self @@ -846,7 +851,7 @@ impl RenameLocations { lsp::TextDocumentEdit { text_document: lsp::OptionalVersionedTextDocumentIdentifier { uri: uri.clone(), - version: language_server.document_version(specifier.clone()), + version: language_server.document_version(&specifier), }, edits: Vec::<lsp::OneOf<lsp::TextEdit, lsp::AnnotatedTextEdit>>::new(), @@ -860,7 +865,7 @@ impl RenameLocations { range: location .document_span .text_span - .to_range(&language_server.get_line_index(specifier.clone()).await?), + .to_range(language_server.get_line_index(specifier.clone()).await?), new_text: new_name.to_string(), })); } @@ -919,14 +924,16 @@ pub struct DefinitionInfoAndBoundSpan { impl DefinitionInfoAndBoundSpan { pub(crate) async fn to_definition( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, 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, language_server).await + if let Some(link) = di + .document_span + .to_link(line_index.clone(), language_server) + .await { location_links.push(link); } @@ -948,13 +955,13 @@ pub struct DocumentHighlights { impl DocumentHighlights { pub fn to_highlight( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, ) -> Vec<lsp::DocumentHighlight> { self .highlight_spans .iter() .map(|hs| lsp::DocumentHighlight { - range: hs.text_span.to_range(line_index), + range: hs.text_span.to_range(line_index.clone()), kind: match hs.kind { HighlightSpanKind::WrittenReference => { Some(lsp::DocumentHighlightKind::Write) @@ -976,7 +983,7 @@ pub struct TextChange { impl TextChange { pub fn as_text_edit( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, ) -> lsp::OneOf<lsp::TextEdit, lsp::AnnotatedTextEdit> { lsp::OneOf::Left(lsp::TextEdit { range: self.span.to_range(line_index), @@ -1004,12 +1011,12 @@ impl FileTextChanges { let edits = self .text_changes .iter() - .map(|tc| tc.as_text_edit(&line_index)) + .map(|tc| tc.as_text_edit(line_index.clone())) .collect(); Ok(lsp::TextDocumentEdit { text_document: lsp::OptionalVersionedTextDocumentIdentifier { uri: specifier.clone(), - version: language_server.document_version(specifier), + version: language_server.document_version(&specifier), }, edits, }) @@ -1024,7 +1031,7 @@ impl FileTextChanges { let line_index = if !self.is_new_file.unwrap_or(false) { language_server.get_line_index(specifier.clone()).await? } else { - LineIndex::new("") + Arc::new(LineIndex::new("")) }; if self.is_new_file.unwrap_or(false) { @@ -1043,12 +1050,12 @@ impl FileTextChanges { let edits = self .text_changes .iter() - .map(|tc| tc.as_text_edit(&line_index)) + .map(|tc| tc.as_text_edit(line_index.clone())) .collect(); ops.push(lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit { text_document: lsp::OptionalVersionedTextDocumentIdentifier { uri: specifier.clone(), - version: language_server.document_version(specifier), + version: language_server.document_version(&specifier), }, edits, })); @@ -1066,7 +1073,7 @@ pub struct Classifications { impl Classifications { pub fn to_semantic_tokens( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, ) -> lsp::SemanticTokens { let token_count = self.spans.len() / 3; let mut builder = SemanticTokensBuilder::new(); @@ -1299,7 +1306,7 @@ pub struct ReferenceEntry { impl ReferenceEntry { pub(crate) fn to_location( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, language_server: &mut language_server::Inner, ) -> lsp::Location { let specifier = normalize_specifier(&self.document_span.file_name) @@ -1342,7 +1349,7 @@ impl CallHierarchyItem { .ok()?; Some(self.to_call_hierarchy_item( - &target_line_index, + target_line_index, language_server, maybe_root_path, )) @@ -1350,7 +1357,7 @@ impl CallHierarchyItem { pub(crate) fn to_call_hierarchy_item( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, language_server: &mut language_server::Inner, maybe_root_path: Option<&Path>, ) -> lsp::CallHierarchyItem { @@ -1410,7 +1417,7 @@ impl CallHierarchyItem { uri, detail: Some(detail), kind: self.kind.clone().into(), - range: self.span.to_range(line_index), + range: self.span.to_range(line_index.clone()), selection_range: self.selection_span.to_range(line_index), data: None, } @@ -1444,14 +1451,14 @@ impl CallHierarchyIncomingCall { Some(lsp::CallHierarchyIncomingCall { from: self.from.to_call_hierarchy_item( - &target_line_index, + target_line_index.clone(), language_server, maybe_root_path, ), from_ranges: self .from_spans .iter() - .map(|span| span.to_range(&target_line_index)) + .map(|span| span.to_range(target_line_index.clone())) .collect(), }) } @@ -1467,7 +1474,7 @@ pub struct CallHierarchyOutgoingCall { impl CallHierarchyOutgoingCall { pub(crate) async fn try_resolve_call_hierarchy_outgoing_call( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, language_server: &mut language_server::Inner, maybe_root_path: Option<&Path>, ) -> Option<lsp::CallHierarchyOutgoingCall> { @@ -1479,14 +1486,14 @@ impl CallHierarchyOutgoingCall { Some(lsp::CallHierarchyOutgoingCall { to: self.to.to_call_hierarchy_item( - &target_line_index, + target_line_index, language_server, maybe_root_path, ), from_ranges: self .from_spans .iter() - .map(|span| span.to_range(line_index)) + .map(|span| span.to_range(line_index.clone())) .collect(), }) } @@ -1560,7 +1567,7 @@ pub struct CompletionInfo { impl CompletionInfo { pub fn as_completion_response( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, settings: &config::CompletionSettings, specifier: &ModuleSpecifier, position: u32, @@ -1569,8 +1576,13 @@ impl CompletionInfo { .entries .iter() .map(|entry| { - entry - .as_completion_item(line_index, self, settings, specifier, position) + entry.as_completion_item( + line_index.clone(), + self, + settings, + specifier, + position, + ) }) .collect(); let is_incomplete = self @@ -1711,7 +1723,7 @@ impl CompletionEntry { pub fn as_completion_item( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, info: &CompletionInfo, settings: &config::CompletionSettings, specifier: &ModuleSpecifier, @@ -1837,11 +1849,11 @@ const FOLD_END_PAIR_CHARACTERS: &[u8] = &[b'}', b']', b')', b'`']; impl OutliningSpan { pub fn to_folding_range( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, content: &[u8], line_folding_only: bool, ) -> lsp::FoldingRange { - let range = self.text_span.to_range(line_index); + let range = self.text_span.to_range(line_index.clone()); lsp::FoldingRange { start_line: range.start.line, start_character: if line_folding_only { @@ -1867,7 +1879,7 @@ impl OutliningSpan { fn adjust_folding_end_line( &self, range: &lsp::Range, - line_index: &LineIndex, + line_index: Arc<LineIndex>, content: &[u8], line_folding_only: bool, ) -> u32 { @@ -1991,10 +2003,10 @@ pub struct SelectionRange { impl SelectionRange { pub fn to_selection_range( &self, - line_index: &LineIndex, + line_index: Arc<LineIndex>, ) -> lsp::SelectionRange { lsp::SelectionRange { - range: self.text_span.to_range(line_index), + range: self.text_span.to_range(line_index.clone()), parent: self.parent.as_ref().map(|parent_selection| { Box::new(parent_selection.to_selection_range(line_index)) }), @@ -2065,19 +2077,13 @@ fn cache_snapshot( .snapshots .contains_key(&(specifier.clone(), version.clone().into())) { - let content = if state.state_snapshot.documents.contains_key(specifier) { - state - .state_snapshot - .documents - .content(specifier) - .ok_or_else(|| { - anyhow!("Specifier unexpectedly doesn't have content: {}", specifier) - })? - } else { - state.state_snapshot.sources.get_source(specifier).ok_or_else(|| { - anyhow!("Specifier (\"{}\") is not an in memory document or on disk resource.", specifier) - })? - }; + let content = state + .state_snapshot + .documents + .content(specifier) + .ok_or_else(|| { + anyhow!("Specifier unexpectedly doesn't have content: {}", specifier) + })?; state .snapshots .insert((specifier.clone(), version.into()), content.to_string()); @@ -2140,7 +2146,10 @@ fn op_exists(state: &mut State, args: SpecifierArgs) -> Result<bool, AnyError> { .performance .mark("op_exists", Some(&args)); let specifier = state.normalize_specifier(args.specifier)?; - let result = state.state_snapshot.sources.contains_key(&specifier); + let result = state + .state_snapshot + .documents + .contains_specifier(&specifier); state.state_snapshot.performance.measure(mark); Ok(result) } @@ -2268,7 +2277,7 @@ fn op_load( .performance .mark("op_load", Some(&args)); let specifier = state.normalize_specifier(args.specifier)?; - let result = state.state_snapshot.sources.get_source(&specifier); + let result = state.state_snapshot.documents.content(&specifier); state.state_snapshot.performance.measure(mark); Ok(result.map(|t| t.to_string())) } @@ -2281,89 +2290,33 @@ fn op_resolve( .state_snapshot .performance .mark("op_resolve", Some(&args)); - let mut resolved = Vec::new(); let referrer = state.normalize_specifier(&args.base)?; - let sources = &mut state.state_snapshot.sources; - if state.state_snapshot.documents.contains_key(&referrer) { - if let Some(dependencies) = - state.state_snapshot.documents.dependencies(&referrer) - { - for specifier in &args.specifiers { - if specifier.starts_with("asset:///") { - resolved.push(Some(( - specifier.clone(), - MediaType::from(specifier).as_ts_extension().into(), - ))) - } else if let Some(dependency) = dependencies.get(specifier) { - let resolved_import = - if let Some(resolved_import) = &dependency.maybe_type { - resolved_import.clone() - } else if let Some(resolved_import) = &dependency.maybe_code { - resolved_import.clone() - } else { - ResolvedDependency::Err(ResolvedDependencyErr::Missing) - }; - if let ResolvedDependency::Resolved(resolved_specifier) = - resolved_import - { - if state - .state_snapshot - .documents - .contains_key(&resolved_specifier) - { - let media_type = MediaType::from(&resolved_specifier); - resolved.push(Some(( - resolved_specifier.to_string(), - media_type.as_ts_extension().into(), - ))); - } else if sources.contains_key(&resolved_specifier) { - let media_type = if let Some(media_type) = - sources.get_media_type(&resolved_specifier) - { - media_type - } else { - MediaType::from(&resolved_specifier) - }; - resolved.push(Some(( - resolved_specifier.to_string(), - media_type.as_ts_extension().into(), - ))); - } else { - resolved.push(None); - } - } else { - resolved.push(None); - } - } - } - } - } else if sources.contains_key(&referrer) { - for specifier in &args.specifiers { - if let Some((resolved_specifier, media_type)) = - sources.resolve_import(specifier, &referrer) - { - resolved.push(Some(( - resolved_specifier.to_string(), - media_type.as_ts_extension().into(), - ))); - } else { - resolved.push(None); - } - } + let result = if let Some(resolved) = state + .state_snapshot + .documents + .resolve(args.specifiers, &referrer) + { + Ok( + resolved + .into_iter() + .map(|o| { + o.map(|(s, mt)| (s.to_string(), mt.as_ts_extension().to_string())) + }) + .collect(), + ) } else { - state.state_snapshot.performance.measure(mark); - return Err(custom_error( + Err(custom_error( "NotFound", format!( - "the referring ({}) specifier is unexpectedly missing", - referrer + "Error resolving. Referring specifier \"{}\" was not found.", + args.base ), - )); - } + )) + }; state.state_snapshot.performance.measure(mark); - Ok(resolved) + result } fn op_respond(state: &mut State, args: Response) -> Result<bool, AnyError> { @@ -2375,15 +2328,7 @@ fn op_script_names( state: &mut State, _args: Value, ) -> Result<Vec<ModuleSpecifier>, AnyError> { - Ok( - state - .state_snapshot - .documents - .open_specifiers() - .into_iter() - .cloned() - .collect(), - ) + Ok(state.state_snapshot.documents.specifiers(true, true)) } #[derive(Debug, Deserialize, Serialize)] @@ -2407,17 +2352,8 @@ fn op_script_version( } else { Ok(None) } - } else if let Some(version) = - state.state_snapshot.documents.version(&specifier) - { - Ok(Some(version.to_string())) } else { - let sources = &mut state.state_snapshot.sources; - if let Some(version) = sources.get_script_version(&specifier) { - Ok(Some(version)) - } else { - Ok(None) - } + Ok(state.state_snapshot.documents.version(&specifier)) }; state.state_snapshot.performance.measure(mark); @@ -2868,7 +2804,7 @@ impl RequestMethod { } /// Send a request into a runtime and return the JSON value of the response. -pub fn request( +pub(crate) fn request( runtime: &mut JsRuntime, state_snapshot: StateSnapshot, method: RequestMethod, @@ -2908,10 +2844,8 @@ mod tests { use super::*; use crate::http_cache::HttpCache; use crate::http_util::HeadersMap; - use crate::lsp::analysis; - use crate::lsp::documents::DocumentCache; + use crate::lsp::documents::Documents; use crate::lsp::documents::LanguageId; - use crate::lsp::sources::Sources; use crate::lsp::text::LineIndex; use std::path::Path; use std::path::PathBuf; @@ -2921,37 +2855,19 @@ mod tests { fixtures: &[(&str, &str, i32, LanguageId)], location: &Path, ) -> StateSnapshot { - let mut documents = DocumentCache::default(); + let documents = Documents::new(location); for (specifier, source, version, language_id) in fixtures { let specifier = resolve_url(specifier).expect("failed to create specifier"); documents.open( specifier.clone(), *version, - *language_id, + language_id.clone(), Arc::new(source.to_string()), ); - let media_type = MediaType::from(&specifier); - if let Some(Ok(parsed_module)) = - documents.get(&specifier).unwrap().source().module() - { - let (deps, _) = analysis::analyze_dependencies( - &specifier, - media_type, - parsed_module, - &None, - ); - let dep_ranges = - analysis::analyze_dependency_ranges(parsed_module).ok(); - documents - .set_dependencies(&specifier, Some(deps), dep_ranges) - .unwrap(); - } } - let sources = Sources::new(location); StateSnapshot { documents, - sources, ..Default::default() } } |