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
This commit is contained in:
Conrad Irwin 2025-04-22 22:28:13 -06:00 committed by GitHub
parent 4a8f114528
commit 5e31d86f1f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 4 deletions

View file

@ -2,7 +2,7 @@ use std::sync::Arc;
use collections::HashMap; use collections::HashMap;
use editor::{ use editor::{
Bias, DisplayPoint, Editor, ToOffset, Bias, DisplayPoint, Editor,
display_map::{DisplaySnapshot, ToDisplayPoint}, display_map::{DisplaySnapshot, ToDisplayPoint},
movement, movement,
scroll::Autoscroll, scroll::Autoscroll,
@ -132,16 +132,26 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
} }
vim.update_editor(window, cx, |_, editor, window, cx| { 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| { editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
let map = s.display_map(); let map = s.display_map();
let ranges = ranges let ranges = ranges
.into_iter() .into_iter()
.map(|(start, end, reversed)| { .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 { Selection {
id: s.new_selection_id(), id: s.new_selection_id(),
start: start.to_offset(&map.buffer_snapshot), start: new_start.to_point(&map),
end: new_end.to_offset(&map, Bias::Left), end: new_end.to_point(&map),
reversed, reversed,
goal: SelectionGoal::None, goal: SelectionGoal::None,
} }
@ -1729,4 +1739,25 @@ mod test {
Mode::Visual, 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");
}
} }

View file

@ -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"}}