Home

Awesome

Vim Filetype Formatter

A simple, cross-language Vim code formatter plugin supporting both range and full-file formatting. It uses code formatters available in your $PATH; it does not install them.

See our pre-configured languages and formatters. Don't like the defaults? Writing your own is easy! Each Vim filetype maps to one command-line command. This plugin supports any code formatter command as long as it:

  1. Reads from standard input.
  2. Writes to standard output.
  3. Is in your $PATH.

Requires Bash and a recent version of Vim or Neovim.

Differentiating Features

The following screencast demonstrates :FiletypeFormat, :LogFiletypeFormat, and :DebugFiletypeFormat.

Screencast

Although black works out of the box for Python, the above example overrides the default and combines black with isort and docformatter using Unix pipes. This specific example can be achieved with the following configuration in your vimrc or init.vim:

let g:vim_filetype_formatter_commands = {
      \ 'python': 'black -q - | isort -q - | docformatter -',
      \ }

For further customization (e.g., where you need anything dynamic), you can pass either a Funcref or a lambda expression. For example, you might want to pass the current filename as an argument to your command line program. Here is an example for Python using a lambda expression:

let g:vim_filetype_formatter_commands = {
      \ 'python': {-> printf('black -q --stdin-filename="%1$s" - | isort -q --filename="%1$s" - | docformatter -', expand('%:p'))},
      \ }

Here's another Python example involving ruff.

function s:formatter_python()
  return printf(
        \ 'ruff check --unsafe-fixes -q --fix-only --stdin-filename="%1$s" - | ' ..
        \ 'ruff format -q --stdin-filename="%1$s" -',
        \ expand('%:p'))
endfunction
let g:vim_filetype_formatter_commands = {'python': function('s:formatter_python')}

Finally, here's an example of how we can support prettier's built-in range functionality:

function! s:prettier(startline, endline)
  return printf(
        \ 'npx --no-update-notifier --silent --no-install prettier --range-start=%i --range-end=%i --stdin-filepath="%s"',
        \ line2byte(a:startline) - 1,
        \ line2byte(a:endline + 1) - 1,
        \ expand('%:p')
        \ )
endfunction
let g:vim_filetype_formatter_commands = {'javascript': function('s:prettier')}

Installation

If using vim-plug, place the following line in the Plugin section of your init.vim / vimrc:

Plug 'pappasam/vim-filetype-formatter'

Then run the Ex command:

:PlugInstall

I personally use vim-packager, so if you'd like to go down the "package" rabbit hole, I suggest giving that a try.

Full Documentation

From within Vim, type:

:help filetype_formatter

Key mappings

This plugin provides no default key mappings. I recommend setting a key mapping for normal mode and visual mode like this:

nnoremap <silent> <leader>f <Cmd>FiletypeFormat<CR>
xnoremap <silent> <leader>f :FiletypeFormat<CR>

Default configurations

Default configurations may be overridden by creating our own g:vim_filetype_formatter_commands dictionary. If you would like to map one filetype to another, see g:vim_filetype_formatter_ft_maps. See here for specifics on how to do this.

If you would like to use a formatter listed above in "Other Formatters", you'll first need to packadd vim-filetype-formatter and then add it to g:vim_filetype_formatter commands. Here is an example of how to override Python's formatter with the built-in configuration for ruff:

packadd vim-filetype-formatter
let g:vim_filetype_formatter_commands.python = g:vim_filetype_formatter_builtins.ruff

Non-standard code formatters

In the rare case where a required code formatter does not read from standard input and/or write to standard output, don't panic. With some effort, you can probably still create a working command by chaining the code formatter with standard Unix programs. See the following example, using nginxbeautifier:

\ 'nginx':
\   'dd status=none of=/tmp/nginx.conf >& /dev/null && '
\   .. 'nginxbeautifier --space 4 /tmp/nginx.conf >& /dev/null && '
\   .. 'cat /tmp/nginx.conf && '
\   .. 'rm /tmp/nginx.conf',
  1. dd: read vim-filetype-formatter's standard output as standard input, writing to a temporary file named /tmp/nginx.conf
  2. nginxbeautifier: read from the temporary file and modify that file in-place
  3. cat: write the contents of the temporary file to stdout
  4. rm: remove the temporary file to keep things tidy

It's not exactly pretty, but:

  1. Reality isn't always pretty
  2. We can use the command because it reads from standard input and writes to standard output

Batteries Included

LanguageDefault FormatterOther Formatters
bash/shshfmt
biblatexbibtool
cssprettier
gogofmt
graphqlprettier
htmlprettier
javascript/jsxprettier
jsonprettier
jsoncprettier
luastylua
markdownprettier
mdxprettier
nginxnginxfmt
ocamlocamlformat
prismaprettier_prisma
pythonblackruff
rstyler
rustrustfmtleptosfmt
scssprettier
svelteprettier_svelte
terraformterraform_fmt
tomltoml_sort
typescript/tsxprettier
yamlprettier
<!-- formatters --> <!-- languages -->

FAQ

How can I have per-project settings?

If using a recent version of Neovim, see :help 'exrc'.

" $XDG_CONFIG_HOME/init.vim
set exrc
" $PROJECT_PATH/.nvimrc
packadd vim-filetype-formatter
let g:vim_filetype_formatter_commands['python'] = g:vim_filetype_formatter_builtins['ruff']
let g:vim_filetype_formatter_commands['rust'] = g:vim_filetype_formatter_builtins['leptosfmt']