summaryrefslogtreecommitdiff
path: root/cli/lsp/language_server.rs
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2021-03-25 11:13:37 +1100
committerGitHub <noreply@github.com>2021-03-25 11:13:37 +1100
commit5ebb4017030c065c31d52be50dc7fa7a4c128d64 (patch)
tree2983a0deeb164cc64ab45feb0f892e969b386115 /cli/lsp/language_server.rs
parentd6d5ced1ab90404d25a87a242ee5b03ca655abe5 (diff)
feat(lsp): add import completions (#9821)
Diffstat (limited to 'cli/lsp/language_server.rs')
-rw-r--r--cli/lsp/language_server.rs170
1 files changed, 93 insertions, 77 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 5489a0b9b..0dc9a95cb 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -39,6 +39,7 @@ use super::analysis::CodeLensData;
use super::analysis::CodeLensSource;
use super::analysis::ResolvedDependency;
use super::capabilities;
+use super::completions;
use super::config::Config;
use super::diagnostics;
use super::diagnostics::DiagnosticSource;
@@ -146,12 +147,16 @@ impl Inner {
specifier: &ModuleSpecifier,
source: &str,
) {
- if let Some((mut deps, _)) = analysis::analyze_dependencies(
- specifier,
- source,
- &MediaType::from(specifier),
- &self.maybe_import_map,
- ) {
+ let media_type = MediaType::from(specifier);
+ if let Ok(parsed_module) =
+ analysis::parse_module(specifier, source, &media_type)
+ {
+ let (mut deps, _) = analysis::analyze_dependencies(
+ specifier,
+ &media_type,
+ &parsed_module,
+ &self.maybe_import_map,
+ );
for (_, dep) in deps.iter_mut() {
if dep.maybe_type.is_none() {
if let Some(ResolvedDependency::Resolved(resolved)) = &dep.maybe_code
@@ -1354,55 +1359,67 @@ impl Inner {
let specifier = self
.url_map
.normalize_url(&params.text_document_position.text_document.uri);
- let line_index =
- if let Some(line_index) = self.get_line_index_sync(&specifier) {
- line_index
+ // Import specifiers are something wholly internal to Deno, so for
+ // completions, we will use internal logic and if there are completions
+ // for imports, we will return those and not send a message into tsc, where
+ // other completions come from.
+ let response = if let Some(response) = completions::get_import_completions(
+ &specifier,
+ &params.text_document_position.position,
+ &self.snapshot(),
+ ) {
+ Some(response)
+ } else {
+ let line_index =
+ if let Some(line_index) = self.get_line_index_sync(&specifier) {
+ line_index
+ } else {
+ return Err(LspError::invalid_params(format!(
+ "An unexpected specifier ({}) was provided.",
+ specifier
+ )));
+ };
+ let trigger_character = if let Some(context) = &params.context {
+ context.trigger_character.clone()
} else {
- return Err(LspError::invalid_params(format!(
- "An unexpected specifier ({}) was provided.",
- specifier
- )));
+ None
};
- let trigger_character = if let Some(context) = &params.context {
- context.trigger_character.clone()
- } else {
- None
- };
- let position =
- line_index.offset_tsc(params.text_document_position.position)?;
- let req = tsc::RequestMethod::GetCompletions((
- specifier.clone(),
- position,
- tsc::GetCompletionsAtPositionOptions {
- user_preferences: tsc::UserPreferences {
- include_completions_with_insert_text: Some(true),
- ..Default::default()
+ let position =
+ line_index.offset_tsc(params.text_document_position.position)?;
+ let req = tsc::RequestMethod::GetCompletions((
+ specifier.clone(),
+ position,
+ tsc::GetCompletionsAtPositionOptions {
+ user_preferences: tsc::UserPreferences {
+ include_completions_with_insert_text: Some(true),
+ ..Default::default()
+ },
+ trigger_character,
},
- trigger_character,
- },
- ));
- let maybe_completion_info: Option<tsc::CompletionInfo> = self
- .ts_server
- .request(self.snapshot(), req)
- .await
- .map_err(|err| {
- error!("Unable to get completion info from TypeScript: {}", err);
- LspError::internal_error()
- })?;
+ ));
+ let maybe_completion_info: Option<tsc::CompletionInfo> = self
+ .ts_server
+ .request(self.snapshot(), req)
+ .await
+ .map_err(|err| {
+ error!("Unable to get completion info from TypeScript: {}", err);
+ LspError::internal_error()
+ })?;
- if let Some(completions) = maybe_completion_info {
- let results = completions.as_completion_response(
- &line_index,
- &self.config.settings.suggest,
- &specifier,
- position,
- );
- self.performance.measure(mark);
- Ok(Some(results))
- } else {
- self.performance.measure(mark);
- Ok(None)
- }
+ if let Some(completions) = maybe_completion_info {
+ let results = completions.as_completion_response(
+ &line_index,
+ &self.config.settings.suggest,
+ &specifier,
+ position,
+ );
+ Some(results)
+ } else {
+ None
+ }
+ };
+ self.performance.measure(mark);
+ Ok(response)
}
async fn completion_resolve(
@@ -1410,40 +1427,39 @@ impl Inner {
params: CompletionItem,
) -> LspResult<CompletionItem> {
let mark = self.performance.mark("completion_resolve");
- if let Some(data) = &params.data {
- let data: tsc::CompletionItemData = serde_json::from_value(data.clone())
- .map_err(|err| {
+ let completion_item = if let Some(data) = &params.data {
+ let data: completions::CompletionItemData =
+ serde_json::from_value(data.clone()).map_err(|err| {
error!("{}", err);
LspError::invalid_params(
"Could not decode data field of completion item.",
)
})?;
- let req = tsc::RequestMethod::GetCompletionDetails(data.into());
- let maybe_completion_info: Option<tsc::CompletionEntryDetails> = self
- .ts_server
- .request(self.snapshot(), req)
- .await
- .map_err(|err| {
- error!("Unable to get completion info from TypeScript: {}", err);
- LspError::internal_error()
- })?;
- if let Some(completion_info) = maybe_completion_info {
- let completion_item = completion_info.as_completion_item(&params);
- self.performance.measure(mark);
- Ok(completion_item)
+ if let Some(data) = data.tsc {
+ let req = tsc::RequestMethod::GetCompletionDetails(data.into());
+ let maybe_completion_info: Option<tsc::CompletionEntryDetails> =
+ self.ts_server.request(self.snapshot(), req).await.map_err(
+ |err| {
+ error!("Unable to get completion info from TypeScript: {}", err);
+ LspError::internal_error()
+ },
+ )?;
+ if let Some(completion_info) = maybe_completion_info {
+ completion_info.as_completion_item(&params)
+ } else {
+ error!(
+ "Received an undefined response from tsc for completion details."
+ );
+ params
+ }
} else {
- error!(
- "Received an undefined response from tsc for completion details."
- );
- self.performance.measure(mark);
- Ok(params)
+ params
}
} else {
- self.performance.measure(mark);
- Err(LspError::invalid_params(
- "The completion item is missing the data field.",
- ))
- }
+ params
+ };
+ self.performance.measure(mark);
+ Ok(completion_item)
}
async fn goto_implementation(