Вложенный скрипт автодополнения bash

Я пытался добавить поддержку завершения bash в программу командной строки, которую я использовал в последнее время, но, похоже, я наткнулся на стену.

Вот команды и подкоманды, которые я хотел бы выполнять автоматически

  • Основная команда foo, для подкоманд version, process и help должно выполняться автодополнение. Дальнейшее автодополнение зависит от подкоманды.

    • Если пользователь вводит - после основной команды, автодополнение выполняет завершение для этих слов: --activate или --deactivate

    • Если пользователь вводит --deactivate, он должен выполнить автодополнение вывода команды bash (скажем, ls).

  • version: автодополнение не выполняется
  • process: автозаполнение по умолчанию для списка каталогов (включая текущий и родительский)

    • If the user enters -, autocompletion performs completion for these words: --color, --verbose and then stops afterward
  • Если пользователь вводит help, автодополнение будет для других подкоманд (process или version).

Вот моя текущая реализация скрипта автозаполнения (который плохо работает):

_foo() {
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    words=("${COMP_WORDS[@]}")
    cword=$COMP_WORD
    opts="process version help"

    case "$prev" in
    -*)
        local subopts="--activate --deactivate"
            COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
            case "$cur" in
                --deactivate)
                    COMPREPLY=( $(ls) )
                ;;
            esac
         ;;
    version)
        COMPREPLY=()
        ;;
    process)
        case "$cur" in
            -*)
                local subopts="--color --verbose"
                COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
                ;;
            *)
                COMPREPLY=( $(compgen -A directory))
                ;;
        esac
        ;;
    help)
        COMPREPLY=( $(compgen -W "process version" -- ${cur}) )
        ;;
   esac
   } 
 complete -F _foo foo

Вы, наверное, видите, что Bash также не является моей сильной стороной. Я думал о написании отдельных функций bash для каждой подкоманды, но пока не знаю, как это сделать. Если у вас есть предложения о том, как реализовать это, я был бы очень признателен.

Спасибо!


person bow    schedule 18.02.2012    source источник


Ответы (1)


В случае с возможными подкомандами на первом уровне мне немного непонятно. Должна ли быть возможность ввести foo --activate или foo - --activate? Последнее выглядит как-то странно, но подходит скорее под ваш код. Первый звучит более разумно, но подразумевает наличие --activate и т. д. в качестве глобального параметра, который следует рассматривать на том же уровне, что и ваши подкоманды.

Тем не менее вы пропустили значение по умолчанию, когда вы еще ничего не вводили. Попробуйте следующий код:

_foo() {
    local cur prev opts

    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    words=("${COMP_WORDS[@]}")
    cword=$COMP_CWORD
    opts="process version help"

    case "$prev" in
    -*)
        local subopts="--activate --deactivate"
        COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
        case "$cur" in
            --deactivate)
                COMPREPLY=( $(ls) )
            ;;
        esac
        return 0
         ;;
    version)
        COMPREPLY=()
        return 0
        ;;
    process)
        case "$cur" in
            -*)
                local subopts="--color --verbose"
                COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
                ;;
            *)
                COMPREPLY=( $(compgen -A directory))
                ;;
        esac
        return 0
        ;;
    help)
        COMPREPLY=( $(compgen -W "process version" -- ${cur}) )
        return 0
        ;;
   esac
   COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
   return 0
} 
complete -F _foo foo

который в основном такой же, как ваш, но: Внизу установите COMPREPLY для ваших подкоманд первого уровня, чтобы они были завершены. В случае ввода подкоманды вы должны вернуть (0), чтобы не дойти до финального оператора.

Приведенный пример будет работать с foo - --activate, что может не соответствовать вашим ожиданиям. Итак, если вы хотите ввести foo --activate, измените соответствующие строки на

    case "$prev" in
    --activate)
        COMPREPLY=()
        return 0
        ;;
    --deactivate)
        COMPREPLY=( $(compgen -W "$(ls)" -- ${cur}) )
        return 0
        ;;
    version)
    ...
person Karsten S.    schedule 21.02.2012