bash-completion:添加带空格的引用建议

bash-completion:添加带空格的引用建议

我正在将 bash-completion 添加到现有工具中。

在有人传递-s标志后,我想提供几个关于 bash-completion 的选项:

  • Closed
  • Feedback
  • "In Progress"
  • New
  • Rejected
  • Resolved

里面的空间"In Progress"引起了问题。

#!/usr/bin/env bash
_remote-redmine()
{
    local cur

    COMPREPLY=()
    cur=${COMP_WORDS[$COMP_CWORD]}

    case "${COMP_WORDS[($COMP_CWORD-1)]}" in
        -s)
            s_opts=( "New" "In Progress" "Resolved" "Feedback" "Closed" "Rejected" )
            COMPREPLY=( $( compgen -W "${s_opts[*]}" -- "$cur") )
            ;;
    esac
    return 0
}
complete -F _remote-redmine remote-redmine

当我运行该工具时,我得到:

$ remote-redmine -s <tab><tab>
Closed    Feedback  In        New       Progress  Rejected  Resolved

但我想得到:

$ remote-redmine -s <tab><tab>
Closed    Feedback  "In Progress"       New       Rejected  Resolved

或者

$ remote-redmine -s <tab><tab>
Closed    Feedback  In\ Progress        New       Rejected  Resolved

我尝试过的事情:

  • s_opts=( ... "In\ Progress" ... ): 没有不同

  • s_opts( ... "In\\ Progress" ...): 没有不同

  • s_opts( ... "In\\\ Progress" ...): 两个选项是In\Progress

  • s_opts( ... "\"In Progress\"" ...): 没有不同

  • compgen -o nospace ...: 没有不同

  • compgen -o noquote ...: 没有不同

  • 至少compgen可以放In Progress一行,但这并不能转化为complete

    $ compgen -W 'New "In Progress"'
    New
    In Progress
    
  • 转义额外的引号有助于compgen,但这并不能转化为complete

    $ compgen -W 'New "\"In Progress\""'
    New
    "In Progress"
    
  • 转义空格三次确实有帮助,但仍然没有帮助;不能转化为complete

    $ compgen -W 'New In\\\ Progress'
    New
    In\ Progress
    
  • 我认为逃离该空间七次是有希望的,因为这样complete可以解决其中的一些问题,但这也没有帮助:

    $ compgen -W 'New In\\\\\\\ Progress'
    New
    In\\\ Progress
    ...
    $ remote-redmine -s <tab><tab>
    ...   In\\\  New  Progress ...
    
  • 绕过compgen会起作用,但随后我会失去单选项卡上的自动填充和双选项卡上的过滤功能

    COMPREPLY=( ... 'In\ Progress' ... )
    COMPREPLY=( ,,, '"In Progress"' ... )
    

答案1

这与分词和 IFS 的默认值有关,这并不奇怪。

compgen -W "${s_opts[*]}"

数组扩展使用 的第一个字符作为分隔符[*]将数组元素连接到单个字符串。IFS默认情况下它是空格,因此值中的空格和作为分隔符的空格之间的区别丢失了。幸运的是,compgen -W将参数解释为由字符分隔的值的字符串,因此如果您只是更改为类似的值或值中未出现的任何其他内容,IFS它可以正常工作。[*]IFS:

然后,在

COMPREPLY=( $( compgen ...) )

compgen您隐式地分割了使用打印的字符串IFS(并通过通配符传递它们),但compgen似乎打印了专门由换行符分隔的值。通过分割来做到这一点需要设置IFS换行符,但实际上更适合使用 来读取readarray,因为它无论如何都使用换行符并且不会通配符。

所以,你可以这样做

_remote-redmine() {
    local cur
    local IFS=:

    COMPREPLY=()
    cur=${COMP_WORDS[$COMP_CWORD]}

    case "${COMP_WORDS[($COMP_CWORD-1)]}" in
        -s)
            s_opts=( "New" "In Progress" "Resolves" "Feedback" "Closed" "Rejected" )
            readarray -t COMPREPLY < <( printf "%q\n" $(compgen -W "${s_opts[*]}" -- "$cur"))
            ;;
    esac
    return 0
}

或者,由于换行符在两个地方都有效,因此您可以像IFS=$'\n'以前一样设置并分割输出,但您仍然应该在函数的持续时间内禁用通配符,这是要保存和恢复的又一个全局状态。

答案2

这对我有用。我们不使用compgen,而是循环数组并添加前缀为 的项目$cur

_remote-redmine()
{
    local cur
    local item

    COMPREPLY=()
    cur=${COMP_WORDS[$COMP_CWORD]}

    case "${COMP_WORDS[($COMP_CWORD-1)]}" in
        -s)
            local s_opts=( "New" "In\ Progress" "Resolved" "Feedback" "Closed" "Rejected" )
            for item in "${s_opts[@]}"; do
                case "$item" in
                    ( "$cur"* )
                        COMPREPLY+=( "$item" )
                        ;;
                esac
            done
            ;;
    esac
    return 0
}
complete -F _remote-redmine remote-redmine

请注意我添加的反斜杠:"In\ Progress"。这是该项目的字面部分。当您键入In并点击时Tab,您将In\ Progress进入命令行:转义符现在位于双引号之外,因此处于活动状态:它可以防止单词拆分。

相关内容