Merge pull request #2013 from zed-industries/autocomplete-require-word-start-match

Require first codepoint of autocomplete query to match the first codepoint of some completion's subword
This commit is contained in:
Julia 2023-01-09 13:06:43 -05:00 committed by GitHub
commit 2be4f41964
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 0 deletions

View file

@ -828,6 +828,23 @@ impl CompletionsMenu {
})
.collect()
};
//Remove all candidates where the query's start does not match the start of any word in the candidate
if let Some(query) = query {
if let Some(query_start) = query.chars().next() {
matches.retain(|string_match| {
split_words(&string_match.string).any(|word| {
//Check that the first codepoint of the word as lowercase matches the first
//codepoint of the query as lowercase
word.chars()
.flat_map(|codepoint| codepoint.to_lowercase())
.zip(query_start.to_lowercase())
.all(|(word_cp, query_cp)| word_cp == query_cp)
})
});
}
}
matches.sort_unstable_by_key(|mat| {
let completion = &self.completions[mat.candidate_id];
(
@ -6802,6 +6819,34 @@ pub fn styled_runs_for_code_label<'a>(
})
}
pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
let mut index = 0;
let mut codepoints = text.char_indices().peekable();
std::iter::from_fn(move || {
let start_index = index;
while let Some((new_index, codepoint)) = codepoints.next() {
index = new_index + codepoint.len_utf8();
let current_upper = codepoint.is_uppercase();
let next_upper = codepoints
.peek()
.map(|(_, c)| c.is_uppercase())
.unwrap_or(false);
if !current_upper && next_upper {
return Some(&text[start_index..index]);
}
}
index = text.len();
if start_index < text.len() {
return Some(&text[start_index..]);
}
None
})
.flat_map(|word| word.split_inclusive('_'))
}
trait RangeExt<T> {
fn sorted(&self) -> Range<T>;
fn to_inclusive(&self) -> RangeInclusive<T>;