From c9dc9404288f98316c9e41ecf8bfbb8491c2fd0f Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 29 Jan 2025 09:53:42 -0500 Subject: [PATCH] Fix byte/char indexing mix-up in path completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- helix-term/src/handlers/completion/path.rs | 10 +++++----- 1 file 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()))