如何编辑 bash 的选项卡完成列表并为其着色

如何编辑 bash 的选项卡完成列表并为其着色

以下是我想要的。当制表符补全不明确时,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

但它不起作用......当我打字时

ls D[TAB]

它自动完成为

ls D\033[91m

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

更新1:

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

所以我不认为这种编辑 COMPREPLY 数组的方法是正确的方法。还有其他方法吗?

更新2:

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

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

现在它会打印可能的制表符补全,如下所示。

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

这意味着列表会照原样打印。没有对 \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

这将打印下一个唯一击键的选项,并用 分隔:

但该代码仍然存在两个令人恼火的问题。我必须解决这个问题

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

有什么建议么?

答案1

虽然这不完全是你要求的,但我决定发布这个答案,因为最初我和你有同样的想法,但最终我这样解决了,我发现它比着色更好。

可以将此选项设置为GNU 读行库:

完成前缀显示长度 未经修改显示的可能完成列表的公共前缀的字符长度。当设置为大于零的值时,在显示可能的补全时,长于该值的公共前缀将被替换为省略号。

例如这一行〜/.inputrc:

set completion-prefix-display-length 2

也成功了(当公共前缀长于两个字符时)。

答案2

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

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

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

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

相关内容