Following some tweet I found myself desultory watching an episode of the awesome VimGolf in Emacs video series by Tim Visher. Those series are about picking some challenge from vimgolf and implementing it with our favorite editor instead. Because Emacs Rocks guys.

Let me tell you upfront that I really dislike the whole idea of the vim golf challenge. I’ve been a user of both Emacs and Vim for many years, and finally decided to switch to living in Emacs; or if you prefer, climbing my way up from level 2 as in The Levels Of Emacs Proficiency. The reason why is that I found that in my case, using Vim would mean spending more time thinking about how to do some editing operation rather than the problem I wanted to solve by editing some text, most often code.

Of course, the main effect of Vim Golf is to make you focus even more on the wrong problem. There’s still a good side of it though, which is that such challenges are good excuses to discover new features of your editor. So let’s use that excuse to talk about some nice Emacs features.

Vim Golf Challenge: Complete the hex array data

The challenge

The previous image will lead you to a particular challenge where it’s all about filling in an array with consecutive hexadecimal numbers written as 0xab, where you begin with a template containing only the 0x00 entry. The idea is of course to use the Vim feature that will increment the number at point, and is available through the C-a keystroke.

unsigned int hex[] = {
        0x00,
};

A first solution

Emacs does not ship with an increment-number-at-point, much less so with one that would support decimal, octal and hexadecimal and even automatically recognize 0x as a prefix meaning that the next number is hexadecimal. But Emacs ship with Emacs Keyboard Macros and those have a counter, so it’s easy enough to fill in numbers from 1 to 255 that way: M-1 F3 F3 , F4 will register a macro where the counter starts at 1, and each time you hit F4 it will insert the current counter value, increment it and insert a coma. You want to do that 254 times, so you do C-u 2 5 4 F4 and Emacs just does that.

Now, to transform those decimal numbers into their hexadecimal representation, you can use advanced Emacs Regexp Replace features. Replace [0-9]+ with the result from the following Emacs Lisp code: \,(format "0x%02x" (string-to-number \&)). The \& in there will be replaced by the matching text, so that will do what we need here, turning 10 into 0x0a.

Let’s get some better tools

We could do better, though. I happen to already use a key chord to duplicate the current line, and we would need a function to Increment Number At Point. Those I found over at EmacsWiki were not to my taste as they were not able to figure out easily which base to use. So here’s a little Emacs Lisp example showing how to extend your favorite editor to have some Vim common features, which is why Emacs ships with Emacs Lisp in the first place.

(defun duplicate-current-line (&optional n)
  "duplicate current line, make more than 1 copy given a numeric argument"
  (interactive "p")
  (let ((nb (or n 1))
	(current-line (thing-at-point 'line)))
    (save-excursion
      ;; when on last line, insert a newline first
      (when (or (= 1 (forward-line 1)) (eq (point) (point-max)))
	(insert "\n"))

      ;; now insert as many time as requested
      (while (> n 0)
	(insert current-line)
	(decf n)))
    ;; now move down as many lines as we inserted
    (next-line nb)))

(global-set-key (kbd "C-S-d") 'duplicate-current-line)

(require 'cl)  ; destructuring-bind is found there

(defun dim:increment-number-at-point (&optional prefix)
  (interactive "p")
  (let* ((beg    (skip-chars-backward "0-9a-fA-F"))
	 (hexa   (save-excursion (forward-char -2) (looking-at-p "0x")))
	 ;; force the prefix to hexa (4) we see "0x" before the number
	 (prefix (if hexa 4 prefix))
	 (end    (re-search-forward "[0-9a-fA-F]+" nil t))
	 (nstr   (match-string 0))
	 (l      (- (match-end 0) (match-beginning 0)))
	 (fmt    (format "%%0%d" l)))
    (message "PLOP: %d" prefix)
    (destructuring-bind (base format)
	(case prefix
	  ((1)  '(10 "d"))		; no command prefix, decimal
	  ((4)  '(16 "x"))		; C-u, hexadecimal
	  ((16) '(8 "o")))		; C-u C-u, octal
      (let* ((n   (string-to-number nstr base))
	     (n+1 (+ n 1))
	     (fmt (format "%s%s" fmt format)))
	(replace-match (format fmt n+1))))))

(global-set-key (kbd "C-c +") 'dim:increment-number-at-point)

So if you’re using

Another solution

Anyway, now that we are much better equipped, we can picture a better way to solve the problem. Instead of using a macro that inserts the next counter value, we can use one that duplicate current line, increment number at point (and figures out on its own that the number prefixed with 0x is hexadecimal), and does that 254 times more. Then it’s all about reformatting the text so that if fits nicely on screen, and for that the command M-q runs the command fill-paragraph is exactly what we need. The command C-x f runs the command set-fill-column can be used to set the maximum column we allow Emacs to reach before going to the next line.

Our Golf then becomes a 19 steps solution if you start with the cursor at the ',' in the previous example:

C-x f 5 6 RET
F3 C-S-d C-c + F4
C-u 2 5 4 F4
C-SPC M-< C-n M-q

First, set the fill column, then register a macro (in between F3 and F4) that will duplicate current line (using C-S-d) then increment number at point (using C-c +). Third line, replay that macro 254 times ( C-u 2 5 4 F4). Fourth line, select all those hexadecimal numbers and fill the paragraph they form correctly, so as to get:

All those tips for…

unsigned int hex[] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
        0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
        0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
        0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
        0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
        0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
        0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
        0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
        0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
        0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
        0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
        0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
        0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
        0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
};

Conclusion

Thanks to the excuse of that challenge we now have a generic facility to increment a number at point in different common bases, which is a nice building block for all kinds of Emacs Keyboard Macros. We also now have a function to duplicate the line at point, which is something I use very often myself.

More importantly, we’ve been refreshing our memory on how to use some advanced replacement facilities wherein you can actually use inline Emacs Lisp code as a replacement pattern, and for the most interested readers here we have a good excuse to learn some more about Emacs Lisp programming.

The main thing I want to say is that using Emacs Keyboard Macros is an interactive process: you don’t have to pause your current activity to write some code in another language (here, that would be either Vim Script or Emacs Lisp) just to save a few minutes on a boring task.

How effective your are at solving that challenge, for me, is not at all about measure how many keystrokes you ended up using, it’s all about being able to get some precious help from your working tools without having to stop focusing on the main problem you are solving.

I wouldn’t ever get to write such Emacs Lisp code when doing that kind of editing once. I would only do that when I’m thinking I’ve just been doing a boring task by hand one time too many already. Like for example copying and pasting the pg_backend_pid() of the PostgreSQL backend I’m working with at the psql prompt so that I can attach gdb to it. I’ll get back to talking about pgdevenv-el later!

Hope you did enjoy that article, whose goal is to help you while you’re journeying in The Levels Of Emacs Proficiency.

Update

While looking at the docs for the Keyboard Macro Counter to check how to reset it without having to record the macro again, I just stumbled on this part of the docs: C-x C-k C-f runs the command kmacro-set-format. So another way to solve our problem with only facilities that come with a bare Emacs is the following:

C-x f 5 6 RET
C-x C-k C-f 0x%02x RET
C-1 F3 SPC F3 , F4
C-u 2 5 4 F4
DEL C-SPC C-a C-q

We’re now at 30 keystrokes, so much more than previously, but it’s stock Emacs features and that kmacro-set-format is a wonderful little tool you might as well have a need for in the future.