I have a command defined in my ftplugin/markdown.vim to maintain a consistent style, and check for any errors:

command! Lint !pandoc % -o % --columns=80

However, when I run :Lint I then need to hit L<CR> followed by :e.

Is there any way of defining this command such that it will reload automatically, with no further keypress?

1 Answer 1


Your command tells pandoc to filter your file (%) instead of your buffer. This is problematic because there's no guarantee that the content of the buffer and the content of the file are identical. What you need is a filter, not something that acts on actual files.

The default behavior of pandoc is to act as a filter, which happens to be exactly what you want: take text from stdin and return a filtered version of it to stdout:

:!pandoc --columns=80

But pandoc's default output format for markdown is HTML if you don't specify any so you should use -t markdown to force markdown output:

!pandoc -t markdown --columns=80

But even that is not enough to make a proper custom command:

command! Lint !pandoc -t markdown --columns=80

The first problem is that custom commands don't accept a range by default. This is easy to "fix" with :help :command-range:

command! -range=% Lint execute <line1> . "," . <line2> . "!pandoc -t markdown --columns=80"

At this stage, you can do :Lint or :24,67Lint or vjjjjj:Lint and get exactly what you want… But we still have three problems to address.

The second problem is that this command will leave the cursor on the last line of the buffer. This is not really a showstopper but… oh well! We can fix it with :help winsaveview() and :help winrestview():

command! -range=% Lint let myview = winsaveview() |
  \ execute <line1> . "," . <line2> . "!pandoc -t markdown --columns=80" |
  \ call winrestview(myview)

The third problem is that this command will also be available in non-markdown buffers because all custom commands are global by default. This is another easy fix thanks to :help :command-buffer:

command! -buffer -range=% Lint let myview = winsaveview() |
  \ execute <line1> . "," . <line2> . "!pandoc -t markdown --columns=80" |
  \ call winrestview(myview)

The fourth and last problem is a lot less severe than the others. It's just that ftplugin/markdown.vim is not really the right place for language-specific settings/mappings/commands due to the order in which filetype plugins are sourced:

#1 $HOME/.vim/ftplugin/markdown.vim
#2 $VIMRUNTIME/ftplugin/markdown.vim
#3 $HOME/after/ftplugin/markdown.vim

You should use $HOME/after/ftplugin/foo.vim for all your filetype specific needs.

Wow… What a ride!

  • Just to clarify on the last point though, I meant it's in .vim/ftplugin. Is that still wrong; it should be in after/ftplugin? Then when would I use the former?
    – OJFord
    Oct 17, 2016 at 1:13
  • Putting anything in $HOME/.vim/ftplugin/markdown.vim is risky because it is sourced before $VIMRUNTIME/ftplugin/markdown.vim which may or may not override some of your settings. Since $HOME/after/ftplugin/markdown.vim is sourced last, that file is the safest place for your markdown-specific settings.
    – romainl
    Oct 17, 2016 at 6:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.