From 28bfcc603ccef62287d79bbfb555ac847fd310ec Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 09:06:58 -0600 Subject: [PATCH] Fix panic in vim selection restoration (cherry-pick #29251) (#29254) Cherry-picked Fix panic in vim selection restoration (#29251) Closes #27986 Closes #ISSUE Release Notes: - vim: Fixed a panic when using `gv` after `p` in visual line mode Co-authored-by: Conrad Irwin --- crates/vim/src/visual.rs | 39 +++++++++++++++++++++++--- crates/vim/test_data/test_p_g_v_y.json | 11 ++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 crates/vim/test_data/test_p_g_v_y.json diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs index 6827c2c0554862181e1d853b4955a81a985160f5..29ef3943b57086021844d8f65644fbe24e80392d 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use collections::HashMap; use editor::{ - Bias, DisplayPoint, Editor, ToOffset, + Bias, DisplayPoint, Editor, display_map::{DisplaySnapshot, ToDisplayPoint}, movement, scroll::Autoscroll, @@ -132,16 +132,26 @@ pub fn register(editor: &mut Editor, cx: &mut Context) { } vim.update_editor(window, cx, |_, editor, window, cx| { + editor.set_clip_at_line_ends(false, cx); editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| { let map = s.display_map(); let ranges = ranges .into_iter() .map(|(start, end, reversed)| { - let new_end = movement::saturating_right(&map, end.to_display_point(&map)); + let mut new_end = + movement::saturating_right(&map, end.to_display_point(&map)); + let mut new_start = start.to_display_point(&map); + if new_start >= new_end { + if new_end.column() == 0 { + new_end = movement::right(&map, new_end) + } else { + new_start = movement::saturating_left(&map, new_end); + } + } Selection { id: s.new_selection_id(), - start: start.to_offset(&map.buffer_snapshot), - end: new_end.to_offset(&map, Bias::Left), + start: new_start.to_point(&map), + end: new_end.to_point(&map), reversed, goal: SelectionGoal::None, } @@ -1729,4 +1739,25 @@ mod test { Mode::Visual, ); } + + #[gpui::test] + async fn test_p_g_v_y(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + + cx.set_shared_state(indoc! { + "The + quicˇk + brown + fox" + }) + .await; + cx.simulate_shared_keystrokes("y y j shift-v p g v y").await; + cx.shared_state().await.assert_eq(indoc! { + "The + quick + ˇquick + fox" + }); + cx.shared_clipboard().await.assert_eq("quick\n"); + } } diff --git a/crates/vim/test_data/test_p_g_v_y.json b/crates/vim/test_data/test_p_g_v_y.json new file mode 100644 index 0000000000000000000000000000000000000000..a275c333a3b069ccf456c332b44d4f5375d50cb6 --- /dev/null +++ b/crates/vim/test_data/test_p_g_v_y.json @@ -0,0 +1,11 @@ +{"Put":{"state":"The\nquicˇk\nbrown\nfox"}} +{"Key":"y"} +{"Key":"y"} +{"Key":"j"} +{"Key":"shift-v"} +{"Key":"p"} +{"Key":"g"} +{"Key":"v"} +{"Key":"y"} +{"Get":{"state":"The\nquick\nˇquick\nfox","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"quick\n"}}