More Vim: Save Time With Macros

by Matthew Russell



The following is a section that we left out of this week's Mac DevCenter article What Is Vim (It's Easier than You Think) because of length constraints. I hope you find it useful as one more point on your radar screen as you ponder the productivity that Vim may be able to add to your daily workflow.



Save Time With Vim Macros



Do you find yourself frequently whipping out the python interpreter or cooking up regular expressions in Perl just to munge some text? Even if you're already really good, I bet Vim macros can still make you even better. A Vim macro is simply a set of keystrokes that you can record and use over again to perform repetitious tasks.



But wait a tick. "What's wrong with regexes," you ask? We'll, consider this conventional wisdom:


Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. --Jamie Zawinski, in comp.lang.emacs



Although I do commonly use regular expressions in production level code that I write, day-to-day events involving a quick transform of a text file hardly require the effort of cooking up a regex. Read on to see why.


21 Comments

mathie
2006-07-12 00:46:36

Ach, the regex in vim is only:


:%s/^[0-9]* -- \(.*\) \(([0-9]*)\)$/<li><em>\1<\/em> \2<\/li>/


It's pretty straightforward. :-) I suppose, in vim style, followed up with :



  • 1GO

  • <ol>

  • press escape

  • 0Go

  • </ol>

  • press escape

ptwobrussell
2006-07-12 04:40:32
By the way, one thing that would makes long regexes involving forward slashes easier to read (for me, anyway) would be to substitute the forward slashes that separate the actual pieces of the substitute command with something else, like hash characters. i.e. instead of substituting a command with :%s/foo/bar/ you can type :%s#foo#bar Sometimes that ends up saving you some trouble. At any rate, the first time I discovered that (you can do it with Perl too as I recall), I thought it was pretty neat.
Mark
2006-07-12 09:36:19
I use this recording all the time. One question I have, is there any way to save this recorded macro? Granted, these are usually just throw away scripts, but there are times it'd be nice to save.
ptwobrussell
2006-07-12 19:09:33
A book I recommend to everyone I know is Stephen Covey's Seven Habits of Highly Effective People. I just ran across a document by the primary developer of Vim himself that uses this particular motif. It's a really good read too. I highly recommend reading it. It has some good tips in it:


http://www.moolenaar.net/habits.html

ptwobrussell
2006-07-12 19:12:35
@Mark: Unfortunately, I'm not aware of a way to save the macro itself between sessions. To repeat this sequence of keystrokes, I believe you'd have to write a Vim script that you could call or else map the series of keystrokes with one of the "map" commands. Of course, you could always send in feature request to Bram Moolenaar and ask him to provide this capability for you (or hack at it yourself, if you dare!)
Clint
2006-07-13 08:37:37
You can insert the contents of the register into a text buffer using the " command. Using the article as an example, you could type (in normal mode)


"wp


and this would insert the contents of the w register (where the macro was stored) at the current cursor location. You can read more about working with registers by typing


:help registers.

ptwobrussell
2006-07-13 11:13:10
@Clint: Awesome tip! that's the thing about Vim...just when you think you're getting good, you find out there's a whole lot you never even knew about!
Mark
2006-07-14 09:24:36
@Clint: ditto. This is really an amazing program. And just when you think you've learned all you'll need, you can always get plugins to make it do more. A quick and dirty favorite of mine is "Align". If you have a section of code with say "='s" and you want them all lined up (as you should!), you can use Align to quickly neaten things up.Like most things vim, it does much more too.


http://vim.sourceforge.net/scripts/script.php?script_id=294

semifor
2006-07-18 08:32:37
@Mark: Registers can indeed be saved between sessions. I have the following line in my ~/.vimrc file:


set viminfo=%,'50,\"100,n~/.viminfo


"100 tells vim to save the first 100 lines of each register in the viminfo file. Once I've recorded a macro, it is available in all future vim sessions until I overwrite it.


:help 'viminfo'
:help viminfo

Tim
2006-07-22 22:49:47
Only problem with this macro, is that you really need 2 or use a small regex.
xxxxx Works for the first 9 lines, then you need xxxxxx otherwise you end up with a leading space.


Still, I have learnt some things here, and it's a bit of a wake up call, to learn some of the more advanced Vim features! :-D

jonathantan86
2006-08-10 17:59:44
Instead of


xxxxx


you can use


d2f


followed by a space (in normal mode, of course). This will overcome the preceding space problem and can be extended to lists with more than 99 elements.

Matt
2007-03-25 16:39:22
For anyone who sees this in the future you can also use d2W or 2dW to delete the first 2 WORDS.


see help for word for the difference betweens words and WORDS.

grok
2007-10-15 00:54:25
This is great, people. You finally forced me to learn macros. I've escaped regex Hell!
Dr. CATIA
2007-12-20 16:25:26
Nice tip! I am a 20 year vi user just being forced onto PC's from Unix and learning VIM. I love it! Do you know if it is possible to save a recorded macro so that it can be used next week or next year? Can it be predefined in the .vimrc file? Thanks.
Anschel
2008-01-19 15:58:07
Instead of "$a" to append at EOL you can use "A"
donovan
2008-03-28 20:18:09
personally I would do it with three quick regex find and replaces which are quicker than recording the macro or doing the whole search and replace in a single line with \1 captures.


:%s:.*-- :

  • :
    :%s: (:
    :
    :%s:)$:
  • :
    donovan
    2008-03-28 20:21:20
    stupid comment system ... whats the verbatim tag round here? Theres sposed to be html tags in the comment above ...
    Regexer
    2008-04-22 12:28:45
    You can also use regexp's in a series for doing one-off transformations, you don't have write a big complicated single one.


    I do wish that vim supported 'normal' extended regexp's though (so you could do /^.*? -- /); not having that makes it a little harder to do it right:


    :%s/^\d\d* --/<li><em>/g
    :%s,\( (\d\d*)\),</em>\1</li>,g


    And for the macro'ed version I would use:


    0d2Wi<li><em> .escape. t(i</em> .escape. A</li> .escape. j


    0 - goto start of line
    d2W - delete 2 words
    i - insert ... escape
    t( -- go to the next (
    i - insert ... escape
    A - append to end of line
    j - down a line

    P J Moy
    2008-08-03 13:02:49
    Thanks! I've been looking for a replacement for the VMS TPU editor's learn and repeat commands.


    This seems to fit the bill, and is a nice writeup.

    Brian H
    2008-08-03 15:07:45
    Actually I would tackle this a different way:


    :%s/^\d\+ --
    gg c-v G I


  • :%s: (:
    &
    :%s:$:

  • G o
    gg O


      But that's just how I've evolved.

    Brian H
    2008-08-03 15:16:11
    This comment system could use a cheatsheet.



    :%s/^\d\+ -- <cr>
    gg <c-v> G I <li><em><esc>
    :%s: (:</em>&<cr>
    :%s:$:</li><cr>
    G o <ol><esc>
    gg O </ol><esc>