vim: Add g M
motion to go to the middle of a line (#30227)
Adds the "g M" vim motion to go to the middle of the line. --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
parent
c7725e31d9
commit
d791c6cdb1
3 changed files with 146 additions and 0 deletions
|
@ -152,6 +152,7 @@
|
|||
"g end": ["vim::EndOfLine", { "display_lines": true }],
|
||||
"g 0": ["vim::StartOfLine", { "display_lines": true }],
|
||||
"g home": ["vim::StartOfLine", { "display_lines": true }],
|
||||
"g shift-m": ["vim::MiddleOfLine", { "display_lines": true }],
|
||||
"g ^": ["vim::FirstNonWhitespace", { "display_lines": true }],
|
||||
"g v": "vim::RestoreVisualSelection",
|
||||
"g ]": "editor::GoToDiagnostic",
|
||||
|
|
|
@ -84,6 +84,9 @@ pub enum Motion {
|
|||
StartOfLine {
|
||||
display_lines: bool,
|
||||
},
|
||||
MiddleOfLine {
|
||||
display_lines: bool,
|
||||
},
|
||||
EndOfLine {
|
||||
display_lines: bool,
|
||||
},
|
||||
|
@ -265,6 +268,13 @@ pub struct StartOfLine {
|
|||
pub(crate) display_lines: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct MiddleOfLine {
|
||||
#[serde(default)]
|
||||
display_lines: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct UnmatchedForward {
|
||||
|
@ -283,6 +293,7 @@ impl_actions!(
|
|||
vim,
|
||||
[
|
||||
StartOfLine,
|
||||
MiddleOfLine,
|
||||
EndOfLine,
|
||||
FirstNonWhitespace,
|
||||
Down,
|
||||
|
@ -409,6 +420,15 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
|||
cx,
|
||||
)
|
||||
});
|
||||
Vim::action(editor, cx, |vim, action: &MiddleOfLine, window, cx| {
|
||||
vim.motion(
|
||||
Motion::MiddleOfLine {
|
||||
display_lines: action.display_lines,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
Vim::action(editor, cx, |vim, action: &EndOfLine, window, cx| {
|
||||
vim.motion(
|
||||
Motion::EndOfLine {
|
||||
|
@ -737,6 +757,7 @@ impl Motion {
|
|||
| SentenceBackward
|
||||
| SentenceForward
|
||||
| GoToColumn
|
||||
| MiddleOfLine { .. }
|
||||
| UnmatchedForward { .. }
|
||||
| UnmatchedBackward { .. }
|
||||
| NextWordStart { .. }
|
||||
|
@ -769,6 +790,7 @@ impl Motion {
|
|||
Down { .. }
|
||||
| Up { .. }
|
||||
| EndOfLine { .. }
|
||||
| MiddleOfLine { .. }
|
||||
| Matching
|
||||
| UnmatchedForward { .. }
|
||||
| UnmatchedBackward { .. }
|
||||
|
@ -894,6 +916,10 @@ impl Motion {
|
|||
start_of_line(map, *display_lines, point),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
MiddleOfLine { display_lines } => (
|
||||
middle_of_line(map, *display_lines, point, maybe_times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
EndOfLine { display_lines } => (
|
||||
end_of_line(map, *display_lines, point, times),
|
||||
SelectionGoal::None,
|
||||
|
@ -1944,6 +1970,36 @@ pub(crate) fn start_of_line(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn middle_of_line(
|
||||
map: &DisplaySnapshot,
|
||||
display_lines: bool,
|
||||
point: DisplayPoint,
|
||||
times: Option<usize>,
|
||||
) -> DisplayPoint {
|
||||
let percent = if let Some(times) = times.filter(|&t| t <= 100) {
|
||||
times as f64 / 100.
|
||||
} else {
|
||||
0.5
|
||||
};
|
||||
if display_lines {
|
||||
map.clip_point(
|
||||
DisplayPoint::new(
|
||||
point.row(),
|
||||
(map.line_len(point.row()) as f64 * percent) as u32,
|
||||
),
|
||||
Bias::Left,
|
||||
)
|
||||
} else {
|
||||
let mut buffer_point = point.to_point(map);
|
||||
buffer_point.column = (map
|
||||
.buffer_snapshot
|
||||
.line_len(MultiBufferRow(buffer_point.row)) as f64
|
||||
* percent) as u32;
|
||||
|
||||
map.clip_point(buffer_point.to_display_point(map), Bias::Left)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn end_of_line(
|
||||
map: &DisplaySnapshot,
|
||||
display_lines: bool,
|
||||
|
@ -3906,6 +3962,61 @@ mod test {
|
|||
assert_eq!(cx.cx.forced_motion(), false);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_forced_motion_delete_to_middle_of_line(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
ˇthe quick brown fox
|
||||
jumped over the lazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes("d v g shift-m").await;
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
ˇbrown fox
|
||||
jumped over the lazy dog"});
|
||||
assert_eq!(cx.cx.forced_motion(), false);
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
the quick bˇrown fox
|
||||
jumped over the lazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes("d v g shift-m").await;
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
the quickˇown fox
|
||||
jumped over the lazy dog"});
|
||||
assert_eq!(cx.cx.forced_motion(), false);
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
the quick brown foˇx
|
||||
jumped over the lazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes("d v g shift-m").await;
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
the quicˇk
|
||||
jumped over the lazy dog"});
|
||||
assert_eq!(cx.cx.forced_motion(), false);
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
ˇthe quick brown fox
|
||||
jumped over the lazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes("d v 7 5 g shift-m").await;
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
ˇ fox
|
||||
jumped over the lazy dog"});
|
||||
assert_eq!(cx.cx.forced_motion(), false);
|
||||
|
||||
cx.set_shared_state(indoc! {"
|
||||
ˇthe quick brown fox
|
||||
jumped over the lazy dog"})
|
||||
.await;
|
||||
cx.simulate_shared_keystrokes("d v 2 3 g shift-m").await;
|
||||
cx.shared_state().await.assert_eq(indoc! {"
|
||||
ˇuick brown fox
|
||||
jumped over the lazy dog"});
|
||||
assert_eq!(cx.cx.forced_motion(), false);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_forced_motion_delete_to_end_of_line(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = NeovimBackedTestContext::new(cx).await;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
{"Put":{"state":"ˇthe quick brown fox\njumped over the lazy dog"}}
|
||||
{"Key":"d"}
|
||||
{"Key":"v"}
|
||||
{"Key":"g"}
|
||||
{"Key":"shift-m"}
|
||||
{"Get":{"state":"ˇbrown fox\njumped over the lazy dog","mode":"Normal"}}
|
||||
{"Put":{"state":"the quick bˇrown fox\njumped over the lazy dog"}}
|
||||
{"Key":"d"}
|
||||
{"Key":"v"}
|
||||
{"Key":"g"}
|
||||
{"Key":"shift-m"}
|
||||
{"Get":{"state":"the quickˇown fox\njumped over the lazy dog","mode":"Normal"}}
|
||||
{"Put":{"state":"the quick brown foˇx\njumped over the lazy dog"}}
|
||||
{"Key":"d"}
|
||||
{"Key":"v"}
|
||||
{"Key":"g"}
|
||||
{"Key":"shift-m"}
|
||||
{"Get":{"state":"the quicˇk\njumped over the lazy dog","mode":"Normal"}}
|
||||
{"Put":{"state":"ˇthe quick brown fox\njumped over the lazy dog"}}
|
||||
{"Key":"d"}
|
||||
{"Key":"v"}
|
||||
{"Key":"7"}
|
||||
{"Key":"5"}
|
||||
{"Key":"g"}
|
||||
{"Key":"shift-m"}
|
||||
{"Get":{"state":"ˇ fox\njumped over the lazy dog","mode":"Normal"}}
|
||||
{"Put":{"state":"ˇthe quick brown fox\njumped over the lazy dog"}}
|
||||
{"Key":"d"}
|
||||
{"Key":"v"}
|
||||
{"Key":"2"}
|
||||
{"Key":"3"}
|
||||
{"Key":"g"}
|
||||
{"Key":"shift-m"}
|
||||
{"Get":{"state":"ˇuick brown fox\njumped over the lazy dog","mode":"Normal"}}
|
Loading…
Add table
Add a link
Reference in a new issue