diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide/src/lib.rs | 4 | ||||
-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 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 34 |
5 files changed, 82 insertions, 37 deletions
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index d1a250d48..16302eb2f 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -87,8 +87,8 @@ pub use crate::{ | |||
87 | pub use hir::{Documentation, Semantics}; | 87 | pub use hir::{Documentation, Semantics}; |
88 | pub use ide_assists::{Assist, AssistConfig, AssistId, AssistKind}; | 88 | pub use ide_assists::{Assist, AssistConfig, AssistId, AssistKind}; |
89 | pub use ide_completion::{ | 89 | pub use ide_completion::{ |
90 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, | 90 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance, CompletionScore, |
91 | InsertTextFormat, | 91 | ImportEdit, InsertTextFormat, |
92 | }; | 92 | }; |
93 | pub use ide_db::{ | 93 | pub use ide_db::{ |
94 | base_db::{ | 94 | base_db::{ |
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 | }, |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index a9846fa70..a467bc685 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -6,9 +6,10 @@ use std::{ | |||
6 | 6 | ||
7 | use ide::{ | 7 | use ide::{ |
8 | Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, | 8 | Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, |
9 | Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, | 9 | CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, |
10 | HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, Markup, NavigationTarget, | 10 | Highlight, HlMod, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, |
11 | ReferenceAccess, RenameError, Runnable, Severity, SourceChange, TextEdit, TextRange, TextSize, | 11 | Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity, SourceChange, |
12 | TextEdit, TextRange, TextSize, | ||
12 | }; | 13 | }; |
13 | use ide_db::SymbolKind; | 14 | use ide_db::SymbolKind; |
14 | use itertools::Itertools; | 15 | use itertools::Itertools; |
@@ -213,12 +214,22 @@ pub(crate) fn completion_item( | |||
213 | ..Default::default() | 214 | ..Default::default() |
214 | }; | 215 | }; |
215 | 216 | ||
216 | if item.relevance().is_relevant() { | 217 | fn set_score(res: &mut lsp_types::CompletionItem, relevance: CompletionRelevance) { |
217 | lsp_item.preselect = Some(true); | 218 | if relevance.is_relevant() { |
218 | // HACK: sort preselect items first | 219 | res.preselect = Some(true); |
219 | lsp_item.sort_text = Some(format!(" {}", item.label())); | 220 | } |
221 | // The relevance needs to be inverted to come up with a sort score | ||
222 | // because the client will sort ascending. | ||
223 | let sort_score = relevance.score() ^ 0xFF; | ||
224 | // Zero pad the string to ensure values are sorted numerically | ||
225 | // even though the client is sorting alphabetically. Three | ||
226 | // characters is enough to fit the largest u8, which is the | ||
227 | // type of the relevance score. | ||
228 | res.sort_text = Some(format!("{:03}", sort_score)); | ||
220 | } | 229 | } |
221 | 230 | ||
231 | set_score(&mut lsp_item, item.relevance()); | ||
232 | |||
222 | if item.deprecated() { | 233 | if item.deprecated() { |
223 | lsp_item.tags = Some(vec![lsp_types::CompletionItemTag::Deprecated]) | 234 | lsp_item.tags = Some(vec![lsp_types::CompletionItemTag::Deprecated]) |
224 | } | 235 | } |
@@ -228,10 +239,9 @@ pub(crate) fn completion_item( | |||
228 | } | 239 | } |
229 | 240 | ||
230 | let mut res = match item.ref_match() { | 241 | let mut res = match item.ref_match() { |
231 | Some(mutability) => { | 242 | Some((mutability, relevance)) => { |
232 | let mut lsp_item_with_ref = lsp_item.clone(); | 243 | let mut lsp_item_with_ref = lsp_item.clone(); |
233 | lsp_item.preselect = Some(true); | 244 | set_score(&mut lsp_item_with_ref, relevance); |
234 | lsp_item.sort_text = Some(format!(" {}", item.label())); | ||
235 | lsp_item_with_ref.label = | 245 | lsp_item_with_ref.label = |
236 | format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label); | 246 | format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label); |
237 | if let Some(lsp_types::CompletionTextEdit::Edit(it)) = &mut lsp_item_with_ref.text_edit | 247 | if let Some(lsp_types::CompletionTextEdit::Edit(it)) = &mut lsp_item_with_ref.text_edit |
@@ -1107,13 +1117,13 @@ mod tests { | |||
1107 | ( | 1117 | ( |
1108 | "&arg", | 1118 | "&arg", |
1109 | Some( | 1119 | Some( |
1110 | " arg", | 1120 | "253", |
1111 | ), | 1121 | ), |
1112 | ), | 1122 | ), |
1113 | ( | 1123 | ( |
1114 | "arg", | 1124 | "arg", |
1115 | Some( | 1125 | Some( |
1116 | " arg", | 1126 | "254", |
1117 | ), | 1127 | ), |
1118 | ), | 1128 | ), |
1119 | ] | 1129 | ] |