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
|
@ -182,6 +182,9 @@ impl Vim {
|
|||
Some(Operator::ToggleComments) => {
|
||||
self.toggle_comments_motion(motion, times, window, cx)
|
||||
}
|
||||
Some(Operator::ReplaceWithRegister) => {
|
||||
self.replace_with_register_motion(motion, times, window, cx)
|
||||
}
|
||||
Some(operator) => {
|
||||
// Can't do anything for text objects, Ignoring
|
||||
error!("Unexpected normal mode motion operator: {:?}", operator)
|
||||
|
@ -228,6 +231,9 @@ impl Vim {
|
|||
Some(Operator::ToggleComments) => {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ use serde::Deserialize;
|
|||
use std::cmp;
|
||||
|
||||
use crate::{
|
||||
motion::Motion,
|
||||
object::Object,
|
||||
state::{Mode, Register},
|
||||
Vim,
|
||||
};
|
||||
|
@ -192,12 +194,85 @@ impl Vim {
|
|||
});
|
||||
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)]
|
||||
mod test {
|
||||
use crate::{
|
||||
state::Mode,
|
||||
state::{Mode, Register},
|
||||
test::{NeovimBackedTestContext, VimTestContext},
|
||||
UseSystemClipboard, VimSettings,
|
||||
};
|
||||
|
@ -742,4 +817,37 @@ mod test {
|
|||
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,
|
||||
ReplayRegister,
|
||||
ToggleComments,
|
||||
ReplaceWithRegister,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
|
@ -499,6 +500,7 @@ impl Operator {
|
|||
Operator::AutoIndent => "eq",
|
||||
Operator::ShellCommand => "sh",
|
||||
Operator::Rewrap => "gq",
|
||||
Operator::ReplaceWithRegister => "gr",
|
||||
Operator::Outdent => "<",
|
||||
Operator::Uppercase => "gU",
|
||||
Operator::Lowercase => "gu",
|
||||
|
@ -551,6 +553,7 @@ impl Operator {
|
|||
| Operator::ShellCommand
|
||||
| Operator::Lowercase
|
||||
| Operator::Uppercase
|
||||
| Operator::ReplaceWithRegister
|
||||
| Operator::Object { .. }
|
||||
| Operator::ChangeSurrounds { target: None }
|
||||
| Operator::OppositeCase
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue