fix: floor word_end to char boundary in abbreviation expansion (panic on multibyte char before cursor)#1121
Conversation
`try_expand_abbreviation_at_cursor` computed `word_end` by subtracting a raw byte `offset` (0 on <enter>, 1 on <space>) from the byte cursor position, then sliced `&buffer[..word_end]`. When a multi-byte UTF-8 char (e.g. pasted CJK text) sits immediately before the cursor, `word_end` can land inside that char, panicking with "byte index N is not a char boundary". Floor `word_end` down to the nearest char boundary before slicing. Adds a regression test that reproduces the panic with a multi-byte char before the cursor. Signed-off-by: easyinplay <easyinplay@gmail.com>
|
I have had this bug on my mind already, nice for you to pick it up. But could it be that you used an LLM for this? I will take a closer look next week. |
Because I have been away from school for too long, my English may not be very accurate in describing some technical vocabulary. Therefore, I provided the relevant PR content to AI in Chinese, hoping that it could help me describe it as clearly as possible. Perhaps I missed the task of using a template, which I will pay attention to later. |
|
No problem, thanks for clarifying. I will take a look at it more closely this week. |
|
One thing to add here. |
Signed-off-by: easyinplay <easyinplay@gmail.com>
|
Done — reused |
Summary
try_expand_abbreviation_at_cursorinsrc/engine.rspanics when a multi-byte UTF-8 character (e.g. CJK text) sits immediately before the cursor at expansion time. This PR floors the word-end index down to the nearest char boundary before slicing, so the function returnsNoneinstead of panicking when the cursor is mid-char.No change to Reedline's public API. The only observable behavior change: an input that previously aborted the process now expands nothing at that position (instead of panicking).
Before
try_expand_abbreviation_at_cursorcomputes the word end as a raw byte subtraction:When the byte just before the cursor belongs to a multi-byte char,
word_endlands inside that char, and&buffer[..word_end]panics:Repro: paste CJK text into a reedline prompt with abbreviations enabled (both terminal bracketed paste and system-clipboard paste trigger it); the following expansion check slices the buffer at a non-char-boundary and the process panics. Minimal in-crate case: buffer
"中", cursor at byte offset 1,try_expand_abbreviation_at_cursor(true)panics on the slice on currentmain.After
word_endis floored to the nearest char boundary before slicing:The rest of the function is unchanged. The slice now always lands on a char boundary; when the cursor is mid-char there is no complete word to expand, so the function returns
Noneinstead of panicking.Additional notes
try_expand_abbreviation_survives_multibyte_char_before_cursorin the existingengine::testsmodule: it places the cursor inside a multi-byte char and asserts the call returns without panicking. Verified the test panics onmainand passes with the fix. Fullcargo test --libremains green (1173 passed).