Transcript

Do you want to know more about how to use macros in Vim? In this talk, learn tips and tricks for mastering macros in Vim with an example project.

This talk was presented by Camilo Payan at VimConf 2021 on October 29, 2021.

00:00
(techno music)
00:04
- Hi, my name is Camilo Payan
00:07
and thank you for coming to this talk,
00:08
Mastering the Macro-Machine.
00:10
You can find me online at cam.bio,
00:12
and let's go right into it.
00:14
I work for a company called Test Double,
00:16
where we work to make software better,
00:17
and as an aside, we're hiring,
00:21
but as part of my work as a consultant at Test Double,
00:23
I maintain a library that we have, called Standard RB,
00:27
which helps Ruby developers get started
00:28
with a baseline for the popular Ruby linting tool, RuboCop.
00:32
So for this talk, I went ahead
00:33
and made myself some silly little tasks.
00:35
We're gonna disable every cup, and we're going
00:37
to create a table of contents for the readme file,
00:40
and I wanna do this all in Vim
00:42
with the power of movements and macros.
00:45
So what do I mean by movements?
00:47
Movements are the building blocks of text editing in Vim.
00:50
There are commands in normal mode
00:52
that will move you somewhere else.
00:53
The most basic, which you probably already know,
00:55
are H, J, K and L, and what's really great is
00:58
you can combine those movements by prefixing them
01:00
with a number to have it more than once.
01:03
So let's go ahead and demo that
01:05
by opening up our base config file,
01:07
and, you know, J goes down, K goes up.
01:09
If we go over here, L goes
01:11
to the right, and H goes to the left.
01:13
Now, if we do 5J, it takes us down five lines,
01:18
and what do we mean by macros?
01:20
So a macro is, basically, a recording of the keystroke.
01:24
So you start one by using Q and the letter
01:28
that you wanna name your macro.
01:29
You can also use numbers,
01:30
but I recommend you use letters for a reason
01:33
that'll become more obvious later,
01:35
then you do all your keystrokes, and Vim is recording them,
01:39
and then you can finish your recording with Q,
01:42
then you can repeat your with at
01:44
and the letter that you gave your macro.
01:49
So let's get to work on disabling every cup in this file,
01:54
and if we take a look at the config,
01:57
all these cups are enabled or disabled using this kind
01:59
of line here where it says enabled true or enabled false.
02:02
So let's start our macro.
02:04
I wanna call it A and, first thing's first,
02:09
we're going to search for the word enabled,
02:12
then we're gonna hit L a bunch of times
02:13
to get to where we wanna be, and then we'll change the rest.
02:17
We'll just put an F for now,
02:19
and then once we're back in normal mode,
02:21
we hit Q to finish recording.
02:24
So now, if I go down to line 17,
02:26
and I run @A, it runs it again.
02:29
So this is the general idea of macros.
02:32
I don't have to redo all of the keystrokes
02:35
by hand over and over again.
02:36
Saves to you a bunch of time.
02:38
Now, F is for respect, but we actually want
02:41
the whole word false, and we're gonna do that
02:43
by appending to the end of the macro.
02:45
So I made my macro QA.
02:49
So I'm going ahead and, at the same spot
02:51
where my macro ends, use Q, capital A,
02:54
and you can see, it now says "recording @A,"
02:57
and let's append to the end of the line
03:01
and finish recording our macro with Q
03:04
and now, even if I change this
03:05
to something really cool, it works.
03:10
I didn't have to re-record my macro
03:11
from scratch, and the reason that
03:12
that works is because of Vim's registers.
03:16
So your macros are stored, just
03:19
like everything else in Vim's registers.
03:21
So if you run the registers command,
03:22
you can take a look at them.
03:23
There's a bunch of them around here.
03:25
They are named after letters and numbers
03:27
and there are some special names too
03:29
but in this case, we chose the name A, for our macro,
03:32
and you can see here, these are all the keystrokes
03:34
that I was doing to make the macro work,
03:38
even the part that we appended
03:39
to the end of the macro is still there.
03:43
Now, the cool part about this is
03:44
because we know where this is,
03:47
we can start manipulating our macro by taking it out
03:53
of the register, and we can change it
03:57
and in this way, we can go ahead and improve our macro
03:59
by using some more interesting movements than HJKL.
04:04
So, you know, one kind
04:06
of low-hanging fruit here is all these Ls.
04:09
We wanna replace those with something
04:11
a little more elegant, a little smaller.
04:14
So let me go ahead and introduce you to these movements.
04:17
W takes you to the beginning of the next word.
04:19
So to the slash, to the capital G,
04:21
and to the colon on this line.
04:24
E actually goes to the end of the word
04:26
that you are currently on.
04:27
So instead of going to the slash, you're gonna go to the R.
04:30
Slash is considered a word and for the next one,
04:33
it's gonna go to this T, instead of going to the G.
04:36
So that's a useful thing, especially if you need
04:38
to append to the end of the word.
04:40
B goes backward a word.
04:42
So it's kind of the opposite of W,
04:45
and I really like using these a lot, in my day-to-day.
04:49
F forward-searches on a letter.
04:52
So if I do F to the colon, that goes to the end.
04:55
Let's do FE, and then you can use a semicolon
04:58
to keep searching forward for the next E that happens
05:01
and similarly, there's a reverse version
05:02
with the capital F, capital FE, and you can use colon
05:06
and go backward to wherever the next E is.
05:10
So I'm looking at this line.
05:12
I'm thinking we go ahead and use F;
05:14
to get to the colon and use W to get
05:16
to the beginning of the next word,
05:17
and that should do great, and it's actually a pattern
05:20
that you can use a lot in YAML files like this.
05:23
So let's change all these Ls and hit F;W.
05:31
Now, we can yank all of this into our A-register,
05:37
and I can show you, right?
05:39
Those Ls are gone.
05:40
F;W, that's what we've got now,
05:44
and let's go ahead and change this to some really cool name
05:47
that I just made up and run it again,
05:50
and we get exactly what we were expecting
05:53
'cause, you know, nothing actually changed,
05:54
but we did make this macro a little smaller,
05:56
a little more easy to read, if we need
05:57
to keep changing it, which we are going to.
06:00
So one handy tip is to go ahead and prefix your macros.
06:03
This helps a lot with consistency.
06:05
So sometimes your macro, especially if you're working
06:07
with a less structured document like this,
06:09
like code or a text document, you don't know exactly
06:12
where your macros going to end up.
06:14
So it would be who of you to make sure
06:16
your macro always starts in the same kind of spot.
06:19
So these movements will help you a lot with that.
06:21
You can use zero to get to the zeroth character,
06:24
which will always be the very first character
06:26
on the line, or you can use caret to get
06:28
to the first non-white-space character on the line.
06:31
Those are both pretty useful for this.
06:32
I'm going to go ahead and use zero,
06:36
and let's yank that back into our register.
06:40
Make sure it's there.
06:41
All right, there's a zero that we wanted
06:44
and now, even if I'm at the end of the line,
06:50
I run my macro with @A, and because it goes back
06:53
to the beginning of the line, and make sure
06:54
to change it right there, instead of, you know,
06:56
maybe going to the line like the search would've.
06:59
Another thing you can do is suffix your macros.
07:02
So you wanna suffix your macro in order
07:04
to set up the next one of the macro,
07:06
and then you can repeat it like we did with 5J
07:09
and really unlock the repetition of your macro.
07:14
Now, these are different movements that you could be using.
07:17
So Plus takes you to the beginning of the next line.
07:21
So here it goes to the dash.
07:22
Over there, went to the capital E,
07:25
and it's basically the same as using J
07:27
and then the caret key, but, you know, it's only one key.
07:29
So that's nice.
07:31
Another thing that you could use
07:32
for suffixing is N, which takes you
07:35
to the next instance of your search,
07:36
and that could be useful here because, actually,
07:38
we are search for the word enabled,
07:41
and another thing that you could do is use star,
07:44
which takes you to the next instance
07:45
of the word under your cursor, which is really useful,
07:48
depending on what you're doing,
07:49
but it's worth remembering that it does replace your search.
07:53
So now, if you hit N, it's gonna be looking
07:55
for bundler and not enabled.
07:58
For the purposes of this macro,
08:00
I'm gonna go ahead and add a plus.
08:02
Let's go ahead and yank it back into our A-register,
08:05
which we won't actually be able to see that
08:08
and now, I can go ahead, and let's go
08:11
to number 10, hit @A, and it works,
08:15
and it takes us to the next line,
08:16
which means I could do something like 20@A,
08:19
and it's just gonna keep running without having any problem.
08:23
This is a long file.
08:24
So we could let it run for quite a while,
08:25
but since we suffixed it with something
08:27
that sets up the next run, we can take advantage
08:29
of this and look how little typing I'm doing,
08:33
but a lot of work got done.
08:36
All right, so the next task that I gave myself was creating
08:39
a table of contents for reading use.
08:41
So when a reading file gets pretty long
08:43
for an open source project like this,
08:45
I really like for there to be some kind
08:48
of table of contents.
08:49
That way I can go straight to information
08:50
that I want without having to, like, kind
08:52
of read through the whole file
08:54
and since this is a Markdown file, we can kind of guess
08:57
that every heading is gonna start with a hash.
09:00
There's actually a Ruby comment here,
09:02
but it looks like we're starting with two hashes anyway.
09:06
So that's how we're gonna get our information,
09:09
and I want to create this table
09:10
of contents using marks and jumps.
09:16
So here we are starting at the top.
09:17
I think after the intro would be a good place
09:19
for the table of contents,
09:24
and what is a mark?
09:25
So a mark is a way that Vim keeps track
09:28
of a spot that you tell it
09:32
and in this case, we're gonna do
09:33
that with the command M and Z
09:36
to set a mark called Z right here on line 38.
09:38
Now, no matter where I am, I can use the jump command,
09:41
which is a single quote and in this case,
09:43
a Z to go back to the same spot.
09:45
As a matter of fact, at the beginning
09:46
of the document or at the end, I can always go back
09:48
to the same spot as long as I remember the name.
09:52
So let's get to work on our macro.
09:55
We're gonna go ahead and record it in A again,
09:58
and we'll prefix it with a zero.
09:59
Start with searching forward for the next heading.
10:04
Let's go forward a word and into our S-register.
10:08
I'm gonna go ahead and yank all of this.
10:11
Now, let's go to the next line,
10:12
and I want to start thinking ahead
10:14
and set up the next run of this
10:15
by creating a mark right here.
10:17
We're gonna call it X.
10:19
Now, let's jump back to where we want our table of contents.
10:23
That's not great. We'll get rid of that in a second.
10:29
Go to INSERT
10:33
and put in our stuff.
10:35
Gonna make a markdown link.
10:37
I give it anchor.
10:39
I'm really not sure if GitHub will accept just
10:42
the text like that, but, you know,
10:44
we can figure that out some other time.
10:48
Now, I wanna create a new mark here.
10:51
That's gonna be our new Z mark,
10:53
and let's go back to our X mark, and that's it.
10:57
That's our macro.
10:59
Now, I already remember that there was actually
11:04
a problem in my macro.
11:08
I'm not really sure where that was,
11:09
but let's see if it works.
11:12
Now, the next heading, I think, is usage.
11:16
So let's see if that works. Yeah.
11:18
See, I have an error in the middle of my macro.
11:21
So this is when I started putting this stuff together.
11:27
This looks good. This is.
11:33
All of that must go.
11:43
Cool. Now, we have a macro that works.
11:50
Now, if you run it again, we should get usage.
11:53
Let's take a look for our table of contents.
11:55
Yeah, we have usage going up here
11:58
and now, if you run it, you know, like five more times,
12:00
that's gonna be fun to watch, 10 more times.
12:03
I don't actually know how many headers there are here.
12:05
Let's try another five. I think that takes us.
12:08
Let's do another one and now, we have a problem.
12:10
We went to the beginning of the document again.
12:13
So let's take a look at a table of contents.
12:16
We have everything that we expect
12:17
but now, we have the title.
12:19
We don't want that. How can we solve this?
12:21
We can do it using a recursive macro, and let's go ahead
12:27
and get rid of the table of contents that we've created.
12:30
Make a new mark.
12:31
Now, recursive macros will we'll go ahead
12:33
and run the macro inside your macro.
12:34
So then it just keeps running,
12:36
but in this case, since we're relying on a search,
12:39
Vim we'll go ahead and wrap to the beginning
12:40
of the document if you are still searching at that point,
12:44
and you're at the end of the document,
12:45
but we wanna get rid of that because a recursive macro
12:47
won't stop unless there's an error,
12:49
which is actually why I had to fix that out of the macro
12:51
'cause it was gonna stop in the middle of it.
12:53
So how are we gonna get it to error out?
12:55
We're gonna use this setting, nowrapscan.
12:58
So if you hit nowrapscan, what happens is,
13:02
even if you're at the end
13:03
of the document and you keep searching.
13:05
So we wanna search for table of contents.
13:07
It's not gonna keep going past the end of the document.
13:11
So that will be useful in this case
13:14
because now, if I finish my macro
13:17
by hitting @A and yank that back into my register
13:25
and let it run, it's just gonna run itself over
13:29
and over, but when it gets to the end
13:30
of the document, it's going to stop.
13:32
So code of conduct is the last one that we were looking at.
13:35
Let's take a look at table of contents.
13:36
Yeah, it goes all the way from the rules to code of conduct.
13:39
Looks great. Mission accomplished.
13:44
Now, one more thing that we could take a look
13:45
at is this setting here, lazyredraw.
13:48
It's really fun, and it's cool for demos
13:49
to watch your macro run but with lazyredraw,
13:54
you can skip all of that and, you know,
13:57
not just sit here and watching your computer work.
13:59
It's going to wait until all of the commands are finished,
14:03
and then that's when it's going
14:06
to actually redraw your file.
14:12
So there we go.
14:16
It can be useful, but I kind of like watching macros.
14:20
Anyways, thank you so much for coming to this talk.
14:22
I hope you enjoy the rest of the conference.
14:24
You can find me online at cam.bio.
14:26
I'm Cam on the discord and also a reminder,
14:30
Test Double is hiring and, you know, if you'd like
14:33
to come work, just go ahead and ask any questions
14:35
that you have, and there's also of information at that link.
14:39
All right, let me see where my thingy is.
14:44
(hands clapping)
14:45
Cool.
14:48
That's it. Thank you so much, everybody.
14:55
(Camilo laughs)
15:16
I guess I can stop screen-sharing
15:17
Mic's all the way down.
15:18
Yeah, I turned the mic down.
15:19
I see that. - Okay.
15:20
Yeah, we've been talking for 30 seconds now.
15:22
Yep, they can bang, scuffed in the chat.
15:24
Bang, scuffed, great streamer here.
15:26
(laughs) That talk was awesome.
15:29
Super cool, really Vimy. I love it.
15:31
Chat? Does anyone have any questions
15:33
they'd like to give to Camilo quick?
15:39
I mean, I, personally,
15:40
have something I would like to say which is,
15:44
I mean, you were doing a lot of macros there,
15:46
yet I didn't see any macro pressure.
15:48
You seem to be breezing.
15:50
How does one master macro so well
15:52
that you don't feel macro pressure?
15:54
- Yeah. (Camilo laughs)
15:55
How do you move from just being a normy macro user.
15:57
Yeah, I'm a normy.
15:58
To sort of this no pressure,
16:00
never cracks under pressure macro master?
16:03
Macroception, macro master?
16:04
- Oh, my God. (laughs)
16:08
For these macros, practicing, maybe,
16:10
like 30, 40 times before this talk,
16:12
but, generally, you know, the more you use 'em,
16:14
the more you'll end up with like patterns that you go back
16:16
to a bunch of times, you know, like prefixing, suffixing,
16:19
all that stuff is gonna end up coming naturally
16:21
as long as you're intentional about doing it
16:25
and then yeah, repetition just like learning Vim.
16:28
As long as you keep repeating it,
16:31
you'll end up figuring it out.
16:34
- Okay, I mean, I'm shocked. (Camilo laughs)
16:37
Okay, I tried that.
16:39
I thought I tried that, but it-
16:41
I thought a good question was asked
16:42
in the chat about running macros over multiple files.
16:46
Do you have any tricks for that?
16:48
- Oh yeah.
16:49
So actually, one thing that you can do
16:51
that I find makes that easier is creating a function,
16:53
and then you can kind of slam your macro
16:55
into that by using the normal command,
16:57
and then you can use something like.
17:00
I find it easier to go ahead and do that
17:02
with, you know things like the arg list,
17:04
and I forget what the other list is called
17:07
to have like a function that you call,
17:09
but I do remember doing it with just macros in the past.
17:12
I just don't remember (laughs) how I did it.
17:15
Yeah that seems like magic to me.
17:17
I don't know about any of that.
17:19
Yeah, I guess the only other way I could think
17:21
of would be if you tried to do something like, maybe,
17:24
run it over your quick-fix list or something like that.
17:27
If you added all of them to the quick-fix list.
17:30
- What's that for? - You could try
17:30
and run something with like cdo or something like that.
17:32
- Yeah. I've see done. - I always laugh
17:34
when I say cdo 'cause I imagine myself riding
17:36
around on a Sea-Doo in the water using Vim,
17:39
and it's just kind of a hilarious mental picture for myself.
17:42
I like cdo because sea stands for quick,
17:45
and it makes me really happy.
17:47
(Moderator 1 laughs)
17:48
- I'm pretty sure that you could do something
17:50
like cdo and normal and then whatever
17:54
your macro is here. - Yeah, I think so.
17:55
- Which you probably get out of the register
17:57
by doing something like Control A.
18:00
Yeah, there's a macro. (laughs)
18:02
Cool. Awesome.
18:03
Well, thanks a bunch, Camilo and-
18:05
We do have one more question.
18:06
- Oh, okay. - It's a good question.
18:07
How do you edit an existing macro?
18:10
- Yeah, so it's kind of hard to demo.
18:13
So I kind of glossed over it,
18:14
but the idea is you just want to kind of put it somewhere.
18:18
So I have a little scratch buffer here,
18:20
and then you can do whatever edits that you want to it,
18:23
then the next step is to yank it back
18:26
into the register that you had it in in the first place,
18:28
and so that would be the same way
18:31
that you yank anything else.
18:32
You use a double quote and the register that you want
18:34
and then why and however you wanna do that.
18:37
Just make sure you don't use, you know,
18:39
YY to get the whole line because
18:41
you'll end up with a carriage return at the end
18:42
of your macro, and that will definitely mess up the macro.
18:46
So you wanna use Y, usually,
18:47
to dollar sign the end of the line.
18:49
So what you're trying to tell me is
18:51
that when you yank into a register,
18:54
it's the same thing as recording a macro to a register.
18:57
That's where the macros go?
18:58
- Yeah, yeah.
18:59
So once you look at your register,
19:01
these are the key strokes that you did,
19:03
and so it just runs 'em over and over again,
19:05
then it's cool.

Camilo Payan

Person An icon of a human figure Status
Double Agent
Hash An icon of a hash sign Code Name
Agent 0081
Location An icon of a map marker Location
South Florida