Adjust the yss surrounds operator (#11212)
For #11084 In the case of an indentation in front of the current line, it may also be necessary to deal with the start point of the selected range Release Notes: - N/A --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
parent
c9778a36ff
commit
f39a24255c
4 changed files with 87 additions and 14 deletions
|
@ -447,6 +447,7 @@ pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) {
|
||||||
vim.clear_operator(cx);
|
vim.clear_operator(cx);
|
||||||
if let Some(operator) = waiting_operator {
|
if let Some(operator) = waiting_operator {
|
||||||
vim.push_operator(operator, cx);
|
vim.push_operator(operator, cx);
|
||||||
|
vim.update_state(|state| state.pre_count = count)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -755,7 +756,7 @@ impl Motion {
|
||||||
},
|
},
|
||||||
NextLineStart => (next_line_start(map, point, times), SelectionGoal::None),
|
NextLineStart => (next_line_start(map, point, times), SelectionGoal::None),
|
||||||
StartOfLineDownward => (next_line_start(map, point, times - 1), SelectionGoal::None),
|
StartOfLineDownward => (next_line_start(map, point, times - 1), SelectionGoal::None),
|
||||||
EndOfLineDownward => (next_line_end(map, point, times), SelectionGoal::None),
|
EndOfLineDownward => (last_non_whitespace(map, point, times), SelectionGoal::None),
|
||||||
GoToColumn => (go_to_column(map, point, times), SelectionGoal::None),
|
GoToColumn => (go_to_column(map, point, times), SelectionGoal::None),
|
||||||
WindowTop => window_top(map, point, &text_layout_details, times - 1),
|
WindowTop => window_top(map, point, &text_layout_details, times - 1),
|
||||||
WindowMiddle => window_middle(map, point, &text_layout_details),
|
WindowMiddle => window_middle(map, point, &text_layout_details),
|
||||||
|
@ -1422,6 +1423,26 @@ pub(crate) fn first_non_whitespace(
|
||||||
start_offset.to_display_point(map)
|
start_offset.to_display_point(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn last_non_whitespace(
|
||||||
|
map: &DisplaySnapshot,
|
||||||
|
from: DisplayPoint,
|
||||||
|
count: usize,
|
||||||
|
) -> DisplayPoint {
|
||||||
|
let mut end_of_line = end_of_line(map, false, from, count).to_offset(map, Bias::Left);
|
||||||
|
let scope = map.buffer_snapshot.language_scope_at(from.to_point(map));
|
||||||
|
for (ch, offset) in map.reverse_buffer_chars_at(end_of_line) {
|
||||||
|
if ch == '\n' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
end_of_line = offset;
|
||||||
|
if char_kind(&scope, ch) != CharKind::Whitespace || ch == '\n' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end_of_line.to_display_point(map)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn start_of_line(
|
pub(crate) fn start_of_line(
|
||||||
map: &DisplaySnapshot,
|
map: &DisplaySnapshot,
|
||||||
display_lines: bool,
|
display_lines: bool,
|
||||||
|
@ -1899,6 +1920,16 @@ mod test {
|
||||||
cx.assert_shared_state("one\n ˇtwo\nthree").await;
|
cx.assert_shared_state("one\n ˇtwo\nthree").await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_end_of_line_downward(cx: &mut gpui::TestAppContext) {
|
||||||
|
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||||
|
cx.set_shared_state("ˇ one \n two \nthree").await;
|
||||||
|
cx.simulate_shared_keystrokes(["g", "_"]).await;
|
||||||
|
cx.assert_shared_state(" onˇe \n two \nthree").await;
|
||||||
|
cx.simulate_shared_keystrokes(["2", "g", "_"]).await;
|
||||||
|
cx.assert_shared_state(" one \n twˇo \nthree").await;
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_window_top(cx: &mut gpui::TestAppContext) {
|
async fn test_window_top(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
use crate::{motion::Motion, object::Object, state::Mode, Vim};
|
use crate::{
|
||||||
|
motion::{self, Motion},
|
||||||
|
object::Object,
|
||||||
|
state::Mode,
|
||||||
|
Vim,
|
||||||
|
};
|
||||||
use editor::{movement, scroll::Autoscroll, Bias};
|
use editor::{movement, scroll::Autoscroll, Bias};
|
||||||
use gpui::WindowContext;
|
use gpui::WindowContext;
|
||||||
use language::BracketPair;
|
use language::BracketPair;
|
||||||
|
@ -23,6 +28,7 @@ impl<'de> Deserialize<'de> for SurroundsType {
|
||||||
pub fn add_surrounds(text: Arc<str>, target: SurroundsType, cx: &mut WindowContext) {
|
pub fn add_surrounds(text: Arc<str>, target: SurroundsType, cx: &mut WindowContext) {
|
||||||
Vim::update(cx, |vim, cx| {
|
Vim::update(cx, |vim, cx| {
|
||||||
vim.stop_recording();
|
vim.stop_recording();
|
||||||
|
let count = vim.take_count(cx);
|
||||||
vim.update_active_editor(cx, |_, editor, cx| {
|
vim.update_active_editor(cx, |_, editor, cx| {
|
||||||
let text_layout_details = editor.text_layout_details(cx);
|
let text_layout_details = editor.text_layout_details(cx);
|
||||||
editor.transact(cx, |editor, cx| {
|
editor.transact(cx, |editor, cx| {
|
||||||
|
@ -52,22 +58,26 @@ pub fn add_surrounds(text: Arc<str>, target: SurroundsType, cx: &mut WindowConte
|
||||||
.range(
|
.range(
|
||||||
&display_map,
|
&display_map,
|
||||||
selection.clone(),
|
selection.clone(),
|
||||||
Some(1),
|
count,
|
||||||
true,
|
true,
|
||||||
&text_layout_details,
|
&text_layout_details,
|
||||||
)
|
)
|
||||||
.map(|mut range| {
|
.map(|mut range| {
|
||||||
// The Motion::CurrentLine operation will contain the newline of the current line,
|
// The Motion::CurrentLine operation will contain the newline of the current line and leading/trailing whitespace
|
||||||
// so we need to deal with this edge case
|
|
||||||
if let Motion::CurrentLine = motion {
|
if let Motion::CurrentLine = motion {
|
||||||
let offset = range.end.to_offset(&display_map, Bias::Left);
|
range.start = motion::first_non_whitespace(
|
||||||
if let Some((last_ch, _)) =
|
&display_map,
|
||||||
display_map.reverse_buffer_chars_at(offset).next()
|
false,
|
||||||
{
|
range.start,
|
||||||
if last_ch == '\n' {
|
);
|
||||||
range.end = movement::left(&display_map, range.end);
|
range.end = movement::saturating_right(
|
||||||
}
|
&display_map,
|
||||||
}
|
motion::last_non_whitespace(
|
||||||
|
&display_map,
|
||||||
|
movement::left(&display_map, range.end),
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
range
|
range
|
||||||
});
|
});
|
||||||
|
@ -627,6 +637,30 @@ mod test {
|
||||||
the lazy dog."},
|
the lazy dog."},
|
||||||
Mode::Normal,
|
Mode::Normal,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
cx.set_state(
|
||||||
|
indoc! {"
|
||||||
|
The quˇick brown•
|
||||||
|
fox jumps over
|
||||||
|
the lazy dog."},
|
||||||
|
Mode::Normal,
|
||||||
|
);
|
||||||
|
cx.simulate_keystrokes(["y", "s", "s", "{"]);
|
||||||
|
cx.assert_state(
|
||||||
|
indoc! {"
|
||||||
|
ˇ{ The quick brown }•
|
||||||
|
fox jumps over
|
||||||
|
the lazy dog."},
|
||||||
|
Mode::Normal,
|
||||||
|
);
|
||||||
|
cx.simulate_keystrokes(["2", "y", "s", "s", ")"]);
|
||||||
|
cx.assert_state(
|
||||||
|
indoc! {"
|
||||||
|
ˇ({ The quick brown }•
|
||||||
|
fox jumps over)
|
||||||
|
the lazy dog."},
|
||||||
|
Mode::Normal,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
|
|
@ -526,7 +526,7 @@ impl Vim {
|
||||||
| Operator::ChangeSurrounds { .. }
|
| Operator::ChangeSurrounds { .. }
|
||||||
| Operator::DeleteSurrounds
|
| Operator::DeleteSurrounds
|
||||||
) {
|
) {
|
||||||
self.clear_operator(cx);
|
self.update_state(|state| state.operator_stack.clear());
|
||||||
};
|
};
|
||||||
self.update_state(|state| state.operator_stack.push(operator));
|
self.update_state(|state| state.operator_stack.push(operator));
|
||||||
self.sync_vim_settings(cx);
|
self.sync_vim_settings(cx);
|
||||||
|
|
8
crates/vim/test_data/test_end_of_line_downward.json
Normal file
8
crates/vim/test_data/test_end_of_line_downward.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{"Put":{"state":"ˇ one \n two \nthree"}}
|
||||||
|
{"Key":"g"}
|
||||||
|
{"Key":"_"}
|
||||||
|
{"Get":{"state":" onˇe \n two \nthree","mode":"Normal"}}
|
||||||
|
{"Key":"2"}
|
||||||
|
{"Key":"g"}
|
||||||
|
{"Key":"_"}
|
||||||
|
{"Get":{"state":" one \n twˇo \nthree","mode":"Normal"}}
|
Loading…
Add table
Add a link
Reference in a new issue