Mix Format and Vim

Automatically run mix format on save in NeoVim.

keywords

vim elixir

2022-06-21


There Are a few challenges when it comes to automatically mix format-ing your files on save in Vim.

This simple config seems to do a pretty good job at solving these challenges:

First, in $nvim_config_dir/ftplugin/elixir.vim (and eelixir.vim) I have an autocommand set up. It uses BufWritePost because the work is going to happen async. I think BufWritePre should be OK too.

augroup formatting
  autocmd! * <buffer>
  autocmd BufWritePost <buffer> :call elixir#formatting#mix_format()
augroup END

Then in $nvim_config_dir/autoload/elixir/formatting.vim I have these two functions.

function elixir#formatting#on_mix_format_exit(id, data, event)
  if a:data > 0
    echom "⚠ mix format "
  else
    execute 'edit'
    echom "✓ mix format "
  endif
endfunction

function elixir#formatting#mix_format()
  let l:filepath = expand('%:p')
  let l:mixformatcmd = 'nohup mix format '
        \. l:filepath
        \. ' 2>&1 > /dev/null'

  call jobstart(
        \['bash', '-c', mixformatcmd],
        \{'detach': 1,
        \ 'on_exit': function(
        \ 'elixir#formatting#on_mix_format_exit')})
endfunction

Since the mix_format function spawns a job to run the actual mix format program, it happens in the background so you can continue typing.

Instead of doing just mix format path/to/file, I am using nohup, which allows mix format to keep going even if the parent process dies.

I also set the detach option on the job so that it will not be killed when nvim exits.

When the job finishes, on_mix_format_exit is called and checks if mix format ran with errors or not. execute edit reloads the buffer contents, which has the formatted version at this point, and it does it without changing where the cursor is at.