如何编辑和着色 bash 的选项卡完成列表

ind*_*joe 10 colors bash autocomplete

以下是我想要的。当标签完成模糊时,Bash打印可能性列表。我希望它为我应该在列表中的每个单词中按下的下一个字符着色。

以下是我到目前为止所做的。在我的 .bashrc 中,我定义了以下函数并调用了完整的命令

_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
Run Code Online (Sandbox Code Playgroud)

但它不起作用......当我输入时

ls D[TAB]
Run Code Online (Sandbox Code Playgroud)

它自动完成为

ls D\033[91m
Run Code Online (Sandbox Code Playgroud)

而不是列出可能性文档,桌面等。这里可能出了什么问题?还是有其他一些直接的方法来实现这一点?

更新1:

我想我明白这里发生了什么。由于我在 COMPREPLY 中的每个单词中都添加了 \033[91m,bash 认为这部分是通用的,并将该通用术语自动补全到命令提示符中。(而不是简单地打印列表)

所以我不认为这种编辑 COMPREPLY 数组的方法是这样做的。有没有其他方法?

更新 2:

为了保持唯一性,我尝试在字符串中添加 $i 和 \b 。

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

现在它打印可能的选项卡完成如下。

D0\b\033[91mo\033[0mwnloads  D1\b\033[91me\033[0msktop
Run Code Online (Sandbox Code Playgroud)

这意味着,列表是这样打印的。没有对 \b 或 \033[91m 字符的评估。:-(

更新 3:

由于回复看起来像,没有办法在 bash 中完成我想要的(除非我转向 zsh)。我决定接受另一种选择。我将尝试将下一个唯一的击键附加到每个单词的末尾,以使其脱颖而出。

以下是到目前为止的代码。

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
Run Code Online (Sandbox Code Playgroud)

这将打印带有下一个唯一按键的选项,以 分隔:

但是代码仍然有两个令人恼火的问题。我必须解决

  1. 它不再在自动完成目录的末尾附加 /
  2. 自动完成后不再进行智能间距。

有什么建议?

小智 0

我的 .c 不是那么热,但是从http://git.savannah.gnu.org/cgit/bash.git/snapshot/bash-master.tar.gz 的内部阅读来看,在我看来 COMPREPLY 仅此而已比未执行操作的文本数据。iow,即使在那里正确地得到一个转义符,最终也会被打印为我们用来表达它们的字符的非魔法/非特殊表示。

类似\033or\e不是单个字符“Escape”,而是四个或两个反斜杠字符以及零、三和 Es。

在深入 .c 之前,我研究了printf/ echo/的各种迭代,看看它实际上是如何处理COMPREPLY 中的值的。eval

可能是错误的,但签strlist_print()lib/sh/stringlist.c看起来像 COMPREPLY 是 STRINGLIST 类型的结构(如 中所定义externs.h)。