diff options
Diffstat (limited to 'crates/ide_completion/src/render.rs')
-rw-r--r-- | crates/ide_completion/src/render.rs | 99 |
1 files changed, 41 insertions, 58 deletions
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 0a1b0f95d..8c8b149a1 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -20,8 +20,8 @@ use ide_db::{ | |||
20 | use syntax::TextRange; | 20 | use syntax::TextRange; |
21 | 21 | ||
22 | use crate::{ | 22 | use crate::{ |
23 | item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, | 23 | item::{ImportEdit, Relevance}, |
24 | CompletionScore, | 24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; | 27 | use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; |
@@ -117,7 +117,7 @@ impl<'a> RenderContext<'a> { | |||
117 | node.docs(self.db()) | 117 | node.docs(self.db()) |
118 | } | 118 | } |
119 | 119 | ||
120 | fn active_name_and_type(&self) -> Option<(String, Type)> { | 120 | fn expected_name_and_type(&self) -> Option<(String, Type)> { |
121 | if let Some(record_field) = &self.completion.record_field_syntax { | 121 | if let Some(record_field) = &self.completion.record_field_syntax { |
122 | cov_mark::hit!(record_field_type_match); | 122 | cov_mark::hit!(record_field_type_match); |
123 | let (struct_field, _local) = self.completion.sema.resolve_record_field(record_field)?; | 123 | let (struct_field, _local) = self.completion.sema.resolve_record_field(record_field)?; |
@@ -155,8 +155,8 @@ impl<'a> Render<'a> { | |||
155 | .set_documentation(field.docs(self.ctx.db())) | 155 | .set_documentation(field.docs(self.ctx.db())) |
156 | .set_deprecated(is_deprecated); | 156 | .set_deprecated(is_deprecated); |
157 | 157 | ||
158 | if let Some(score) = compute_score(&self.ctx, &ty, &name.to_string()) { | 158 | if let Some(relevance) = compute_relevance(&self.ctx, &ty, &name.to_string()) { |
159 | item = item.set_score(score); | 159 | item = item.set_relevance(relevance); |
160 | } | 160 | } |
161 | 161 | ||
162 | item.build() | 162 | item.build() |
@@ -247,18 +247,15 @@ impl<'a> Render<'a> { | |||
247 | }; | 247 | }; |
248 | 248 | ||
249 | if let ScopeDef::Local(local) = resolution { | 249 | if let ScopeDef::Local(local) = resolution { |
250 | if let Some((active_name, active_type)) = self.ctx.active_name_and_type() { | 250 | let ty = local.ty(self.ctx.db()); |
251 | let ty = local.ty(self.ctx.db()); | 251 | if let Some(relevance) = compute_relevance(&self.ctx, &ty, &local_name) { |
252 | if let Some(score) = | 252 | item = item.set_relevance(relevance) |
253 | compute_score_from_active(&active_type, &active_name, &ty, &local_name) | 253 | } |
254 | { | 254 | if let Some((_expected_name, expected_type)) = self.ctx.expected_name_and_type() { |
255 | item = item.set_score(score); | 255 | if let Some(ty_without_ref) = expected_type.remove_ref() { |
256 | } | ||
257 | |||
258 | if let Some(ty_without_ref) = active_type.remove_ref() { | ||
259 | if ty_without_ref == ty { | 256 | if ty_without_ref == ty { |
260 | cov_mark::hit!(suggest_ref); | 257 | cov_mark::hit!(suggest_ref); |
261 | let mutability = if active_type.is_mutable_reference() { | 258 | let mutability = if expected_type.is_mutable_reference() { |
262 | Mutability::Mut | 259 | Mutability::Mut |
263 | } else { | 260 | } else { |
264 | Mutability::Shared | 261 | Mutability::Shared |
@@ -326,33 +323,14 @@ impl<'a> Render<'a> { | |||
326 | } | 323 | } |
327 | } | 324 | } |
328 | 325 | ||
329 | fn compute_score_from_active( | 326 | fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> Option<Relevance> { |
330 | active_type: &Type, | 327 | let (expected_name, expected_type) = ctx.expected_name_and_type()?; |
331 | active_name: &str, | 328 | let mut res = Relevance::default(); |
332 | ty: &Type, | 329 | res.exact_type_match = ty == &expected_type; |
333 | name: &str, | 330 | res.exact_name_match = name == &expected_name; |
334 | ) -> Option<CompletionScore> { | ||
335 | // Compute score | ||
336 | // For the same type | ||
337 | if active_type != ty { | ||
338 | return None; | ||
339 | } | ||
340 | |||
341 | let mut res = CompletionScore::TypeMatch; | ||
342 | |||
343 | // If same type + same name then go top position | ||
344 | if active_name == name { | ||
345 | res = CompletionScore::TypeAndNameMatch | ||
346 | } | ||
347 | |||
348 | Some(res) | 331 | Some(res) |
349 | } | 332 | } |
350 | 333 | ||
351 | fn compute_score(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionScore> { | ||
352 | let (active_name, active_type) = ctx.active_name_and_type()?; | ||
353 | compute_score_from_active(&active_type, &active_name, ty, name) | ||
354 | } | ||
355 | |||
356 | #[cfg(test)] | 334 | #[cfg(test)] |
357 | mod tests { | 335 | mod tests { |
358 | use std::cmp::Reverse; | 336 | use std::cmp::Reverse; |
@@ -361,7 +339,7 @@ mod tests { | |||
361 | 339 | ||
362 | use crate::{ | 340 | use crate::{ |
363 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, | 341 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, |
364 | CompletionKind, CompletionScore, | 342 | CompletionKind, Relevance, |
365 | }; | 343 | }; |
366 | 344 | ||
367 | fn check(ra_fixture: &str, expect: Expect) { | 345 | fn check(ra_fixture: &str, expect: Expect) { |
@@ -369,24 +347,25 @@ mod tests { | |||
369 | expect.assert_debug_eq(&actual); | 347 | expect.assert_debug_eq(&actual); |
370 | } | 348 | } |
371 | 349 | ||
372 | fn check_scores(ra_fixture: &str, expect: Expect) { | 350 | fn check_relevance(ra_fixture: &str, expect: Expect) { |
373 | fn display_score(score: Option<CompletionScore>) -> &'static str { | 351 | fn display_relevance(relevance: Relevance) -> &'static str { |
374 | match score { | 352 | match relevance { |
375 | Some(CompletionScore::TypeMatch) => "[type]", | 353 | Relevance { exact_type_match: true, exact_name_match: true } => "[type+name]", |
376 | Some(CompletionScore::TypeAndNameMatch) => "[type+name]", | 354 | Relevance { exact_type_match: true, exact_name_match: false } => "[type]", |
377 | None => "[]".into(), | 355 | Relevance { exact_type_match: false, exact_name_match: true } => "[name]", |
356 | Relevance { exact_type_match: false, exact_name_match: false } => "[]", | ||
378 | } | 357 | } |
379 | } | 358 | } |
380 | 359 | ||
381 | let mut completions = get_all_items(TEST_CONFIG, ra_fixture); | 360 | let mut completions = get_all_items(TEST_CONFIG, ra_fixture); |
382 | completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); | 361 | completions.sort_by_key(|it| (Reverse(it.relevance()), it.label().to_string())); |
383 | let actual = completions | 362 | let actual = completions |
384 | .into_iter() | 363 | .into_iter() |
385 | .filter(|it| it.completion_kind == CompletionKind::Reference) | 364 | .filter(|it| it.completion_kind == CompletionKind::Reference) |
386 | .map(|it| { | 365 | .map(|it| { |
387 | let tag = it.kind().unwrap().tag(); | 366 | let tag = it.kind().unwrap().tag(); |
388 | let score = display_score(it.score()); | 367 | let relevance = display_relevance(it.relevance()); |
389 | format!("{} {} {}\n", tag, it.label(), score) | 368 | format!("{} {} {}\n", tag, it.label(), relevance) |
390 | }) | 369 | }) |
391 | .collect::<String>(); | 370 | .collect::<String>(); |
392 | expect.assert_eq(&actual); | 371 | expect.assert_eq(&actual); |
@@ -849,9 +828,9 @@ fn foo(xs: Vec<i128>) | |||
849 | } | 828 | } |
850 | 829 | ||
851 | #[test] | 830 | #[test] |
852 | fn active_param_score() { | 831 | fn active_param_relevance() { |
853 | cov_mark::check!(active_param_type_match); | 832 | cov_mark::check!(active_param_type_match); |
854 | check_scores( | 833 | check_relevance( |
855 | r#" | 834 | r#" |
856 | struct S { foo: i64, bar: u32, baz: u32 } | 835 | struct S { foo: i64, bar: u32, baz: u32 } |
857 | fn test(bar: u32) { } | 836 | fn test(bar: u32) { } |
@@ -866,9 +845,9 @@ fn foo(s: S) { test(s.$0) } | |||
866 | } | 845 | } |
867 | 846 | ||
868 | #[test] | 847 | #[test] |
869 | fn record_field_scores() { | 848 | fn record_field_relevances() { |
870 | cov_mark::check!(record_field_type_match); | 849 | cov_mark::check!(record_field_type_match); |
871 | check_scores( | 850 | check_relevance( |
872 | r#" | 851 | r#" |
873 | struct A { foo: i64, bar: u32, baz: u32 } | 852 | struct A { foo: i64, bar: u32, baz: u32 } |
874 | struct B { x: (), y: f32, bar: u32 } | 853 | struct B { x: (), y: f32, bar: u32 } |
@@ -883,8 +862,8 @@ fn foo(a: A) { B { bar: a.$0 }; } | |||
883 | } | 862 | } |
884 | 863 | ||
885 | #[test] | 864 | #[test] |
886 | fn record_field_and_call_scores() { | 865 | fn record_field_and_call_relevances() { |
887 | check_scores( | 866 | check_relevance( |
888 | r#" | 867 | r#" |
889 | struct A { foo: i64, bar: u32, baz: u32 } | 868 | struct A { foo: i64, bar: u32, baz: u32 } |
890 | struct B { x: (), y: f32, bar: u32 } | 869 | struct B { x: (), y: f32, bar: u32 } |
@@ -897,7 +876,7 @@ fn foo(a: A) { B { bar: f(a.$0) }; } | |||
897 | fd baz [] | 876 | fd baz [] |
898 | "#]], | 877 | "#]], |
899 | ); | 878 | ); |
900 | check_scores( | 879 | check_relevance( |
901 | r#" | 880 | r#" |
902 | struct A { foo: i64, bar: u32, baz: u32 } | 881 | struct A { foo: i64, bar: u32, baz: u32 } |
903 | struct B { x: (), y: f32, bar: u32 } | 882 | struct B { x: (), y: f32, bar: u32 } |
@@ -914,7 +893,7 @@ fn foo(a: A) { f(B { bar: a.$0 }); } | |||
914 | 893 | ||
915 | #[test] | 894 | #[test] |
916 | fn prioritize_exact_ref_match() { | 895 | fn prioritize_exact_ref_match() { |
917 | check_scores( | 896 | check_relevance( |
918 | r#" | 897 | r#" |
919 | struct WorldSnapshot { _f: () }; | 898 | struct WorldSnapshot { _f: () }; |
920 | fn go(world: &WorldSnapshot) { go(w$0) } | 899 | fn go(world: &WorldSnapshot) { go(w$0) } |
@@ -929,7 +908,7 @@ fn go(world: &WorldSnapshot) { go(w$0) } | |||
929 | 908 | ||
930 | #[test] | 909 | #[test] |
931 | fn too_many_arguments() { | 910 | fn too_many_arguments() { |
932 | check_scores( | 911 | check_relevance( |
933 | r#" | 912 | r#" |
934 | struct Foo; | 913 | struct Foo; |
935 | fn f(foo: &Foo) { f(foo, w$0) } | 914 | fn f(foo: &Foo) { f(foo, w$0) } |
@@ -997,6 +976,10 @@ fn main() { | |||
997 | Local, | 976 | Local, |
998 | ), | 977 | ), |
999 | detail: "S", | 978 | detail: "S", |
979 | relevance: Relevance { | ||
980 | exact_name_match: true, | ||
981 | exact_type_match: false, | ||
982 | }, | ||
1000 | ref_match: "&mut ", | 983 | ref_match: "&mut ", |
1001 | }, | 984 | }, |
1002 | ] | 985 | ] |