Stop mutating completion match state + reject fuzzy match text change (#22061)

This fixes #21837, where CompletionsMenu fuzzy match positions were
desynchronized from completion label text. The solution is to not mutate
`match_candidates` and instead offset the highlight positions in the
rendering code.

This solution requires that the fuzzy match text not change on
completion resolution. This is a property we want anyway, since fuzzy
match text changing means items unexpectedly changing position in the
menu.

What happened:

* #21521 updated completion resolution to modify labels on resolution.

- This interacted poorly with the code
[here](341e65e122/crates/editor/src/code_context_menus.rs (L604)),
where the fuzzy match results are updated to include the full label, and
the fuzzy match result positions are offset to be in the correct place.
The fuzzy mach positions were now invalid because they were based on the
old text.

* #21705 caused completion resolution to occur more frequently. Before
this only the selected item was being resolved. This caused the panic
due to invalid positions to happen much more frequently.

Closes #21837

Release Notes:

- N/A
This commit is contained in:
Michael Sloan 2024-12-16 01:21:26 -07:00 committed by GitHub
parent 18b6d142c3
commit 7b721efe2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 77 additions and 24 deletions

View file

@ -423,8 +423,14 @@ impl CompletionsMenu {
&None
};
let filter_start = completion.label.filter_range.start;
let highlights = gpui::combine_highlights(
mat.ranges().map(|range| (range, FontWeight::BOLD.into())),
mat.ranges().map(|range| {
(
filter_start + range.start..filter_start + range.end,
FontWeight::BOLD.into(),
)
}),
styled_runs_for_code_label(&completion.label, &style.syntax).map(
|(range, mut highlight)| {
// Ignore font weight for syntax highlighting, as we'll use it
@ -594,14 +600,6 @@ impl CompletionsMenu {
}
});
}
for mat in &mut matches {
let completion = &completions[mat.candidate_id];
mat.string.clone_from(&completion.label.text);
for position in &mut mat.positions {
*position += completion.label.filter_range.start;
}
}
drop(completions);
self.matches = matches.into();