模拟 Bash 的 COMPREPLY 响应而不实际完成它

Simulate Bash's COMPREPLY response without actually completing it

重现步骤


预期结果

$ foo.sh --restart examplefile <tab><tab>
examplefile           
$ foo.sh --restart examplefile <tab><tab>
examplefile        
$ foo.sh --restart examplefile <tab><tab>
examplefile     
$ foo.sh --restart examplefile <tab><tab>

取而代之的是什么

$ foo.sh --restart examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile

我希望建议显示为可能已完成,但并未实际完成(出于显示目的)。这个问题已经被问到 before,但到目前为止还没有答案。

关于-o nosort

我查看了那个选项,它只适用于 Bash 4.4+,我在我的 16.04 机器上试过但失败了。寻找更多全球解决方案

尝试以下 compspec.sh(基于 OP 的代码):

function _foo_complete()
{
    local comnum cur opts

    [[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;

    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    opts="--help --restart -h -r"

    if (( COMP_CWORD > comnum )); then
        COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
        if [[ ${#COMPREPLY[@]} -gt 0 ]]; then
            #
            # you can try COMPREPLY+=( zzz ) and see what's happening
            #
            COMPREPLY+=( ' ' )
        fi
        return
    fi

    if [[ ${cur} == -* ]]; then
        COMPREPLY=( $( compgen -W "${opts}" -- ${cur} ) )
        return 0
    else
        COMPREPLY=( $( for filelist in /tmp/testdir/""*; do echo ${filelist##*/}; done ) )
    fi
}

complete -F _foo_complete foo.sh


更新:

is it possible to move the empty string to end of completion, so it doesn't look like there are empty space?

如果你可以自己对完成候选进行排序,你可以使用complete -o nosort (需要Bash 4.4+)

根据您的完整要求编辑的代码:

_test(){
   COMPREPLY=(                                                                                                                      
      $( [[ "" == -* ]] && compgen -W'-a -ab -c' -- "" \                                                                
      || [[ -d test ]] && compgen -W'$(basename -a test/*)' -- "" | grep -v -w -f <(printf "%s\n" "${COMP_WORDS[@    ]}:1:((COMP_CWORD-1))"))
   )
}

if the test directory doesn't exist completion would work with current directory contents so we have to check it

options can be used multiple times as you didn't specify it. 

1 2 完成 -F _test 测试

你可以试试这个技巧;根据您的 OS,这可能适合您:

note:我将完成功能剥离到相关的 TabTab 功能

#!/bin/bash
mkdir -p /tmp/testdir && touch /tmp/testdir/examplefile

_foo_complete() {
    local dirpath=/tmp/testdir
    local nullglob=$( shopt -q nullglob && echo true || echo false )

    $nullglob || shopt -s nullglob
    COMPREPLY=( "$dirpath"/* )
    $nullglob || shopt -u nullglob

    COMPREPLY=( "${COMPREPLY[@]#"$dirpath"/}" )

    [ ${#COMPREPLY[@]} -eq 1 ] && COMPREPLY+=( $'\xC2\xA0' )
}
complete -F _foo_complete foo.sh

后记:

它与@pynexj 的想法基本相同:向 COMPREPLY 添加第二个不可见元素,从而禁用 Tab 自动完成同时保留 TabTab 列表。

现在的问题是 bash 自动排序 COMREPLY,因此,ASCII space 字符在数字上是第一个 printable 字符,它将显示为列表的第一列。

为了解决这个问题,我尝试了 UTF-8 字符集中的几乎所有其他白色-space 字符,它们都被排序到与 ASCII space 字符相同的级别; NON-BREAKING-SPACE 以外的所有内容,这就是我在这里使用的内容。

该修复程序不是完整的证明,因为有很多 UTF-8 字符将在它之后排序,最重要的是,它根据 OS 得到不同的处理:一些 sort实现将赋予它与 ASCII space 字符相同的等级,而其他实现则不会。想一想,NON-BREAKING-SPACE从概念上讲是什么? 是白色的-space,同时也像字母!