Drawing Key Sequences In Emacs (Updated)

This is a sad story of my HTML ineptitude but one in which I eventually find the right solution. I’ve written several times (here, here, and here) about how I implemented Xah Lee’s trick of representing key sequences in a visual manner like this: 【⌘ Cmd+Tab

When I was first experimenting with the markup I used <key>...</key> tags to delimit the keys and added the appropriate bit of CSS with a key tag. That worked perfectly in my local testing but when I tried it out with the live blog it turned out that WordPress disappeared the <key> tags, presumably because it didn’t recognize them. After a bit of thinking, I came up with the <span class="key"> that I’ve been using ever since. That works well and the only complaint I have is that the markup for a complicated key sequence is pretty long and I tend to get problems when Emacs tries to split lines.

Then Aankhen asked why I wasn’t using <kbd>...</kbd> instead of the longer <span...> method. I replied that I’d originally used <key> but that WordPress eliminated them from the text. He explained to me (probably more politely than I deserved) that <key> isn’t an HTML tag but that <kbd> is. By this time I already knew that Lee used <kbd> but I had just assumed that he had made it up—just as I had made up <key>—and that it worked for him because he wasn’t using WordPress. So, I thought, I’ll just add a kbd tag to the CSS and both methods will work. Tested it locally and everything was fine. Added the kbd to the site CSS, ran a test and it didn’t work. I concluded that this was just more WordPress weirdness and gave up. Several weeks later it popped into my head that the reason it hadn’t worked was that my browser hadn’t reloaded the site’s style sheet when I changed it. Fortunately, I had left the change in so when I retried it, everything worked as expected.

I like the shorter <kbd> tags because they avoid the overly long markup sequences that were causing me a slight irritation. All that was left to do was to change prettify-key-sequence to use the new method. Here, for the record, is the new code

(defmacro key (k)
  "Convenience macro to generate a key sequence map entry
for \\[prettify-key-sequence]."
  `'(,k . ,(concat "@<kbd>" k "@</kbd>")))

(defun prettify-key-sequence (&optional omit-brackets)
  "Markup a key sequence for pretty display in HTML.
If OMIT-BRACKETS is non-null then don't include the key sequence brackets."
  (interactive "P")
  (let* ((seq (region-or-thing 'symbol))
         (key-seq (elt seq 0))
         (beg (elt seq 1))
         (end (elt seq 2))
         (key-seq-map (list (key "Ctrl") (key "Meta") (key "Shift") (key "Tab")
                            (key "Alt") (key "Esc") (key "Backspace")
                            (key "Enter") (key "Return") (key "Space")
                            (key "Delete") (key "F10") (key "F11")
                            (key "F12") (key "F2") (key "F3")
                            (key "F4") (key "F5") (key "F6") (key "F7")
                            (key "F8") (key "F9")
                            ;; Disambiguate F1
                            '("\\`F1" . "@<kbd>F1@</kbd>")
                            '("\\([^>]\\)F1" .
                              "\\1@<kbd>F1@</kbd>")
                            ;; Symbol on key
                            '("Opt" . "@<kbd>⌥ Opt@</kbd>")
                            '("Cmd" . "@<kbd>⌘ Cmd@</kbd>")
                            ;; Combining rules
                            '("\+\\(.\\) \\(.\\)\\'" .
                              "+@<kbd>\\1@</kbd> @<kbd>\\2@</kbd>")
                            '("\+\\(.\\) \\(.\\) " .
                              "+@<kbd>\\1@</kbd> @<kbd>\\2@</kbd> ")
                            '("\+\\(.\\) " .
                              "+@<kbd>\\1@</kbd> ")
                            '("\+\\(.\\)\\'" .
                              "+@<kbd>\\1@</kbd>"))))
    (mapc (lambda (m) (setq key-seq (replace-regexp-in-string
                                     (car m) (cdr m) key-seq t)))
          key-seq-map)
    ;; Single key
    (if (= (length key-seq) 1)
        (setq key-seq (concat "@<kbd>" key-seq "@</kbd>")))
    (delete-region beg end)
    (if omit-brackets
        (insert key-seq)
      (insert (concat "【" key-seq "】")))))
This entry was posted in General and tagged , . Bookmark the permalink.