模拟 Bash 的 COMPREPLY 响应而不实际完成它
Simulate Bash's COMPREPLY response without actually completing it
重现步骤
在tmp上创建目录,在里面添加1个文件。
mkdir /tmp/testdir && touch /tmp/testdir/examplefile
在 /tmp/completion.sh
上粘贴下面的脚本
# BEGIN AUTOCOMPLETE
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) )
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
# END AUTOCOMPLETE
那就来源吧。
. /tmp/completion.sh
预期结果
$ 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,同时也像字母!
重现步骤
在tmp上创建目录,在里面添加1个文件。
mkdir /tmp/testdir && touch /tmp/testdir/examplefile
在
上粘贴下面的脚本/tmp/completion.sh
# BEGIN AUTOCOMPLETE 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) ) 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 # END AUTOCOMPLETE
那就来源吧。
. /tmp/completion.sh
预期结果
$ 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,同时也像字母!