Unnamed repository; edit this file 'description' to name the repository.
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).
| -rw-r--r-- | helix-term/src/handlers/completion/path.rs | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/helix-term/src/handlers/completion/path.rs b/helix-term/src/handlers/completion/path.rs index 102de6b0..9fd24ac8 100644 --- a/helix-term/src/handlers/completion/path.rs +++ b/helix-term/src/handlers/completion/path.rs @@ -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())) |