feat: add counted word change actions
Add cw/cb and configurable core actions using the same line-local spans as dw/db. Enter Insert with grouped replacement undo and native dot repeat.
This commit is contained in:
+94
-3
@@ -191,7 +191,7 @@ fn substitute_deletes_counted_whole_graphemes_and_groups_replacement_with_undo()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn word_delete_counts_before_and_after_operator_multiply_in_both_directions() {
|
||||
fn word_cut_counts_before_and_after_operator_multiply_in_both_directions() {
|
||||
let source = "one two three four five six seven eight nine\n";
|
||||
for (position, command, expected) in [
|
||||
("", "dw", "two three four five six seven eight nine\n"),
|
||||
@@ -202,18 +202,66 @@ fn word_delete_counts_before_and_after_operator_multiply_in_both_directions() {
|
||||
("4w", "d2b", "one two five six seven eight nine\n"),
|
||||
("4w", "2db", "one two five six seven eight nine\n"),
|
||||
("6w", "2d3b", "seven eight nine\n"),
|
||||
] {
|
||||
for operator in ["d", "c"] {
|
||||
let fixture = Fixture::new();
|
||||
let mut editor = fixture.editor(source);
|
||||
keys(&mut editor, position);
|
||||
let caret = editor.cursor();
|
||||
let command = command.replacen('d', operator, 1);
|
||||
keys(&mut editor, &command);
|
||||
assert_eq!(editor.context().text, expected, "{position} {command}");
|
||||
assert_eq!(
|
||||
editor.mode(),
|
||||
if operator == "c" {
|
||||
Mode::Insert
|
||||
} else {
|
||||
Mode::Normal
|
||||
}
|
||||
);
|
||||
if operator == "c" {
|
||||
keys(&mut editor, "Q");
|
||||
editor.handle(Input::Escape);
|
||||
}
|
||||
keys(&mut editor, "u");
|
||||
assert_eq!(editor.context().text, source);
|
||||
assert_eq!(editor.cursor(), caret);
|
||||
assert!(!editor.dirty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn word_changes_preserve_line_boundaries_and_group_replacement_with_undo() {
|
||||
for (source, position, command, after_cut, expected) in [
|
||||
("one two\nnext\n", "", "cw", "two\nnext\n", "Qtwo\nnext\n"),
|
||||
("one two\nnext\n", "w", "cb", "two\nnext\n", "Qtwo\nnext\n"),
|
||||
("one\ntwo\n", "", "c9w", "\ntwo\n", "Q\ntwo\n"),
|
||||
("one\ntwo\n", "j0", "c9b", "one\ntwo\n", "one\nQtwo\n"),
|
||||
("one\n\ntwo\n", "j", "cw", "one\n\ntwo\n", "one\nQ\ntwo\n"),
|
||||
("one\n\ntwo\n", "j", "cb", "one\n\ntwo\n", "one\nQ\ntwo\n"),
|
||||
("one\n \ntwo\n", "j", "cw", "one\n\ntwo\n", "one\nQ\ntwo\n"),
|
||||
("one \nnext\n", "", "cw", "\nnext\n", "Q\nnext\n"),
|
||||
("e\u{301}lan 世界 fin\n", "", "c2w", "fin\n", "Qfin\n"),
|
||||
("e\u{301}lan 世界", "$", "c9b", "界", "Q界"),
|
||||
("👩🚀!!! next\n", "", "cw", "next\n", "Qnext\n"),
|
||||
] {
|
||||
let fixture = Fixture::new();
|
||||
let mut editor = fixture.editor(source);
|
||||
keys(&mut editor, position);
|
||||
let caret = editor.cursor();
|
||||
keys(&mut editor, command);
|
||||
assert_eq!(editor.context().text, after_cut, "{position} {command}");
|
||||
assert_eq!(editor.mode(), Mode::Insert);
|
||||
keys(&mut editor, "Q");
|
||||
editor.handle(Input::Escape);
|
||||
assert_eq!(editor.context().text, expected, "{position} {command}");
|
||||
assert_eq!(editor.mode(), Mode::Normal);
|
||||
keys(&mut editor, "u");
|
||||
assert_eq!(editor.context().text, source);
|
||||
assert_eq!(editor.cursor(), caret);
|
||||
assert!(!editor.dirty());
|
||||
keys(&mut editor, "U");
|
||||
assert_eq!(editor.context().text, expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +354,7 @@ fn word_delete_handles_eof_and_saturating_counts_without_splitting_graphemes() {
|
||||
|
||||
#[test]
|
||||
fn pending_operator_and_replace_cancellation_clear_counts_without_editing() {
|
||||
for prefix in ["3d", "d2", "2d3", "3c", "c2", "3r"] {
|
||||
for prefix in ["3d", "d2", "2d3", "3c", "c2", "2c3", "3r"] {
|
||||
let fixture = Fixture::new();
|
||||
let source = "abcd\nnext\n";
|
||||
let mut editor = fixture.editor(source);
|
||||
@@ -387,6 +435,34 @@ fn new_edit_recipes_repeat_against_the_current_text_and_undo_as_single_changes()
|
||||
"j02w",
|
||||
"keep\nstay\n",
|
||||
),
|
||||
(
|
||||
"one two keep\nthree four stay\n",
|
||||
"c2wQ",
|
||||
"Qkeep\nthree four stay\n",
|
||||
"j0",
|
||||
"Qkeep\nQstay\n",
|
||||
),
|
||||
(
|
||||
"one two keep\nthree four stay\n",
|
||||
"2wc2bQ",
|
||||
"Qkeep\nthree four stay\n",
|
||||
"j02w",
|
||||
"Qkeep\nQstay\n",
|
||||
),
|
||||
(
|
||||
"one\nthree four\n",
|
||||
"c9wQ",
|
||||
"Q\nthree four\n",
|
||||
"j0",
|
||||
"Q\nQ\n",
|
||||
),
|
||||
(
|
||||
"one keep\nthree four stay\n",
|
||||
"wc9bQ",
|
||||
"Qkeep\nthree four stay\n",
|
||||
"j02w",
|
||||
"Qkeep\nQstay\n",
|
||||
),
|
||||
] {
|
||||
let fixture = Fixture::new();
|
||||
let mut editor = fixture.editor(source);
|
||||
@@ -474,12 +550,19 @@ fn native_multicarets_edit_whole_graphemes_and_yank_matching_suffix_fragments()
|
||||
("2wd2b", "keep\nstay\n"),
|
||||
("d9w", "\n\n"),
|
||||
("2wd9b", "keep\nstay\n"),
|
||||
("c2wQ", "Qkeep\nQstay\n"),
|
||||
("2wc2bQ", "Qkeep\nQstay\n"),
|
||||
("c9wQ", "Q\nQ\n"),
|
||||
("2wc9bQ", "Qkeep\nQstay\n"),
|
||||
] {
|
||||
let fixture = Fixture::new();
|
||||
let source = "one two keep\nthree four stay\n";
|
||||
let mut editor = fixture.editor(source);
|
||||
editor.handle(Input::Ctrl('e'));
|
||||
keys(&mut editor, command);
|
||||
if editor.mode() == Mode::Insert {
|
||||
editor.handle(Input::Escape);
|
||||
}
|
||||
assert_eq!(editor.context().text, expected, "{command}");
|
||||
assert_eq!(editor.selection_count(), 2);
|
||||
keys(&mut editor, "u");
|
||||
@@ -516,6 +599,14 @@ fn remapped_core_edit_actions_keep_counts_pending_input_and_clipboard_semantics(
|
||||
),
|
||||
("core.delete_word_forward", "d", "", "2q", "ghi\nnext\n"),
|
||||
("core.delete_word_backward", "d", "2w", "2q", "ghi\nnext\n"),
|
||||
("core.change_word_forward", "c", "", "2qQ", "Qghi\nnext\n"),
|
||||
(
|
||||
"core.change_word_backward",
|
||||
"c",
|
||||
"2w",
|
||||
"2qQ",
|
||||
"Qghi\nnext\n",
|
||||
),
|
||||
] {
|
||||
let fixture = Fixture::new();
|
||||
let mut editor = fixture.editor("abc def ghi\nnext\n");
|
||||
|
||||
Reference in New Issue
Block a user