January 16, 2007 — jao

I use pretty often emacs-w3m to read technical HTML docs within Emacs. When you’re programming, reading manuals, blogs or tutorials without leaving your operating system editor is all but convenient.

Actually, emacs-w3m does a very, very good job rendering even moderately complex sites, and i’ve been known to use it as my default browser. It is not limited to plain text (Emacs groks images these days), has tabs (shameless plug: take a look at my w3m-session package to add session management) and renders tables and other HTML constructs nicely. And of course, navigating sites like the Emacs wiki without leaving Emacs is just the way to go. Besides, if you don’t like how a page looks in emacs-w3m, opening it in your graphical browser is just a keystroke away (C-h w w3m-view-url-with-external-browser to discover it).

I also have usually open a tab with my Gmail account, to quickly check my email every now and then. As you can see in the screenshot on the right, emacs-w3m renders Gmail pages very decently (hint: you’ll need to activate cookies to use Gmail, by setting the variable w3m-use-cookies to a non-nil value). But of course the Gmail page i visit more frequently is the Spam tab, and the operation i want to perform more frequently in there is to mark all the mails and press ‘Delete Forever’. But alas, w3m does not support javascript, and the handy ‘Select All’ link is missing. Obviously, tabbing your way to every single spam mail to select it would be a pain, and one is tempted to follow the advice at the top of the page about a better Gmail experience.

But wait, this is not your regular browser. We’re inside Emacs, and in here, when we need something, we usually just hack it and keep on working. After all, what we need to do is quite simple: look for occurrences of ‘[ ]’ in the buffer, click them, and leave the pointer over the ‘Delete forever’ button, ready to send all our spam where it deserves. As it happens, our life is even easier thanks to the functions provided by emacs-w3m. w3m-form-goto-next-field allows easy navigation inside a form, and w3m-view-this-url will perform a click for us. So here we go: let’s write an Elisp command that looks for unmarked checkboxes and clicks them:

(defun jao-w3m-gmail-mark-all () (interactive) (beginning-of-buffer) (when (search-forward "[ ]" nil t) (backward-char 4) (w3m-form-goto-next-field) (while (looking-at " \\\\]") (w3m-view-this-url) (w3m-form-goto-next-field))))

That’s it. After evaluating this definition, we just M-x jao-w3m-gmail-mark-all to mark all our mails. Of course, a keyboard shortcut will come in handy:

(define-key w3m-mode-map (kbd "C-ck") 'jao-w3m-gmail-mark-all)

and now we only need to press C-ck to get the job done. While we’re at it, it would be nice if typing a prefix would unmark mails instead of marking it, wouldn’t it? Well, that only needs a few tweaks in our original definition:

(defun jao-w3m-gmail-mark-all (unmark) (interactive "P") (beginning-of-buffer) (when (search-forward (if unmark "[*]" "[ ]") nil t) (backward-char 4) (w3m-form-goto-next-field) (while (looking-at (if unmark "\\\\*\\\\]" " \\\\]")) (w3m-view-this-url) (w3m-form-goto-next-field))))

Now, C-ck will mark, and C-uC-ck will unmark.

As you can see, the limit is just your imagination. For instance, when i’m reading non-spam, i usually mark some mails for deletion. Then i need to go to the ‘More actions…’ menu, select the ‘Delete’ operation and press ‘Go’. Hmm, a bit of a chore. Elisp to the rescue:

(defun jao-w3m-gmail-delete () (interactive) (beginning-of-buffer) (when (search-forward "[More Actions" nil t) (w3m-view-this-url) (search-forward "Trash") (beginning-of-line) (w3m-form-input-select-set) (w3m-form-goto-next-field)))

Admittedly, these little extensions are far from earth-shattering, but i think that they illustrate quite well what having an extensible system means. You control your environment and adapt it to your particular needs, often building upon functionality provided either by the system or by some other extension library. Another nice example of extensibility at work is my w3m-session package: i wanted persistent sessions, so i wrote an extension. And it was easy, thanks to the nice work of the emacs-w3m hackers and, let’s not forget, the dynamic nature of Elisp.

In addition, the programmer in me finds tweaks like this a continuous source of fun. You know, that fuzzy warm feeling… but i digress. Happy hacking!