3

I was reading How do I get bash completion for command aliases? and I thought, that the answer by Shawn J. Goff needed a little something: less user setup so I wrote a little script that is intended to be sourced from your .bashrc, but it doesn't quite work, so hopefully someone can spot my error.

function make-completion-wrapper-1 () {
    local function_name="$2"
    local arg_count=$(($#-3))
    local comp_function_name="$(complete -pr $1|sed -e 's/^\(.* -F \)\([^ ]*\) [^ ]*$/\2/')"
    shift 2
    local function="
        function $function_name {
            ((COMP_CWORD+=$arg_count))
            COMP_WORDS=( "$@" \${COMP_WORDS[@]:1} )
            "$comp_function_name"
            return 0
        }"
    echo "$function"
    eval "$function"
}

function make-completion-wrapper-2 () {
    local function_name="$1"
    local alias_name="$2"
    local comp_function_base="$(complete -pr $3|sed -e 's/^\(.* -F\)\( [^ ]*\) [^ ]*$/\1/')"
    echo "$comp_function_base $function_name $alias_name"
    eval "$comp_function_base $function_name $alias_name"
}

[ -e ~/.cache/bash_alias_complete ] && rm ~/.cache/bash_alias_complete

alias | \
    sed \
        -e 's/^alias //' \
        -e '/^\([^=]\+\)='\''\1 /d' \
        -e "/'.*=/d" -e '/\$/d' \
        -e h \
        -e "s/.*='\([^ ]*\)\( .*\)'$/\1! \1\2/" \
        -e 'y/ -!/__ /' -eG -e 's!\n[^=]*='\''\(.*\)'\''! \1!' \
        -e 's/^/make-completion-wrapper-1 /p' \
        -e 's/^[^ ]* [^ ]* \([^ ]*\) .*$/\1/' \
        -e x \
        -e 's!='\''\([^ ]*\) .*$! \1!' \
        -e x \
        -e 's!^!make-completion-wrapper-2 !' \
        -e G \
        -e 'y/\n/ /' \
    > ~/.cache/bash_alias_complete

. ~/.cache/bash_alias_complete

I'm getting the following error when I pres the Tab key:

bash: COMP_POINT - : syntax error: operand expected (error token is "- ")

NOTE: The above code can be placed in a file, such as myfuncs.bash, which can then either be sourced directly in the shell or from $HOME/.bashrc.

For full change history on this code see https://github.com/hildred/scripts.git

hildred
  • 5,829
  • 3
  • 31
  • 43

1 Answers1

1

The error message COMP_POINT from the Bash Reference Manual:

COMP_POINT

The index of the current cursor position relative to the beginning of the current command. If the current cursor position is at the end of the current command, the value of this variable is equal to ${#COMP_LINE}. This variable is available only in shell functions and external commands invoked by the programmable completion facilities (see Programmable Completion).

Trying this out

I attempted to use your code as is. When sourcing everything up to the the last line works fine. When that line runs, . ~/.cache/bash_alias_complete I get errors. Too many to include here.

There seems to be some issues with the resulting being generated into the file, ~/.cache/bash_alias_complete.

Errors I encountered

I have the following aliases:

$ alias|grep cdc
alias cdl='cdctl -o1'
alias cdu='cdctl -o0'

And your sed command is letting this through, which then is getting propagated to my the cache file, resulting in these commands which cause the following errors:

$ make-completion-wrapper-1 cdctl _cdctl__o1 cdctl -o1
$ make-completion-wrapper-2 _cdctl__o1 cdl cdctl
$ make-completion-wrapper-1 cdctl _cdctl__o0 cdctl -o0
$ make-completion-wrapper-2 _cdctl__o0 cdu cdctl
bash: complete: cdctl: no completion specification
 _cdctl__o1 cdl

There are other examples, but the point is that the sed command isn't as tight as it probably needs to be, which is ultimately your problem you're encountering.

slm
  • 369,824
  • @hildred - I'd rather not since it includes my environment aliases and such. I'm not willing to share these things. – slm Nov 23 '13 at 20:31
  • ok, the design of the sed script is to take your list of aliases, ignore the ones that just add options to existing commands and all the aliases that play with environment variables then take the remaining aliases, figure out what command they call, lookup the expansion for the long command and use that for the expansion of the short command, with the long command passed into the expansion instead of the short. – hildred Nov 23 '13 at 20:40
  • @hildred - yeah I'm going through this now and I think that there is additional complexity that one can do in aliases that your approach isn't able to deal with. – slm Nov 23 '13 at 20:42
  • @hildred - I've added the 1st error I encountered. BTW, I tried your change and now the cache file is empty. I think you want to find a dash preceded by a space perhaps? – slm Nov 23 '13 at 20:48
  • @hildred - maybe this? -e '/ -[a-zA-Z0-9]/d'? Is the intent to delete any aliases that include a single and double dash? This can be accomplished like this: -e '/ [-]\{1,2\}[a-zA-Z0-9]/d' if so. – slm Nov 23 '13 at 20:54