Emacs: Toggle Letter Case π
Emacs has these commands for changing letter case. They are:
upcase-word
γAlt + uγdowncase-word
γAlt + lγcapitalize-word
γAlt + cγ
There are also βregionβ versions for each:
upcase-region
γCtrl + x Ctrl + uγdowncase-region
γCtrl + x Ctrl + lγcapitalize-region
upcase-initials-region
(Note: for elisp programing, there are also these functions: upcase
, capitalize
, downcase
, upcase-initials
.)
One problem with these commands is that you need to move your cursor to the beginning of the word first. For example, if you have the text βTHatβ, and your cursor is on the βaβ, and you Alt + x downcase-word
, but it doesn't do anything because it only start at the cursor point to end of word. It would be nice if it'll just automatically perform the operation on the whole word.
Another problem is that it does not consider the final result. For example, if you have βoncE upon a time β¦β, and you select the whole sentence and Alt + x upcase-initials-region
, it becomes βOncE Upon A Time β¦β. Note the capital E is not automatically lowered. For elisp programing, the orthogonal precision is nice, but as user commands, it is better to change the whole sentence.
Also, these commands have a β-wordβ and β-regionβ variants. You have to chose which one to use. It would be nice if emacs automatically choose the right command depending whether there is text selection.
Solution
Here's a command that combines letter-case commands into one.
(defun xah-toggle-letter-case () "Toggle the letter case of current word or text selection. Always cycle in this order: Init Caps, ALL CAPS, all lower. URL `http://xahlee.info/emacs/emacs/modernization_upcase-word.html' Version 2020-06-26" (interactive) (let ( (deactivate-mark nil) $p1 $p2) (if (use-region-p) (setq $p1 (region-beginning) $p2 (region-end)) (save-excursion (skip-chars-backward "[:alpha:]") (setq $p1 (point)) (skip-chars-forward "[:alpha:]") (setq $p2 (point)))) (when (not (eq last-command this-command)) (put this-command 'state 0)) (cond ((equal 0 (get this-command 'state)) (upcase-initials-region $p1 $p2) (put this-command 'state 1)) ((equal 1 (get this-command 'state)) (upcase-region $p1 $p2) (put this-command 'state 2)) ((equal 2 (get this-command 'state)) (downcase-region $p1 $p2) (put this-command 'state 0)))))
Give it a easy key, such as Ctrl + 9. [see Emacs: How to Define Keybinding]
Toggle Previous Letter Case
Another issue, not related to emacs, but related to efficiency of Shift key, is that the conventional way of typing capital letter using the Shift key is inefficient. You have to hold it, type a letter, then release it. (For detail about the Shift key problem, see Banish Shift Key.)
A better way to type capital letters, is to have a designated key, so that, when pressed, the previous letter is capitalized. (alternatively, press this key first, then next letter key pressed is capitalized. This is like a Compose key. [see Alt Graph Key, Compose Key, Dead Key] )
This is better because:
- No more awkward holding key problem.
- Simpler model. Type a letter key, then press another key to capitalize it.
Here's the command.
(defun xah-toggle-previous-letter-case () "Toggle the letter case of the letter to the left of cursor. URL `http://xahlee.info/emacs/emacs/modernization_upcase-word.html' Version 2015-12-22" (interactive) (let ((case-fold-search nil)) (left-char 1) (cond ((looking-at "[[:lower:]]") (upcase-region (point) (1+ (point)))) ((looking-at "[[:upper:]]") (downcase-region (point) (1+ (point))))) (right-char)))
For this to work, you need to assign a easy key for this. For example, if you have a ergodox keyboard [see Best Keyboards for Emacs], set it to a thumb key.
If you have a normal PC keyboard, you could set the right Shift to something such as F20, then bind F20 to the command.
For how to remap keys in OS, see: Keyboard Tutorial: Layout, Keybinding, Key Macro β¨.