aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/presentation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion/presentation.rs')
-rw-r--r--crates/ra_ide/src/completion/presentation.rs82
1 files changed, 66 insertions, 16 deletions
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 2edb130cf..440ffa31d 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -3,7 +3,7 @@
3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; 3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type};
4use ra_syntax::ast::NameOwner; 4use ra_syntax::ast::NameOwner;
5use stdx::SepBy; 5use stdx::SepBy;
6use test_utils::tested_by; 6use test_utils::mark;
7 7
8use crate::{ 8use crate::{
9 completion::{ 9 completion::{
@@ -17,12 +17,11 @@ use crate::{
17impl Completions { 17impl Completions {
18 pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { 18 pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) {
19 let is_deprecated = is_deprecated(field, ctx.db); 19 let is_deprecated = is_deprecated(field, ctx.db);
20 let ty = ty.display(ctx.db).to_string();
21 let name = field.name(ctx.db); 20 let name = field.name(ctx.db);
22 let mut completion_item = 21 let mut completion_item =
23 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 22 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
24 .kind(CompletionItemKind::Field) 23 .kind(CompletionItemKind::Field)
25 .detail(ty.clone()) 24 .detail(ty.display(ctx.db).to_string())
26 .set_documentation(field.docs(ctx.db)) 25 .set_documentation(field.docs(ctx.db))
27 .set_deprecated(is_deprecated); 26 .set_deprecated(is_deprecated);
28 27
@@ -107,6 +106,12 @@ impl Completions {
107 } 106 }
108 }; 107 };
109 108
109 if let ScopeDef::Local(local) = resolution {
110 if let Some(score) = compute_score(ctx, &local.ty(ctx.db), &local_name) {
111 completion_item = completion_item.set_score(score);
112 }
113 }
114
110 // Add `<>` for generic types 115 // Add `<>` for generic types
111 if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { 116 if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis {
112 if let Some(cap) = ctx.config.snippet_cap { 117 if let Some(cap) = ctx.config.snippet_cap {
@@ -116,7 +121,7 @@ impl Completions {
116 _ => false, 121 _ => false,
117 }; 122 };
118 if has_non_default_type_params { 123 if has_non_default_type_params {
119 tested_by!(inserts_angle_brackets_for_generics); 124 mark::hit!(inserts_angle_brackets_for_generics);
120 completion_item = completion_item 125 completion_item = completion_item
121 .lookup_by(local_name.clone()) 126 .lookup_by(local_name.clone())
122 .label(format!("{}<…>", local_name)) 127 .label(format!("{}<…>", local_name))
@@ -171,7 +176,7 @@ impl Completions {
171 } 176 }
172 None if needs_bang => builder.insert_text(format!("{}!", name)), 177 None if needs_bang => builder.insert_text(format!("{}!", name)),
173 _ => { 178 _ => {
174 tested_by!(dont_insert_macro_call_parens_unncessary); 179 mark::hit!(dont_insert_macro_call_parens_unncessary);
175 builder.insert_text(name) 180 builder.insert_text(name)
176 } 181 }
177 }; 182 };
@@ -319,19 +324,20 @@ impl Completions {
319 324
320pub(crate) fn compute_score( 325pub(crate) fn compute_score(
321 ctx: &CompletionContext, 326 ctx: &CompletionContext,
322 // FIXME: this definitely should be a `Type` 327 ty: &Type,
323 ty: &str,
324 name: &str, 328 name: &str,
325) -> Option<CompletionScore> { 329) -> Option<CompletionScore> {
330 // FIXME: this should not fall back to string equality.
331 let ty = &ty.display(ctx.db).to_string();
326 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { 332 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
327 tested_by!(test_struct_field_completion_in_record_lit); 333 mark::hit!(test_struct_field_completion_in_record_lit);
328 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; 334 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
329 ( 335 (
330 struct_field.name(ctx.db).to_string(), 336 struct_field.name(ctx.db).to_string(),
331 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), 337 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(),
332 ) 338 )
333 } else if let Some(active_parameter) = &ctx.active_parameter { 339 } else if let Some(active_parameter) = &ctx.active_parameter {
334 tested_by!(test_struct_field_completion_in_func_call); 340 mark::hit!(test_struct_field_completion_in_func_call);
335 (active_parameter.name.clone(), active_parameter.ty.clone()) 341 (active_parameter.name.clone(), active_parameter.ty.clone())
336 } else { 342 } else {
337 return None; 343 return None;
@@ -392,7 +398,7 @@ impl Builder {
392 None => return self, 398 None => return self,
393 }; 399 };
394 // If not an import, add parenthesis automatically. 400 // If not an import, add parenthesis automatically.
395 tested_by!(inserts_parens_for_function_calls); 401 mark::hit!(inserts_parens_for_function_calls);
396 402
397 let (snippet, label) = if params.is_empty() { 403 let (snippet, label) = if params.is_empty() {
398 (format!("{}()$0", name), format!("{}()", name)) 404 (format!("{}()$0", name), format!("{}()", name))
@@ -451,7 +457,7 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s
451#[cfg(test)] 457#[cfg(test)]
452mod tests { 458mod tests {
453 use insta::assert_debug_snapshot; 459 use insta::assert_debug_snapshot;
454 use test_utils::covers; 460 use test_utils::mark;
455 461
456 use crate::completion::{ 462 use crate::completion::{
457 test_utils::{do_completion, do_completion_with_options}, 463 test_utils::{do_completion, do_completion_with_options},
@@ -601,7 +607,7 @@ mod tests {
601 607
602 #[test] 608 #[test]
603 fn inserts_parens_for_function_calls() { 609 fn inserts_parens_for_function_calls() {
604 covers!(inserts_parens_for_function_calls); 610 mark::check!(inserts_parens_for_function_calls);
605 assert_debug_snapshot!( 611 assert_debug_snapshot!(
606 do_reference_completion( 612 do_reference_completion(
607 r" 613 r"
@@ -986,7 +992,7 @@ mod tests {
986 992
987 #[test] 993 #[test]
988 fn inserts_angle_brackets_for_generics() { 994 fn inserts_angle_brackets_for_generics() {
989 covers!(inserts_angle_brackets_for_generics); 995 mark::check!(inserts_angle_brackets_for_generics);
990 assert_debug_snapshot!( 996 assert_debug_snapshot!(
991 do_reference_completion( 997 do_reference_completion(
992 r" 998 r"
@@ -1109,7 +1115,7 @@ mod tests {
1109 1115
1110 #[test] 1116 #[test]
1111 fn dont_insert_macro_call_parens_unncessary() { 1117 fn dont_insert_macro_call_parens_unncessary() {
1112 covers!(dont_insert_macro_call_parens_unncessary); 1118 mark::check!(dont_insert_macro_call_parens_unncessary);
1113 assert_debug_snapshot!( 1119 assert_debug_snapshot!(
1114 do_reference_completion( 1120 do_reference_completion(
1115 r" 1121 r"
@@ -1175,7 +1181,7 @@ mod tests {
1175 1181
1176 #[test] 1182 #[test]
1177 fn test_struct_field_completion_in_func_call() { 1183 fn test_struct_field_completion_in_func_call() {
1178 covers!(test_struct_field_completion_in_func_call); 1184 mark::check!(test_struct_field_completion_in_func_call);
1179 assert_debug_snapshot!( 1185 assert_debug_snapshot!(
1180 do_reference_completion( 1186 do_reference_completion(
1181 r" 1187 r"
@@ -1265,7 +1271,7 @@ mod tests {
1265 1271
1266 #[test] 1272 #[test]
1267 fn test_struct_field_completion_in_record_lit() { 1273 fn test_struct_field_completion_in_record_lit() {
1268 covers!(test_struct_field_completion_in_record_lit); 1274 mark::check!(test_struct_field_completion_in_record_lit);
1269 assert_debug_snapshot!( 1275 assert_debug_snapshot!(
1270 do_reference_completion( 1276 do_reference_completion(
1271 r" 1277 r"
@@ -1405,4 +1411,48 @@ mod tests {
1405 "### 1411 "###
1406 ); 1412 );
1407 } 1413 }
1414
1415 #[test]
1416 fn prioritize_exact_ref_match() {
1417 assert_debug_snapshot!(
1418 do_reference_completion(
1419 r"
1420 struct WorldSnapshot { _f: () };
1421 fn go(world: &WorldSnapshot) {
1422 go(w<|>)
1423 }
1424 ",
1425 ),
1426 @r###"
1427 [
1428 CompletionItem {
1429 label: "WorldSnapshot",
1430 source_range: 132..133,
1431 delete: 132..133,
1432 insert: "WorldSnapshot",
1433 kind: Struct,
1434 },
1435 CompletionItem {
1436 label: "go(…)",
1437 source_range: 132..133,
1438 delete: 132..133,
1439 insert: "go(${1:world})$0",
1440 kind: Function,
1441 lookup: "go",
1442 detail: "fn go(world: &WorldSnapshot)",
1443 trigger_call_info: true,
1444 },
1445 CompletionItem {
1446 label: "world",
1447 source_range: 132..133,
1448 delete: 132..133,
1449 insert: "world",
1450 kind: Binding,
1451 detail: "&WorldSnapshot",
1452 score: TypeAndNameMatch,
1453 },
1454 ]
1455 "###
1456 );
1457 }
1408} 1458}