Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Following is what i would like to have. When the tab completion is ambiguous, and bash prints the list of possibilities. I would like it to colour the next character I should press inside every word in the list.

Following is what i have done so far. In my .bashrc i have defined the following function and have called the complete command

_colourunique() {
    local word=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=($(compgen -f -- "${word}"))
    if [[ "$word" ]] && [[ ${#COMPREPLY[@]} -gt 1 ]]; then
        local  w
        local  i=0
        for ((i=0;i<${#COMPREPLY[@]};i++)) ; do
            w=${COMPREPLY[$i]}
            n=${#word}
            COMPREPLY[$i]="${w:0:n}\033[91m${w:n:1}\033[0m${w:$((n+1))}"
        done
    fi
}

complete -D -F _colourunique

But it is not working... When i type

ls D[TAB]

It autocompletes as

ls D\033[91m

Instead of listing the possibilities Documents, Desktop etc. What could be going wrong here? Or is there some other direct way to accomplish this?

UPDATE 1:

I think i understand what is happening here. Since i add \033[91m to every word in COMPREPLY, bash sees this part is common to all, and autocompletes that common term into the command prompt itself. (instead of simply printing the list)

So I don't think this method of editing COMPREPLY array is the way to do it. Is there any other method?

UPDATE 2:

To preserve the uniqness, i tried to add a $i and \b in the string.

COMPREPLY[$i]="${w:0:n}$i\b\033[91m${w:n:1}\033[0m${w:$((n+1))}"

Now it prints the possible tab completions as following.

D0\b\033[91mo\033[0mwnloads  D1\b\033[91me\033[0msktop

Which means, the list is printed as such. There is no evaluation of \b or \033[91m characters. :-(

UPDATE 3:

Since the replies looks like, there is no way to accomplish what i want in bash (unless i shift to zsh). I decided to settle for another option. I will try to append the next unique key stroke to end of every word, so that it stands out.

Following is the code so far.

SanitiseString () {
    local String="$1"
    local j
    for j in \\ \! \@ \# \$ \% \^ \& \* \( \) \+ \{ \[ \] \} \| \; \: \" \' \, \? \ ; do
        String=${String//"$j"/\\"$j"}
    done
    echo "$String"
}

_colourunique() {
    saveIFS=$IFS
    IFS=$'\n'                                   
    local word=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=($(compgen -f -- "${word}"))
    if [[ "$word" ]] ; then
        local  w
        local  i=0
        for ((i=0;i<${#COMPREPLY[@]};i++)) ; do
            w="${COMPREPLY[$i]}"
            n=${#word}
            w=$(SanitiseString "$w")
            if  [[ ${#COMPREPLY[@]} -gt 1 ]] ; then
                COMPREPLY[$i]="$w :${w:n:1}"
            else
                COMPREPLY[$i]="$w"
            fi
        done
    fi
    IFS=$saveIFS
}

complete -D -F _colourunique

This will print the options with the next unique keystroke separated by :

But the code still has two irritating issues. which i have to solve

  1. It no longer appends the / at the end of autocompleted directories
  2. It no longer does the intelligent spacing after the auto complete.

Any suggestions?

share|improve this question
    
I don't think you can do what you are attempting. The escapes sequences used to format the output should not actually be part of the output, but bash simply doesn't provide a hook for custom formatting of the possible completions. –  chepner Apr 6 at 13:20
    
The easy answer is to switch to zsh, where this is a configuration option. –  Gilles Apr 6 at 22:50
    
Since it looks like I cannot do what i want in bash. I am trying to do a different thing instead. I have added an update which appends the next unique keyword separated by : to the list to print. –  indiajoe Apr 7 at 18:47

1 Answer 1

my .c is not so hot, but from reading around inside http://git.savannah.gnu.org/cgit/bash.git/snapshot/bash-master.tar.gz, it looks to me like COMPREPLY is nothing more than non-actioned text data. iow, even getting an Escape in there correctly ends up being printed as a non-magical/non-special representation of the characters we use to express them.

like \033 or \e isn't the single character "Escape", but the four or two characters of backslashes and zeros, threes, and Es.

I poked with various iterations of printf/echo/eval before diving into the .c to see how it actually handled the values in COMPREPLY.

might be wrong, but check strlist_print() in lib/sh/stringlist.c looks like COMPREPLY is a struct of type STRINGLIST (as defined in externs.h).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.