-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Macros #1234
Macros #1234
Changes from all commits
85ffa0a
6cd343f
b48269e
b8ffc54
1517311
d0a7eb6
36ccc0a
46ae406
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,7 +70,7 @@ pub struct Context<'a> { | |
impl<'a> Context<'a> { | ||
/// Push a new component onto the compositor. | ||
pub fn push_layer(&mut self, component: Box<dyn Component>) { | ||
self.callback = Some(Box::new(|compositor: &mut Compositor| { | ||
self.callback = Some(Box::new(|compositor: &mut Compositor, _| { | ||
compositor.push(component) | ||
})); | ||
} | ||
|
@@ -394,6 +394,8 @@ impl MappableCommand { | |
rename_symbol, "Rename symbol", | ||
increment, "Increment", | ||
decrement, "Decrement", | ||
record_macro, "Record macro", | ||
play_macro, "Play macro", | ||
); | ||
} | ||
|
||
|
@@ -3437,7 +3439,7 @@ fn apply_workspace_edit( | |
|
||
fn last_picker(cx: &mut Context) { | ||
// TODO: last picker does not seem to work well with buffer_picker | ||
cx.callback = Some(Box::new(|compositor: &mut Compositor| { | ||
cx.callback = Some(Box::new(|compositor: &mut Compositor, _| { | ||
if let Some(picker) = compositor.last_picker.take() { | ||
compositor.push(picker); | ||
} | ||
|
@@ -5860,3 +5862,56 @@ fn increment_impl(cx: &mut Context, amount: i64) { | |
doc.append_changes_to_history(view.id); | ||
} | ||
} | ||
|
||
fn record_macro(cx: &mut Context) { | ||
if let Some((reg, mut keys)) = cx.editor.macro_recording.take() { | ||
// Remove the keypress which ends the recording | ||
keys.pop(); | ||
let s = keys | ||
.into_iter() | ||
.map(|key| format!("{}", key)) | ||
.collect::<Vec<_>>() | ||
.join(" "); | ||
cx.editor.registers.get_mut(reg).write(vec![s]); | ||
cx.editor | ||
.set_status(format!("Recorded to register {}", reg)); | ||
} else { | ||
let reg = cx.register.take().unwrap_or('@'); | ||
cx.editor.macro_recording = Some((reg, Vec::new())); | ||
cx.editor | ||
.set_status(format!("Recording to register {}", reg)); | ||
} | ||
} | ||
|
||
fn play_macro(cx: &mut Context) { | ||
let reg = cx.register.unwrap_or('@'); | ||
let keys = match cx | ||
.editor | ||
.registers | ||
.get(reg) | ||
.and_then(|reg| reg.read().get(0)) | ||
Comment on lines
+5891
to
+5892
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can just use |
||
.context("Register empty") | ||
.and_then(|s| { | ||
s.split_whitespace() | ||
.map(str::parse::<KeyEvent>) | ||
.collect::<Result<Vec<_>, _>>() | ||
.context("Failed to parse macro") | ||
}) { | ||
Ok(keys) => keys, | ||
Err(e) => { | ||
cx.editor.set_error(format!("{}", e)); | ||
return; | ||
} | ||
}; | ||
let count = cx.count(); | ||
|
||
cx.callback = Some(Box::new( | ||
move |compositor: &mut Compositor, cx: &mut compositor::Context| { | ||
for _ in 0..count { | ||
for &key in keys.iter() { | ||
compositor.handle_event(crossterm::event::Event::Key(key.into()), cx); | ||
} | ||
} | ||
}, | ||
)); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -593,6 +593,9 @@ impl Default for Keymaps { | |
// paste_all | ||
"P" => paste_before, | ||
|
||
"q" => record_macro, | ||
"Q" => play_macro, | ||
Comment on lines
+596
to
+597
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be the reverse, Since it's a macro, it's expected to play more than record. And since play is expected to be used more frequently, it would be best use without extra shift. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, kakoune has this as well. I didn't realize it during review There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Vim, record is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (it's also "replay" instead of "play" but I didn't have strong opinions there) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, yeah sorry if I get stuff inconsistent with Kakoune, I've never used it and am not very familiar with it. Though in this situation, I do believe "play" makes very slightly more sense than "replay", since it is possible to play a macro without actually recording it, in which case playing it would not be a "replay". |
||
|
||
">" => indent, | ||
"<" => unindent, | ||
"=" => format_selections, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does our macro reuse the same register as the normal registers? IIRC vim macros have separate registers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We reuse the normal register since that means you can edit the macro as text (paste it in the buffer, edit, yank it back). I think vim also allowed for that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vim macros do not have separate registers.