vim: Support for q and @ (#13761)
Fixes: #1504 Release Notes: - vim: Support for macros (`q` and `@`) to record and replay (#1506, #4448)
This commit is contained in:
parent
dceb0827e8
commit
3348c3ab4c
13 changed files with 491 additions and 316 deletions
|
@ -31,7 +31,11 @@ use gpui::{
|
|||
use language::{CursorShape, Point, SelectionGoal, TransactionId};
|
||||
pub use mode_indicator::ModeIndicator;
|
||||
use motion::Motion;
|
||||
use normal::{mark::create_visual_marks, normal_replace};
|
||||
use normal::{
|
||||
mark::create_visual_marks,
|
||||
normal_replace,
|
||||
repeat::{observe_action, observe_insertion, record_register, replay_register},
|
||||
};
|
||||
use replace::multi_replace;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
@ -170,18 +174,7 @@ fn observe_keystrokes(keystroke_event: &KeystrokeEvent, cx: &mut WindowContext)
|
|||
.as_ref()
|
||||
.map(|action| action.boxed_clone())
|
||||
{
|
||||
Vim::update(cx, |vim, _| {
|
||||
if vim.workspace_state.recording {
|
||||
vim.workspace_state
|
||||
.recorded_actions
|
||||
.push(ReplayableAction::Action(action.boxed_clone()));
|
||||
|
||||
if vim.workspace_state.stop_recording_after_next_action {
|
||||
vim.workspace_state.recording = false;
|
||||
vim.workspace_state.stop_recording_after_next_action = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
observe_action(action.boxed_clone(), cx);
|
||||
|
||||
// Keystroke is handled by the vim system, so continue forward
|
||||
if action.name().starts_with("vim::") {
|
||||
|
@ -201,7 +194,9 @@ fn observe_keystrokes(keystroke_event: &KeystrokeEvent, cx: &mut WindowContext)
|
|||
| Operator::DeleteSurrounds
|
||||
| Operator::Mark
|
||||
| Operator::Jump { .. }
|
||||
| Operator::Register,
|
||||
| Operator::Register
|
||||
| Operator::RecordRegister
|
||||
| Operator::ReplayRegister,
|
||||
) => {}
|
||||
Some(_) => {
|
||||
vim.clear_operator(cx);
|
||||
|
@ -254,12 +249,12 @@ impl Vim {
|
|||
}
|
||||
EditorEvent::InputIgnored { text } => {
|
||||
Vim::active_editor_input_ignored(text.clone(), cx);
|
||||
Vim::record_insertion(text, None, cx)
|
||||
observe_insertion(text, None, cx)
|
||||
}
|
||||
EditorEvent::InputHandled {
|
||||
text,
|
||||
utf16_range_to_replace: range_to_replace,
|
||||
} => Vim::record_insertion(text, range_to_replace.clone(), cx),
|
||||
} => observe_insertion(text, range_to_replace.clone(), cx),
|
||||
EditorEvent::TransactionBegun { transaction_id } => Vim::update(cx, |vim, cx| {
|
||||
vim.transaction_begun(*transaction_id, cx);
|
||||
}),
|
||||
|
@ -288,27 +283,6 @@ impl Vim {
|
|||
self.sync_vim_settings(cx);
|
||||
}
|
||||
|
||||
fn record_insertion(
|
||||
text: &Arc<str>,
|
||||
range_to_replace: Option<Range<isize>>,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
Vim::update(cx, |vim, _| {
|
||||
if vim.workspace_state.recording {
|
||||
vim.workspace_state
|
||||
.recorded_actions
|
||||
.push(ReplayableAction::Insertion {
|
||||
text: text.clone(),
|
||||
utf16_range_to_replace: range_to_replace,
|
||||
});
|
||||
if vim.workspace_state.stop_recording_after_next_action {
|
||||
vim.workspace_state.recording = false;
|
||||
vim.workspace_state.stop_recording_after_next_action = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn update_active_editor<S>(
|
||||
&mut self,
|
||||
cx: &mut WindowContext,
|
||||
|
@ -333,8 +307,8 @@ impl Vim {
|
|||
/// When doing an action that modifies the buffer, we start recording so that `.`
|
||||
/// will replay the action.
|
||||
pub fn start_recording(&mut self, cx: &mut WindowContext) {
|
||||
if !self.workspace_state.replaying {
|
||||
self.workspace_state.recording = true;
|
||||
if !self.workspace_state.dot_replaying {
|
||||
self.workspace_state.dot_recording = true;
|
||||
self.workspace_state.recorded_actions = Default::default();
|
||||
self.workspace_state.recorded_count = None;
|
||||
|
||||
|
@ -376,15 +350,18 @@ impl Vim {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn stop_replaying(&mut self) {
|
||||
self.workspace_state.replaying = false;
|
||||
pub fn stop_replaying(&mut self, _: &mut WindowContext) {
|
||||
self.workspace_state.dot_replaying = false;
|
||||
if let Some(replayer) = self.workspace_state.replayer.take() {
|
||||
replayer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/// When finishing an action that modifies the buffer, stop recording.
|
||||
/// as you usually call this within a keystroke handler we also ensure that
|
||||
/// the current action is recorded.
|
||||
pub fn stop_recording(&mut self) {
|
||||
if self.workspace_state.recording {
|
||||
if self.workspace_state.dot_recording {
|
||||
self.workspace_state.stop_recording_after_next_action = true;
|
||||
}
|
||||
}
|
||||
|
@ -394,11 +371,11 @@ impl Vim {
|
|||
///
|
||||
/// This doesn't include the current action.
|
||||
pub fn stop_recording_immediately(&mut self, action: Box<dyn Action>) {
|
||||
if self.workspace_state.recording {
|
||||
if self.workspace_state.dot_recording {
|
||||
self.workspace_state
|
||||
.recorded_actions
|
||||
.push(ReplayableAction::Action(action.boxed_clone()));
|
||||
self.workspace_state.recording = false;
|
||||
self.workspace_state.dot_recording = false;
|
||||
self.workspace_state.stop_recording_after_next_action = false;
|
||||
}
|
||||
}
|
||||
|
@ -511,7 +488,7 @@ impl Vim {
|
|||
}
|
||||
|
||||
fn take_count(&mut self, cx: &mut WindowContext) -> Option<usize> {
|
||||
if self.workspace_state.replaying {
|
||||
if self.workspace_state.dot_replaying {
|
||||
return self.workspace_state.recorded_count;
|
||||
}
|
||||
|
||||
|
@ -522,7 +499,7 @@ impl Vim {
|
|||
state.post_count.take().unwrap_or(1) * state.pre_count.take().unwrap_or(1)
|
||||
}))
|
||||
};
|
||||
if self.workspace_state.recording {
|
||||
if self.workspace_state.dot_recording {
|
||||
self.workspace_state.recorded_count = count;
|
||||
}
|
||||
self.sync_vim_settings(cx);
|
||||
|
@ -898,6 +875,8 @@ impl Vim {
|
|||
Some(Operator::Mark) => Vim::update(cx, |vim, cx| {
|
||||
normal::mark::create_mark(vim, text, false, cx)
|
||||
}),
|
||||
Some(Operator::RecordRegister) => record_register(text.chars().next().unwrap(), cx),
|
||||
Some(Operator::ReplayRegister) => replay_register(text.chars().next().unwrap(), cx),
|
||||
Some(Operator::Register) => Vim::update(cx, |vim, cx| match vim.state().mode {
|
||||
Mode::Insert => {
|
||||
vim.update_active_editor(cx, |vim, editor, cx| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue