2

I want to be able to lint my code from within vim, using tools like clang-format and yapf and I'd rather do this without installing a more complex plugin.

I can pipe the current buffer through a text processing command:

:%!clang-format

However, if my buffer contents results in an error for the external command, my buffer will be replaced with stderr output and I will have to reset this manually (with an undo).

Is there any way to only replace the buffer if the text-processing command returns exit success?

I know I can undo but, ideally, I would like to be able to run this on vim exit but I can't risk the buffer being clobbered. This has other applications than linting, so a more general solution than just install the xxx plugin would be appreciated, if anyone knows of one!

1

2 Answers 2

4

Hmmm. Good question. Is there really not a Vim mechanism for dealing with this? I can't recall seeing one.

If there's not I was able to leverage Bash semantics to get something to work. I'm using sort as an example command as it's a common filter and easy to make fail...

Valid invocation:

:%!sort -n 2> /dev/null || cat %

Result: the buffer contents are sorted.

Invalid invocation (simulating any error condition):

:%!sort -x 2> /dev/null || cat %

Result: the buffer contents are undisturbed.

So the general pattern is:

:%!{your command and args} 2> /dev/null || cat %

2> /dev/null discards any error messages (assuming they are properly emitted from stderr). Alternatively, you could send error output to a temporary file so at least you can diagnose things when there's a failure. Just replace /dev/null with a valid path/filename.

A hack? Not in the context of Bash. In this Vim context...perhaps. Should be pretty steady for any filtering as long as you're not doing anything else with redirects or the like.

This can, of course, be made a little more convenient by integrating it into a user command.

3
  • 2
    the || cat % bit was what I needed. I had already tried redirecting the output. Upvoted. Thank you
    – moo
    Commented Jul 24, 2021 at 16:56
  • 1
    This is what I use btw: github.com/arp242/dotfiles/blob/master/vim/vimrc#L497-L501 – a little bit of ceremony around it to make it a bit more smooth. The undjoin doesn't quite work as I'd like, but haven't really looked at it much. Also, errors fail very silently which isn't super-great. Commented Jul 24, 2021 at 17:04
  • 1
    It was useful, thanks
    – moo
    Commented Aug 4, 2021 at 15:21
0

Not really a plugin, but you'll need a few lines of VimScript. Sort of this:

let result = systemlist('clang-format', bufnr())
if v:shell_error != 0
    throw "failure"
endif
call deletebufline('', 1, '$')
call setline(1, result)

Then pack it into a function, bind it to some key etc.etc.

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.