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 viwhere _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;}
Command argument completion of `~/bin/*` filenames from any directory in bash
bash;files;autocomplete
The easiest approach is to avoid stripping the path from $item when you add it to $COMPREPLY[$i]:_vi () {    local word=${COMP_WORDS[COMP_CWORD]};    local pat=~/bin/*    COMPREPLY=($(compgen -f -G $pat -- ~/bin/${word}));    return 0;}The list of possibles is shown without a path component, but on successful completion the path is inserted.Another approach is to extend vi itself with a shell script that looks in the current directory for the filename, and if not found then checks ~/bin/. But at this point it starts to make sense to have the editor equivalent of $CDPATH for completion directories rather than limiting the code to searching ~/bin/.