Is there a way to customize "Programmable Completion" in the current session?
In the bash_completion
mechanism it's the bash function _filedir_xspec()
that is responsible for filename and dirname completions. This funtion can be found in the script /etc/bash_completion
.
You can edit that function and add a line that contains your regex. For example use this function (it's a copy of the original function):
_filedir_xspec()
{
local IFS cur xspec
IFS=$'\n'
COMPREPLY=()
_get_comp_words_by_ref cur
_expand || return 0
# get first exclusion compspec that matches this command
xspec=$( awk "/^complete[ \t]+.*[ \t]${1##*/}([ \t]|\$)/ { print \$0; exit }" \
"$BASH_COMPLETION" )
# prune to leave nothing but the -X spec
xspec=${xspec#*-X }
xspec=${xspec%% *}
local -a toks
local tmp
toks=( ${toks[@]-} $(
compgen -d -- "$(quote_readline "$cur")" | {
while read -r tmp; do
# see long TODO comment in _filedir() --David
printf '%s\n' $tmp
done
}
))
# Munge xspec to contain uppercase version too
eval xspec="${xspec}"
eval xspec="!*.txt" #<---- HERE add your regex, that's the only line changed
local matchop=!
if [[ $xspec == !* ]]; then
xspec=${xspec#!}
matchop=@
fi
[[ ${BASH_VERSINFO[0]} -ge 4 ]] && \
xspec="$matchop($xspec|${xspec^^})" || \
xspec="$matchop($xspec|$(printf %s $xspec | tr '[:lower:]' '[:upper:]'))"
toks=( ${toks[@]-} $(
eval compgen -f -X "!$xspec" -- "\$(quote_readline "\$cur")" | {
while read -r tmp; do
[ -n $tmp ] && printf '%s\n' $tmp
done
}
))
[ ${#toks[@]} -ne 0 ] && _compopt_o_filenames
COMPREPLY=( "${toks[@]}" )
}
Notice the new part at line 32:
eval xspec="!*.txt"
This statement is later used in compgen
to remove all entries, that do not match the regular expression. I wouldn't recommend to edit the file /etc/bash_completion
. Instead make a new file with the content above and source
the file if needed:
source /path/to/file
Now, all commands/applications in the shell, that where completed by the function _filedir_xspec()
, complete now only with *.txt
filenames.
You can also use this only for certain programs, or your custom script or command.
For showing only files that have the txt
extension in the suggestion, simply write a shell script and source
in the current session:
# Autocomplete file /path/to/file/sample-completion.sh
# for the command `sample`
_sample(){
COMPREPLY=($(compgen -f -X "!.*[.][tT][xX][tT]$" -- "$2"))
}
complete -F _sample sample
And source it by calling:
$ source /path/to/file/sample-completion.sh
In this code, $2
is the current word being completed. The -- "$2"
part makes compgen
filter out only the suggestions that contain the current word being completed and put it into COMPREPLY
. Also, the -f
option tells compgen
to only look for files in the current directory. Last but not least the -X
option is a filter pattern (look here) that excludes matching file names. The !
in the beginning of pattern negates this behavior. As a result, only the files with .txt
extension will be shown. The $
sign at the end of the regex looks for matches that end with given pattern. The [.]
means it will look for a literal dot, not just any character - which is the default meaning of a dot in regex. The [tT][xX][tT]
part means the pattern will match all these situations: "txt, txT, tXt, tXT, Txt, TxT, TXT, TXt".