[Bash-completion-devel] script to generate bash completions

Andreas Politz politza at fh-trier.de
Tue Oct 28 03:29:06 UTC 2008


On Fri, 24 Oct 2008 19:12:01 +0200, Andreas Politz wrote:

 > > David Paleino wrote:
 >> > > On Mon, 20 Oct 2008 20:03:57 +0200, A.Politz wrote:
 >>> > >> _dpkg_source contains a inappropriate exit statement, which forces
 >>> > >> the shell to exit. I suppose this should be 'return' instead.
 >>> > >>
 >>> > >> Reproduce: Open a bash-shell , type '_dpkg_source<RET>'.
 >> > >
 >> > > Why are you calling _dpkg_source() directly?
 >> > >
 >> > > David
 >> > >
 > >
 > > I have written a wrapper around bashs completion mechanism
 > > in order to use it programatically.

Uhm, interesting. Would you please keep
<bash-completion-devel at lists.alioth.debian.org> informed?
It would be interesting to integrate what you're doing upstream. What are you
using to achieve that?

Hi, I am attaching the script here. It's working for my needs, but I doubt it
is fully compatible. Come to think about it, maybe it would be easier to

- patch bash so that it does not invalidate COMP_WORDS etc.
- or only wrap the -F argument and set them back up

I am not writing many shell scripts, this is probably painfull to read
for some people.

-ap

$ cat gencomp.bash


# if declare -f quote_readline > /dev/null; then
#     quote_readline () { echo "$1" ; } ;
# fi;


gencomp ()
{
     #gencomp 'apt-get ' | xargs -n1 -0
     local IFS=$' \t\n';

     COMPREPLY=();
     COMP_LINE="$*";
     COMP_POINT=${#COMP_LINE};
     COMP_WORDS=($@);
     COMP_CWORD=$((${#COMP_WORDS[@]} - 1));

     local compfunc_args="";
     local complete_cmd="";
     local to_complete="";
     local got_completion=0;

     #complete options
     local add_slash=0;
     local f_arg=0;
     local d_arg=0;
     local plusdirs=0;
     local prefix="";
     local suffix="";
     local filterpat="";
     local psx_opts="";
     local globpat="";
     local action="";
     local wordlist="";
     local dirnames=0;
     local default=0;

     if [ $COMP_CWORD -ge 0 ] ;then

         if [ "${COMP_LINE: -1:1}" == " " ] ;then
             let ++COMP_CWORD ;
             COMP_WORDS[$COMP_CWORD]="";
         fi;
	to_complete=${COMP_WORDS[@]: -1:1};
	
	if [ $COMP_CWORD -gt 0 ] ;then
             compfunc_args="${COMP_WORDS[0]} ${COMP_WORDS[$COMP_CWORD]}";
             if [ $COMP_CWORD -gt 1 ];then
		compfunc_args+=" ${COMP_WORDS[$(($COMP_CWORD - 1))]}";
             fi;
             complete_cmd=$(complete 2>/dev/null -p ${COMP_WORDS[0]});
         fi;
     fi;

     if [ -n "$complete_cmd" ]; then
	echo -ne "$complete_cmd\0";
         eval "set $complete_cmd";
         shift;
         while [ $# -gt 1 ]; do
             case $1 in
                 -F)
                     eval "$2 $compfunc_args";
                     shift ;;
                 -C)
                     shift ;;
                 -o)
                     case $2 in
                         filenames) add_slash=1 ;;
                         plusdirs) plusdirs=1 ;;
                         default|bashdefault) default=1;;
                         dirnames) dirnames=1;;
		    esac;
                     shift ;;
                 -A)
                     case $2 in
                         directory) d_arg=1 ;;
			filenames) f_arg=1 ;;
                         *) action+="-A $2 ";
                     esac;
                     shift ;;
                 -[abceghjksouv])
                     action+="$1 " ;;
                 -f)
                     f_arg=1 ;;
                 -d)
                     d_arg=1;;
                 -G)
                     globpat="-G $2";
                     shift ;;
                 -W)
                     wordlist="-W $2";
                     shift ;;
                 -P)
                     prefix="-P $2 ";
                     shift ;;
                 -S)
                     suffix="-S $2 ";
                     shift ;;
                 -X)
                     filterpat="-X $2 ";
                     shift ;;
             esac;
             shift;
         done;

         psx_opts="$prefix$suffix$filterpat";
         got_completion=${#COMPREPLY[*]};

	eval "compgen $action $globpat $wordlist $suffix $prefix $filterpat -- \"$to_complete\"" | gencomp_echo $(test $add_slash -ne 0);

	IFS=$'\n';
	if [ -n "$psx_opts" ] ;then
	    eval "compgen -W'\${COMPREPLY[*]}' $suffix $prefix  $filterpat" | gencomp_echo $(test $add_slash -ne 0);
         else
	    echo "${COMPREPLY[*]}" | gencomp_echo $(test $add_slash -ne 0);
         fi;
         IFS=$' \t\n';

         if [ $f_arg -ne 0 ] ; then
             eval "compgen -f $suffix $prefix $filterpat  -- \"$to_complete\"" | gencomp_echo "add_slash";
         elif [ $d_arg -ne 0 ] ;then
             eval "compgen -d $suffix $prefix $filterpat  -- \"$to_complete\"" | gencomp_echo "add_slash";
         fi;

	if [ $plusdirs -ne 0 ] ;then
             compgen -d  -- "$to_complete" | gencomp_echo "add_slash" ;
         fi;

	
         if [ $got_completion -eq 0 ] ;then
	    if [ 0 -ne $dirnames ] ;then
                 compgen -d  -- "$to_complete" | gencomp_echo "add_slash";
             elif [ 0 -ne $default ] ;then
		compgen -f -- "$to_complete" | gencomp_echo "add_slash" ;
	    fi;
	fi;

     else
         echo -ne "no complete definition\0";

	if [ 0 -eq $COMP_CWORD ]; then
             compgen -A alias -A enabled -A command -A function -- "$to_complete" | gencomp_echo;
	elif [ $COMP_CWORD -gt 0 ] && [ "${to_complete:0:1}" == "$" ]; then
	    compgen -P'$' -v -- "${to_complete:1}" | gencomp_echo;
	elif [ $COMP_CWORD -gt 0 ]; then
	    compgen -f -- "$to_complete" | gencomp_echo "add_slash";
	fi;
     fi;
     return 0;
} ;

gencomp_echo ()
{
     while read comp; do
	if $1 && [ -d "$comp" ] && [ "${comp: -1:1}" != "/" ] ; then
             echo -ne "$comp/\0";
	else
             echo -ne "$comp\0";
	fi;
	got_completion=1;
     done;
} ;



More information about the Bash-completion-devel mailing list