diff options
author | Benjamin Coenen <[email protected]> | 2020-04-17 09:29:32 +0100 |
---|---|---|
committer | Benjamin Coenen <[email protected]> | 2020-04-17 09:29:32 +0100 |
commit | 071ef268b5c8fb9afec1db912ebcc5d6577f5e73 (patch) | |
tree | 78d3889c33d0591653ca3fac976b2224d3ec4148 /crates/ra_ide/src/completion | |
parent | 6ebc8bbeb005f5d3f2b00d1ae1f1804116e3a8f5 (diff) |
feat: improve dot completions with scoring
Signed-off-by: Benjamin Coenen <[email protected]>
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 19 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_item.rs | 106 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 1 |
3 files changed, 52 insertions, 74 deletions
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 174b39964..c16357a7e 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -1,16 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{ | 3 | use hir::{HasVisibility, Type}; |
4 | HasVisibility, | ||
5 | // HirDisplay, | ||
6 | Type, | ||
7 | }; | ||
8 | 4 | ||
9 | use crate::{ | 5 | use crate::{ |
10 | call_info::call_info, | ||
11 | completion::{ | 6 | completion::{ |
12 | completion_context::CompletionContext, | 7 | completion_context::CompletionContext, |
13 | completion_item::{CompletionKind, Completions, ScoreOption}, | 8 | completion_item::{CompletionKind, Completions}, |
14 | }, | 9 | }, |
15 | // CallInfo, | 10 | // CallInfo, |
16 | CompletionItem, | 11 | CompletionItem, |
@@ -46,15 +41,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
46 | 41 | ||
47 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | 42 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { |
48 | for receiver in receiver.autoderef(ctx.db) { | 43 | for receiver in receiver.autoderef(ctx.db) { |
49 | let fields = receiver.fields(ctx.db); | 44 | for (field, ty) in receiver.fields(ctx.db) { |
50 | |||
51 | if let Some(record_field) = &ctx.record_field_syntax { | ||
52 | acc.with_score_option(ScoreOption::RecordField(record_field.clone())); | ||
53 | } else if let Some(call_info) = call_info(ctx.db, ctx.file_position) { | ||
54 | acc.with_score_option(ScoreOption::CallFn(call_info)); | ||
55 | } | ||
56 | |||
57 | for (field, ty) in fields { | ||
58 | if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { | 45 | if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { |
59 | // Skip private field. FIXME: If the definition location of the | 46 | // Skip private field. FIXME: If the definition location of the |
60 | // field is editable, we should show the completion | 47 | // field is editable, we should show the completion |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 84d51bafe..a3ae9c86b 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{cmp::Ordering, fmt}; | 3 | use std::fmt; |
4 | 4 | ||
5 | use super::completion_context::CompletionContext; | 5 | use super::completion_context::CompletionContext; |
6 | use crate::CallInfo; | 6 | use crate::call_info::call_info; |
7 | use hir::{Documentation, HirDisplay}; | 7 | use hir::{Documentation, HirDisplay}; |
8 | use ra_syntax::{ast::RecordField, TextRange}; | 8 | use ra_syntax::TextRange; |
9 | use ra_text_edit::TextEdit; | 9 | use ra_text_edit::TextEdit; |
10 | 10 | ||
11 | /// `CompletionItem` describes a single completion variant in the editor pop-up. | 11 | /// `CompletionItem` describes a single completion variant in the editor pop-up. |
@@ -199,6 +199,10 @@ impl CompletionItem { | |||
199 | self.score.clone() | 199 | self.score.clone() |
200 | } | 200 | } |
201 | 201 | ||
202 | pub fn set_score(&mut self, score: CompletionScore) { | ||
203 | self.score = Some(score); | ||
204 | } | ||
205 | |||
202 | pub fn trigger_call_info(&self) -> bool { | 206 | pub fn trigger_call_info(&self) -> bool { |
203 | self.trigger_call_info | 207 | self.trigger_call_info |
204 | } | 208 | } |
@@ -300,6 +304,47 @@ impl Builder { | |||
300 | self.deprecated = Some(deprecated); | 304 | self.deprecated = Some(deprecated); |
301 | self | 305 | self |
302 | } | 306 | } |
307 | #[allow(unused)] | ||
308 | pub(crate) fn compute_score(mut self, ctx: &CompletionContext) -> Builder { | ||
309 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { | ||
310 | if let Some((struct_field, _)) = ctx.sema.resolve_record_field(record_field) { | ||
311 | ( | ||
312 | struct_field.name(ctx.db).to_string(), | ||
313 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), | ||
314 | ) | ||
315 | } else { | ||
316 | return self; | ||
317 | } | ||
318 | } else if let Some(call_info) = call_info(ctx.db, ctx.file_position) { | ||
319 | if call_info.active_parameter_type().is_some() | ||
320 | && call_info.active_parameter_name().is_some() | ||
321 | { | ||
322 | ( | ||
323 | call_info.active_parameter_name().unwrap(), | ||
324 | call_info.active_parameter_type().unwrap(), | ||
325 | ) | ||
326 | } else { | ||
327 | return self; | ||
328 | } | ||
329 | } else { | ||
330 | return self; | ||
331 | }; | ||
332 | |||
333 | // Compute score | ||
334 | // For the same type | ||
335 | if let Some(a_parameter_type) = &self.detail { | ||
336 | if &active_type == a_parameter_type { | ||
337 | // If same type + same name then go top position | ||
338 | if active_name == self.label { | ||
339 | return self.set_score(CompletionScore::TypeAndNameMatch); | ||
340 | } else { | ||
341 | return self.set_score(CompletionScore::TypeMatch); | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | |||
346 | self | ||
347 | } | ||
303 | pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder { | 348 | pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder { |
304 | self.score = Some(score); | 349 | self.score = Some(score); |
305 | self | 350 | self |
@@ -316,12 +361,6 @@ impl<'a> Into<CompletionItem> for Builder { | |||
316 | } | 361 | } |
317 | } | 362 | } |
318 | 363 | ||
319 | #[derive(Debug)] | ||
320 | pub(crate) enum ScoreOption { | ||
321 | CallFn(CallInfo), | ||
322 | RecordField(RecordField), | ||
323 | } | ||
324 | |||
325 | #[derive(Debug, Clone)] | 364 | #[derive(Debug, Clone)] |
326 | pub enum CompletionScore { | 365 | pub enum CompletionScore { |
327 | TypeMatch, | 366 | TypeMatch, |
@@ -332,7 +371,6 @@ pub enum CompletionScore { | |||
332 | #[derive(Debug, Default)] | 371 | #[derive(Debug, Default)] |
333 | pub(crate) struct Completions { | 372 | pub(crate) struct Completions { |
334 | buf: Vec<CompletionItem>, | 373 | buf: Vec<CompletionItem>, |
335 | score_option: Option<ScoreOption>, | ||
336 | } | 374 | } |
337 | 375 | ||
338 | impl Completions { | 376 | impl Completions { |
@@ -346,54 +384,6 @@ impl Completions { | |||
346 | { | 384 | { |
347 | items.into_iter().for_each(|item| self.add(item.into())) | 385 | items.into_iter().for_each(|item| self.add(item.into())) |
348 | } | 386 | } |
349 | |||
350 | pub(crate) fn with_score_option(&mut self, score_option: ScoreOption) { | ||
351 | self.score_option = Some(score_option); | ||
352 | } | ||
353 | |||
354 | pub(crate) fn compute_score(&mut self, ctx: &CompletionContext) { | ||
355 | if self.score_option.is_none() { | ||
356 | return; | ||
357 | } | ||
358 | |||
359 | let (active_name, active_type) = match self.score_option.as_ref().unwrap() { | ||
360 | ScoreOption::CallFn(call_info) => { | ||
361 | if call_info.active_parameter_type().is_none() | ||
362 | || call_info.active_parameter_name().is_none() | ||
363 | { | ||
364 | return; | ||
365 | } | ||
366 | ( | ||
367 | call_info.active_parameter_name().unwrap(), | ||
368 | call_info.active_parameter_type().unwrap(), | ||
369 | ) | ||
370 | } | ||
371 | ScoreOption::RecordField(record_field) => { | ||
372 | if let Some((struct_field, _)) = ctx.sema.resolve_record_field(record_field) { | ||
373 | ( | ||
374 | struct_field.name(ctx.db).to_string(), | ||
375 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), | ||
376 | ) | ||
377 | } else { | ||
378 | return; | ||
379 | } | ||
380 | } | ||
381 | }; | ||
382 | |||
383 | for completion_item in &mut self.buf { | ||
384 | // For the same type | ||
385 | if let Some(a_parameter_type) = &completion_item.detail { | ||
386 | if &active_type == a_parameter_type { | ||
387 | // If same type + same name then go top position | ||
388 | if active_name == completion_item.label { | ||
389 | completion_item.score = Some(CompletionScore::TypeAndNameMatch); | ||
390 | } else { | ||
391 | completion_item.score = Some(CompletionScore::TypeMatch); | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | } | 387 | } |
398 | 388 | ||
399 | impl Into<Vec<CompletionItem>> for Completions { | 389 | impl Into<Vec<CompletionItem>> for Completions { |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 55f75b15a..5c3360ce4 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -31,6 +31,7 @@ impl Completions { | |||
31 | .detail(ty.display(ctx.db).to_string()) | 31 | .detail(ty.display(ctx.db).to_string()) |
32 | .set_documentation(field.docs(ctx.db)) | 32 | .set_documentation(field.docs(ctx.db)) |
33 | .set_deprecated(is_deprecated) | 33 | .set_deprecated(is_deprecated) |
34 | .compute_score(ctx) | ||
34 | .add_to(self); | 35 | .add_to(self); |
35 | } | 36 | } |
36 | 37 | ||