I write my todo lists like this:

- DONE! morning exercise
- DONE! buy milk
- pet the cat
- get your shit done
- read some book

..or like this:

- ✅ morning exercise
- ✅ buy milk
- pet the cat
- get your shit done
- read some book

Typing “DONE!” a bunch of times each day gets old pretty quick, as does searching for the emoji character so I wanted a way to make it faster to mark things as done. Also, it’d be nice to have a way of making items I’ve done stand out more. Here are some of the approaches I use:

Quickly mark items as done using a normal mode remap

This remap allows you to type ‘,done’ when in normal mode to insert ‘DONE!’ at the start of the todo item. It will then move the cursor down to the next line.

noremap ,done 02liDONE! <Esc>j

Prefer using the checkbox emoji? No probs…

noremap ,done 02li✅ <Esc>j

This approach would be ideal if you could hit ‘.’ to check off a load of items one after the other but there is a limitation of Vim that prevents this: The movements are not repeated. This means that the ‘0’ (move to start of the line), ‘2l’ (move 2 characters to the right), and ‘j’ (move to next line) won’t work so you’ll have to type ‘,done’ each time. Very frustrating.

Quickly mark items as done using an abbreviation

This is the simplest way to mark a completed todo item as done, and it works with the “.” repeat. The downsides is that you’ll have to position the cursor yourself each time you use it.

iabbrev ,done DONE!

Or for checkboxes:

iabbrev ,done ✅

Because the action of marking something as done involves putting a checkbox or string in a specific place, it’s probably best to use the abbreviation approach as a generic emoji inserting tool.

Highlight the “DONE!” string

To make ‘DONE!’ items stand out we can make a highlight rule which sets the foreground and background color of the string.

" Highlight the string DONE! with green background and black text
highlight HighlightDone guifg=black guibg=green
highlight HighlightDone ctermfg=16 ctermbg=28
call matchadd('HighlightDone', 'DONE\!')

Note how we’re using matchadd here, this allows us to add additional matches later on. If you only have a single match then match HighlightDone /DONE\!/ will work also.

Highlight lines with the checkbox emoji

The following highlight rule will make all lines starting with “- ✅” have green text making them stand out as done.

" Items starting with the checkbox emjoi have green text
highlight HighlightCheckbox ctermfg=46
call matchadd('HighlightCheckbox', '^\s*-\s✅.*$')

It’d be nice to have a strike through effect here too but alas, that is not available.

Quickly insert the checkbox emoji with function

Add a checkbox to the current line with the following function. After defining the function we map it to a normal mode keystroke. To use it enter normal mode then type ‘,done’, the function will add a check box then move down to the below line.

" Insert checkbox emoji
function! InsertCheckEmoji()
    " Get the current line
        let l:line = getline('.')
    " If it starts with '- ', insert the check emoji
        if l:line =~ '^-\s'
            let l:line = substitute(l:line, '^\(- \)', '\1✅ ', '')
            call setline('.', l:line)
            normal! j
        else
            echo "Line doesn't start with '- '"
    endif
endfunction

noremap ,done :call InsertCheckEmoji()<CR>

Why bother will all these lines when a simple normal mode remap will do? Well I’d hoped that this approach would let me use ‘.’ to repeat but nope, it suffers the same limitation as before. That said, having the logic available does make this approach more powerful should you need it.

Notes