mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
internal: better factoring for to_proto::completion
One source completion can produce up to two lsp completions. Additionally, `preselct` and `sort_text` are global properties of the whole set of completions, so the right granularity here is to convert many completions. As a side-benefit, we no loger allocate intermediate vec.
This commit is contained in:
parent
108b56f354
commit
f34762abb7
4 changed files with 98 additions and 85 deletions
|
@ -22,12 +22,10 @@ use lsp_types::{
|
|||
FoldingRangeParams, HoverContents, Location, NumberOrString, Position, PrepareRenameResponse,
|
||||
Range, RenameParams, SemanticTokensDeltaParams, SemanticTokensFullDeltaResult,
|
||||
SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult,
|
||||
SemanticTokensResult, SymbolInformation, SymbolTag, TextDocumentIdentifier,
|
||||
TextDocumentPositionParams, Url, WorkspaceEdit,
|
||||
SemanticTokensResult, SymbolInformation, SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
|
||||
};
|
||||
use project_model::TargetKind;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, to_value};
|
||||
use serde_json::json;
|
||||
use stdx::format_to;
|
||||
use syntax::{algo, ast, AstNode, TextRange, TextSize};
|
||||
|
||||
|
@ -764,23 +762,13 @@ pub(crate) fn handle_completion(
|
|||
};
|
||||
let line_index = snap.file_line_index(position.file_id)?;
|
||||
|
||||
let insert_replace_support =
|
||||
snap.config.insert_replace_support().then(|| text_document_position.position);
|
||||
let items: Vec<CompletionItem> = items
|
||||
.into_iter()
|
||||
.flat_map(|item| {
|
||||
let mut new_completion_items =
|
||||
to_proto::completion_item(insert_replace_support, &line_index, item.clone());
|
||||
|
||||
if completion_config.enable_imports_on_the_fly {
|
||||
for new_item in &mut new_completion_items {
|
||||
fill_resolve_data(&mut new_item.data, &item, &text_document_position);
|
||||
}
|
||||
}
|
||||
|
||||
new_completion_items
|
||||
})
|
||||
.collect();
|
||||
let items = to_proto::completion_items(
|
||||
snap.config.insert_replace_support(),
|
||||
completion_config.enable_imports_on_the_fly,
|
||||
&line_index,
|
||||
text_document_position.clone(),
|
||||
items.clone(),
|
||||
);
|
||||
|
||||
let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
|
||||
Ok(Some(completion_list.into()))
|
||||
|
@ -800,16 +788,13 @@ pub(crate) fn handle_completion_resolve(
|
|||
.into());
|
||||
}
|
||||
|
||||
let resolve_data = match original_completion
|
||||
.data
|
||||
.take()
|
||||
.map(serde_json::from_value::<CompletionResolveData>)
|
||||
.transpose()?
|
||||
{
|
||||
Some(data) => data,
|
||||
let data = match original_completion.data.take() {
|
||||
Some(it) => it,
|
||||
None => return Ok(original_completion),
|
||||
};
|
||||
|
||||
let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?;
|
||||
|
||||
let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
|
||||
let line_index = snap.file_line_index(file_id)?;
|
||||
let offset = from_proto::offset(&line_index, resolve_data.position.position);
|
||||
|
@ -1760,29 +1745,3 @@ fn run_rustfmt(
|
|||
Ok(Some(to_proto::text_edit_vec(&line_index, diff(&file, &new_text))))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct CompletionResolveData {
|
||||
position: lsp_types::TextDocumentPositionParams,
|
||||
full_import_path: String,
|
||||
imported_name: String,
|
||||
}
|
||||
|
||||
fn fill_resolve_data(
|
||||
resolve_data: &mut Option<serde_json::Value>,
|
||||
item: &ide::CompletionItem,
|
||||
position: &TextDocumentPositionParams,
|
||||
) -> Option<()> {
|
||||
let import_edit = item.import_to_add()?;
|
||||
let import_path = &import_edit.import.import_path;
|
||||
|
||||
*resolve_data = Some(
|
||||
to_value(CompletionResolveData {
|
||||
position: position.to_owned(),
|
||||
full_import_path: import_path.to_string(),
|
||||
imported_name: import_path.segments().last()?.to_string(),
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
Some(())
|
||||
}
|
||||
|
|
|
@ -499,3 +499,10 @@ pub enum WorkspaceSymbolSearchKind {
|
|||
OnlyTypes,
|
||||
AllSymbols,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CompletionResolveData {
|
||||
pub position: lsp_types::TextDocumentPositionParams,
|
||||
pub full_import_path: String,
|
||||
pub imported_name: String,
|
||||
}
|
||||
|
|
|
@ -197,11 +197,35 @@ pub(crate) fn snippet_text_edit_vec(
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn completion_item(
|
||||
insert_replace_support: Option<lsp_types::Position>,
|
||||
pub(crate) fn completion_items(
|
||||
insert_replace_support: bool,
|
||||
enable_imports_on_the_fly: bool,
|
||||
line_index: &LineIndex,
|
||||
item: CompletionItem,
|
||||
tdpp: lsp_types::TextDocumentPositionParams,
|
||||
items: Vec<CompletionItem>,
|
||||
) -> Vec<lsp_types::CompletionItem> {
|
||||
let mut res = Vec::with_capacity(items.len());
|
||||
for item in items {
|
||||
completion_item(
|
||||
&mut res,
|
||||
insert_replace_support,
|
||||
enable_imports_on_the_fly,
|
||||
line_index,
|
||||
&tdpp,
|
||||
item,
|
||||
)
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn completion_item(
|
||||
acc: &mut Vec<lsp_types::CompletionItem>,
|
||||
insert_replace_support: bool,
|
||||
enable_imports_on_the_fly: bool,
|
||||
line_index: &LineIndex,
|
||||
tdpp: &lsp_types::TextDocumentPositionParams,
|
||||
item: CompletionItem,
|
||||
) {
|
||||
let mut additional_text_edits = Vec::new();
|
||||
|
||||
// LSP does not allow arbitrary edits in completion, so we have to do a
|
||||
|
@ -211,6 +235,7 @@ pub(crate) fn completion_item(
|
|||
let source_range = item.source_range();
|
||||
for indel in item.text_edit().iter() {
|
||||
if indel.delete.contains_range(source_range) {
|
||||
let insert_replace_support = insert_replace_support.then(|| tdpp.position);
|
||||
text_edit = Some(if indel.delete == source_range {
|
||||
self::completion_text_edit(line_index, insert_replace_support, indel.clone())
|
||||
} else {
|
||||
|
@ -253,29 +278,38 @@ pub(crate) fn completion_item(
|
|||
lsp_item.command = Some(command::trigger_parameter_hints());
|
||||
}
|
||||
|
||||
let mut res = match item.ref_match() {
|
||||
Some((mutability, relevance)) => {
|
||||
let mut lsp_item_with_ref = lsp_item.clone();
|
||||
set_score(&mut lsp_item_with_ref, relevance);
|
||||
lsp_item_with_ref.label =
|
||||
format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
|
||||
if let Some(it) = &mut lsp_item_with_ref.text_edit {
|
||||
let new_text = match it {
|
||||
lsp_types::CompletionTextEdit::Edit(it) => &mut it.new_text,
|
||||
lsp_types::CompletionTextEdit::InsertAndReplace(it) => &mut it.new_text,
|
||||
lsp_item.insert_text_format = Some(insert_text_format(item.insert_text_format()));
|
||||
if enable_imports_on_the_fly {
|
||||
if let Some(import_edit) = item.import_to_add() {
|
||||
let import_path = &import_edit.import.import_path;
|
||||
if let Some(import_name) = import_path.segments().last() {
|
||||
let data = lsp_ext::CompletionResolveData {
|
||||
position: tdpp.clone(),
|
||||
full_import_path: import_path.to_string(),
|
||||
imported_name: import_name.to_string(),
|
||||
};
|
||||
*new_text = format!("&{}{}", mutability.as_keyword_for_ref(), new_text);
|
||||
lsp_item.data = Some(to_value(data).unwrap());
|
||||
}
|
||||
vec![lsp_item_with_ref, lsp_item]
|
||||
}
|
||||
None => vec![lsp_item],
|
||||
};
|
||||
|
||||
for lsp_item in res.iter_mut() {
|
||||
lsp_item.insert_text_format = Some(insert_text_format(item.insert_text_format()));
|
||||
}
|
||||
|
||||
return res;
|
||||
if let Some((mutability, relevance)) = item.ref_match() {
|
||||
let mut lsp_item_with_ref = lsp_item.clone();
|
||||
set_score(&mut lsp_item_with_ref, relevance);
|
||||
lsp_item_with_ref.label =
|
||||
format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
|
||||
if let Some(it) = &mut lsp_item_with_ref.text_edit {
|
||||
let new_text = match it {
|
||||
lsp_types::CompletionTextEdit::Edit(it) => &mut it.new_text,
|
||||
lsp_types::CompletionTextEdit::InsertAndReplace(it) => &mut it.new_text,
|
||||
};
|
||||
*new_text = format!("&{}{}", mutability.as_keyword_for_ref(), new_text);
|
||||
}
|
||||
|
||||
acc.push(lsp_item_with_ref);
|
||||
};
|
||||
|
||||
acc.push(lsp_item);
|
||||
|
||||
fn set_score(res: &mut lsp_types::CompletionItem, relevance: CompletionRelevance) {
|
||||
if relevance.is_relevant() {
|
||||
|
@ -1179,7 +1213,9 @@ mod tests {
|
|||
encoding: OffsetEncoding::Utf16,
|
||||
};
|
||||
let (analysis, file_id) = Analysis::from_single_file(text);
|
||||
let completions: Vec<(String, Option<String>)> = analysis
|
||||
|
||||
let file_position = ide_db::base_db::FilePosition { file_id, offset };
|
||||
let mut items = analysis
|
||||
.completions(
|
||||
&ide::CompletionConfig {
|
||||
enable_postfix_completions: true,
|
||||
|
@ -1196,15 +1232,26 @@ mod tests {
|
|||
skip_glob_imports: true,
|
||||
},
|
||||
},
|
||||
ide_db::base_db::FilePosition { file_id, offset },
|
||||
file_position,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.filter(|c| c.label().ends_with("arg"))
|
||||
.map(|c| completion_item(None, &line_index, c))
|
||||
.flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text)))
|
||||
.collect();
|
||||
.unwrap();
|
||||
items.retain(|c| c.label().ends_with("arg"));
|
||||
let items = completion_items(
|
||||
false,
|
||||
false,
|
||||
&line_index,
|
||||
lsp_types::TextDocumentPositionParams {
|
||||
text_document: lsp_types::TextDocumentIdentifier {
|
||||
uri: "file://main.rs".parse().unwrap(),
|
||||
},
|
||||
position: position(&line_index, file_position.offset),
|
||||
},
|
||||
items,
|
||||
);
|
||||
let items: Vec<(String, Option<String>)> =
|
||||
items.into_iter().map(|c| (c.label, c.sort_text)).collect();
|
||||
|
||||
expect_test::expect![[r#"
|
||||
[
|
||||
(
|
||||
|
@ -1221,7 +1268,7 @@ mod tests {
|
|||
),
|
||||
]
|
||||
"#]]
|
||||
.assert_debug_eq(&completions);
|
||||
.assert_debug_eq(&items);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!---
|
||||
lsp_ext.rs hash: 3f2879db0013a72
|
||||
lsp_ext.rs hash: 3b2931972b33198b
|
||||
|
||||
If you need to change the above hash to make the test pass, please check if you
|
||||
need to adjust this doc as well and ping this issue:
|
||||
|
|
Loading…
Reference in a new issue