Emacs: Letter-Case Commands Usability Problems

Buy Xah Emacs Tutorial. Master emacs benefits for life.
, , …,

This page discuss a usability problem of emacs's letter-case changing commands, and offers code for improvement.

Emacs has several user level commands for changing letter case. They are: upcase-wordAlt+u】, downcase-wordAlt+l】, capitalize-wordAlt+c】.

There are also “region” versions for each: upcase-regionCtrl+x Ctrl+u】, downcase-regionCtrl+x Ctrl+l】, capitalize-region, and also 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 call 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 call 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, great for precision in elisp programing but not smart as user commands. It would be nice if emacs automatically choose the right command depending whether there is text selection.

The following code combines the letter-case-changing commands into one command and should fix these problems.

(defun toggle-letter-case ()
  "Toggle the letter case of current word or text selection.
Toggles between: “all lower”, “Init Caps”, “ALL CAPS”."
  (interactive)
  (let (p1 p2 (deactivate-mark nil) (case-fold-search nil))
    (if (use-region-p)
        (setq p1 (region-beginning) p2 (region-end))
      (let ((bds (bounds-of-thing-at-point 'word) ) )
        (setq p1 (car bds) p2 (cdr bds)) ) )

    (when (not (eq last-command this-command))
      (save-excursion
        (goto-char p1)
        (cond
         ((looking-at "[[:lower:]][[:lower:]]") (put this-command 'state "all lower"))
         ((looking-at "[[:upper:]][[:upper:]]") (put this-command 'state "all caps") )
         ((looking-at "[[:upper:]][[:lower:]]") (put this-command 'state "init caps") )
         ((looking-at "[[:lower:]]") (put this-command 'state "all lower"))
         ((looking-at "[[:upper:]]") (put this-command 'state "all caps") )
         (t (put this-command 'state "all lower") ) ) ) )

    (cond
     ((string= "all lower" (get this-command 'state))
      (upcase-initials-region p1 p2) (put this-command 'state "init caps"))
     ((string= "init caps" (get this-command 'state))
      (upcase-region p1 p2) (put this-command 'state "all caps"))
     ((string= "all caps" (get this-command 'state))
      (downcase-region p1 p2) (put this-command 'state "all lower")) )
    ) )

This toggle-letter-case command is implemented in ErgoEmacs Keybinding and has a single keyboard shortcut.

Like it?
Buy Xah Emacs Tutorial
or share
blog comments powered by Disqus