mirror of
https://github.com/denoland/deno.git
synced 2025-08-03 10:33:54 +00:00
refactor(lsp): refactor completions and add tests (#9789)
This commit is contained in:
parent
2ff9b01551
commit
506b321d47
9 changed files with 800 additions and 148 deletions
|
@ -917,7 +917,7 @@ impl Inner {
|
|||
let mut code_lenses = cl.borrow_mut();
|
||||
|
||||
// TSC Implementations Code Lens
|
||||
if self.config.settings.enabled_code_lens_implementations() {
|
||||
if self.config.settings.code_lens.implementations {
|
||||
let source = CodeLensSource::Implementations;
|
||||
match i.kind {
|
||||
tsc::ScriptElementKind::InterfaceElement => {
|
||||
|
@ -941,7 +941,7 @@ impl Inner {
|
|||
}
|
||||
|
||||
// TSC References Code Lens
|
||||
if self.config.settings.enabled_code_lens_references() {
|
||||
if self.config.settings.code_lens.references {
|
||||
let source = CodeLensSource::References;
|
||||
if let Some(parent) = &mp {
|
||||
if parent.kind == tsc::ScriptElementKind::EnumElement {
|
||||
|
@ -950,11 +950,7 @@ impl Inner {
|
|||
}
|
||||
match i.kind {
|
||||
tsc::ScriptElementKind::FunctionElement => {
|
||||
if self
|
||||
.config
|
||||
.settings
|
||||
.enabled_code_lens_references_all_functions()
|
||||
{
|
||||
if self.config.settings.code_lens.references_all_functions {
|
||||
code_lenses.push(i.to_code_lens(
|
||||
&line_index,
|
||||
&specifier,
|
||||
|
@ -1358,7 +1354,6 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position.text_document.uri);
|
||||
// TODO(lucacasonato): handle error correctly
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -1368,13 +1363,22 @@ impl Inner {
|
|||
specifier
|
||||
)));
|
||||
};
|
||||
let trigger_character = if let Some(context) = ¶ms.context {
|
||||
context.trigger_character.clone()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let position =
|
||||
line_index.offset_tsc(params.text_document_position.position)?;
|
||||
let req = tsc::RequestMethod::GetCompletions((
|
||||
specifier,
|
||||
line_index.offset_tsc(params.text_document_position.position)?,
|
||||
tsc::UserPreferences {
|
||||
// TODO(lucacasonato): enable this. see https://github.com/denoland/deno/pull/8651
|
||||
include_completions_with_insert_text: Some(false),
|
||||
..Default::default()
|
||||
specifier.clone(),
|
||||
position,
|
||||
tsc::GetCompletionsAtPositionOptions {
|
||||
user_preferences: tsc::UserPreferences {
|
||||
include_completions_with_insert_text: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
trigger_character,
|
||||
},
|
||||
));
|
||||
let maybe_completion_info: Option<tsc::CompletionInfo> = self
|
||||
|
@ -1387,7 +1391,12 @@ impl Inner {
|
|||
})?;
|
||||
|
||||
if let Some(completions) = maybe_completion_info {
|
||||
let results = completions.into_completion_response(&line_index);
|
||||
let results = completions.as_completion_response(
|
||||
&line_index,
|
||||
&self.config.settings.suggest,
|
||||
&specifier,
|
||||
position,
|
||||
);
|
||||
self.performance.measure(mark);
|
||||
Ok(Some(results))
|
||||
} else {
|
||||
|
@ -1396,6 +1405,47 @@ impl Inner {
|
|||
}
|
||||
}
|
||||
|
||||
async fn completion_resolve(
|
||||
&mut self,
|
||||
params: CompletionItem,
|
||||
) -> LspResult<CompletionItem> {
|
||||
let mark = self.performance.mark("completion_resolve");
|
||||
if let Some(data) = ¶ms.data {
|
||||
let data: tsc::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(¶ms);
|
||||
self.performance.measure(mark);
|
||||
Ok(completion_item)
|
||||
} else {
|
||||
error!(
|
||||
"Received an undefined response from tsc for completion details."
|
||||
);
|
||||
self.performance.measure(mark);
|
||||
Ok(params)
|
||||
}
|
||||
} else {
|
||||
self.performance.measure(mark);
|
||||
Err(LspError::invalid_params(
|
||||
"The completion item is missing the data field.",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
async fn goto_implementation(
|
||||
&mut self,
|
||||
params: GotoImplementationParams,
|
||||
|
@ -1715,6 +1765,13 @@ impl lspower::LanguageServer for LanguageServer {
|
|||
self.0.lock().await.completion(params).await
|
||||
}
|
||||
|
||||
async fn completion_resolve(
|
||||
&self,
|
||||
params: CompletionItem,
|
||||
) -> LspResult<CompletionItem> {
|
||||
self.0.lock().await.completion_resolve(params).await
|
||||
}
|
||||
|
||||
async fn goto_implementation(
|
||||
&self,
|
||||
params: GotoImplementationParams,
|
||||
|
@ -2740,6 +2797,58 @@ mod tests {
|
|||
harness.run().await;
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CompletionResult {
|
||||
pub result: Option<CompletionResponse>,
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_completions() {
|
||||
let mut harness = LspTestHarness::new(vec![
|
||||
("initialize_request.json", LspResponse::RequestAny),
|
||||
("initialized_notification.json", LspResponse::None),
|
||||
("did_open_notification_completions.json", LspResponse::None),
|
||||
(
|
||||
"completion_request.json",
|
||||
LspResponse::RequestAssert(|value| {
|
||||
let response: CompletionResult =
|
||||
serde_json::from_value(value).unwrap();
|
||||
let result = response.result.unwrap();
|
||||
match result {
|
||||
CompletionResponse::List(list) => {
|
||||
// there should be at least 90 completions for `Deno.`
|
||||
assert!(list.items.len() > 90);
|
||||
}
|
||||
_ => panic!("unexpected result"),
|
||||
}
|
||||
}),
|
||||
),
|
||||
(
|
||||
"completion_resolve_request.json",
|
||||
LspResponse::Request(
|
||||
4,
|
||||
json!({
|
||||
"label": "build",
|
||||
"kind": 6,
|
||||
"detail": "const Deno.build: {\n target: string;\n arch: \"x86_64\";\n os: \"darwin\" | \"linux\" | \"windows\";\n vendor: string;\n env?: string | undefined;\n}",
|
||||
"documentation": {
|
||||
"kind": "markdown",
|
||||
"value": "Build related information."
|
||||
},
|
||||
"sortText": "1",
|
||||
"insertTextFormat": 1,
|
||||
}),
|
||||
),
|
||||
),
|
||||
(
|
||||
"shutdown_request.json",
|
||||
LspResponse::Request(3, json!(null)),
|
||||
),
|
||||
("exit_notification.json", LspResponse::None),
|
||||
]);
|
||||
harness.run().await;
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct PerformanceAverages {
|
||||
averages: Vec<PerformanceAverage>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue