A basic bash feature is the completion of commands stored in the various bin directories, regardless of the current working directory. This allows users to keep commands and binaries organized without requiring them to specify full paths from whichever directory they need to be run.
Exactly how bash provides this command completion before I run these bin files, I think, from a design standpoint, it makes sense to expect the same command completion before I edit them.
In my particular case this means modifying the completion function of my editor, vi
, so it includes filenames not only from my current working dir but also from my ~/bin/
(I don't actually care about adding commands from the other bins).
A simple modification of this SO answer does this:
$ source _vi
$ complete -f -F _vi vi
where _vi is defined as:
_vi ()
{
local word=${COMP_WORDS[COMP_CWORD]};
local pat="~/bin/*"
COMPREPLY=($(compgen -f -G "$pat" -- "~/bin/${word}"));
i=0
for item in "${COMPREPLY[@]}"; do
COMPREPLY[$i]="${item##*/}"
i+=1
done;
return 0;
}
But vi needs to be passed full paths to open the file!
So my question is: How can I tab-complete filenames from ~/bin/
but still pass the full paths to vi
? Is this only a |
dream? Should I try a wholly different approach?
Bonus points if you can help me color these ~/bin/*
filenames differently from the files actually in the working directory when I pull up all the possible completions with vi (TAB)(TAB)
!
EDIT:
Below is the function I'm using, based on @roaima's answer and their suggestion for generalize below. It's easy to add directory-independent completion access for files in directories other than the two (binaries and config files) that I care about.
_vi ()
{
local word=${COMP_WORDS[COMP_CWORD]};
local bin_dir="~/bin/"
local dot_dir="~/dotfiles/"
COMPREPLY=($(compgen -f -G "$bin_dir*" -- "$bin_dir${word}"));
COMPREPLY+=($(compgen -f -G "$dot_dir*" -- "$dot_dir${word}"));
return 0;
}