5

I wanted to delete every 2 lines and then skip one, so I tried recording a macro. I did q1 then d2dj to delete 2 lines and go one down, then q and @1 to execute it. The first time it worked well. However the next time I type @1 weird stuff happens. I go down a lot of lines and get into insert mode, instead of doing the same.

Why does this happen? How should I have typed it?

1 Answer 1

10

TL;DR if you're going to make a macro, choose a letter to record to instead of any symbol.


This is very odd behavior, but it does make sense. To understand why, first we need to back up a little bit and explain how registers and macros really work.

Try this.

qqiHello World<esc>q

and then

"qp

This second command tells vim to paste from register 'q', rather than from the default register. You should see

iHello World^[

in your buffer. This is because when you run q<reg><commands>q, you're not really recording keystrokes for later use, but you are sending those keystrokes to a particular buffer name, in this case 'q', in your case '1'. The @ command will run whatever is in a particular register. Try this too:

iYp<esc>

and then delete that line with dd. Now, that really deleted the text to the unnamed register, so we can run it as if it was a macro with @".

So on to your example. Set up everything exactly the same. Do the same steps. But when you get to

However the next time I type @1 weird stuff happens.

Instead of typing @1, run the :reg command. This will tell you the contents of every register. Note the contents of "1. That should have the last two lines you deleted. When you run @1 the second time, it's like you typed out each character from those lines, which explains why you get weird stuff. From :h "1:

2. Numbered registers "0 to "9      *quote_number* *quote0* *quote1*
                    *quote2* *quote3* *quote4* *quote9*
Vim fills these registers with text from yank and delete commands.
   Numbered register 0 contains the text from the most recent yank command,
unless the command specified another register with ["x].
   Numbered register 1 contains the text deleted by the most recent delete or
change command, unless the command specified another register or the text is
less than one line (the small delete register is used then).  An exception is
made for the delete operator with these movement commands: |%|, |(|, |)|, |`|,
|/|, |?|, |n|, |N|, |{| and |}|.  Register "1 is always used then (this is Vi
compatible).  The "- register is used as well if the delete is within a line.
Note that these characters may be mapped.  E.g. |%| is mapped by the matchit
plugin.
   With each successive deletion or change, Vim shifts the previous contents
of register 1 into register 2, 2 into 3, and so forth, losing the previous
contents of register 9.
{Vi: numbered register contents are lost when changing files; register 0 does
not exist}
1
  • 1
    Thank you so much. I am doing some of the most annoying refactoring ever and you saved me a lot of time and fury. Particularly thank you for the TL;DR at the bottom because everything started glossing over me once I realized how complicated what I had in :reg was. I had no idea there were numbered registers, and the first person who showed me macro recording was also using numbers for some reason, maybe cuz they're close to the @ key. So you are helping me break a bad habit I learned elsewhere and also not go totally insane. The best!
    – sinback
    Commented Nov 1, 2022 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.