Fix byte/char indexing mix-up in path completion

The positions passed to `Transaction::change_by_selection` should be
character indexes. `edit_diff` is meant to track the number of
characters that should be deleted to erase the file name that has been
typed so far (if any). Mistakenly this was using `str::len` which is
the byte count. This fixes a bug that could cause more text to be
deleted than intended or a panic when completing a directory with
multi-byte characters like 'éclair'.

This change also moves the `edit_diff` binding out of the loop since
it's now performing some non-trivial work (counting characters, where
before it was just accessing the pre-computed number of bytes).
This commit is contained in:
Michael Davis 2025-01-29 09:53:42 -05:00
parent 8328c422b7
commit c9dc940428
No known key found for this signature in database

View file

@ -72,6 +72,11 @@ pub(crate) fn path_completion(
return Vec::new();
};
let edit_diff = typed_file_name
.as_ref()
.map(|s| s.chars().count())
.unwrap_or_default();
read_dir
.filter_map(Result::ok)
.filter_map(|dir_entry| {
@ -88,11 +93,6 @@ pub(crate) fn path_completion(
let kind = path_kind(&md);
let documentation = path_documentation(&md, &dir_path.join(&file_name), kind);
let edit_diff = typed_file_name
.as_ref()
.map(|f| f.len())
.unwrap_or_default();
let transaction = Transaction::change_by_selection(&text, &selection, |range| {
let cursor = range.cursor(text.slice(..));
(cursor - edit_diff, cursor, Some((&file_name).into()))