Posted on Apr 22, 2014.
TL;DR: In this blog post, I will describe Emacs Lisp functions that automatically change the language of the citation line in the email client mu4e, depending on the ispell dictionary language.
I use Emacs for several years now. Since a couple of months, I switched from Claws Mail to Mu4e. Don’t get me wrong—Claws Mail is the best graphical e-mail client that I know. It was really easy to handle several accounts with one IMAP account and to have different settings for folders. However, since I spend most of my time in Emacs, I was getting uncomfortable writing e-mails with Claws Mail. I missed all my key bindings that burned in my muscle memory. I tried Gnus a couple of times, but it was quite hard to get a working setup.
I gave Mu4e a try; it was easy to get a working setup. There are a couple of blog posts that helped me a lot. Mu4e is just a Emacs front-end for mu. Mu itself is an e-mail maildir indexer and search engine. Combined with tools like Offlineimap and msmtp you will get a efficient and comfortable email setup.
h2. The Problem
After a couple of months, I’m still satisfied with my choice. One thing, however, that bothered me was the citation line format. I write a lot of e-mails in German and English, but my citation line looked always the same, e.g.:
The unique feature of Emacs is that you can change everything. The idea is that whenever I change the ispell language, the citation line should change the format, too. This is an indicator that I write in German or in English. So, let’s moo this:
h2. The Solution
The following animated gif shows the solution and the general idea:
The algorithm works in three simple steps:
Firstly, we need to collect all the information to create the citation line. The function
message-insert-formatted-citation-line takes the e-mail address from the sender and the date as an argument and inserts the citation line. These arguments are not available if we reply to a message. Therefore, we need to switch to the
*mu4e-headers* buffer and save those values in variables.
Secondly, we create the old citation line and save it a variable. This is necessary, since we need to find the line where the old citation line is. The function
with-temp-buffer creates a temporary buffer and switches to it. Then we can insert the old citation line and remove all newlines. Then we can save the content of the buffer to a variable with
Lastly, we need to find the old citation line and replace it with the new one. The old citation line can be found with
search forward; after we have found it, we can delete the old citation line. Before we can insert the new citation line, we have to change the language. The variable
system-time-locale controls the language of the format specifiers of
message-citation-line-format. To switch easily between the different ispell languages and the citation lines I created the following variables:
It is important that the different formats begin with name of the locale. Depending on the parameter
locale, we then replace the citation line with new one. The source code of the above described function is in the following:
Before I decided that I would like to publish my code, I had a simple solution to circle between two languages. But since there are people out there, which speak and write more than two languages; I made my solution more general. To circle easily between the
language variable, we need to treat the association list (alist) like a circular list. Therefore, I wrote the following helper functions:
fa/reverse-nth does the opposite of
nth. The function
nth returns the Nth element of a list;
fa/reverse-nth searches for an element in a list and returns N if it founds it. The next function
fa/assoc-next-element makes use of that function and increases N to return the next element in an alist. If
(nth (1+ n) list) returns
nil, the function returns the first element. With both functions, we can cycle through an alist.
The next function changes the ispell language and if the current buffer is in
mu4e-compose-mode it also changes the citation line. I have bound this function to the F6 Key.
This should work as expected. However, most of my time I reply my emails in my mother language; that’s why I would like to set German as my default format. Luckily, Mu4e provides hooks for that:
That’s all! Hopefully, this blog post showed you how easy it is to extend Emacs or Mu4e with some basic Emacs Lisp skills. The complete source code of the extension is available on this gist. Happy Hacking!