Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide_completion/src/item.rs')
| -rw-r--r-- | crates/ide_completion/src/item.rs | 153 |
1 files changed, 54 insertions, 99 deletions
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs index 89cbddbad3..3c2be32f4e 100644 --- a/crates/ide_completion/src/item.rs +++ b/crates/ide_completion/src/item.rs @@ -3,17 +3,10 @@ use std::fmt; use hir::{Documentation, Mutability}; -use ide_db::{ - helpers::mod_path_to_ast, - imports::{ - import_assets::LocatedImport, - insert_use::{self, ImportScope, InsertUseConfig}, - }, - SnippetCap, SymbolKind, -}; +use ide_db::{imports::import_assets::LocatedImport, SnippetCap, SymbolKind}; use smallvec::SmallVec; use stdx::{impl_from, never}; -use syntax::{algo, SmolStr, TextRange}; +use syntax::{SmolStr, TextRange}; use text_edit::TextEdit; /// `CompletionItem` describes a single completion variant in the editor pop-up. @@ -73,7 +66,7 @@ pub struct CompletionItem { ref_match: Option<Mutability>, /// The import data to add to completion's edits. - import_to_add: SmallVec<[ImportEdit; 1]>, + import_to_add: SmallVec<[LocatedImport; 1]>, } // We use custom debug for CompletionItem to make snapshot tests more readable. @@ -187,7 +180,6 @@ pub enum CompletionRelevancePostfixMatch { } impl CompletionRelevance { - const BASE_LINE: u32 = 3; /// Provides a relevance score. Higher values are more relevant. /// /// The absolute value of the relevance score is not meaningful, for @@ -197,35 +189,42 @@ impl CompletionRelevance { /// /// See is_relevant if you need to make some judgement about score /// in an absolute sense. - pub fn score(&self) -> u32 { - let mut score = Self::BASE_LINE; - - // score decreases - if self.is_op_method { - score -= 1; - } - if self.is_private_editable { - score -= 1; + pub fn score(self) -> u32 { + let mut score = 0; + let CompletionRelevance { + exact_name_match, + type_match, + is_local, + is_op_method, + is_private_editable, + postfix_match, + } = self; + + // lower rank private things + if !is_private_editable { + score += 1; } - if self.postfix_match.is_some() { - score -= 3; + // lower rank trait op methods + if !is_op_method { + score += 10; } - - // score increases - if self.exact_name_match { - score += 1; + if exact_name_match { + score += 10; } - score += match self.type_match { - Some(CompletionRelevanceTypeMatch::Exact) => 4, + score += match postfix_match { + Some(CompletionRelevancePostfixMatch::Exact) => 100, + Some(CompletionRelevancePostfixMatch::NonExact) => 0, + None => 3, + }; + score += match type_match { + Some(CompletionRelevanceTypeMatch::Exact) => 8, Some(CompletionRelevanceTypeMatch::CouldUnify) => 3, None => 0, }; - if self.is_local { + // slightly prefer locals + if is_local { score += 1; } - if self.postfix_match == Some(CompletionRelevancePostfixMatch::Exact) { - score += 100; - } score } @@ -234,7 +233,7 @@ impl CompletionRelevance { /// some threshold such that we think it is especially likely /// to be relevant. pub fn is_relevant(&self) -> bool { - self.score() > Self::BASE_LINE + self.score() > 0 } } @@ -374,40 +373,17 @@ impl CompletionItem { self.ref_match.map(|mutability| (mutability, relevance)) } - pub fn imports_to_add(&self) -> &[ImportEdit] { + pub fn imports_to_add(&self) -> &[LocatedImport] { &self.import_to_add } } -/// An extra import to add after the completion is applied. -#[derive(Debug, Clone)] -pub struct ImportEdit { - pub import: LocatedImport, - pub scope: ImportScope, -} - -impl ImportEdit { - /// Attempts to insert the import to the given scope, producing a text edit. - /// May return no edit in edge cases, such as scope already containing the import. - pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> { - let _p = profile::span("ImportEdit::to_text_edit"); - - let new_ast = self.scope.clone_for_update(); - insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), &cfg); - let mut import_insert = TextEdit::builder(); - algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) - .into_text_edit(&mut import_insert); - - Some(import_insert.finish()) - } -} - /// A helper to make `CompletionItem`s. #[must_use] #[derive(Clone)] pub(crate) struct Builder { source_range: TextRange, - imports_to_add: SmallVec<[ImportEdit; 1]>, + imports_to_add: SmallVec<[LocatedImport; 1]>, trait_name: Option<SmolStr>, label: SmolStr, insert_text: Option<String>, @@ -433,7 +409,7 @@ impl Builder { if let [import_edit] = &*self.imports_to_add { // snippets can have multiple imports, but normal completions only have up to one - if let Some(original_path) = import_edit.import.original_path.as_ref() { + if let Some(original_path) = import_edit.original_path.as_ref() { lookup = lookup.or_else(|| Some(label.clone())); label = SmolStr::from(format!("{} (use {})", label, original_path)); } @@ -527,7 +503,7 @@ impl Builder { self.trigger_call_info = Some(true); self } - pub(crate) fn add_import(&mut self, import_to_add: ImportEdit) -> &mut Builder { + pub(crate) fn add_import(&mut self, import_to_add: LocatedImport) -> &mut Builder { self.imports_to_add.push(import_to_add); self } @@ -584,55 +560,34 @@ mod tests { #[test] fn relevance_score() { + use CompletionRelevance as Cr; + let default = Cr::default(); // This test asserts that the relevance score for these items is ascending, and // that any items in the same vec have the same score. let expected_relevance_order = vec![ - vec![CompletionRelevance { - postfix_match: Some(CompletionRelevancePostfixMatch::NonExact), - ..CompletionRelevance::default() - }], - vec![CompletionRelevance { - is_op_method: true, - is_private_editable: true, - ..CompletionRelevance::default() - }], - vec![ - CompletionRelevance { is_private_editable: true, ..CompletionRelevance::default() }, - CompletionRelevance { is_op_method: true, ..CompletionRelevance::default() }, - ], - vec![CompletionRelevance::default()], - vec![ - CompletionRelevance { exact_name_match: true, ..CompletionRelevance::default() }, - CompletionRelevance { is_local: true, ..CompletionRelevance::default() }, - ], - vec![CompletionRelevance { + vec![], + vec![Cr { is_op_method: true, is_private_editable: true, ..default }], + vec![Cr { is_op_method: true, ..default }], + vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::NonExact), ..default }], + vec![Cr { is_private_editable: true, ..default }], + vec![default], + vec![Cr { is_local: true, ..default }], + vec![Cr { type_match: Some(CompletionRelevanceTypeMatch::CouldUnify), ..default }], + vec![Cr { type_match: Some(CompletionRelevanceTypeMatch::Exact), ..default }], + vec![Cr { exact_name_match: true, ..default }], + vec![Cr { exact_name_match: true, is_local: true, ..default }], + vec![Cr { exact_name_match: true, - is_local: true, - ..CompletionRelevance::default() - }], - vec![CompletionRelevance { - type_match: Some(CompletionRelevanceTypeMatch::CouldUnify), - ..CompletionRelevance::default() - }], - vec![CompletionRelevance { type_match: Some(CompletionRelevanceTypeMatch::Exact), - ..CompletionRelevance::default() + ..default }], - vec![CompletionRelevance { - exact_name_match: true, - type_match: Some(CompletionRelevanceTypeMatch::Exact), - ..CompletionRelevance::default() - }], - vec![CompletionRelevance { + vec![Cr { exact_name_match: true, type_match: Some(CompletionRelevanceTypeMatch::Exact), is_local: true, - ..CompletionRelevance::default() - }], - vec![CompletionRelevance { - postfix_match: Some(CompletionRelevancePostfixMatch::Exact), - ..CompletionRelevance::default() + ..default }], + vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::Exact), ..default }], ]; check_relevance_score_ordered(expected_relevance_order); |