From 68c0fcb157bb47bbf58bcdcecf59d237fb84f201 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 12 May 2023 19:07:40 -0400 Subject: [PATCH] refactor(lsp): make `RequestMethod` private (#19114) --- cli/lsp/code_lens.rs | 21 +- cli/lsp/diagnostics.rs | 6 +- cli/lsp/language_server.rs | 525 ++++++++++++++----------------------- cli/lsp/tsc.rs | 443 ++++++++++++++++++++++++++++--- cli/npm/cache.rs | 15 -- 5 files changed, 628 insertions(+), 382 deletions(-) diff --git a/cli/lsp/code_lens.rs b/cli/lsp/code_lens.rs index fd7f350061..c451e30bdc 100644 --- a/cli/lsp/code_lens.rs +++ b/cli/lsp/code_lens.rs @@ -230,13 +230,14 @@ async fn resolve_implementation_code_lens( ) -> Result { let asset_or_doc = language_server.get_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)?, - )); - let snapshot = language_server.snapshot(); - let maybe_implementations: Option> = - language_server.ts_server.request(snapshot, req).await?; + let maybe_implementations = language_server + .ts_server + .get_implementations( + language_server.snapshot(), + data.specifier.clone(), + line_index.offset_tsc(code_lens.range.start)?, + ) + .await?; if let Some(implementations) = maybe_implementations { let mut locations = Vec::new(); for implementation in implementations { @@ -325,12 +326,12 @@ async fn resolve_references_code_lens( let asset_or_document = language_server.get_asset_or_document(&data.specifier)?; let line_index = asset_or_document.line_index(); - let snapshot = language_server.snapshot(); + let maybe_referenced_symbols = language_server .ts_server .find_references( - snapshot, - &data.specifier, + language_server.snapshot(), + data.specifier.clone(), line_index.offset_tsc(code_lens.range.start)?, ) .await?; diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index 7d13cfdb5f..0f96a498bd 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -50,7 +50,6 @@ pub type DiagnosticRecord = pub type DiagnosticVec = Vec; type DiagnosticMap = HashMap, Vec)>; -type TsDiagnosticsMap = HashMap>; type DiagnosticsByVersionMap = HashMap, Vec>; #[derive(Clone)] @@ -539,10 +538,9 @@ async fn generate_ts_diagnostics( let (enabled_specifiers, disabled_specifiers) = specifiers .into_iter() .partition::, _>(|s| config.specifier_enabled(s)); - let ts_diagnostics_map: TsDiagnosticsMap = if !enabled_specifiers.is_empty() { - let req = tsc::RequestMethod::GetDiagnostics(enabled_specifiers); + let ts_diagnostics_map = if !enabled_specifiers.is_empty() { ts_server - .request_with_cancellation(snapshot.clone(), req, token) + .get_diagnostics(snapshot.clone(), enabled_specifiers, token) .await? } else { Default::default() diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 7fe986bfee..de5cd6f09c 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -578,10 +578,7 @@ impl Inner { } else { let navigation_tree: tsc::NavigationTree = self .ts_server - .request( - self.snapshot(), - tsc::RequestMethod::GetNavigationTree(specifier.clone()), - ) + .get_navigation_tree(self.snapshot(), specifier.clone()) .await?; let navigation_tree = Arc::new(navigation_tree); match asset_or_doc { @@ -1051,10 +1048,7 @@ impl Inner { if let Err(err) = self.merge_user_tsconfig(&mut tsconfig) { self.client.show_message(MessageType::WARNING, err); } - let _ok: bool = self - .ts_server - .request(self.snapshot(), tsc::RequestMethod::Configure(tsconfig)) - .await?; + let _ok = self.ts_server.configure(self.snapshot(), tsconfig).await?; self.performance.measure(mark); Ok(()) } @@ -1142,14 +1136,10 @@ impl Inner { } if capabilities.code_action_provider.is_some() { - let fixable_diagnostics: Vec = self + let fixable_diagnostics = self .ts_server - .request(self.snapshot(), tsc::RequestMethod::GetSupportedCodeFixes) - .await - .map_err(|err| { - error!("Unable to get fixable diagnostics: {}", err); - LspError::internal_error() - })?; + .get_supported_code_fixes(self.snapshot()) + .await?; self.ts_fixable_diagnostics = fixable_diagnostics; } @@ -1383,7 +1373,7 @@ impl Inner { self.refresh_documents_config(); self.refresh_npm_specifiers().await; self.diagnostics_server.invalidate_all(); - self.restart_ts_server().await; + self.ts_server.restart(self.snapshot()).await; self.send_diagnostics_update(); self.send_testing_update(); } @@ -1594,18 +1584,12 @@ impl Inner { }) } else { let line_index = asset_or_doc.line_index(); - let req = tsc::RequestMethod::GetQuickInfo(( - specifier, - line_index.offset_tsc(params.text_document_position_params.position)?, - )); - let maybe_quick_info: Option = self + let position = + line_index.offset_tsc(params.text_document_position_params.position)?; + let maybe_quick_info = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Unable to get quick info: {}", err); - LspError::internal_error() - })?; + .get_quick_info(self.snapshot(), specifier.clone(), position) + .await?; maybe_quick_info.map(|qi| qi.to_hover(line_index, self)) }; self.performance.measure(mark); @@ -1666,24 +1650,16 @@ impl Inner { NumberOrString::Number(code) => code.to_string(), }; let codes = vec![code]; - let req = tsc::RequestMethod::GetCodeFixes(( - specifier.clone(), - line_index.offset_tsc(diagnostic.range.start)?, - line_index.offset_tsc(diagnostic.range.end)?, - codes, - )); - let actions: Vec = - match self.ts_server.request(self.snapshot(), req).await { - Ok(items) => items, - Err(err) => { - // sometimes tsc reports errors when retrieving code actions - // because they don't reflect the current state of the document - // so we will log them to the output, but we won't send an error - // message back to the client. - error!("Error getting actions from TypeScript: {}", err); - Vec::new() - } - }; + let actions = self + .ts_server + .get_code_fixes( + self.snapshot(), + specifier.clone(), + line_index.offset_tsc(diagnostic.range.start)? + ..line_index.offset_tsc(diagnostic.range.end)?, + codes, + ) + .await; for action in actions { code_actions .add_ts_fix_action(&specifier, &action, diagnostic, self) @@ -1726,27 +1702,22 @@ impl Inner { } // Refactor - let start = line_index.offset_tsc(params.range.start)?; - let length = line_index.offset_tsc(params.range.end)? - start; let only = params .context .only .as_ref() .and_then(|values| values.first().map(|v| v.as_str().to_owned())) .unwrap_or_default(); - let req = tsc::RequestMethod::GetApplicableRefactors(( - specifier.clone(), - tsc::TextSpan { start, length }, - only, - )); - let refactor_infos: Vec = self + let refactor_infos = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .get_applicable_refactors( + self.snapshot(), + specifier.clone(), + line_index.offset_tsc(params.range.start)? + ..line_index.offset_tsc(params.range.end)?, + only, + ) + .await?; let mut refactor_actions = Vec::::new(); for refactor_info in refactor_infos.iter() { refactor_actions @@ -1788,24 +1759,15 @@ impl Inner { let result = if kind.as_str().starts_with(CodeActionKind::QUICKFIX.as_str()) { - let snapshot = self.snapshot(); let code_action_data: CodeActionData = from_value(data).map_err(|err| { error!("Unable to decode code action data: {}", err); LspError::invalid_params("The CodeAction's data is invalid.") })?; - let req = tsc::RequestMethod::GetCombinedCodeFix(( - code_action_data.specifier.clone(), - json!(code_action_data.fix_id.clone()), - )); - let combined_code_actions: tsc::CombinedCodeActions = self + let combined_code_actions = self .ts_server - .request(snapshot.clone(), req) - .await - .map_err(|err| { - error!("Unable to get combined fix from TypeScript: {}", err); - LspError::internal_error() - })?; + .get_combined_code_fix(self.snapshot(), &code_action_data) + .await?; if combined_code_actions.commands.is_some() { error!("Deno does not support code actions with commands."); return Err(LspError::invalid_request()); @@ -1831,7 +1793,6 @@ impl Inner { })?; code_action } else if kind.as_str().starts_with(CodeActionKind::REFACTOR.as_str()) { - let snapshot = self.snapshot(); let mut code_action = params; let action_data: refactor::RefactorCodeActionData = from_value(data) .map_err(|err| { @@ -1840,19 +1801,17 @@ impl Inner { })?; let asset_or_doc = self.get_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(( - action_data.specifier, - tsc::TextSpan { start, length }, - action_data.refactor_name, - action_data.action_name, - )); - let refactor_edit_info: tsc::RefactorEditInfo = - self.ts_server.request(snapshot, req).await.map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + let refactor_edit_info = self + .ts_server + .get_edits_for_refactor( + self.snapshot(), + action_data.specifier, + line_index.offset_tsc(action_data.range.start)? + ..line_index.offset_tsc(action_data.range.end)?, + action_data.refactor_name, + action_data.action_name, + ) + .await?; code_action.edit = refactor_edit_info .to_workspace_edit(self) .await @@ -1950,19 +1909,15 @@ impl Inner { let asset_or_doc = self.get_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, - line_index.offset_tsc(params.text_document_position_params.position)?, - files_to_search, - )); - let maybe_document_highlights: Option> = self + let maybe_document_highlights = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Unable to get document highlights from TypeScript: {}", err); - LspError::internal_error() - })?; + .get_document_highlights( + self.snapshot(), + specifier, + line_index.offset_tsc(params.text_document_position_params.position)?, + files_to_search, + ) + .await?; if let Some(document_highlights) = maybe_document_highlights { let result = document_highlights @@ -1998,7 +1953,7 @@ impl Inner { .ts_server .find_references( self.snapshot(), - &specifier, + specifier.clone(), line_index.offset_tsc(params.text_document_position.position)?, ) .await?; @@ -2050,18 +2005,14 @@ impl Inner { let mark = self.performance.mark("goto_definition", Some(¶ms)); let asset_or_doc = self.get_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)?, - )); - let maybe_definition: Option = self + let maybe_definition = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Unable to get definition from TypeScript: {}", err); - LspError::internal_error() - })?; + .get_definition( + self.snapshot(), + specifier, + line_index.offset_tsc(params.text_document_position_params.position)?, + ) + .await?; if let Some(definition) = maybe_definition { let results = definition.to_definition(line_index, self).await; @@ -2090,19 +2041,14 @@ impl Inner { let mark = self.performance.mark("goto_definition", Some(¶ms)); let asset_or_doc = self.get_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); - let req = tsc::RequestMethod::GetTypeDefinition { - specifier, - position: line_index - .offset_tsc(params.text_document_position_params.position)?, - }; - let maybe_definition_info: Option> = self + let maybe_definition_info = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Unable to get type definition from TypeScript: {}", err); - LspError::internal_error() - })?; + .get_type_definition( + self.snapshot(), + specifier, + line_index.offset_tsc(params.text_document_position_params.position)?, + ) + .await?; let response = if let Some(definition_info) = maybe_definition_info { let mut location_links = Vec::new(); @@ -2167,48 +2113,47 @@ impl Inner { let position = line_index.offset_tsc(params.text_document_position.position)?; let use_snippets = self.config.client_capabilities.snippet_support; - let req = tsc::RequestMethod::GetCompletions(( - specifier.clone(), - position, - tsc::GetCompletionsAtPositionOptions { - user_preferences: tsc::UserPreferences { - allow_incomplete_completions: Some(true), - allow_text_changes_in_new_files: Some(specifier.scheme() == "file"), - import_module_specifier_ending: Some( - tsc::ImportModuleSpecifierEnding::Index, - ), - include_automatic_optional_chain_completions: Some(true), - include_completions_for_import_statements: Some( - self.config.workspace_settings().suggest.auto_imports, - ), - include_completions_for_module_exports: Some(true), - include_completions_with_object_literal_method_snippets: Some( - use_snippets, - ), - include_completions_with_class_member_snippets: Some(use_snippets), - include_completions_with_insert_text: Some(true), - include_completions_with_snippet_text: Some(use_snippets), - jsx_attribute_completion_style: Some( - tsc::JsxAttributeCompletionStyle::Auto, - ), - provide_prefix_and_suffix_text_for_rename: Some(true), - provide_refactor_not_applicable_reason: Some(true), - use_label_details_in_completion_entries: Some(true), - ..Default::default() + let maybe_completion_info = self + .ts_server + .get_completions( + self.snapshot(), + specifier.clone(), + position, + tsc::GetCompletionsAtPositionOptions { + user_preferences: tsc::UserPreferences { + allow_incomplete_completions: Some(true), + allow_text_changes_in_new_files: Some( + specifier.scheme() == "file", + ), + import_module_specifier_ending: Some( + tsc::ImportModuleSpecifierEnding::Index, + ), + include_automatic_optional_chain_completions: Some(true), + include_completions_for_import_statements: Some( + self.config.workspace_settings().suggest.auto_imports, + ), + include_completions_for_module_exports: Some(true), + include_completions_with_object_literal_method_snippets: Some( + use_snippets, + ), + include_completions_with_class_member_snippets: Some( + use_snippets, + ), + include_completions_with_insert_text: Some(true), + include_completions_with_snippet_text: Some(use_snippets), + jsx_attribute_completion_style: Some( + tsc::JsxAttributeCompletionStyle::Auto, + ), + provide_prefix_and_suffix_text_for_rename: Some(true), + provide_refactor_not_applicable_reason: Some(true), + use_label_details_in_completion_entries: Some(true), + ..Default::default() + }, + trigger_character, + trigger_kind, }, - trigger_character, - trigger_kind, - }, - )); - let snapshot = self.snapshot(); - let maybe_completion_info: Option = - match self.ts_server.request(snapshot, req).await { - Ok(maybe_info) => maybe_info, - Err(err) => { - error!("Unable to get completion info from TypeScript: {:#}", err); - None - } - }; + ) + .await; if let Some(completions) = maybe_completion_info { let results = completions.as_completion_response( @@ -2241,9 +2186,10 @@ impl Inner { })?; if let Some(data) = &data.tsc { let specifier = &data.specifier; - let req = tsc::RequestMethod::GetCompletionDetails(data.into()); - let result: Result, _> = - self.ts_server.request(self.snapshot(), req).await; + let result = self + .ts_server + .get_completion_details(self.snapshot(), data.into()) + .await; match result { Ok(maybe_completion_info) => { if let Some(completion_info) = maybe_completion_info { @@ -2302,18 +2248,14 @@ impl Inner { let asset_or_doc = self.get_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); - let req = tsc::RequestMethod::GetImplementation(( - specifier, - line_index.offset_tsc(params.text_document_position_params.position)?, - )); - let maybe_implementations: Option> = self + let maybe_implementations = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .get_implementations( + self.snapshot(), + specifier, + line_index.offset_tsc(params.text_document_position_params.position)?, + ) + .await?; let result = if let Some(implementations) = maybe_implementations { let mut links = Vec::new(); @@ -2347,15 +2289,10 @@ impl Inner { let mark = self.performance.mark("folding_range", Some(¶ms)); let asset_or_doc = self.get_asset_or_document(&specifier)?; - let req = tsc::RequestMethod::GetOutliningSpans(specifier); - let outlining_spans: Vec = self + let outlining_spans = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .get_outlining_spans(self.snapshot(), specifier) + .await?; let response = if !outlining_spans.is_empty() { Some( @@ -2394,18 +2331,14 @@ impl Inner { let asset_or_doc = self.get_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); - let req = tsc::RequestMethod::ProvideCallHierarchyIncomingCalls(( - specifier, - line_index.offset_tsc(params.item.selection_range.start)?, - )); let incoming_calls: Vec = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .provide_call_hierarchy_incoming_calls( + self.snapshot(), + specifier, + line_index.offset_tsc(params.item.selection_range.start)?, + ) + .await?; let maybe_root_path_owned = self .config @@ -2442,18 +2375,14 @@ impl Inner { let asset_or_doc = self.get_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); - let req = tsc::RequestMethod::ProvideCallHierarchyOutgoingCalls(( - specifier, - line_index.offset_tsc(params.item.selection_range.start)?, - )); let outgoing_calls: Vec = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .provide_call_hierarchy_outgoing_calls( + self.snapshot(), + specifier, + line_index.offset_tsc(params.item.selection_range.start)?, + ) + .await?; let maybe_root_path_owned = self .config @@ -2494,19 +2423,14 @@ impl Inner { let asset_or_doc = self.get_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); - let req = tsc::RequestMethod::PrepareCallHierarchy(( - specifier, - line_index.offset_tsc(params.text_document_position_params.position)?, - )); - let maybe_one_or_many: Option> = - self - .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + let maybe_one_or_many = self + .ts_server + .prepare_call_hierarchy( + self.snapshot(), + specifier, + line_index.offset_tsc(params.text_document_position_params.position)?, + ) + .await?; let response = if let Some(one_or_many) = maybe_one_or_many { let maybe_root_path_owned = self @@ -2561,23 +2485,14 @@ impl Inner { let asset_or_doc = self.get_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); - let req = tsc::RequestMethod::FindRenameLocations { - specifier, - position: line_index - .offset_tsc(params.text_document_position.position)?, - find_in_strings: false, - find_in_comments: false, - provide_prefix_and_suffix_text_for_rename: false, - }; - - let maybe_locations: Option> = self + let maybe_locations = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .find_rename_locations( + self.snapshot(), + specifier, + line_index.offset_tsc(params.text_document_position.position)?, + ) + .await?; if let Some(locations) = maybe_locations { let rename_locations = tsc::RenameLocations { locations }; @@ -2615,19 +2530,14 @@ impl Inner { let mut selection_ranges = Vec::::new(); for position in params.positions { - let req = tsc::RequestMethod::GetSmartSelectionRange(( - specifier.clone(), - line_index.offset_tsc(position)?, - )); - let selection_range: tsc::SelectionRange = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .get_smart_selection_range( + self.snapshot(), + specifier.clone(), + line_index.offset_tsc(position)?, + ) + .await?; selection_ranges .push(selection_range.to_selection_range(line_index.clone())); @@ -2653,21 +2563,14 @@ impl Inner { let asset_or_doc = self.get_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); - let req = tsc::RequestMethod::GetEncodedSemanticClassifications(( - specifier, - tsc::TextSpan { - start: 0, - length: line_index.text_content_length_utf16().into(), - }, - )); - let semantic_classification: tsc::Classifications = self + let semantic_classification = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .get_encoded_semantic_classifications( + self.snapshot(), + specifier, + 0..line_index.text_content_length_utf16().into(), + ) + .await?; let semantic_tokens = semantic_classification.to_semantic_tokens(&asset_or_doc, line_index)?; @@ -2699,20 +2602,15 @@ impl Inner { let asset_or_doc = self.get_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; - let req = tsc::RequestMethod::GetEncodedSemanticClassifications(( - specifier, - tsc::TextSpan { start, length }, - )); - let semantic_classification: tsc::Classifications = self + let semantic_classification = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - })?; + .get_encoded_semantic_classifications( + self.snapshot(), + specifier, + line_index.offset_tsc(params.range.start)? + ..line_index.offset_tsc(params.range.end)?, + ) + .await?; let semantic_tokens = semantic_classification.to_semantic_tokens(&asset_or_doc, line_index)?; @@ -2754,19 +2652,15 @@ impl Inner { trigger_reason: None, } }; - let req = tsc::RequestMethod::GetSignatureHelpItems(( - specifier, - line_index.offset_tsc(params.text_document_position_params.position)?, - options, - )); let maybe_signature_help_items: Option = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed to request to tsserver: {}", err); - LspError::invalid_request() - })?; + .get_signature_help_items( + self.snapshot(), + specifier, + line_index.offset_tsc(params.text_document_position_params.position)?, + options, + ) + .await?; if let Some(signature_help_items) = maybe_signature_help_items { let signature_help = signature_help_items.into_signature_help(self); @@ -2784,21 +2678,18 @@ impl Inner { ) -> LspResult>> { let mark = self.performance.mark("symbol", Some(¶ms)); - let req = tsc::RequestMethod::GetNavigateToItems { - search: params.query, - // this matches vscode's hard coded result count - max_result_count: Some(256), - file: None, - }; - - let navigate_to_items: Vec = self + let navigate_to_items = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Failed request to tsserver: {}", err); - LspError::invalid_request() - })?; + .get_navigate_to_items( + self.snapshot(), + tsc::GetNavigateToItemsArgs { + search: params.query, + // this matches vscode's hard coded result count + max_result_count: Some(256), + file: None, + }, + ) + .await?; let maybe_symbol_information = if navigate_to_items.is_empty() { None @@ -3287,21 +3178,13 @@ impl Inner { // the language server for TypeScript (as it might hold to some stale // documents). self.diagnostics_server.invalidate_all(); - self.restart_ts_server().await; + self.ts_server.restart(self.snapshot()).await; self.send_diagnostics_update(); self.send_testing_update(); self.performance.measure(mark); } - async fn restart_ts_server(&self) { - let _: bool = self - .ts_server - .request(self.snapshot(), tsc::RequestMethod::Restart) - .await - .unwrap(); - } - fn get_performance(&self) -> Value { let averages = self.performance.averages(); json!({ "averages": averages }) @@ -3334,24 +3217,22 @@ impl Inner { let mark = self.performance.mark("inlay_hint", Some(¶ms)); let asset_or_doc = self.get_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); - let range = tsc::TextSpan::from_range(¶ms.range, line_index.clone()) - .map_err(|err| { - error!("Failed to convert range to text_span: {}", err); - LspError::internal_error() - })?; - let req = tsc::RequestMethod::ProvideInlayHints(( - specifier, - range, - workspace_settings.into(), - )); - let maybe_inlay_hints: Option> = self + let text_span = + tsc::TextSpan::from_range(¶ms.range, line_index.clone()).map_err( + |err| { + error!("Failed to convert range to text_span: {}", err); + LspError::internal_error() + }, + )?; + let maybe_inlay_hints = self .ts_server - .request(self.snapshot(), req) - .await - .map_err(|err| { - error!("Unable to get inlay hints: {}", err); - LspError::internal_error() - })?; + .provide_inlay_hints( + self.snapshot(), + specifier, + text_span, + workspace_settings.into(), + ) + .await?; let maybe_inlay_hints = maybe_inlay_hints.map(|hints| { hints .iter() diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index 92407bec1a..bfbb5cf9ac 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -1,5 +1,6 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +use super::analysis::CodeActionData; use super::code_lens; use super::config; use super::documents::AssetOrDocument; @@ -53,6 +54,7 @@ use serde_repr::Serialize_repr; use std::cmp; use std::collections::HashMap; use std::collections::HashSet; +use std::ops::Range; use std::path::Path; use std::sync::Arc; use std::thread; @@ -118,7 +120,403 @@ impl TsServer { Self(tx) } - pub async fn request( + pub async fn get_diagnostics( + &self, + snapshot: Arc, + specifiers: Vec, + token: CancellationToken, + ) -> Result>, AnyError> { + let req = RequestMethod::GetDiagnostics(specifiers); + self.request_with_cancellation(snapshot, req, token).await + } + + pub async fn find_references( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result>, LspError> { + let req = RequestMethod::FindReferences { + specifier, + position, + }; + self.request(snapshot, req).await.map_err(|err| { + log::error!("Unable to get references from TypeScript: {}", err); + LspError::internal_error() + }) + } + + pub async fn get_navigation_tree( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + ) -> Result { + self + .request(snapshot, RequestMethod::GetNavigationTree(specifier)) + .await + } + + pub async fn configure( + &self, + snapshot: Arc, + tsconfig: TsConfig, + ) -> Result { + self + .request(snapshot, RequestMethod::Configure(tsconfig)) + .await + } + + pub async fn get_supported_code_fixes( + &self, + snapshot: Arc, + ) -> Result, LspError> { + self + .request(snapshot, RequestMethod::GetSupportedCodeFixes) + .await + .map_err(|err| { + log::error!("Unable to get fixable diagnostics: {}", err); + LspError::internal_error() + }) + } + + pub async fn get_quick_info( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result, LspError> { + let req = RequestMethod::GetQuickInfo((specifier, position)); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Unable to get quick info: {}", err); + LspError::internal_error() + }) + } + + pub async fn get_code_fixes( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + range: Range, + codes: Vec, + ) -> Vec { + let req = + RequestMethod::GetCodeFixes((specifier, range.start, range.end, codes)); + match self.request(snapshot, req).await { + Ok(items) => items, + Err(err) => { + // sometimes tsc reports errors when retrieving code actions + // because they don't reflect the current state of the document + // so we will log them to the output, but we won't send an error + // message back to the client. + log::error!("Error getting actions from TypeScript: {}", err); + Vec::new() + } + } + } + + pub async fn get_applicable_refactors( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + range: Range, + only: String, + ) -> Result, LspError> { + let req = RequestMethod::GetApplicableRefactors(( + specifier.clone(), + TextSpan { + start: range.start, + length: range.end - range.start, + }, + only, + )); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn get_combined_code_fix( + &self, + snapshot: Arc, + code_action_data: &CodeActionData, + ) -> Result { + let req = RequestMethod::GetCombinedCodeFix(( + code_action_data.specifier.clone(), + json!(code_action_data.fix_id.clone()), + )); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Unable to get combined fix from TypeScript: {}", err); + LspError::internal_error() + }) + } + + pub async fn get_edits_for_refactor( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + range: Range, + refactor_name: String, + action_name: String, + ) -> Result { + let req = RequestMethod::GetEditsForRefactor(( + specifier, + TextSpan { + start: range.start, + length: range.end - range.start, + }, + refactor_name, + action_name, + )); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn get_document_highlights( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + files_to_search: Vec, + ) -> Result>, LspError> { + let req = RequestMethod::GetDocumentHighlights(( + specifier, + position, + files_to_search, + )); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Unable to get document highlights from TypeScript: {}", err); + LspError::internal_error() + }) + } + + pub async fn get_definition( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result, LspError> { + let req = RequestMethod::GetDefinition((specifier, position)); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Unable to get definition from TypeScript: {}", err); + LspError::internal_error() + }) + } + + pub async fn get_type_definition( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result>, LspError> { + let req = RequestMethod::GetTypeDefinition { + specifier, + position, + }; + self.request(snapshot, req).await.map_err(|err| { + log::error!("Unable to get type definition from TypeScript: {}", err); + LspError::internal_error() + }) + } + + pub async fn get_completions( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + options: GetCompletionsAtPositionOptions, + ) -> Option { + let req = RequestMethod::GetCompletions((specifier, position, options)); + match self.request(snapshot, req).await { + Ok(maybe_info) => maybe_info, + Err(err) => { + log::error!("Unable to get completion info from TypeScript: {:#}", err); + None + } + } + } + + pub async fn get_completion_details( + &self, + snapshot: Arc, + args: GetCompletionDetailsArgs, + ) -> Result, AnyError> { + let req = RequestMethod::GetCompletionDetails(args); + self.request(snapshot, req).await + } + + pub async fn get_implementations( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result>, LspError> { + let req = RequestMethod::GetImplementation((specifier, position)); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn get_outlining_spans( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + ) -> Result, LspError> { + let req = RequestMethod::GetOutliningSpans(specifier); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn provide_call_hierarchy_incoming_calls( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result, LspError> { + let req = + RequestMethod::ProvideCallHierarchyIncomingCalls((specifier, position)); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn provide_call_hierarchy_outgoing_calls( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result, LspError> { + let req = + RequestMethod::ProvideCallHierarchyOutgoingCalls((specifier, position)); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn prepare_call_hierarchy( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result>, LspError> { + let req = RequestMethod::PrepareCallHierarchy((specifier, position)); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn find_rename_locations( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result>, LspError> { + let req = RequestMethod::FindRenameLocations { + specifier, + position, + find_in_strings: false, + find_in_comments: false, + provide_prefix_and_suffix_text_for_rename: false, + }; + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn get_smart_selection_range( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + ) -> Result { + let req = RequestMethod::GetSmartSelectionRange((specifier, position)); + + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn get_encoded_semantic_classifications( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + range: Range, + ) -> Result { + let req = RequestMethod::GetEncodedSemanticClassifications(( + specifier, + TextSpan { + start: range.start, + length: range.end - range.start, + }, + )); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) + } + + pub async fn get_signature_help_items( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + position: u32, + options: SignatureHelpItemsOptions, + ) -> Result, LspError> { + let req = + RequestMethod::GetSignatureHelpItems((specifier, position, options)); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed to request to tsserver: {}", err); + LspError::invalid_request() + }) + } + + pub async fn get_navigate_to_items( + &self, + snapshot: Arc, + args: GetNavigateToItemsArgs, + ) -> Result, LspError> { + let req = RequestMethod::GetNavigateToItems(args); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Failed request to tsserver: {}", err); + LspError::invalid_request() + }) + } + + pub async fn provide_inlay_hints( + &self, + snapshot: Arc, + specifier: ModuleSpecifier, + text_span: TextSpan, + user_preferences: UserPreferences, + ) -> Result>, LspError> { + let req = RequestMethod::ProvideInlayHints(( + specifier, + text_span, + user_preferences, + )); + self.request(snapshot, req).await.map_err(|err| { + log::error!("Unable to get inlay hints: {}", err); + LspError::internal_error() + }) + } + + pub async fn restart(&self, snapshot: Arc) { + let _: bool = self + .request(snapshot, RequestMethod::Restart) + .await + .unwrap(); + } + + async fn request( &self, snapshot: Arc, req: RequestMethod, @@ -131,7 +529,7 @@ impl TsServer { .await } - pub async fn request_with_cancellation( + async fn request_with_cancellation( &self, snapshot: Arc, req: RequestMethod, @@ -147,26 +545,6 @@ impl TsServer { let value = rx.await??; Ok(serde_json::from_value::(value)?) } - - // todo(dsherret): refactor the rest of the request methods to have - // methods to call on this struct, then make `RequestMethod` and - // friends internal - - pub async fn find_references( - &self, - snapshot: Arc, - specifier: &ModuleSpecifier, - position: u32, - ) -> Result>, LspError> { - let req = RequestMethod::FindReferences { - specifier: specifier.clone(), - position, - }; - self.request(snapshot, req).await.map_err(|err| { - log::error!("Unable to get references from TypeScript: {}", err); - LspError::internal_error() - }) - } } #[derive(Debug, Clone)] @@ -3161,9 +3539,16 @@ impl From<&CompletionItemData> for GetCompletionDetailsArgs { } } +#[derive(Debug)] +pub struct GetNavigateToItemsArgs { + pub search: String, + pub max_result_count: Option, + pub file: Option, +} + /// Methods that are supported by the Language Service in the compiler isolate. #[derive(Debug)] -pub enum RequestMethod { +enum RequestMethod { /// Configure the compilation settings for the server. Configure(TsConfig), /// Get rename locations at a given position. @@ -3198,11 +3583,7 @@ pub enum RequestMethod { /// Get implementation information for a specific position. GetImplementation((ModuleSpecifier, u32)), /// Get "navigate to" items, which are converted to workspace symbols - GetNavigateToItems { - search: String, - max_result_count: Option, - file: Option, - }, + GetNavigateToItems(GetNavigateToItemsArgs), /// Get a "navigation tree" for a specifier. GetNavigationTree(ModuleSpecifier), /// Get outlining spans for a specifier. @@ -3356,11 +3737,11 @@ impl RequestMethod { "specifier": state.denormalize_specifier(specifier), "position": position, }), - RequestMethod::GetNavigateToItems { + RequestMethod::GetNavigateToItems(GetNavigateToItemsArgs { search, max_result_count, file, - } => json!({ + }) => json!({ "id": id, "method": "getNavigateToItems", "search": search, @@ -3470,7 +3851,7 @@ impl RequestMethod { } /// Send a request into a runtime and return the JSON value of the response. -pub fn request( +fn request( runtime: &mut JsRuntime, state_snapshot: Arc, method: RequestMethod, diff --git a/cli/npm/cache.rs b/cli/npm/cache.rs index cda40fd172..aba6c0cca7 100644 --- a/cli/npm/cache.rs +++ b/cli/npm/cache.rs @@ -20,7 +20,6 @@ use deno_semver::Version; use once_cell::sync::Lazy; use crate::args::CacheSetting; -use crate::cache::DenoDir; use crate::http_util::HttpClient; use crate::util::fs::canonicalize_path; use crate::util::fs::hard_link_dir_recursive; @@ -120,20 +119,6 @@ pub struct ReadonlyNpmCache { root_dir_url: Url, } -// todo(dsherret): implementing Default for this is error prone because someone -// might accidentally use the default implementation instead of getting the -// correct location of the deno dir, which might be provided via a CLI argument. -// That said, the rest of the LSP code does this at the moment and so this code -// copies that. -impl Default for ReadonlyNpmCache { - fn default() -> Self { - // This only gets used when creating the tsc runtime and for testing, and so - // it shouldn't ever actually access the DenoDir, so it doesn't support a - // custom root. - Self::new(DenoDir::new(None).unwrap().npm_folder_path()) - } -} - impl ReadonlyNpmCache { pub fn new(root_dir: PathBuf) -> Self { fn try_get_canonicalized_root_dir(