vim: Replace with Register (#24326)
Closes #18813 Release Notes: - vim: Add `gr` for [replace with register](https://github.com/vim-scripts/ReplaceWithRegister)
This commit is contained in:
parent
d83c316e6d
commit
8646d37c0c
5 changed files with 120 additions and 1 deletions
|
@ -102,6 +102,7 @@
|
||||||
"ctrl-e": "vim::LineDown",
|
"ctrl-e": "vim::LineDown",
|
||||||
"ctrl-y": "vim::LineUp",
|
"ctrl-y": "vim::LineUp",
|
||||||
// "g" commands
|
// "g" commands
|
||||||
|
"g r": ["vim::PushOperator", "ReplaceWithRegister"],
|
||||||
"g g": "vim::StartOfDocument",
|
"g g": "vim::StartOfDocument",
|
||||||
"g h": "editor::Hover",
|
"g h": "editor::Hover",
|
||||||
"g t": "pane::ActivateNextItem",
|
"g t": "pane::ActivateNextItem",
|
||||||
|
|
|
@ -182,6 +182,9 @@ impl Vim {
|
||||||
Some(Operator::ToggleComments) => {
|
Some(Operator::ToggleComments) => {
|
||||||
self.toggle_comments_motion(motion, times, window, cx)
|
self.toggle_comments_motion(motion, times, window, cx)
|
||||||
}
|
}
|
||||||
|
Some(Operator::ReplaceWithRegister) => {
|
||||||
|
self.replace_with_register_motion(motion, times, window, cx)
|
||||||
|
}
|
||||||
Some(operator) => {
|
Some(operator) => {
|
||||||
// Can't do anything for text objects, Ignoring
|
// Can't do anything for text objects, Ignoring
|
||||||
error!("Unexpected normal mode motion operator: {:?}", operator)
|
error!("Unexpected normal mode motion operator: {:?}", operator)
|
||||||
|
@ -228,6 +231,9 @@ impl Vim {
|
||||||
Some(Operator::ToggleComments) => {
|
Some(Operator::ToggleComments) => {
|
||||||
self.toggle_comments_object(object, around, window, cx)
|
self.toggle_comments_object(object, around, window, cx)
|
||||||
}
|
}
|
||||||
|
Some(Operator::ReplaceWithRegister) => {
|
||||||
|
self.replace_with_register_object(object, around, window, cx)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Can't do anything for namespace operators. Ignoring
|
// Can't do anything for namespace operators. Ignoring
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ use serde::Deserialize;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
motion::Motion,
|
||||||
|
object::Object,
|
||||||
state::{Mode, Register},
|
state::{Mode, Register},
|
||||||
Vim,
|
Vim,
|
||||||
};
|
};
|
||||||
|
@ -192,12 +194,85 @@ impl Vim {
|
||||||
});
|
});
|
||||||
self.switch_mode(Mode::Normal, true, window, cx);
|
self.switch_mode(Mode::Normal, true, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn replace_with_register_object(
|
||||||
|
&mut self,
|
||||||
|
object: Object,
|
||||||
|
around: bool,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
self.stop_recording(cx);
|
||||||
|
let selected_register = self.selected_register.take();
|
||||||
|
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||||
|
editor.transact(window, cx, |editor, window, cx| {
|
||||||
|
editor.set_clip_at_line_ends(false, cx);
|
||||||
|
editor.change_selections(None, window, cx, |s| {
|
||||||
|
s.move_with(|map, selection| {
|
||||||
|
object.expand_selection(map, selection, around);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let Some(Register { text, .. }) = Vim::update_globals(cx, |globals, cx| {
|
||||||
|
globals.read_register(selected_register, Some(editor), cx)
|
||||||
|
})
|
||||||
|
.filter(|reg| !reg.text.is_empty()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
editor.insert(&text, window, cx);
|
||||||
|
editor.set_clip_at_line_ends(true, cx);
|
||||||
|
editor.change_selections(None, window, cx, |s| {
|
||||||
|
s.move_with(|map, selection| {
|
||||||
|
selection.start = map.clip_point(selection.start, Bias::Left);
|
||||||
|
selection.end = selection.start
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_with_register_motion(
|
||||||
|
&mut self,
|
||||||
|
motion: Motion,
|
||||||
|
times: Option<usize>,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
self.stop_recording(cx);
|
||||||
|
let selected_register = self.selected_register.take();
|
||||||
|
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||||
|
let text_layout_details = editor.text_layout_details(window);
|
||||||
|
editor.transact(window, cx, |editor, window, cx| {
|
||||||
|
editor.set_clip_at_line_ends(false, cx);
|
||||||
|
editor.change_selections(None, window, cx, |s| {
|
||||||
|
s.move_with(|map, selection| {
|
||||||
|
motion.expand_selection(map, selection, times, false, &text_layout_details);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let Some(Register { text, .. }) = Vim::update_globals(cx, |globals, cx| {
|
||||||
|
globals.read_register(selected_register, Some(editor), cx)
|
||||||
|
})
|
||||||
|
.filter(|reg| !reg.text.is_empty()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
editor.insert(&text, window, cx);
|
||||||
|
editor.set_clip_at_line_ends(true, cx);
|
||||||
|
editor.change_selections(None, window, cx, |s| {
|
||||||
|
s.move_with(|map, selection| {
|
||||||
|
selection.start = map.clip_point(selection.start, Bias::Left);
|
||||||
|
selection.end = selection.start
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
state::Mode,
|
state::{Mode, Register},
|
||||||
test::{NeovimBackedTestContext, VimTestContext},
|
test::{NeovimBackedTestContext, VimTestContext},
|
||||||
UseSystemClipboard, VimSettings,
|
UseSystemClipboard, VimSettings,
|
||||||
};
|
};
|
||||||
|
@ -742,4 +817,37 @@ mod test {
|
||||||
Mode::Normal,
|
Mode::Normal,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_replace_with_register(cx: &mut gpui::TestAppContext) {
|
||||||
|
let mut cx = VimTestContext::new(cx, true).await;
|
||||||
|
|
||||||
|
cx.set_state(
|
||||||
|
indoc! {"
|
||||||
|
ˇfish one
|
||||||
|
two three
|
||||||
|
"},
|
||||||
|
Mode::Normal,
|
||||||
|
);
|
||||||
|
cx.simulate_keystrokes("y i w");
|
||||||
|
cx.simulate_keystrokes("w");
|
||||||
|
cx.simulate_keystrokes("g r i w");
|
||||||
|
cx.assert_state(
|
||||||
|
indoc! {"
|
||||||
|
fish fisˇh
|
||||||
|
two three
|
||||||
|
"},
|
||||||
|
Mode::Normal,
|
||||||
|
);
|
||||||
|
cx.simulate_keystrokes("j b g r e");
|
||||||
|
cx.assert_state(
|
||||||
|
indoc! {"
|
||||||
|
fish fish
|
||||||
|
two fisˇh
|
||||||
|
"},
|
||||||
|
Mode::Normal,
|
||||||
|
);
|
||||||
|
let clipboard: Register = cx.read_from_clipboard().unwrap().into();
|
||||||
|
assert_eq!(clipboard.text, "fish");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ pub enum Operator {
|
||||||
RecordRegister,
|
RecordRegister,
|
||||||
ReplayRegister,
|
ReplayRegister,
|
||||||
ToggleComments,
|
ToggleComments,
|
||||||
|
ReplaceWithRegister,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Default, Clone, Debug)]
|
||||||
|
@ -499,6 +500,7 @@ impl Operator {
|
||||||
Operator::AutoIndent => "eq",
|
Operator::AutoIndent => "eq",
|
||||||
Operator::ShellCommand => "sh",
|
Operator::ShellCommand => "sh",
|
||||||
Operator::Rewrap => "gq",
|
Operator::Rewrap => "gq",
|
||||||
|
Operator::ReplaceWithRegister => "gr",
|
||||||
Operator::Outdent => "<",
|
Operator::Outdent => "<",
|
||||||
Operator::Uppercase => "gU",
|
Operator::Uppercase => "gU",
|
||||||
Operator::Lowercase => "gu",
|
Operator::Lowercase => "gu",
|
||||||
|
@ -551,6 +553,7 @@ impl Operator {
|
||||||
| Operator::ShellCommand
|
| Operator::ShellCommand
|
||||||
| Operator::Lowercase
|
| Operator::Lowercase
|
||||||
| Operator::Uppercase
|
| Operator::Uppercase
|
||||||
|
| Operator::ReplaceWithRegister
|
||||||
| Operator::Object { .. }
|
| Operator::Object { .. }
|
||||||
| Operator::ChangeSurrounds { target: None }
|
| Operator::ChangeSurrounds { target: None }
|
||||||
| Operator::OppositeCase
|
| Operator::OppositeCase
|
||||||
|
|
|
@ -159,6 +159,7 @@ Zed's vim mode includes some features that are usually provided by very popular
|
||||||
- You can comment and uncomment selections with `gc` in visual mode and `gcc` in normal mode.
|
- You can comment and uncomment selections with `gc` in visual mode and `gcc` in normal mode.
|
||||||
- The project panel supports many shortcuts modeled after the Vim plugin `netrw`: navigation with `hjkl`, open file with `o`, open file in a new tab with `t`, etc.
|
- The project panel supports many shortcuts modeled after the Vim plugin `netrw`: navigation with `hjkl`, open file with `o`, open file in a new tab with `t`, etc.
|
||||||
- You can add key bindings to your keymap to navigate "camelCase" names. [Head down to the Optional key bindings](#optional-key-bindings) section to learn how.
|
- You can add key bindings to your keymap to navigate "camelCase" names. [Head down to the Optional key bindings](#optional-key-bindings) section to learn how.
|
||||||
|
- You can use `gr` to do [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister).
|
||||||
|
|
||||||
## Command palette
|
## Command palette
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue