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:
+36
-7
@@ -568,6 +568,16 @@ core_actions![
|
||||
Action::DeleteWordBackward,
|
||||
&[Mode::Normal]
|
||||
),
|
||||
(
|
||||
"core.change_word_forward",
|
||||
Action::ChangeWordForward,
|
||||
&[Mode::Normal]
|
||||
),
|
||||
(
|
||||
"core.change_word_backward",
|
||||
Action::ChangeWordBackward,
|
||||
&[Mode::Normal]
|
||||
),
|
||||
("core.paste_before", Action::PasteBefore, &[Mode::Normal]),
|
||||
("core.paste_after", Action::PasteAfter, &[Mode::Normal]),
|
||||
(
|
||||
@@ -953,6 +963,8 @@ impl Action {
|
||||
| Self::SubstituteCharacter
|
||||
| Self::DeleteWordForward
|
||||
| Self::DeleteWordBackward
|
||||
| Self::ChangeWordForward
|
||||
| Self::ChangeWordBackward
|
||||
| Self::Cut
|
||||
| Self::Change
|
||||
| Self::PasteBefore
|
||||
@@ -6106,6 +6118,8 @@ impl Editor {
|
||||
}),
|
||||
Input::Char('w') if operator == 'd' => Some(Action::DeleteWordForward),
|
||||
Input::Char('b') if operator == 'd' => Some(Action::DeleteWordBackward),
|
||||
Input::Char('w') if operator == 'c' => Some(Action::ChangeWordForward),
|
||||
Input::Char('b') if operator == 'c' => Some(Action::ChangeWordBackward),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(action) = action {
|
||||
@@ -6425,7 +6439,9 @@ impl Editor {
|
||||
| Action::CopyToLineEnd
|
||||
| Action::SubstituteCharacter
|
||||
| Action::DeleteWordForward
|
||||
| Action::DeleteWordBackward => self.edit_normal(action, count),
|
||||
| Action::DeleteWordBackward
|
||||
| Action::ChangeWordForward
|
||||
| Action::ChangeWordBackward => self.edit_normal(action, count),
|
||||
Action::LspCompletion => {
|
||||
if self.active.view.mode == Mode::Insert {
|
||||
return Some(Invocation {
|
||||
@@ -8220,8 +8236,11 @@ impl Editor {
|
||||
.map(|(index, target)| {
|
||||
let cursor = target.active;
|
||||
let end = match action {
|
||||
Action::DeleteWordForward | Action::DeleteWordBackward => {
|
||||
self.word_destination(cursor, action, count)
|
||||
Action::DeleteWordForward | Action::ChangeWordForward => {
|
||||
self.word_destination(cursor, Action::DeleteWordForward, count)
|
||||
}
|
||||
Action::DeleteWordBackward | Action::ChangeWordBackward => {
|
||||
self.word_destination(cursor, Action::DeleteWordBackward, count)
|
||||
}
|
||||
Action::SubstituteCharacter => Cursor {
|
||||
row: cursor.row,
|
||||
@@ -8277,7 +8296,10 @@ impl Editor {
|
||||
let start = EditStart::Normal { action, count };
|
||||
if matches!(
|
||||
action,
|
||||
Action::ChangeToLineEnd | Action::SubstituteCharacter
|
||||
Action::ChangeToLineEnd
|
||||
| Action::SubstituteCharacter
|
||||
| Action::ChangeWordForward
|
||||
| Action::ChangeWordBackward
|
||||
) {
|
||||
self.start_insert(before, start);
|
||||
self.edit_ranges(Action::Change, &ranges);
|
||||
@@ -8940,7 +8962,10 @@ impl Editor {
|
||||
clipboard = Some((self.selection_fragments(&ranges), false));
|
||||
let change = matches!(
|
||||
action,
|
||||
Action::ChangeToLineEnd | Action::SubstituteCharacter
|
||||
Action::ChangeToLineEnd
|
||||
| Action::SubstituteCharacter
|
||||
| Action::ChangeWordForward
|
||||
| Action::ChangeWordBackward
|
||||
);
|
||||
self.edit_ranges(if change { Action::Change } else { Action::Cut }, &ranges);
|
||||
if !change {
|
||||
@@ -16024,7 +16049,9 @@ mod tests {
|
||||
let carets = editor.carets();
|
||||
let revision = editor.text_revision();
|
||||
fixture.fail("fail-write", true);
|
||||
for keys in ["yy", "2y3y", "2dd", "cc", "C", "D", "Y", "s", "d2w", "d2b"] {
|
||||
for keys in [
|
||||
"yy", "2y3y", "2dd", "cc", "C", "D", "Y", "s", "d2w", "d2b", "c2w", "c2b",
|
||||
] {
|
||||
type_text(&mut editor, keys);
|
||||
assert_eq!(editor.context().text, "Xone\ntwo\nthree");
|
||||
assert_eq!(editor.carets(), carets);
|
||||
@@ -19673,6 +19700,8 @@ mod tests {
|
||||
("4s", [(0, 0), (0, 2)], "!o three four\nkeep"),
|
||||
("d2w", [(0, 0), (0, 4)], "four\nkeep"),
|
||||
("d2b", [(0, 8), (0, 14)], "four\nkeep"),
|
||||
("c2w", [(0, 0), (0, 4)], "!four\nkeep"),
|
||||
("c2b", [(0, 8), (0, 14)], "!four\nkeep"),
|
||||
("4rX", [(0, 0), (0, 2)], "XXXXXXo three four\nkeep"),
|
||||
] {
|
||||
let mut editor = editor();
|
||||
@@ -19741,7 +19770,7 @@ mod tests {
|
||||
let targets = editor.active.view.targets.clone();
|
||||
let undo = editor.active.undo.len();
|
||||
let clipboard = editor.clipboard.clone();
|
||||
for keys in ["C", "D", "s", "2r", "d2w", "d2b"] {
|
||||
for keys in ["C", "D", "s", "2r", "d2w", "d2b", "c2w", "c2b"] {
|
||||
type_text(&mut editor, keys);
|
||||
assert_eq!(editor.context().text, text, "{keys}");
|
||||
assert_eq!(editor.active.view.targets, targets, "{keys}");
|
||||
|
||||
@@ -30,6 +30,8 @@ Normal: i/a insert, I/A insert at first nonblank/end, o/O new line
|
||||
Normal/Visual: prefix motions with counts (5j, 2w, 3n); Esc cancels count
|
||||
u undo, U redo, : command, / search, n/N next/previous match
|
||||
yy copies whole lines; dd deletes them; cc changes them and enters Insert; counts: 3yy, 2dd, 2cc
|
||||
dw/db cut forward/backward words on the current line; cw/cb cut the same spans and enter Insert
|
||||
Word counts before/after the operator multiply: d2w, 2cw, 2c3b; newlines are preserved
|
||||
Linewise p/P paste below/above the current row; characterwise p/P paste after/before the grapheme
|
||||
Normal/Visual: . repeats last native edit at current targets (one undo group)
|
||||
v characterwise select, V linewise select, p/P paste fragments, Ctrl+k/Ctrl+e clone above/below
|
||||
|
||||
Reference in New Issue
Block a user