diff options
author | Josh Mcguigan <[email protected]> | 2021-03-12 03:11:14 +0000 |
---|---|---|
committer | Josh Mcguigan <[email protected]> | 2021-03-12 14:16:01 +0000 |
commit | 3679821eea94f30f2582ea7bca7569dad3ca31be (patch) | |
tree | 99edbd24d1d5da54af0e3f177cb18719b7880bda /crates/ide_completion/src | |
parent | c0e9530fd095317563532c20f13959619515c9b2 (diff) |
add completion relevance score
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r-- | crates/ide_completion/src/item.rs | 55 | ||||
-rw-r--r-- | crates/ide_completion/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 22 |
3 files changed, 58 insertions, 23 deletions
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs index cf1aaa131..9a4dc915c 100644 --- a/crates/ide_completion/src/item.rs +++ b/crates/ide_completion/src/item.rs | |||
@@ -70,7 +70,7 @@ pub struct CompletionItem { | |||
70 | /// Note that Relevance ignores fuzzy match score. We compute Relevance for | 70 | /// Note that Relevance ignores fuzzy match score. We compute Relevance for |
71 | /// all possible items, and then separately build an ordered completion list | 71 | /// all possible items, and then separately build an ordered completion list |
72 | /// based on relevance and fuzzy matching with the already typed identifier. | 72 | /// based on relevance and fuzzy matching with the already typed identifier. |
73 | relevance: Relevance, | 73 | relevance: CompletionRelevance, |
74 | 74 | ||
75 | /// Indicates that a reference or mutable reference to this variable is a | 75 | /// Indicates that a reference or mutable reference to this variable is a |
76 | /// possible match. | 76 | /// possible match. |
@@ -107,9 +107,11 @@ impl fmt::Debug for CompletionItem { | |||
107 | if self.deprecated { | 107 | if self.deprecated { |
108 | s.field("deprecated", &true); | 108 | s.field("deprecated", &true); |
109 | } | 109 | } |
110 | if self.relevance.is_relevant() { | 110 | |
111 | if self.relevance != CompletionRelevance::default() { | ||
111 | s.field("relevance", &self.relevance); | 112 | s.field("relevance", &self.relevance); |
112 | } | 113 | } |
114 | |||
113 | if let Some(mutability) = &self.ref_match { | 115 | if let Some(mutability) = &self.ref_match { |
114 | s.field("ref_match", &format!("&{}", mutability.as_keyword_for_ref())); | 116 | s.field("ref_match", &format!("&{}", mutability.as_keyword_for_ref())); |
115 | } | 117 | } |
@@ -129,7 +131,7 @@ pub enum CompletionScore { | |||
129 | } | 131 | } |
130 | 132 | ||
131 | #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Default)] | 133 | #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Default)] |
132 | pub struct Relevance { | 134 | pub struct CompletionRelevance { |
133 | /// This is set in cases like these: | 135 | /// This is set in cases like these: |
134 | /// | 136 | /// |
135 | /// ``` | 137 | /// ``` |
@@ -152,9 +154,34 @@ pub struct Relevance { | |||
152 | pub exact_type_match: bool, | 154 | pub exact_type_match: bool, |
153 | } | 155 | } |
154 | 156 | ||
155 | impl Relevance { | 157 | impl CompletionRelevance { |
158 | /// Provides a relevance score. Higher values are more relevant. | ||
159 | /// | ||
160 | /// The absolute value of the relevance score is not meaningful, for | ||
161 | /// example a value of 0 doesn't mean "not relevant", rather | ||
162 | /// it means "least relevant". The score value should only be used | ||
163 | /// for relative ordering. | ||
164 | /// | ||
165 | /// See is_relevant if you need to make some judgement about score | ||
166 | /// in an absolute sense. | ||
167 | pub fn score(&self) -> u8 { | ||
168 | let mut score = 0; | ||
169 | |||
170 | if self.exact_name_match { | ||
171 | score += 1; | ||
172 | } | ||
173 | if self.exact_type_match { | ||
174 | score += 1; | ||
175 | } | ||
176 | |||
177 | score | ||
178 | } | ||
179 | |||
180 | /// Returns true when the score for this threshold is above | ||
181 | /// some threshold such that we think it is especially likely | ||
182 | /// to be relevant. | ||
156 | pub fn is_relevant(&self) -> bool { | 183 | pub fn is_relevant(&self) -> bool { |
157 | self != &Relevance::default() | 184 | self.score() > 0 |
158 | } | 185 | } |
159 | } | 186 | } |
160 | 187 | ||
@@ -249,7 +276,7 @@ impl CompletionItem { | |||
249 | text_edit: None, | 276 | text_edit: None, |
250 | deprecated: false, | 277 | deprecated: false, |
251 | trigger_call_info: None, | 278 | trigger_call_info: None, |
252 | relevance: Relevance::default(), | 279 | relevance: CompletionRelevance::default(), |
253 | ref_match: None, | 280 | ref_match: None, |
254 | import_to_add: None, | 281 | import_to_add: None, |
255 | } | 282 | } |
@@ -292,7 +319,7 @@ impl CompletionItem { | |||
292 | self.deprecated | 319 | self.deprecated |
293 | } | 320 | } |
294 | 321 | ||
295 | pub fn relevance(&self) -> Relevance { | 322 | pub fn relevance(&self) -> CompletionRelevance { |
296 | self.relevance | 323 | self.relevance |
297 | } | 324 | } |
298 | 325 | ||
@@ -300,8 +327,14 @@ impl CompletionItem { | |||
300 | self.trigger_call_info | 327 | self.trigger_call_info |
301 | } | 328 | } |
302 | 329 | ||
303 | pub fn ref_match(&self) -> Option<Mutability> { | 330 | pub fn ref_match(&self) -> Option<(Mutability, CompletionRelevance)> { |
304 | self.ref_match | 331 | // Relevance of the ref match should be the same as the original |
332 | // match, but with exact type match set because self.ref_match | ||
333 | // is only set if there is an exact type match. | ||
334 | let mut relevance = self.relevance; | ||
335 | relevance.exact_type_match = true; | ||
336 | |||
337 | self.ref_match.map(|mutability| (mutability, relevance)) | ||
305 | } | 338 | } |
306 | 339 | ||
307 | pub fn import_to_add(&self) -> Option<&ImportEdit> { | 340 | pub fn import_to_add(&self) -> Option<&ImportEdit> { |
@@ -349,7 +382,7 @@ pub(crate) struct Builder { | |||
349 | text_edit: Option<TextEdit>, | 382 | text_edit: Option<TextEdit>, |
350 | deprecated: bool, | 383 | deprecated: bool, |
351 | trigger_call_info: Option<bool>, | 384 | trigger_call_info: Option<bool>, |
352 | relevance: Relevance, | 385 | relevance: CompletionRelevance, |
353 | ref_match: Option<Mutability>, | 386 | ref_match: Option<Mutability>, |
354 | } | 387 | } |
355 | 388 | ||
@@ -457,7 +490,7 @@ impl Builder { | |||
457 | self.deprecated = deprecated; | 490 | self.deprecated = deprecated; |
458 | self | 491 | self |
459 | } | 492 | } |
460 | pub(crate) fn set_relevance(&mut self, relevance: Relevance) -> &mut Builder { | 493 | pub(crate) fn set_relevance(&mut self, relevance: CompletionRelevance) -> &mut Builder { |
461 | self.relevance = relevance; | 494 | self.relevance = relevance; |
462 | self | 495 | self |
463 | } | 496 | } |
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index d46f521a0..21e489755 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -24,8 +24,8 @@ use crate::{completions::Completions, context::CompletionContext, item::Completi | |||
24 | pub use crate::{ | 24 | pub use crate::{ |
25 | config::CompletionConfig, | 25 | config::CompletionConfig, |
26 | item::{ | 26 | item::{ |
27 | CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, InsertTextFormat, | 27 | CompletionItem, CompletionItemKind, CompletionRelevance, CompletionScore, ImportEdit, |
28 | Relevance, | 28 | InsertTextFormat, |
29 | }, | 29 | }, |
30 | }; | 30 | }; |
31 | 31 | ||
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index f7f9084d9..db31896e5 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -20,7 +20,7 @@ use ide_db::{ | |||
20 | use syntax::TextRange; | 20 | use syntax::TextRange; |
21 | 21 | ||
22 | use crate::{ | 22 | use crate::{ |
23 | item::{ImportEdit, Relevance}, | 23 | item::{CompletionRelevance, ImportEdit}, |
24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, | 24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, |
25 | }; | 25 | }; |
26 | 26 | ||
@@ -322,9 +322,9 @@ impl<'a> Render<'a> { | |||
322 | } | 322 | } |
323 | } | 323 | } |
324 | 324 | ||
325 | fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> Option<Relevance> { | 325 | fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionRelevance> { |
326 | let (expected_name, expected_type) = ctx.expected_name_and_type()?; | 326 | let (expected_name, expected_type) = ctx.expected_name_and_type()?; |
327 | let mut res = Relevance::default(); | 327 | let mut res = CompletionRelevance::default(); |
328 | res.exact_type_match = ty == &expected_type; | 328 | res.exact_type_match = ty == &expected_type; |
329 | res.exact_name_match = name == &expected_name; | 329 | res.exact_name_match = name == &expected_name; |
330 | Some(res) | 330 | Some(res) |
@@ -338,7 +338,7 @@ mod tests { | |||
338 | 338 | ||
339 | use crate::{ | 339 | use crate::{ |
340 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, | 340 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, |
341 | CompletionKind, Relevance, | 341 | CompletionKind, CompletionRelevance, |
342 | }; | 342 | }; |
343 | 343 | ||
344 | fn check(ra_fixture: &str, expect: Expect) { | 344 | fn check(ra_fixture: &str, expect: Expect) { |
@@ -347,12 +347,14 @@ mod tests { | |||
347 | } | 347 | } |
348 | 348 | ||
349 | fn check_relevance(ra_fixture: &str, expect: Expect) { | 349 | fn check_relevance(ra_fixture: &str, expect: Expect) { |
350 | fn display_relevance(relevance: Relevance) -> &'static str { | 350 | fn display_relevance(relevance: CompletionRelevance) -> &'static str { |
351 | match relevance { | 351 | match relevance { |
352 | Relevance { exact_type_match: true, exact_name_match: true } => "[type+name]", | 352 | CompletionRelevance { exact_type_match: true, exact_name_match: true } => { |
353 | Relevance { exact_type_match: true, exact_name_match: false } => "[type]", | 353 | "[type+name]" |
354 | Relevance { exact_type_match: false, exact_name_match: true } => "[name]", | 354 | } |
355 | Relevance { exact_type_match: false, exact_name_match: false } => "[]", | 355 | CompletionRelevance { exact_type_match: true, exact_name_match: false } => "[type]", |
356 | CompletionRelevance { exact_type_match: false, exact_name_match: true } => "[name]", | ||
357 | CompletionRelevance { exact_type_match: false, exact_name_match: false } => "[]", | ||
356 | } | 358 | } |
357 | } | 359 | } |
358 | 360 | ||
@@ -975,7 +977,7 @@ fn main() { | |||
975 | Local, | 977 | Local, |
976 | ), | 978 | ), |
977 | detail: "S", | 979 | detail: "S", |
978 | relevance: Relevance { | 980 | relevance: CompletionRelevance { |
979 | exact_name_match: true, | 981 | exact_name_match: true, |
980 | exact_type_match: false, | 982 | exact_type_match: false, |
981 | }, | 983 | }, |