(or emacs irrelevant)

Ode to the toggle

Man, I just love toggles: the light switches, the f - full-screen key in vlc, and the clicky pens (ooh, those are the best). So I try to model some of my Emacs key bindings as toggles.

Let me just quantify the two features that make a good toggle:

  • only two states: on and off
  • the state is visible at a glance

One could argue that with undo most editing commands become toggles. But they're not, since each time you call undo, you mess with Emacs's undo state. And the undo state isn't visible at a glance, so both requirements for a good toggle aren't fulfilled.

I'll demonstrate the two editing commands that I use every day, capitalize-word-toggle and upcase-word-toggle, that are good toggles.

capitalize-word-toggle

Talk is cheap. Show me the code.

(defun char-upcasep (letter)
  (eq letter (upcase letter)))

(defun capitalize-word-toggle ()
  (interactive)
  (let ((start
         (car
          (save-excursion
            (backward-word)
            (bounds-of-thing-at-point 'symbol)))))
    (if start
        (save-excursion
          (goto-char start)
          (funcall
           (if (char-upcasep (char-after))
               'downcase-region
             'upcase-region)
           start (1+ start)))
      (capitalize-word -1))))
(global-set-key (kbd "C-z") 'capitalize-word-toggle)

I may not have mentioned this before, but you should for the most part ignore the key bindings mentioned on this blog. I'm actually using them, they work for me because of my non-standard layout, but you should assign what works for you.

Anyway, capitalize-word-toggle clearly has a state that's visible at a glance: the first char of the current symbol. Also, there are only two possible states: the char can either be upper-case or lower-case. Hence, I can toggle this state with C-z for fun and profit.

Maybe some background on how this command is useful for me. I write a bunch of C++, and the code features a lot of lines like this:

Triangulation triangulation; // duh

So when I'm using auto-complete, it often eagerly expands to Triangulation when I want triangulation, and the other way around. So capitalize-word-toggle is super-useful there.

upcase-word-toggle

(defun upcase-word-toggle ()
  (interactive)
  (let ((bounds (bounds-of-thing-at-point 'symbol))
        beg end
        (regionp
         (if (eq this-command last-command)
             (get this-command 'regionp)
           (put this-command 'regionp nil))))
    (cond
      ((or (region-active-p) regionp)
       (setq beg (region-beginning)
             end (region-end))
       (put this-command 'regionp t))
      (bounds
       (setq beg (car bounds)
             end (cdr bounds)))
      (t
       (setq beg (point)
             end (1+ beg))))
    (save-excursion
      (goto-char (1- beg))
      (and (re-search-forward "[A-Za-z]" end t)
           (funcall (if (char-upcasep (char-before))
                        'downcase-region
                      'upcase-region)
                    beg end)))))
(global-set-key (kbd "C->") 'upcase-word-toggle)

upcase-word-toggle's state becomes binary after you call it once, since initially the thing at point could have mixed case. But afterwards, it's either all lowercase or all uppercase. So again, a clearly visible binary state is a good thing.

This command works either on (bounds-of-thing-at-point 'symbol) or on the active region. Since region-active-p is deactivated after you call the command once, there's some machinery to remember the state and to toggle when called again.