Simplify CompletionRelevance

This commit is contained in:
Lukas Wirth 2024-09-02 11:49:11 +02:00
parent 21b7608fd7
commit 26cd745104
4 changed files with 85 additions and 90 deletions

View file

@ -221,7 +221,7 @@ fn add_function_impl_(
let mut item = CompletionItem::new(completion_kind, replacement_range, label, ctx.edition); let mut item = CompletionItem::new(completion_kind, replacement_range, label, ctx.edition);
item.lookup_by(format!("{}fn {}", async_, fn_name.display(ctx.db, ctx.edition))) item.lookup_by(format!("{}fn {}", async_, fn_name.display(ctx.db, ctx.edition)))
.set_documentation(func.docs(ctx.db)) .set_documentation(func.docs(ctx.db))
.set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); .set_relevance(CompletionRelevance { exact_name_match: true, ..Default::default() });
if let Some(source) = ctx.sema.source(func) { if let Some(source) = ctx.sema.source(func) {
if let Some(transformed_fn) = if let Some(transformed_fn) =
@ -366,7 +366,7 @@ fn add_type_alias_impl(
CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label, ctx.edition); CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label, ctx.edition);
item.lookup_by(format!("type {alias_name}")) item.lookup_by(format!("type {alias_name}"))
.set_documentation(type_alias.docs(ctx.db)) .set_documentation(type_alias.docs(ctx.db))
.set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); .set_relevance(CompletionRelevance { exact_name_match: true, ..Default::default() });
if let Some(source) = ctx.sema.source(type_alias) { if let Some(source) = ctx.sema.source(type_alias) {
let assoc_item = ast::AssocItem::TypeAlias(source.value); let assoc_item = ast::AssocItem::TypeAlias(source.value);
@ -440,7 +440,7 @@ fn add_const_impl(
item.lookup_by(format_smolstr!("const {const_name}")) item.lookup_by(format_smolstr!("const {const_name}"))
.set_documentation(const_.docs(ctx.db)) .set_documentation(const_.docs(ctx.db))
.set_relevance(CompletionRelevance { .set_relevance(CompletionRelevance {
is_item_from_trait: true, exact_name_match: true,
..Default::default() ..Default::default()
}); });
match ctx.config.snippet_cap { match ctx.config.snippet_cap {

View file

@ -19,8 +19,10 @@ use crate::{
}; };
/// `CompletionItem` describes a single completion entity which expands to 1 or more entries in the /// `CompletionItem` describes a single completion entity which expands to 1 or more entries in the
/// editor pop-up. It is basically a POD with various properties. To construct a /// editor pop-up.
/// [`CompletionItem`], use [`Builder::new`] method and the [`Builder`] struct. ///
/// It is basically a POD with various properties. To construct a [`CompletionItem`],
/// use [`Builder::new`] method and the [`Builder`] struct.
#[derive(Clone)] #[derive(Clone)]
#[non_exhaustive] #[non_exhaustive]
pub struct CompletionItem { pub struct CompletionItem {
@ -129,7 +131,8 @@ impl fmt::Debug for CompletionItem {
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub struct CompletionRelevance { pub struct CompletionRelevance {
/// This is set in cases like these: /// This is set when the identifier being completed matches up with the name that is expected,
/// like in a function argument.
/// ///
/// ``` /// ```
/// fn f(spam: String) {} /// fn f(spam: String) {}
@ -139,9 +142,9 @@ pub struct CompletionRelevance {
/// } /// }
/// ``` /// ```
pub exact_name_match: bool, pub exact_name_match: bool,
/// See CompletionRelevanceTypeMatch doc comments for cases where this is set. /// See [`CompletionRelevanceTypeMatch`].
pub type_match: Option<CompletionRelevanceTypeMatch>, pub type_match: Option<CompletionRelevanceTypeMatch>,
/// This is set in cases like these: /// Set for local variables.
/// ///
/// ``` /// ```
/// fn foo(a: u32) { /// fn foo(a: u32) {
@ -150,25 +153,26 @@ pub struct CompletionRelevance {
/// } /// }
/// ``` /// ```
pub is_local: bool, pub is_local: bool,
/// This is set when trait items are completed in an impl of that trait. /// Populated when the completion item comes from a trait (impl).
pub is_item_from_trait: bool, pub trait_: Option<CompletionRelevanceTraitInfo>,
/// This is set for when trait items are from traits with `#[doc(notable_trait)]` /// This is set when an import is suggested in a use item whose name is already imported.
pub is_item_from_notable_trait: bool,
/// This is set when an import is suggested whose name is already imported.
pub is_name_already_imported: bool, pub is_name_already_imported: bool,
/// This is set for completions that will insert a `use` item. /// This is set for completions that will insert a `use` item.
pub requires_import: bool, pub requires_import: bool,
/// Set for method completions of the `core::ops` and `core::cmp` family.
pub is_op_method: bool,
/// Set for item completions that are private but in the workspace. /// Set for item completions that are private but in the workspace.
pub is_private_editable: bool, pub is_private_editable: bool,
/// Set for postfix snippet item completions /// Set for postfix snippet item completions
pub postfix_match: Option<CompletionRelevancePostfixMatch>, pub postfix_match: Option<CompletionRelevancePostfixMatch>,
/// This is set for type inference results
pub is_definite: bool,
/// This is set for items that are function (associated or method) /// This is set for items that are function (associated or method)
pub function: Option<CompletionRelevanceFn>, pub function: Option<CompletionRelevanceFn>,
} }
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct CompletionRelevanceTraitInfo {
/// The trait this item is from is a `#[doc(notable_trait)]`
pub notable_trait: bool,
/// Set for method completions of the `core::ops` and `core::cmp` family.
pub is_op_method: bool,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CompletionRelevanceTypeMatch { pub enum CompletionRelevanceTypeMatch {
@ -182,7 +186,7 @@ pub enum CompletionRelevanceTypeMatch {
/// } /// }
/// ``` /// ```
CouldUnify, CouldUnify,
/// This is set in cases like these: /// This is set in cases where the type matches the expected type, like:
/// ///
/// ``` /// ```
/// fn f(spam: String) {} /// fn f(spam: String) {}
@ -243,14 +247,11 @@ impl CompletionRelevance {
exact_name_match, exact_name_match,
type_match, type_match,
is_local, is_local,
is_item_from_trait,
is_name_already_imported, is_name_already_imported,
requires_import, requires_import,
is_op_method,
is_private_editable, is_private_editable,
postfix_match, postfix_match,
is_definite, trait_,
is_item_from_notable_trait,
function, function,
} = self; } = self;
@ -258,8 +259,17 @@ impl CompletionRelevance {
if !is_private_editable { if !is_private_editable {
score += 1; score += 1;
} }
// lower rank trait op methods
if !is_op_method { if let Some(trait_) = trait_ {
if trait_.notable_trait {
score += 1;
}
// lower rank trait op methods
if !trait_.is_op_method {
score += 10;
}
} else {
// lower rank trait op methods
score += 10; score += 10;
} }
// lower rank for conflicting import names // lower rank for conflicting import names
@ -287,16 +297,6 @@ impl CompletionRelevance {
if is_local { if is_local {
score += 1; score += 1;
} }
if is_item_from_trait {
score += 1;
}
if is_item_from_notable_trait {
score += 1;
}
if is_definite {
score += 10;
}
score += function score += function
.map(|asf| { .map(|asf| {
let mut fn_score = match asf.return_type { let mut fn_score = match asf.return_type {
@ -701,8 +701,21 @@ mod tests {
// that any items in the same vec have the same score. // that any items in the same vec have the same score.
let expected_relevance_order = vec![ let expected_relevance_order = vec![
vec![], vec![],
vec![Cr { is_op_method: true, is_private_editable: true, ..default }], vec![Cr {
vec![Cr { is_op_method: true, ..default }], trait_: Some(crate::item::CompletionRelevanceTraitInfo {
notable_trait: false,
is_op_method: true,
}),
is_private_editable: true,
..default
}],
vec![Cr {
trait_: Some(crate::item::CompletionRelevanceTraitInfo {
notable_trait: false,
is_op_method: true,
}),
..default
}],
vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::NonExact), ..default }], vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::NonExact), ..default }],
vec![Cr { is_private_editable: true, ..default }], vec![Cr { is_private_editable: true, ..default }],
vec![default], vec![default],

View file

@ -249,7 +249,11 @@ pub(crate) fn render_type_inference(
ty_string, ty_string,
ctx.edition, ctx.edition,
); );
builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() }); builder.set_relevance(CompletionRelevance {
type_match: Some(CompletionRelevanceTypeMatch::Exact),
exact_name_match: true,
..Default::default()
});
builder.build(ctx.db) builder.build(ctx.db)
} }
@ -756,7 +760,7 @@ mod tests {
relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact), relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact),
"snippet", "snippet",
), ),
(relevance.is_op_method, "op_method"), (relevance.trait_.map_or(false, |it| it.is_op_method), "op_method"),
(relevance.requires_import, "requires_import"), (relevance.requires_import, "requires_import"),
] ]
.into_iter() .into_iter()
@ -1272,14 +1276,11 @@ fn main() { let _: m::Spam = S$0 }
Exact, Exact,
), ),
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: None, function: None,
}, },
trigger_call_info: true, trigger_call_info: true,
@ -1300,14 +1301,11 @@ fn main() { let _: m::Spam = S$0 }
Exact, Exact,
), ),
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: None, function: None,
}, },
trigger_call_info: true, trigger_call_info: true,
@ -1380,14 +1378,11 @@ fn foo() { A { the$0 } }
CouldUnify, CouldUnify,
), ),
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: None, function: None,
}, },
}, },
@ -1431,14 +1426,11 @@ impl S {
exact_name_match: false, exact_name_match: false,
type_match: None, type_match: None,
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: Some( function: Some(
CompletionRelevanceFn { CompletionRelevanceFn {
has_params: true, has_params: true,
@ -1558,14 +1550,11 @@ fn foo(s: S) { s.$0 }
exact_name_match: false, exact_name_match: false,
type_match: None, type_match: None,
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: Some( function: Some(
CompletionRelevanceFn { CompletionRelevanceFn {
has_params: true, has_params: true,
@ -1774,14 +1763,11 @@ fn f() -> i32 {
Exact, Exact,
), ),
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: None, function: None,
}, },
}, },
@ -2492,14 +2478,11 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
exact_name_match: false, exact_name_match: false,
type_match: None, type_match: None,
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: Some( function: Some(
CompletionRelevanceFn { CompletionRelevanceFn {
has_params: true, has_params: true,
@ -2574,14 +2557,11 @@ fn foo() {
Exact, Exact,
), ),
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: None, function: None,
}, },
}, },
@ -2624,14 +2604,11 @@ fn main() {
exact_name_match: false, exact_name_match: false,
type_match: None, type_match: None,
is_local: false, is_local: false,
is_item_from_trait: false, trait_: None,
is_item_from_notable_trait: false,
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: Some( function: Some(
CompletionRelevanceFn { CompletionRelevanceFn {
has_params: false, has_params: false,
@ -2996,14 +2973,16 @@ fn main() {
exact_name_match: false, exact_name_match: false,
type_match: None, type_match: None,
is_local: false, is_local: false,
is_item_from_trait: false, trait_: Some(
is_item_from_notable_trait: true, CompletionRelevanceTraitInfo {
notable_trait: true,
is_op_method: false,
},
),
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: None, function: None,
}, },
}, },
@ -3021,14 +3000,16 @@ fn main() {
exact_name_match: false, exact_name_match: false,
type_match: None, type_match: None,
is_local: false, is_local: false,
is_item_from_trait: false, trait_: Some(
is_item_from_notable_trait: true, CompletionRelevanceTraitInfo {
notable_trait: true,
is_op_method: false,
},
),
is_name_already_imported: false, is_name_already_imported: false,
requires_import: false, requires_import: false,
is_op_method: false,
is_private_editable: false, is_private_editable: false,
postfix_match: None, postfix_match: None,
is_definite: false,
function: None, function: None,
}, },
}, },

View file

@ -10,7 +10,7 @@ use crate::{
context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind}, context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind},
item::{ item::{
Builder, CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevanceFn, Builder, CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevanceFn,
CompletionRelevanceReturnType, CompletionRelevanceReturnType, CompletionRelevanceTraitInfo,
}, },
render::{ render::{
compute_exact_name_match, compute_ref_match, compute_type_match, match_types, RenderContext, compute_exact_name_match, compute_ref_match, compute_type_match, match_types, RenderContext,
@ -88,11 +88,13 @@ fn render(
let ret_type = func.ret_type(db); let ret_type = func.ret_type(db);
let assoc_item = func.as_assoc_item(db); let assoc_item = func.as_assoc_item(db);
let trait_ = assoc_item.and_then(|trait_| trait_.container_or_implemented_trait(db)); let trait_info =
let is_op_method = trait_.map_or(false, |trait_| completion.is_ops_trait(trait_)); assoc_item.and_then(|trait_| trait_.container_or_implemented_trait(db)).map(|trait_| {
CompletionRelevanceTraitInfo {
let is_item_from_notable_trait = notable_trait: completion.is_doc_notable_trait(trait_),
trait_.map_or(false, |trait_| completion.is_doc_notable_trait(trait_)); is_op_method: completion.is_ops_trait(trait_),
}
});
let (has_dot_receiver, has_call_parens, cap) = match func_kind { let (has_dot_receiver, has_call_parens, cap) = match func_kind {
FuncKind::Function(&PathCompletionCtx { FuncKind::Function(&PathCompletionCtx {
@ -129,8 +131,7 @@ fn render(
}, },
exact_name_match: compute_exact_name_match(completion, &call), exact_name_match: compute_exact_name_match(completion, &call),
function, function,
is_op_method, trait_: trait_info,
is_item_from_notable_trait,
..ctx.completion_relevance() ..ctx.completion_relevance()
}); });