COMPREPLY 默认情况下返回一个空格分隔的单词列表,但我想让它每行返回一个单词。我尝试在单词末尾添加换行符,并浏览了 compgen 和complete 的文档,但找不到任何内容。
这可能吗?
编辑:
抱歉我真的解释得很糟糕。我有一个通过complete -F 绑定到自动完成函数的脚本。当用户运行脚本时,按两次 Tab 键将通过 compgen 显示可能的选项列表。现在该函数具有如下代码行:
COMPREPLY=( $(compgen -W '$( ls ~/work/dev/jobs/ | cat )' -- $curword ) )
当用户点击选项卡时,这些目录将显示如下:
directory0 directory1 directory2 directory3
但我希望它们显示为:
directory0
directory1
directory2
directory3
我向 /r/bash 发布了一个类似的帖子,有人建议这样做
bind 'set completion-display-width 0'
这是有效的,然后我可以取消它
bind 'set completion-display-width -1'
现在的问题是,如果我在完整函数返回之前取消设置它,它不会产生任何效果,因此我在用户按 Enter 后在脚本中取消设置它。这工作正常,但如果用户开始使用自动完成功能,然后改变主意并删除他们输入的内容并返回到 shell,completion-display-width 仍将设置为 0。
还有其他方法可以解决这个问题吗?
答案1
completion-display-width
我是建议更改readline 变量的人/r/bash,但是您没有指定您只想让它在这一个完成功能上工作。
无论如何,在完成函数中,您可以检测它是由TAB(COMP_TYPE == 9) 还是由TABTAB(COMP_TYPE == 63) 触发,如果是后者,您可以用空格填充结果,以便它们填充整个宽度终端的。这是我能想到的最不黑客的事情。它看起来像这样:
_foo_complete() {
local i file files
files=( ~/work/dev/jobs/"$2"* )
[[ -e ${files[0]} || -L ${files[0]} ]] || return 0
if (( COMP_TYPE == 63 )); then
for file in "${files[@]}"; do
printf -v 'COMPREPLY[i++]' '%*s' "-$COLUMNS" "${file##*/}"
done
else
COMPREPLY=( "${files[@]##*/}" )
fi
}
complete -F _foo_complete foo
顺便说一句,你真的不应该解析 ls 输出。
答案2
要仅为特定完成函数修改 readline 变量,您可以在函数执行期间设置 readline 变量,然后将$PROMPT_COMMAND
其更改回来。
_foo_complete() {
# retrieve the original value
local width=$(bind -v | sed -n 's/^set completion-display-width //p')
if [[ $width -ne 0 ]]; then
# change the readline variable
bind "set completion-display-width 0"
# set up PROMPT_COMMAND to reset itself to its current value
PROMPT_COMMAND="PROMPT_COMMAND=$(printf %q "$PROMPT_COMMAND")"
# set up PROMPT_COMMAND to reset the readline variable
PROMPT_COMMAND+="; bind 'set completion-display-width $width'"
fi
# whatever the function normally does follows
COMPREPLY=(aa bb)
}
complete -F _foo_complete foo