You are not logged in.
Hello there,
I had a hard time trying to understand how programmable command line completion works in bash. After some fumbling around, I wrote the following into my bashrc:
_comp(){
local names=($(compgen -f $2))
local type0="-e :[^:]*"
if [ ${#names[@]} -gt 0 ]; then
case $1 in
cd) type0=$type0"directory" ;;
okular) type0=$type0"PDF" ;;
pdflatex) type0=$type0"LaTeX 2e document" ;;
vim) type0=$type0"ASCII "$type0"UTF-8" ;;
cat) type0=$type0"ASCII "$type0"UTF-8" ;;
esac
COMPREPLY=($( file ${names[@]} | grep $type0 | sed 's/:[^:]*$//' ))
return 0
else
return -1
fi
}
complete -o bashdefault -F _comp cd
complete -o bashdefault -F _comp okular
complete -o bashdefault -F _comp pdflatex
complete -o bashdefault -F _comp vim
complete -o bashdefault -F _comp cat
Inclusion of other commands should be obvious.
Since there are not too many example on the web, I wanted to ask the bash-gurus among us Archers if this looks like a reasonable approach to program completion, or if there are any major flaws.
PS.: I have read the according chapter in the bash manual (https://www.gnu.org/software/bash/manual/bash.pdf) plus its example for "cd" (p. 130-132), but it seemed like a complete overkill to me.
Last edited by Starfish (2016-06-24 15:52:59)
"Yesterday is history, tomorrow is a mystery, but today is a gift. That is why it is called the present." - Master Oogway
Offline
I don't think this is a good approach.
You're shelling out to external programs. This makes the function noticeably slow. You should strive to only use shell builtins.
This is also going to become unmaintainable for large completion functions. Personally, I use the pattern
local cur=${COMP_WORDS[COMP_CWORD]};
local prev=${COMP_WORDS[COMP_CWORD-1]};
# COMP_WORDBREAKS=${COMP_WORDBREAKS/=/}; special case
at the beginning of the function and then base the logic on $prev and $cur resp. doing matching on them. You can use COMP_WORDS for doing arbitrary lookahead and lookbehind.
Your function is also incorrect/incomplete. Create file named [ABC]
echo foo > "[ABC]"
and try to complete that file name using your function. You need to do proper escaping of strings you return to the shell as suggestions (printf %q). This is also only an obvious case; I can imagine that things can break in pretty hilarious ways, even with the seemingly complex default completion functions.
Perhaps you could base your stuff on the default _filedir function; it's not very long:
_filedir ()
{
local IFS='
';
_tilde "$cur" || return 0;
local -a toks;
local x tmp;
x=$( compgen -d -- "$cur" ) && while read -r tmp; do
toks+=("$tmp");
done <<< "$x";
if [[ "$1" != -d ]]; then
local quoted;
_quote_readline_by_ref "$cur" quoted;
local xspec=${1:+"!*.@($1|${1^^})"};
x=$( compgen -f -X "$xspec" -- $quoted ) && while read -r tmp; do
toks+=("$tmp");
done <<< "$x";
[[ -n ${COMP_FILEDIR_FALLBACK:-} && -n "$1" && ${#toks[@]} -lt 1 ]] && x=$( compgen -f -- $quoted ) && while read -r tmp; do
toks+=("$tmp");
done <<< "$x";
fi;
if [[ ${#toks[@]} -ne 0 ]]; then
compopt -o filenames 2> /dev/null;
COMPREPLY+=("${toks[@]}");
fi
}
Last edited by jsoy9pQbYVNu5nfU (2016-06-24 13:13:37)
Offline
You're shelling out to external programs. This makes the function noticeably slow. You should strive to only use shell builtins.
You're right, but the latency is like a jiffy for this small function.
Your function is also incorrect/incomplete. Create file named [ABC]
echo foo > "[ABC]"
and try to complete that file name using your function. You need to do proper escaping of strings you return to the shell as suggestions (printf %q).
That's strange, it worked for me. I created a test file just this way, typed "vim " (with the space), then hit TAB and got "vim [ABC]". It also worked with "vim [". And the file showed "foo".
This is also going to become unmaintainable for large completion functions.
With that I agree. For more complicated completion I will have to separate the functions for each command. I'll save your _filedir function and work myself through it.
Thank you for your feedback!
Last edited by Starfish (2016-06-24 13:43:28)
"Yesterday is history, tomorrow is a mystery, but today is a gift. That is why it is called the present." - Master Oogway
Offline