Make 'wrap selections in tag' work with line selection mode (#41030)

The `wrap selections in tag` action currently did not take line_mode
into account, which means when selecting lines with `shift-v`, the
start/end tags would be inserted into the middle of the selection (where
the cursor sits)


https://github.com/user-attachments/assets/a1cbf3da-d52a-42e2-aecf-1a7b6d1dbb32

This PR fixes this behaviour by checking if the selection uses line_mode
and then adjusting start and end points accordingly.

NOTE: I looked into amending the test cases for this, but I am unsure
how to express line mode with range markers. I would appreciate some
guidance on this and then I am happy to add test cases.

After:


https://github.com/user-attachments/assets/a212c41f-b0db-4f50-866f-fced7bc677ca

Release Notes:

- Fixed `Editor: wrap selection in tags` when in vim visual line mode

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
Lukas
2025-10-28 03:07:41 +00:00
committed by GitHub
co-authored by Conrad Irwin
parent 6823847978
commit 1d0bb5a7a6
2 changed files with 51 additions and 5 deletions
+1 -1
View File
@@ -10522,7 +10522,7 @@ impl Editor {
for selection in self
.selections
.all::<Point>(&self.display_snapshot(cx))
.all_adjusted(&self.display_snapshot(cx))
.iter()
{
let Some(wrap_config) = snapshot
+50 -4
View File
@@ -2,19 +2,21 @@ mod neovim_backed_test_context;
mod neovim_connection;
mod vim_test_context;
use std::time::Duration;
use std::{sync::Arc, time::Duration};
use collections::HashMap;
use command_palette::CommandPalette;
use editor::{
AnchorRangeExt, DisplayPoint, Editor, EditorMode, MultiBuffer, actions::DeleteLine,
code_context_menus::CodeContextMenu, display_map::DisplayRow,
AnchorRangeExt, DisplayPoint, Editor, EditorMode, MultiBuffer,
actions::{DeleteLine, WrapSelectionsInTag},
code_context_menus::CodeContextMenu,
display_map::DisplayRow,
test::editor_test_context::EditorTestContext,
};
use futures::StreamExt;
use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext, px};
use itertools::Itertools;
use language::Point;
use language::{Language, LanguageConfig, Point};
pub use neovim_backed_test_context::*;
use settings::SettingsStore;
use ui::Pixels;
@@ -2319,3 +2321,47 @@ async fn test_clipping_on_mode_change(cx: &mut gpui::TestAppContext) {
Mode::Normal,
);
}
#[gpui::test]
async fn test_wrap_selections_in_tag_line_mode(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
let js_language = Arc::new(Language::new(
LanguageConfig {
name: "JavaScript".into(),
wrap_characters: Some(language::WrapCharactersConfig {
start_prefix: "<".into(),
start_suffix: ">".into(),
end_prefix: "</".into(),
end_suffix: ">".into(),
}),
..LanguageConfig::default()
},
None,
));
cx.update_buffer(|buffer, cx| buffer.set_language(Some(js_language), cx));
cx.set_state(
indoc! {
"
ˇaaaaa
bbbbb
"
},
Mode::Normal,
);
cx.simulate_keystrokes("shift-v j");
cx.dispatch_action(WrapSelectionsInTag);
cx.assert_state(
indoc! {
"
<ˇ>aaaaa
bbbbb</ˇ>
"
},
Mode::VisualLine,
);
}