Deterministic Navigation, or, Learning from Vim

Recently I had the excellent opportunity to hang out and talk shop with Kyle Wild about the state of Computer Science, CS education, and software development environments. While the former are discussions for later posts, the latter will be part of a series elucidating the good parts of Emacs and Vim.

Parties on both sides of the holy war seem to get more distracted with partisan bickering than figuring out how to best get the code out of your head and into a computer. As an Emacs programmer, I’m interested in how I can incorporate the useful bits of Vim. Kyle, coming from the Vim world, wanted to more clearly understand the pros and cons of using one IDE over another before investing the time required to make the switch. However you currently code, I suggest looking over the shoulder of a friend using a different IDE – you’re bound to learn something.

While pair programming, I noticed one advantage Vim has inherently over Emacs: deterministic text navigation. Vim’s keystrokes unambiguously select where to move the cursor. For example, Vim has simple keystrokes to “move the cursor to the 3rd occurrence of the letter ’s’”. I’d never seen this sort of manipulation in Emacs; the closest replacement is probably “search for the letter ’s’. repeat three times”.

Even if Vim comes with this functionality “out of the box”, Emacs rises to the challenge with a powerful and extensible programming language, Elisp. Here is an implementation of Vim’s deterministic text movement:


(defun jump-to-next-char (c &optional count)
  "Jump forward or backward to a specific character.  With a
count, move that many copies of the character."
  (interactive "cchar: \np")
  (when (string= (string c) (buffer-substring (point) (+ 1 (point))))
    (setq count (+ 1 count)))
  (and
   (search-forward (string c) nil t count)
   (> count 0)
   (backward-char)))
(global-set-key (kbd "C-;") 'jump-to-next-char)

Now, the keystrokes “C-u 3 C-; s” will jump to the third ’s’. Neato!