refactor(lsp): make RequestMethod private (#19114)

This commit is contained in:
David Sherret 2023-05-12 19:07:40 -04:00 committed by GitHub
parent 7476ee34fa
commit 68c0fcb157
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 628 additions and 382 deletions

View file

@ -230,13 +230,14 @@ async fn resolve_implementation_code_lens(
) -> Result<lsp::CodeLens, AnyError> {
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<Vec<tsc::ImplementationLocation>> =
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?;

View file

@ -50,7 +50,6 @@ pub type DiagnosticRecord =
pub type DiagnosticVec = Vec<DiagnosticRecord>;
type DiagnosticMap =
HashMap<ModuleSpecifier, (Option<i32>, Vec<lsp::Diagnostic>)>;
type TsDiagnosticsMap = HashMap<String, Vec<crate::tsc::Diagnostic>>;
type DiagnosticsByVersionMap = HashMap<Option<i32>, Vec<lsp::Diagnostic>>;
#[derive(Clone)]
@ -539,10 +538,9 @@ async fn generate_ts_diagnostics(
let (enabled_specifiers, disabled_specifiers) = specifiers
.into_iter()
.partition::<Vec<_>, _>(|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()

View file

@ -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<String> = 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<tsc::QuickInfo> = 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<tsc::CodeFixAction> =
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<tsc::ApplicableRefactorInfo> = 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::<CodeAction>::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<Vec<tsc::DocumentHighlights>> = 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(&params));
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<tsc::DefinitionInfoAndBoundSpan> = 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(&params));
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<Vec<tsc::DefinitionInfo>> = 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<tsc::CompletionInfo> =
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<Option<tsc::CompletionEntryDetails>, _> =
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<Vec<tsc::ImplementationLocation>> = 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(&params));
let asset_or_doc = self.get_asset_or_document(&specifier)?;
let req = tsc::RequestMethod::GetOutliningSpans(specifier);
let outlining_spans: Vec<tsc::OutliningSpan> = 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<tsc::CallHierarchyIncomingCall> = 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<tsc::CallHierarchyOutgoingCall> = 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<tsc::OneOrMany<tsc::CallHierarchyItem>> =
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<Vec<tsc::RenameLocation>> = 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::<SelectionRange>::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<tsc::SignatureHelpItems> = 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<Option<Vec<SymbolInformation>>> {
let mark = self.performance.mark("symbol", Some(&params));
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<tsc::NavigateToItem> = 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(&params));
let asset_or_doc = self.get_asset_or_document(&specifier)?;
let line_index = asset_or_doc.line_index();
let range = tsc::TextSpan::from_range(&params.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<Vec<tsc::InlayHint>> = self
let text_span =
tsc::TextSpan::from_range(&params.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()

View file

@ -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<R>(
pub async fn get_diagnostics(
&self,
snapshot: Arc<StateSnapshot>,
specifiers: Vec<ModuleSpecifier>,
token: CancellationToken,
) -> Result<HashMap<String, Vec<crate::tsc::Diagnostic>>, AnyError> {
let req = RequestMethod::GetDiagnostics(specifiers);
self.request_with_cancellation(snapshot, req, token).await
}
pub async fn find_references(
&self,
snapshot: Arc<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<ReferencedSymbol>>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
) -> Result<NavigationTree, AnyError> {
self
.request(snapshot, RequestMethod::GetNavigationTree(specifier))
.await
}
pub async fn configure(
&self,
snapshot: Arc<StateSnapshot>,
tsconfig: TsConfig,
) -> Result<bool, AnyError> {
self
.request(snapshot, RequestMethod::Configure(tsconfig))
.await
}
pub async fn get_supported_code_fixes(
&self,
snapshot: Arc<StateSnapshot>,
) -> Result<Vec<String>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<QuickInfo>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
range: Range<u32>,
codes: Vec<String>,
) -> Vec<CodeFixAction> {
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<StateSnapshot>,
specifier: ModuleSpecifier,
range: Range<u32>,
only: String,
) -> Result<Vec<ApplicableRefactorInfo>, 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<StateSnapshot>,
code_action_data: &CodeActionData,
) -> Result<CombinedCodeActions, LspError> {
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<StateSnapshot>,
specifier: ModuleSpecifier,
range: Range<u32>,
refactor_name: String,
action_name: String,
) -> Result<RefactorEditInfo, LspError> {
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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
files_to_search: Vec<ModuleSpecifier>,
) -> Result<Option<Vec<DocumentHighlights>>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<DefinitionInfoAndBoundSpan>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<DefinitionInfo>>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
options: GetCompletionsAtPositionOptions,
) -> Option<CompletionInfo> {
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<StateSnapshot>,
args: GetCompletionDetailsArgs,
) -> Result<Option<CompletionEntryDetails>, AnyError> {
let req = RequestMethod::GetCompletionDetails(args);
self.request(snapshot, req).await
}
pub async fn get_implementations(
&self,
snapshot: Arc<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<ImplementationLocation>>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
) -> Result<Vec<OutliningSpan>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Vec<CallHierarchyIncomingCall>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Vec<CallHierarchyOutgoingCall>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<OneOrMany<CallHierarchyItem>>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<RenameLocation>>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
) -> Result<SelectionRange, LspError> {
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<StateSnapshot>,
specifier: ModuleSpecifier,
range: Range<u32>,
) -> Result<Classifications, LspError> {
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<StateSnapshot>,
specifier: ModuleSpecifier,
position: u32,
options: SignatureHelpItemsOptions,
) -> Result<Option<SignatureHelpItems>, 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<StateSnapshot>,
args: GetNavigateToItemsArgs,
) -> Result<Vec<NavigateToItem>, 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<StateSnapshot>,
specifier: ModuleSpecifier,
text_span: TextSpan,
user_preferences: UserPreferences,
) -> Result<Option<Vec<InlayHint>>, 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<StateSnapshot>) {
let _: bool = self
.request(snapshot, RequestMethod::Restart)
.await
.unwrap();
}
async fn request<R>(
&self,
snapshot: Arc<StateSnapshot>,
req: RequestMethod,
@ -131,7 +529,7 @@ impl TsServer {
.await
}
pub async fn request_with_cancellation<R>(
async fn request_with_cancellation<R>(
&self,
snapshot: Arc<StateSnapshot>,
req: RequestMethod,
@ -147,26 +545,6 @@ impl TsServer {
let value = rx.await??;
Ok(serde_json::from_value::<R>(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<StateSnapshot>,
specifier: &ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<ReferencedSymbol>>, 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<u32>,
pub file: Option<String>,
}
/// 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<u32>,
file: Option<String>,
},
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<StateSnapshot>,
method: RequestMethod,

View file

@ -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(