aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/completion_item.rs
diff options
context:
space:
mode:
authorBenjamin Coenen <[email protected]>2020-04-16 17:30:08 +0100
committerBenjamin Coenen <[email protected]>2020-04-16 17:30:08 +0100
commit6ebc8bbeb005f5d3f2b00d1ae1f1804116e3a8f5 (patch)
tree9b0ea7f19402ee17602e7b38d934ae19301e2dee /crates/ra_ide/src/completion/completion_item.rs
parent06076f95a7ca764696b055eb754e163f884eefaa (diff)
feat: improve dot completions with scoring
Signed-off-by: Benjamin Coenen <[email protected]>
Diffstat (limited to 'crates/ra_ide/src/completion/completion_item.rs')
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs62
1 files changed, 39 insertions, 23 deletions
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index c9c3fdc0e..84d51bafe 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -53,6 +53,9 @@ pub struct CompletionItem {
53 /// If completing a function call, ask the editor to show parameter popup 53 /// If completing a function call, ask the editor to show parameter popup
54 /// after completion. 54 /// after completion.
55 trigger_call_info: bool, 55 trigger_call_info: bool,
56
57 /// Score is usefull to pre select or display in better order completion items
58 score: Option<CompletionScore>,
56} 59}
57 60
58// We use custom debug for CompletionItem to make `insta`'s diffs more readable. 61// We use custom debug for CompletionItem to make `insta`'s diffs more readable.
@@ -82,6 +85,9 @@ impl fmt::Debug for CompletionItem {
82 if self.deprecated { 85 if self.deprecated {
83 s.field("deprecated", &true); 86 s.field("deprecated", &true);
84 } 87 }
88 if let Some(score) = &self.score {
89 s.field("score", score);
90 }
85 if self.trigger_call_info { 91 if self.trigger_call_info {
86 s.field("trigger_call_info", &true); 92 s.field("trigger_call_info", &true);
87 } 93 }
@@ -149,6 +155,7 @@ impl CompletionItem {
149 text_edit: None, 155 text_edit: None,
150 deprecated: None, 156 deprecated: None,
151 trigger_call_info: None, 157 trigger_call_info: None,
158 score: None,
152 } 159 }
153 } 160 }
154 /// What user sees in pop-up in the UI. 161 /// What user sees in pop-up in the UI.
@@ -188,6 +195,10 @@ impl CompletionItem {
188 self.deprecated 195 self.deprecated
189 } 196 }
190 197
198 pub fn score(&self) -> Option<CompletionScore> {
199 self.score.clone()
200 }
201
191 pub fn trigger_call_info(&self) -> bool { 202 pub fn trigger_call_info(&self) -> bool {
192 self.trigger_call_info 203 self.trigger_call_info
193 } 204 }
@@ -208,6 +219,7 @@ pub(crate) struct Builder {
208 text_edit: Option<TextEdit>, 219 text_edit: Option<TextEdit>,
209 deprecated: Option<bool>, 220 deprecated: Option<bool>,
210 trigger_call_info: Option<bool>, 221 trigger_call_info: Option<bool>,
222 score: Option<CompletionScore>,
211} 223}
212 224
213impl Builder { 225impl Builder {
@@ -237,6 +249,7 @@ impl Builder {
237 completion_kind: self.completion_kind, 249 completion_kind: self.completion_kind,
238 deprecated: self.deprecated.unwrap_or(false), 250 deprecated: self.deprecated.unwrap_or(false),
239 trigger_call_info: self.trigger_call_info.unwrap_or(false), 251 trigger_call_info: self.trigger_call_info.unwrap_or(false),
252 score: self.score,
240 } 253 }
241 } 254 }
242 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder { 255 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
@@ -287,6 +300,10 @@ impl Builder {
287 self.deprecated = Some(deprecated); 300 self.deprecated = Some(deprecated);
288 self 301 self
289 } 302 }
303 pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder {
304 self.score = Some(score);
305 self
306 }
290 pub(crate) fn trigger_call_info(mut self) -> Builder { 307 pub(crate) fn trigger_call_info(mut self) -> Builder {
291 self.trigger_call_info = Some(true); 308 self.trigger_call_info = Some(true);
292 self 309 self
@@ -300,16 +317,22 @@ impl<'a> Into<CompletionItem> for Builder {
300} 317}
301 318
302#[derive(Debug)] 319#[derive(Debug)]
303pub(crate) enum SortOption { 320pub(crate) enum ScoreOption {
304 CallFn(CallInfo), 321 CallFn(CallInfo),
305 RecordField(RecordField), 322 RecordField(RecordField),
306} 323}
307 324
325#[derive(Debug, Clone)]
326pub enum CompletionScore {
327 TypeMatch,
328 TypeAndNameMatch,
329}
330
308/// Represents an in-progress set of completions being built. 331/// Represents an in-progress set of completions being built.
309#[derive(Debug, Default)] 332#[derive(Debug, Default)]
310pub(crate) struct Completions { 333pub(crate) struct Completions {
311 buf: Vec<CompletionItem>, 334 buf: Vec<CompletionItem>,
312 sort_option: Option<SortOption>, 335 score_option: Option<ScoreOption>,
313} 336}
314 337
315impl Completions { 338impl Completions {
@@ -324,17 +347,17 @@ impl Completions {
324 items.into_iter().for_each(|item| self.add(item.into())) 347 items.into_iter().for_each(|item| self.add(item.into()))
325 } 348 }
326 349
327 pub(crate) fn with_sort_option(&mut self, sort_option: SortOption) { 350 pub(crate) fn with_score_option(&mut self, score_option: ScoreOption) {
328 self.sort_option = Some(sort_option); 351 self.score_option = Some(score_option);
329 } 352 }
330 353
331 pub(crate) fn sort(&mut self, ctx: &CompletionContext) { 354 pub(crate) fn compute_score(&mut self, ctx: &CompletionContext) {
332 if self.sort_option.is_none() { 355 if self.score_option.is_none() {
333 return; 356 return;
334 } 357 }
335 358
336 let (active_name, active_type) = match self.sort_option.as_ref().unwrap() { 359 let (active_name, active_type) = match self.score_option.as_ref().unwrap() {
337 SortOption::CallFn(call_info) => { 360 ScoreOption::CallFn(call_info) => {
338 if call_info.active_parameter_type().is_none() 361 if call_info.active_parameter_type().is_none()
339 || call_info.active_parameter_name().is_none() 362 || call_info.active_parameter_name().is_none()
340 { 363 {
@@ -345,7 +368,7 @@ impl Completions {
345 call_info.active_parameter_type().unwrap(), 368 call_info.active_parameter_type().unwrap(),
346 ) 369 )
347 } 370 }
348 SortOption::RecordField(record_field) => { 371 ScoreOption::RecordField(record_field) => {
349 if let Some((struct_field, _)) = ctx.sema.resolve_record_field(record_field) { 372 if let Some((struct_field, _)) = ctx.sema.resolve_record_field(record_field) {
350 ( 373 (
351 struct_field.name(ctx.db).to_string(), 374 struct_field.name(ctx.db).to_string(),
@@ -357,26 +380,19 @@ impl Completions {
357 } 380 }
358 }; 381 };
359 382
360 self.buf.sort_by(|a, b| { 383 for completion_item in &mut self.buf {
361 // For the same type 384 // For the same type
362 if let Some(a_parameter_type) = &a.detail { 385 if let Some(a_parameter_type) = &completion_item.detail {
363 if &active_type == a_parameter_type { 386 if &active_type == a_parameter_type {
364 // If same type + same name then go top position 387 // If same type + same name then go top position
365 if active_name != a.label { 388 if active_name == completion_item.label {
366 if let Some(b_parameter_type) = &b.detail { 389 completion_item.score = Some(CompletionScore::TypeAndNameMatch);
367 if &active_type == b_parameter_type { 390 } else {
368 return Ordering::Equal; 391 completion_item.score = Some(CompletionScore::TypeMatch);
369 }
370 }
371 } 392 }
372 Ordering::Less
373 } else {
374 Ordering::Greater
375 } 393 }
376 } else {
377 Ordering::Greater
378 } 394 }
379 }); 395 }
380 } 396 }
381} 397}
382 398