Every so often, as I am performing some repetitive or tedious task in my job as a web developer, it dawns on me that I am not taking advantage of technology the way I should. Case in point: a recent project required me to format a large list of URLs and email addresses as HTML hyperlinks. For each one, I had to perform the following keyboard gymnastics in Emacs:
- move point to the beginning of the URL
- set the mark
- move the point to the end of the URL
- kill the selection
- type
<a href="possibly followed by some scheme likemailto: - yank the saved text from the kill ring
- type
"> - type the appropriate display text for the link
- type
</a>
Looks like a prime candidate for a keyboard macro, yes? That is what I thought at first. But a generic macro cannot differentiate between hyperlinks needing an http: scheme and those needing mailto:, or which ones should have a title attribute.
Emacs Lisp to the rescue. Here is what I added to my .emacs configuration to aid the process:
(defun hyperlink-url-at-point ()
(interactive)
(require 'thingatpt)
(let ((url (or (thing-at-point 'url)
(error "No URL at point")))
(text (read-from-minibuffer "Text: "))
(title (read-from-minibuffer "Title: "))
(bounds (bounds-of-thing-at-point 'url)))
(if (equal "" text)
(setq text (buffer-substring-no-properties
(car bounds) (cdr bounds))))
(if (not (equal "" title))
(setq title (concat " title="" title """)))
(delete-region (car bounds) (cdr bounds))
(insert (format "<a href="%s"%s>%s</a>" url title text))))
(global-set-key "C-cu" 'hyperlink-url-at-point)
The resulting keyboard work is greatly reduced:
- move point to anywhere along the URL
- type ctrl-c u
- type optional display text for the hyperlink at the prompt, press enter (defaults to the URL itself)
- type optional
titleattribute text at the prompt, press enter
Here is the best part: thanks to the wonderful thing-at-point library which recognizes all kinds of URLs (among other “things”), hyperlink-url-at-point will automagically insert the proper scheme in the link’s href attribute for a given URL. That means that email addresses will be linked correctly with a mailto: scheme, and that URLs lacking the leading http:// will have it inserted.