M-x all-things-emacs

Keyboard Macros in the Wild #1

January 26th, 2007 by Rob Christie · 5 Comments

This is the first in a series of real world uses of emacs keyboard macros. Emacs macros are normally mentioned as a powerful feature of emacs, but many times I find the examples that are given are more academic in nature and don’t drive home their usefulness. These posts will show examples of macros “in the wild.” Part of the fun of becoming proficient with macros is that it both allows you to quickly complete a mundane task, and at the same time provides a bit of a mental exercise because you must think through the process for generalizing the task at hand.

For the uninitiated, an emacs macro allows you to record your keystrokes and lisp function calls so that you can replay them. Additionally, the macro facility has the ability to do recursive editing. This means you can pause your macro, edit the text, and then restart the recording of the macro. I find recursive editing useful for handling areas of a macro that I can’t generalize for each call of the macro.

  • C-x ( – Start recording macro
  • C-x ) – Stop recording macro
  • C-u C-x q – Pause macro so that you can recursively edit
  • C-M-c – Continue
  • C-x e – End macro and execute (emacs 22)

I have the following set in my .emacs:

(global-set-key [f7] 'call-last-kbd-macro)

I might remove this and go with the kmacro keymaps that have been defined in emacs 22, but for now my brain is wired to hit f7. This allows me to quickly recall the last keyboard macro that I have defined.

Problem

I am a disgruntled java developer by day. I work projects that normally require soup to nuts knowledge. The other day I needed to modify some jsp pages to better handle changing references to a page and deployment at different context locations. The existing links in the jsp page were html anchor tags with relative urls such as: <a href="foo.html">Foo</a>. The links to some of the pages are being “marketized” so the relative location of the page where the links show up is in flux (e.g, today it is /foo/blah.html, but tomorrow it will need to be /foo/widget/blah.html, and then two days from now it will be back to the original).

Drudgery

The not-so-fun way of doing this would be to incrementally search for “href=” and then change the link from:

<a href="foo.html">Foo</a>
to:
<a href="<c:url value="/foo.html" />" >Foo</a>

Note: c:url is part of the java standard tag library (JSTL) and takes care of the web application context issue discussed above.

Macro

Initially, I thought I might be able to use a regular expression search and replace to handle this task, but I also needed to edit some of the links as part of this process. Therefore, I chose to make a macro. When approached with a mundane task like this I normally goto a point in the buffer near the location where I need to start my task, think about the problem, develop my plan of attack, and then start the macro. In this case the general plan was:

  • Incrementally search for href="
  • Pause macro so that I could edit the URL if needed
  • Restart macro
  • Get back to the end of the href=" location
  • Wrap the value of the href in <c:url value="URL" />
  • Stop recording the macro
  • Replay the macro through the rest of the file

A great things about quick and dirty emacs macros is that you can make a mistake, back out your mistake, and fix the problem, and the few extra keystrokes that were added are immaterial when you run it. The following is an example of a quick one-off macro.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
C-s                     ;; isearch-forward
href="                  ;; self-insert-command * 6
RET                     ;; newline-and-indent
C-SPC                   ;; set-mark-command
C-u C-x q               ;; kbd-macro-query
C-x C-x                 ;; exchange-point-and-mark-nomark
<c:url                  ;; self-insert-command * 6
SPC                     ;; self-insert-command
value="                 ;; self-insert-command * 7
C-s                     ;; isearch-forward
>                       ;; self-insert-command
RET                     ;; newline-and-indent
<left>                  ;; backward-char-nomark
/>"                     ;; self-insert-command * 3
SPC                     ;; self-insert-command

You can see a macro in this format by using the command, M-x edit-last-kbd-macro.

Tags: java · kb-macros · tips

5 responses so far ↓

  • 1 Phil // Jan 26, 2007 at 8:21 pm

    Looks interesting.

    Just a thought; you may want to distinguish between keyboard macros and macros as a language feature in emacs.

    I’ve never used keyboard macros simply because binding a lambda to a keystroke seems to be able to achieve the same goals pretty easily. What would you say the pros and cons of this approach is in comparison to that?

  • 2 Rob Christie // Jan 27, 2007 at 5:00 am

    Very true. I changed the title of the blog and a few lines to help make it apparent that the article focuses on keyboard macros rather than lisp macros. I find that many times I use keyboard macros as a quick one-off to automate an immediate need. If I think I am going to use it more, then I name the macro and save it off to a file that gets loaded as part of my .emacs. If I use the macro to the point that I get tired of typing M-x foo, then I bind it to a keystroke. I think binding a lambda to a keystroke is more formalized in terms that you need to explicitly write each lisp function that you plan to call, whereas for the keyboard macros it’s just recording the commands as I type. I think each has its place. I have been meaning to try the Power Macros package which seems like it might automate some of the steps above. Another take on keyboard macros can be found in Steve Yegge’s post on Effective Emacs.

  • 3 Ryan McGeary // Jan 29, 2007 at 5:54 am

    Referring to line #13, I expect to see a C-b (instead of <left>) in your next macro example. :-)

  • 4 Justin Bailey // Apr 6, 2007 at 9:59 pm

    I’ve always loved this feature of Emacs. Visual Studio stole it when they came out with the .NET version, but of course it was much slower. For some reason, starting up the VBA environment (not including the IDE) is slow … :)

    I never knew about recursive editing – that is slick.

    Another feature you might mention is that macros can be repeated.

  • 5 Fay // May 11, 2009 at 2:31 am

    I just use vbscript for my macros. I find it easier to use than the more complicated versions. http://vbscript-macro-template.blogspot.com/