diff --git a/crates/vim/src/normal/convert.rs b/crates/vim/src/normal/convert.rs index 25b425e847..cf9498bec9 100644 --- a/crates/vim/src/normal/convert.rs +++ b/crates/vim/src/normal/convert.rs @@ -212,7 +212,19 @@ impl Vim { } } - Mode::HelixNormal => {} + Mode::HelixNormal => { + if selection.is_empty() { + // Handle empty selection by operating on the whole word + let (word_range, _) = snapshot.surrounding_word(selection.start, false); + let word_start = snapshot.offset_to_point(word_range.start); + let word_end = snapshot.offset_to_point(word_range.end); + ranges.push(word_start..word_end); + cursor_positions.push(selection.start..selection.start); + } else { + ranges.push(selection.start..selection.end); + cursor_positions.push(selection.start..selection.end); + } + } Mode::Insert | Mode::Normal | Mode::Replace => { let start = selection.start; let mut end = start; @@ -245,12 +257,16 @@ impl Vim { }) }); }); - self.switch_mode(Mode::Normal, true, window, cx) + if self.mode != Mode::HelixNormal { + self.switch_mode(Mode::Normal, true, window, cx) + } } } #[cfg(test)] mod test { + use crate::test::VimTestContext; + use crate::{state::Mode, test::NeovimBackedTestContext}; #[gpui::test] @@ -419,4 +435,25 @@ mod test { .await .assert_eq("ˇnopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM"); } + + #[gpui::test] + async fn test_change_case_helix_mode(cx: &mut gpui::TestAppContext) { + let mut cx = VimTestContext::new(cx, true).await; + + // Explicit selection + cx.set_state("«hello worldˇ»", Mode::HelixNormal); + cx.simulate_keystrokes("~"); + cx.assert_state("«HELLO WORLDˇ»", Mode::HelixNormal); + + // Cursor-only (empty) selection + cx.set_state("The ˇquick brown", Mode::HelixNormal); + cx.simulate_keystrokes("~"); + cx.assert_state("The ˇQUICK brown", Mode::HelixNormal); + + // With `e` motion (which extends selection to end of word in Helix) + cx.set_state("The ˇquick brown fox", Mode::HelixNormal); + cx.simulate_keystrokes("e"); + cx.simulate_keystrokes("~"); + cx.assert_state("The «QUICKˇ» brown fox", Mode::HelixNormal); + } }