53

Very frequently I would need to perform the set of steps requiring multiple key strokes. For the same session those steps can be recorded in a keyboard macro.

An example is saving a frequently executed search/replace operation as a keyboard macro. But that macro is lost when I quit emacs.

How can I save my frequently used keyboard macro as a Lisp function?

For the sake of simplicity, I want to save the action of replacing "abc" with "def" as a function so that I can reuse it across emacs sessions.

Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179

3 Answers3

59

Here are the steps that you can follow:

  • Select the region you want to do the search-replace.
  • Start recording macro.

    M-x start-kbd-macro

  • Do the required M-x query-replace-regexp (replace "abc" with "def") and use ! to force search-replace in the whole region.
  • Stop recording macro.

    M-x kmacro-end-or-call-macro.

  • Do M-x kmacro-name-last-macro and give the macro a descriptive name like replace-abc-with-def. You will then be able to call that macro again by doing M-x replace-abc-with-def.
  • Now save this macro as a function to a file that you load during your emacs initialization; for example, init.el.
    • M-x insert-kbd-macro
    • Select your named macro to be inserted there.

The auto-created replace-abc-with-def function definition looks like this:

(fset 'replace-abc-with-def
   (lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ([59 39 return 97 98 99 return 100 101 102 return 33] 0 "%d")) arg)))

Now you can M-x replace-abc-with-def in all your emacs sessions.

Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179
  • 1
    +1 for `insert-kbd-macro`. That is the answer to the question (and the rest of this answer provides additional help). – Drew Sep 24 '14 at 15:31
  • 6
    Note also that Emacs can generate two different formats for keyboard macros. Which one you get when you `insert-kbd-macro` depends upon whether you named it using `kmacro-name-last-macro` (as in the above answer) or `name-last-kbd-macro`. – phils Oct 09 '14 at 06:06
  • 1
    Note that if you use the `name-last-kbd-macro` format (as mentioned by @phils above) you end up with a string, not a function. `fset`ting that to a symbol lets you execute the macro using M-x, but *not* call it from lisp (`commandp` -> `t`, `functionp` -> `nil`). Strangely, even calling it via `call-interactively` doesn't work (although you *can* use `execute-kbd-macro` to run it). – pyrocrasty Mar 12 '19 at 01:01
28

elmacro was already mentioned by @lunaryorn, but as the author of this package I thought it'd be nice to provide an example.

If you record a macro like this:

F3 C-e M-b M-u C-a C-n F4

Then doing M-x elmacro-show-last-macro upcase-last-word produces a buffer with:

(defun upcase-last-word ()
  "Change me!"
  (interactive)
  (move-end-of-line 1)
  (backward-word 1)
  (upcase-word 1)
  (move-beginning-of-line 1)
  (next-line 1 1))
Silex
  • 801
  • 6
  • 6
18

The elmacro package lets you view the last recorded macro as proper Emacs Lisp with M-x elmacro-show-last-macro.