2

So I'm just starting to learn about bash completion scripts, and I started to work on one for a tool I use all the time. First I built the script using a set list of options:

_zf_comp() 
{
    local cur prev actions
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    actions="change configure create disable enable show"

    COMPREPLY=($(compgen -W "${actions}" -- ${cur}))  
    return 0
}
complete -F _zf_comp zf

This works fine. Next, I decided to dynamically create the list of available actions. I put together the following command:

zf | grep "Providers and their actions:" -A 100 | grep -P "^\s*\033\[36m\s*zf" | awk '{gsub(/[[:space:]]*/, "", $3); print $3}' | sort | uniq | awk '{sub("\-", "\\-", $1); print $1}' | tr \\n " " | sed 's/^ *\(.*\) *$/\1/'

Which basically does the following:

  • Grabs all the text in the "zf" command after "Providers and their actions:"
  • Grabs all the lines that start with "zf" (I had to do some fancy work here 'cause the ZF command prints in color)
  • Grab the second piece of the command and remove any spaces from it (the spaces part is probably not needed any more)
  • Sort the list
  • Get rid of any duplicates
  • Escape dashes (I added this when trying to debug the problem—probably not needed)
  • Trim all new lines
  • Trim all leading and ending spaces

The above command produces:

$ zf | grep "Providers and their actions:" -A 100 | grep -P "^\s*\033\[36m\s*zf" | awk '{gsub(/[[:space:]]*/, "", $3); print $3}' | sort | uniq | awk '{sub("\-", "\\-", $1); print $1}' | tr \\n " " | sed 's/^ *\(.*\) *$/\1/'
change configure create disable enable show 
$

So it looks to me like it's producing the exact same string as I had in my original script. But when I do:

_zf_comp() 
{
    local cur prev actions
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    actions=`zf | grep "Providers and their actions:" -A 100 | grep -P "^\s*\033\[36m\s*zf" | awk '{gsub(/[[:space:]]*/, "", $3); print $3}' | sort | uniq | awk '{sub("\-", "\\-", $1); print $1}' | tr \\n " " | sed 's/^ *\(.*\) *$/\1/'`

    COMPREPLY=($(compgen -W "${actions}" -- ${cur}))  
    return 0
}
complete -F _zf_comp zf

My autocompletion starts acting up. First, it won't autocomplete anything with an "n" in it, and second, when it does autocomplete ("zf create" for example) it won't let me backspace over my completed command.

The first issue I'm completely stumped on. The second I'm thinking might have to do with escape characters from the colored text.

Any ideas? It's driving me crazy!

inxilpro
  • 185
  • 2
  • 6

1 Answers1

2

One thing I find useful is to create a debug function that outputs to another terminal:

debug() { echo "$@" >/dev/pts/0; }; export -f de

Then you can call it from within your completion function with contents of variables, etc., and it won't interfere with its own output while you're testing it.

You might try changing your tr to use quotes and see if that fixes your "n" problem:

tr '\n' ' '

Pipe the output of your grep through cat -v to see if you're missing any escape sequences.

Also, it may speed things up if you can avoid calling so many external commands.

Dennis Williamson
  • 62,149
  • 16
  • 116
  • 151