Skip to main content

How to Use Vim's Quickfix and Location Lists

·1206 words·6 mins
Linux Learning Lab
Author
Linux Learning Lab
Writing about code, tools, and workflows.
Table of Contents

What is the Quickfix List?
#

The quickfix list is a navigable list of locations in your project. Each entry has a file, line number, and message. Vim lets you jump between these entries with simple commands.

Common sources that populate the quickfix list:

  • Compiler errors (:make)
  • Grep results (:grep, :vimgrep)
  • Lint output
  • Test failures
  • Any tool that outputs file:line:message format

Instead of manually opening files and jumping to line numbers, you let the quickfix list drive your navigation.

Basic Quickfix Commands
#

CommandAction
:copenOpen the quickfix window
:ccloseClose the quickfix window
:cnext or :cnJump to next entry
:cprev or :cpJump to previous entry
:cfirstJump to first entry
:clastJump to last entry
:cc 5Jump to entry 5
:clistList all entries

The typical workflow:

1. Run a command that populates the quickfix list
2. :copen to see the results
3. :cnext / :cprev to jump between them
4. Fix each issue
5. :cclose when done

Populating the Quickfix List
#

:make — Run your build tool
#

This is where quickfix originated — navigating C compiler errors:

" Run make (default)
:make

If your project uses a Makefile, Vim runs make, parses the output using errorformat, and populates the quickfix list with every error and warning. You jump directly to each one.

C example — compiling with gcc errors:

// main.c
#include <stdio.h>

int main() {
    int x = 10
    printf("Value: %d\n", y);
    return 0;
}
:make
" Quickfix list now contains:
"   main.c|5| error: expected ';' before 'printf'
"   main.c|6| error: 'y' undeclared

:cnext   " Jump to line 5 — add the semicolon
:cnext   " Jump to line 6 — fix the variable name

Configure :make for different build systems:

" Default (uses make)
set makeprg=make

" Build a single C file
set makeprg=gcc\ -Wall\ -Wextra\ -o\ %<\ %

" CMake project
set makeprg=cmake\ --build\ build

" Run with specific target
:make clean
:make all

:grep — Search across files
#

" Search for a pattern across all C source files
:grep "malloc" **/*.c

" Search headers too
:grep "struct node" **/*.{c,h}

" Search in a specific directory
:grep "error" src/

" Case-insensitive
:grep -i "warning" **/*.py

After running :grep, the quickfix list is populated with matches. Press Enter on the first result, then use :cnext to step through them.

:vimgrep — Vim’s built-in grep
#

" Search with a Vim regex
:vimgrep /function\s\+\w\+/ **/*.js

" Find all struct definitions in C headers
:vimgrep /^struct\s\+\w\+\s*{/ **/*.h

" Add to existing list instead of replacing
:vimgrepadd /TODO/ **/*.md

:vimgrep uses Vim’s regex engine and doesn’t depend on external tools. Slower on large projects, but consistent across systems.

:cexpr — Custom command output
#

Populate the quickfix list from any command:

" Run cppcheck static analysis
:cexpr system('cppcheck --template=gcc src/')

" Run Python linter
:cexpr system('pylint --output-format=parseable src/*.py')

" Run tests and capture failures
:cexpr system('pytest --tb=line 2>&1')

Navigating Efficiently#

Open the quickfix window
#

:copen

This splits the screen with a list of all entries. You can:

  • Press Enter on any line to jump to that location
  • Use j/k to browse the list
  • :cnext/:cprev to step through without the window focused

Jump without opening the window
#

If you prefer not to have the window open:

:cnext       " Next error
:cprev       " Previous error

Map keys for faster navigation
#

" In your .vimrc
nnoremap ]q :cnext<CR>
nnoremap [q :cprev<CR>
nnoremap ]Q :clast<CR>
nnoremap [Q :cfirst<CR>

Now ]q and [q step through the list like stepping through search results.

C Programming Workflow
#

Compile, fix, repeat
#

A typical C workflow using quickfix:

" Set up for your project
set makeprg=gcc\ -Wall\ -Wextra\ -std=c99\ -o\ main\ *.c

" Build
:make

" If there are errors, quickfix is populated automatically
:copen        " See all errors at once
:cnext        " Jump to first error, fix it
:cnext        " Next error
:make         " Rebuild to check your fixes

Find all uses of a function
#

:grep "parse_input" **/*.c **/*.h
:copen
" Now you can see every file and line where parse_input is called or declared

Find memory management issues
#

" Find all malloc calls without a corresponding free
:grep "malloc" **/*.c
:copen
" Review each allocation site

Navigate compiler warnings#

" Compile with all warnings
set makeprg=gcc\ -Wall\ -Wextra\ -Wpedantic\ -o\ %<\ %

:make
" Warnings appear in quickfix just like errors
:cnext   " Step through each warning

Multi-file C project with Makefile
#

# Makefile
CC=gcc
CFLAGS=-Wall -Wextra -std=c99
SRC=$(wildcard src/*.c)
OBJ=$(SRC:.c=.o)

main: $(OBJ)
	$(CC) $(CFLAGS) -o $@ $^
" Vim uses make by default, so just:
:make

" Errors from any source file appear in quickfix
" Vim opens the correct file and jumps to the right line

The Location List
#

The location list is identical to the quickfix list but scoped to a single window. Every window can have its own location list, while there’s only one global quickfix list.

QuickfixLocation List Equivalent
:copen:lopen
:cclose:lclose
:cnext:lnext
:cprev:lprev
:grep:lgrep
:vimgrep:lvimgrep
:make:lmake
:clist:llist

When to use which
#

  • Quickfix — project-wide results (build errors, project-wide search)
  • Location list — per-file results (lint for current file, local search) or when you want multiple lists visible in different splits

Filtering the Quickfix List
#

Keep only matching entries
#

" Only show errors containing "undefined"
:cfilter /undefined/

" Invert — remove entries matching a pattern
:cfilter! /warning/

Older and newer lists
#

Vim keeps a stack of quickfix lists. If you run :grep twice, you can go back:

:colder        " Previous quickfix list
:cnewer        " Next quickfix list
:chistory      " Show quickfix list history

Practical Workflows
#

Fix all compiler errors systematically
#

:make
:copen
:cfirst
" Fix the error
:cnext
" Fix the next one
:make
" Repeat until clean build

Find and update a function signature across a project
#

:grep "int process_data" **/*.c **/*.h
:copen
" Jump to each declaration and call site, update the signature

Search for a pattern and review all matches
#

:grep "TODO\|FIXME\|HACK" **/*.c
:copen
" Browse each note and decide what to address

Run :grep with ripgrep for speed
#

" In .vimrc — use ripgrep as the grep program
set grepprg=rg\ --vimgrep\ --smart-case
set grepformat=%f:%l:%c:%m

" Now :grep is fast even in huge projects
:grep "pattern" src/

Quickfix and the Dot Command
#

A powerful pattern: make a fix, then step and repeat.

" Find all uses of an old function name
:grep "old_func" **/*.c
:cnext

" Rename it
ciw new_func Esc

" Jump to next match and repeat
:cnext
.
:cnext
.

Best Practices
#

  • Map ]q and [q for quickfix navigation — you’ll use them constantly
  • Set grepprg to ripgrep or ag for fast project-wide searches
  • Use :cfilter to narrow results rather than re-running the search
  • Use the location list when you need per-window results and want to keep the global quickfix for something else
  • Use :colder/:cnewer to move between search results without losing previous lists
  • Combine quickfix with the dot command for efficient repetitive fixes across files
  • Set makeprg to your project’s build tool so :make gives you navigable errors
  • Compile with -Wall -Wextra in C — more warnings means more quickfix entries to catch issues early