In vim quickfix
feature consists of a dedicated buffer that holds the results,
such as grep and make, and various commands to handle it. It’s a feature that
is commonplace in IDEs, but in vim you can combine it with other features to
make your editing operations much more efficient.
We have a :make
and a :grep
command, and they play nicely with the quickfix
feature.
How does it work?
- Execute the external command with the specified argument.
- Parses the output of file names, line numbers, messages, etc.
- Makes a list that can be used for jumps
To open the quickfix
window with :copen
and close with :cclose
. In the
buffer we have a list and hit enter
on them will jump to that file on that
specific line.
When we call :make
it uses the program specified in grepprg
, and :grep
uses makeprg
. We can play with these variables to get things done. If the
output format is not right, we can configure it with grepformat
and
errorformat
.
Bu default it will print out to stdout
and jumps to the first match, we
sometimes it’s useful, but for me it’s mostly annoying, to disable this we can
call :silent grep!
where silent
will suppresses the output and the !
will
tell the command to do not jump to the first result.
What can we use in format
Vim has a very nice and detailed :help errorformat
, but here is a shorter
list:
%f
: file name (finds a string)%o
: module name (finds a string)%l
: line number (finds a number)%c
: column number (finds a number representing character column of the error, byte index, a is 1 character column)%n
: error number (finds a number)%m
: error message (finds a string)%r
: matches the “rest” of a single-line file message %O/P/Q%%
: the single ‘%’ character%s
: search text (finds a string)%E
: start of a multi-line error message%W
: start of a multi-line warning message%I
: start of a multi-line informational message%N
: start of a multi-line note message%A
: start of a multi-line message (unspecified type)%>
: for next line start with current pattern again%C
: continuation of a multi-line message%Z
: end of a multi-line message
Multi-line can tricky, let’s see an example. We have output in this format:
Error 275
line 42
column 3
' ' expected after '--'
To match this, we can use:
set errorformat=%EError\ %n,%Cline\ %l,%Ccolumn\ %c,%Z%m
Why is it good?
If we have a nice quickfix list, we can jump between them with :cnext
and
:cprevious
, so we can list all the errors, jump to the first one, fix it, call
:next
fix it, and so on.
Use The Silver Searcher or Ripgrep (grep
)
By default it uses grep
, but we can change with grepprg
:
" Set grepformat
set grepformat=%f:%l:%m
" The Silver Searcher
set grepprg=ag\ --vimgrep\ $*
" Ripgrep
set grepprg=rg\ --vimgrep
Git grep (grep
)
" Set grepformat
set grepformat=%f:%l:%m
" Use git grep
set grepprg=git\ --no-pager\ grep\ -n\ --no-color
Use golangci-lint (make
)
set errorformat=%E%f:%l:%c:\ %m,%C%s,%C%s
set makeprg=golangci-lint\ run
Location list
The quickfix buffer is unique, we can have only one, sometimes it would be useful if we have multiple list and we can do that with location list.
This is a cool feature of quickfix, you open if once and all :make
or :grep
will update that buffer. With location list, we can have multiple ones open and
when we call :make
or :grep
it will not update the buffer we already have.
Make our life easier with :compiler
Usually we have more than on tools and it would be painful to set makeprg
and
errorformat
all the time. Fortunately we have a tool to do that and it’s call
:compiler
. We can define compiler sets in $VIM/compiler/
.
For example we can define a compiler called golangci
in
~/.config/nvim/compiler/golangci.vim
(or ~/.vim/compiler/golangci.vim
):
if exists("current_compiler")
finish
endif
let current_compiler = "golangci"
if exists(":CompilerSet") != 2
command -nargs=* CompilerSet setlocal <args>
endif
CompilerSet errorformat=%E%f:%l:%c:\ %m,%C%s,%C%s
CompilerSet makeprg=golangci-lint\ run
With this compiler we can switch to this specific compiler when we want to use
it with :compiler golangci
. It does nothing but updates the errorformat
and
makeprg
variables. With :compiler!
it will be global, otherwise it sets only
for the buffer.