Improve sorting of completion results (#7727)
This is an attempt to fix #5013 by doing two things: 1. Rank "obvious" matches in completions higher (see the code comment) 2. When tied: rank keywords higher than variables Release Notes: - Improved sorting of completion results to prefer literal matches. ([#5013](https://github.com/zed-industries/zed/issues/5013)). ### Before   ### After   Co-authored-by: Antonio <antonio@zed.dev> Co-authored-by: bennetbo <bennetbo@gmx.de>
This commit is contained in:
parent
98fff014da
commit
798c9a7d8b
2 changed files with 49 additions and 7 deletions
|
@ -1017,12 +1017,53 @@ impl CompletionsMenu {
|
||||||
|
|
||||||
let completions = self.completions.read();
|
let completions = self.completions.read();
|
||||||
matches.sort_unstable_by_key(|mat| {
|
matches.sort_unstable_by_key(|mat| {
|
||||||
|
// We do want to strike a balance here between what the language server tells us
|
||||||
|
// to sort by (the sort_text) and what are "obvious" good matches (i.e. when you type
|
||||||
|
// `Creat` and there is a local variable called `CreateComponent`).
|
||||||
|
// So what we do is: we bucket all matches into two buckets
|
||||||
|
// - Strong matches
|
||||||
|
// - Weak matches
|
||||||
|
// Strong matches are the ones with a high fuzzy-matcher score (the "obvious" matches)
|
||||||
|
// and the Weak matches are the rest.
|
||||||
|
//
|
||||||
|
// For the strong matches, we sort by the language-servers score first and for the weak
|
||||||
|
// matches, we prefer our fuzzy finder first.
|
||||||
|
//
|
||||||
|
// The thinking behind that: it's useless to take the sort_text the language-server gives
|
||||||
|
// us into account when it's obviously a bad match.
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum MatchScore<'a> {
|
||||||
|
Strong {
|
||||||
|
sort_text: Option<&'a str>,
|
||||||
|
score: Reverse<OrderedFloat<f64>>,
|
||||||
|
sort_key: (usize, &'a str),
|
||||||
|
},
|
||||||
|
Weak {
|
||||||
|
score: Reverse<OrderedFloat<f64>>,
|
||||||
|
sort_text: Option<&'a str>,
|
||||||
|
sort_key: (usize, &'a str),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
let completion = &completions[mat.candidate_id];
|
let completion = &completions[mat.candidate_id];
|
||||||
(
|
let sort_key = completion.sort_key();
|
||||||
completion.lsp_completion.sort_text.as_ref(),
|
let sort_text = completion.lsp_completion.sort_text.as_deref();
|
||||||
Reverse(OrderedFloat(mat.score)),
|
let score = Reverse(OrderedFloat(mat.score));
|
||||||
completion.sort_key(),
|
|
||||||
)
|
if mat.score >= 0.2 {
|
||||||
|
MatchScore::Strong {
|
||||||
|
sort_text,
|
||||||
|
score,
|
||||||
|
sort_key,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MatchScore::Weak {
|
||||||
|
score,
|
||||||
|
sort_text,
|
||||||
|
sort_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for mat in &mut matches {
|
for mat in &mut matches {
|
||||||
|
|
|
@ -3441,8 +3441,9 @@ impl Completion {
|
||||||
/// them to the user.
|
/// them to the user.
|
||||||
pub fn sort_key(&self) -> (usize, &str) {
|
pub fn sort_key(&self) -> (usize, &str) {
|
||||||
let kind_key = match self.lsp_completion.kind {
|
let kind_key = match self.lsp_completion.kind {
|
||||||
Some(lsp::CompletionItemKind::VARIABLE) => 0,
|
Some(lsp::CompletionItemKind::KEYWORD) => 0,
|
||||||
_ => 1,
|
Some(lsp::CompletionItemKind::VARIABLE) => 1,
|
||||||
|
_ => 2,
|
||||||
};
|
};
|
||||||
(kind_key, &self.label.text[self.label.filter_range.clone()])
|
(kind_key, &self.label.text[self.label.filter_range.clone()])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue