Jérôme Belleman
Home  •  Tools  •  Posts  •  Talks  •  Travels  •  Graphics  •  About Me

Mutt, the Address Book and Completion

4 May 2017

I was astounded to see how easy it was to add some clever completion for my address book contacts to my mail composer. And guess what: all thanks to Vim.

1 Vim as Editor

In fact, mutt doesn't have much to do with this, except that it's got the very good taste of letting you choose which editor to compose mail with. And also that it lets you edit headers such as the subject and, crucially here, the recipient list in that same editor, too.

I should take the opportunity to encourage everyone to set up their mutt to edit their mail right in Vim – or any editor they're completely fluent with. This enables sender to comfortably juggle with short or long lists of recipients, search them, sort them, make searches, even use a spelling checker. All the tools are here to make life easier and also avoid making those blunders which are too easily made with those more graphical and limited modern mailers.

2 Parsing the Address Book

Using a custom, powerful editor for composing lists of recipients unleashes a flexibility which is hard to appreciate at first. But the simple fact that you can, in the case of Vim, write functions to perform any operation gives you an inkling. Here, I wrote a simple function which fuzzily parses my ~/.muttrc file in search for aliases making up my address book:

set completefunc=CompleteAddress
fun! CompleteAddress(findstart, base)
    if a:findstart
        return searchpos('\s', 'b', line('.'))[1]
    else
        let results = []
        for line in readfile($HOME . '/.muttrc')
            if line =~ '^alias' && line =~ a:base
                let line = substitute(line, '^alias\s\+\S\+\s\+', '', '')
                call add(results, line)
            endif
        endfor

        return results
    endif
endfun

Such a function is then summoned by hitting Ctrl x u . The completion system hence triggered displays 2 behaviours depending on the value of that argument called a:findstart:

  1. When it passes a:findstart as true, it searches and returns the position of the previous space (as the 'b' argument makes it search backward) to identify the word typed so far (which will become a:base).
  2. When it passes a:findstart as false, it parses each line in ~/.muttrc in search for matches starting with the alias mutt command and which contain the word typed so far (a:base). It returns such matching lines with the alias command and its key stripped off, leaving only the address. An address can comprise a display name and the actual address in angle brackets: John Doe <john.doe@example.com>

3 References