@@ -585,8 +585,6 @@ impl Motion {
| NextLineStart
| PreviousLineStart
| StartOfLineDownward
- | SentenceBackward
- | SentenceForward
| StartOfParagraph
| EndOfParagraph
| WindowTop
@@ -611,6 +609,8 @@ impl Motion {
| Left
| Backspace
| Right
+ | SentenceBackward
+ | SentenceForward
| Space
| StartOfLine { .. }
| EndOfLineDownward
@@ -28,23 +28,27 @@ impl Vim {
original_columns.insert(selection.id, original_head.column());
motion.expand_selection(map, selection, times, true, &text_layout_details);
+ let start_point = selection.start.to_point(map);
+ let next_line = map
+ .buffer_snapshot
+ .clip_point(Point::new(start_point.row + 1, 0), Bias::Left)
+ .to_display_point(map);
match motion {
// Motion::NextWordStart on an empty line should delete it.
- Motion::NextWordStart { .. } => {
+ Motion::NextWordStart { .. }
if selection.is_empty()
&& map
.buffer_snapshot
- .line_len(MultiBufferRow(selection.start.to_point(map).row))
- == 0
- {
- selection.end = map
- .buffer_snapshot
- .clip_point(
- Point::new(selection.start.to_point(map).row + 1, 0),
- Bias::Left,
- )
- .to_display_point(map)
- }
+ .line_len(MultiBufferRow(start_point.row))
+ == 0 =>
+ {
+ selection.end = next_line
+ }
+ // Sentence motions, when done from start of line, include the newline
+ Motion::SentenceForward | Motion::SentenceBackward
+ if selection.start.column() == 0 =>
+ {
+ selection.end = next_line
}
Motion::EndOfDocument {} => {
// Deleting until the end of the document includes the last line, including
@@ -604,4 +608,62 @@ mod test {
cx.simulate("d t x", "ˇax").await.assert_matches();
cx.simulate("d t x", "aˇx").await.assert_matches();
}
+
+ #[gpui::test]
+ async fn test_delete_sentence(cx: &mut gpui::TestAppContext) {
+ let mut cx = NeovimBackedTestContext::new(cx).await;
+ cx.simulate(
+ "d )",
+ indoc! {"
+ Fiˇrst. Second. Third.
+ Fourth.
+ "},
+ )
+ .await
+ .assert_matches();
+
+ cx.simulate(
+ "d )",
+ indoc! {"
+ First. Secˇond. Third.
+ Fourth.
+ "},
+ )
+ .await
+ .assert_matches();
+
+ // Two deletes
+ cx.simulate(
+ "d ) d )",
+ indoc! {"
+ First. Second. Thirˇd.
+ Fourth.
+ "},
+ )
+ .await
+ .assert_matches();
+
+ // Should delete whole line if done on first column
+ cx.simulate(
+ "d )",
+ indoc! {"
+ ˇFirst.
+ Fourth.
+ "},
+ )
+ .await
+ .assert_matches();
+
+ // Backwards it should also delete the whole first line
+ cx.simulate(
+ "d (",
+ indoc! {"
+ First.
+ ˇSecond.
+ Fourth.
+ "},
+ )
+ .await
+ .assert_matches();
+ }
}
@@ -0,0 +1,22 @@
+{"Put":{"state":"Fiˇrst. Second. Third.\nFourth.\n"}}
+{"Key":"d"}
+{"Key":")"}
+{"Get":{"state":"FiˇSecond. Third.\nFourth.\n","mode":"Normal"}}
+{"Put":{"state":"First. Secˇond. Third.\nFourth.\n"}}
+{"Key":"d"}
+{"Key":")"}
+{"Get":{"state":"First. SecˇThird.\nFourth.\n","mode":"Normal"}}
+{"Put":{"state":"First. Second. Thirˇd.\nFourth.\n"}}
+{"Key":"d"}
+{"Key":")"}
+{"Key":"d"}
+{"Key":")"}
+{"Get":{"state":"First. Second. Thˇi\n","mode":"Normal"}}
+{"Put":{"state":"ˇFirst.\nFourth.\n"}}
+{"Key":"d"}
+{"Key":")"}
+{"Get":{"state":"ˇFourth.\n","mode":"Normal"}}
+{"Put":{"state":"First.\nˇSecond.\nFourth.\n"}}
+{"Key":"d"}
+{"Key":"("}
+{"Get":{"state":"ˇSecond.\nFourth.\n","mode":"Normal"}}