Ode to the toggle25 Dec 2014
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
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,
upcase-word-toggle, that are good
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.
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.
capitalize-word-toggle is super-useful there.
(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.