DEV Community

Peter Benjamin (he/they)
Peter Benjamin (he/they)

Posted on

How To Get Make Target Tab Completion in Vim

Table of Contents

Problem

If you use make frequently, you may be aware that you can tab complete targets in bash. For example, $ make cl<TAB> ins<TAB> may autocomplete to clean then install.

In vim, however, if you type :make <TAB>, by default, vim attempts to autocomplete file names.

This blog post will show you how you can get vim to autocomplete <TAB> with target names from your Makefile instead.

Solution

I recently came across this StackOverflow question, How to list all targets in make?, in which the answer is bash's completion logic:

make -qp |
    awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' |
    sort -u
Enter fullscreen mode Exit fullscreen mode

This will print out a newline-delimited list of possible targets from the Makefile in your current working directory.

With this set of commands, we can write a custom vimscript function that executes them and returns the output as completion candidates for a vim command:

function! MakeCompletion() abort
    return systemlist('make -qp | awk -F'':'' ''/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'' | grep -v Makefile | sort -u')
endfunction

command! -nargs=* -complete=customlist,MakeCompletion Make !make <args>
Enter fullscreen mode Exit fullscreen mode

This alone is a great accomplishment. If you type :Make <TAB>, you can cycle through all the possible make targets!

However, you may notice that if you type part of a target name and hit <TAB>, vim will ignore the partial input and cycle through from the beginning of the list.

Improved

If you read :help :command-completion-customlist, you will discover that the function can take 3 arguments:

The function arguments are:
    ArgLead     the leading portion of the argument currently being completed on
    CmdLine     the entire command line
    CursorPos   the cursor position in it (byte index)
Enter fullscreen mode Exit fullscreen mode

So let's modify our MakeCompletion() function to support filtering results based on ArgLead:

function! MakeCompletion(A,L,P) abort
    let l:targets = systemlist('make -qp | awk -F'':'' ''/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'' | grep -v Makefile | sort -u')
    return filter(l:targets, 'v:val =~ "^' . a:A . '"')
endfunction

command! -nargs=* -complete=customlist,MakeCompletion Make !make <args>
Enter fullscreen mode Exit fullscreen mode

Now, when you type :Make cl<TAB> ins<TAB>, it will successfully auto-complete to :Make clean install.

I hope you find this short vim tip helpful.

For more vim goodies, check out my vimrc.

Happy hacking!

Discussion (0)