Writing Emails In Kakoune

This post will guide you through my setup for using Kakoune as an email composer inside aerc. I’ll also explain how to configure Kakoune to act as the pager for reading text/plain emails. If you only care about the final config, feel free to skip to it here.

Naive Approach

Since aerc uses your $EDITOR for composition, you don’t technically have to do anything. I prefer setting it explicitly in aerc.conf, for good measure:

[compose]
editor=kak

The rest of the magic happens in your kakrc.

Composer Setup

Essentially, we want to hook filetype=mail and set our buffer configuration there. I’ll share a recommended configuration with some explanation.

hook global WinSetOption filetype=mail %~
    set-option window formatcmd '/home/fic/dev/utils/mail-utils/format.py'
    set-option window comment_line '>'
    try autospell-enable
    hook -group mail-auto-format window BufWritePre .* format
    hook -once -always window WinSetOption filetype=.* %{
        unset-option window formatcmd
        remove-hooks window mail-auto-format
    }
~

I use a custom formatter to format emails. It automatically hard-wraps lines while preserving certain markup elements, code blocks, sign-offs, and signature blocks. For more details, check the formatting section of my post on Helix.

I find that setting > as the comment_line token is convenient for working with quotes in replies.

The try autospell-enable enables my kak-autospell plugin for the buffer. Essentially, it provides spellchecking that’s continuously refreshed and hidden in insert mode.

The remaining commands configure auto-formatting on save. I always prefer having this on so I never forget to format my message before sending it.

Reader Setup

I find that using Kakoune to read emails is helpful because of how easy it is to copy quotes, open links, etc. Configuring this is a tad hackier, however. The basic idea is to set Kakoune as the viewer pager in aerc.conf.

However, all this does is pipe the email to kak through standard input, so we need to tell the editor to treat it like an email:

[viewer]
pager=kak -e 'set buffer filetype mail'

When you’re using Kakoune as a pager, you’ll probably want to configure some things differently. In my case, I like to set the buffer as readonly, remove the number-lines and show-whitespaces highlighters, disable soft-wrap & my scrolloff settings, and not set any formatters.

The pager command above sets the filetype, but we need to distinguish between composing and reading in our Kakoune hook. When Kakoune is opened with input through standard input, it loads a buffer that’s conveniently named *stdin*. Thus, we can check the buffer name before continuing.

If we’re in “reading mode”, we define a hidden command called ismailreader which doesn’t do anything. Why? If the command is defined, and we try to invoke it… well, nothing happens! But if it’s not defined, we get an error instead. We can combine this with the try command to for some simple boolean logic.

evaluate-commands %sh{
    # stdin, we assume it's a pager
    if [ "$kak_bufname" = "*stdin*" ]; then
        echo 'define-command -hidden ismailreader nop'
    fi
}
try %{
  ismailreader
  # do reader config here
} catch %{
  # do composer config here
}

I set the following configuration for “reader mode”:

set buffer readonly true
try %{
	remove-highlighter window/number-lines
	remove-highlighter window/show-whitespaces
	# custom commands defined elsewhere in my kakrc
	ui-wrap-disable
	ui-scrolloff-disable
}

Final Configuration

To recap, you’ll want to set this in aerc.conf:

[viewer]
pager=kak -e 'set buffer filetype mail'

# ...

[compose]
editor=kak

And the following in your kakrc:

hook global WinSetOption filetype=mail %~
    evaluate-commands %sh{
        # stdin, we assume it's a pager
        if [ "$kak_bufname" = "*stdin*" ]; then
            echo 'define-command -hidden ismailreader nop'
        fi
    }
    try %{
        # READER MODE setup
        ismailreader
        set buffer readonly true
    	try %{
    		# remove these highlighters so everything displays properly
    		remove-highlighter window/number-lines
    		remove-highlighter window/show-whitespaces
    		ui-wrap-disable
    		ui-scrolloff-disable
    	}
    } catch %{
        # WRITER MODE setup
        set-option window formatcmd '/home/fic/dev/utils/mail-utils/format.py'
        set-option window comment_line '>'
        try autospell-enable
        hook -group mail-auto-format window BufWritePre .* format
        hook -once -always window WinSetOption filetype=.* %{
            unset-option window formatcmd
            remove-hooks window mail-auto-format
        }
    }
~