2

Я часами пытался заставить это работать и чувствую, что не приблизился.

Я пытаюсь сократить наш рабочий процесс, заполнив табуляцию имен каталогов из Mac OS X Terminal.

У нас есть внутренний инструмент, назовем его bob , который автоматически запускает команды в подмодулях git. То, что я хотел бы сделать, это заставить его автоматически заполнять имена подкаталогов. Проблема в том, что эти подкаталоги живут в статическом месте.

   project directory
   ->public
     ->submodules
       ->a-module
       ->another-module
       ->other-module
       ->some-module

Команды запускаются из верхнего каталога проекта следующим образом:

bob start bugfix anothermodule

Вместо того, чтобы вводить «другой модуль» полностью, что мы и делаем в настоящее время, я бы хотел, чтобы автозаполнение вкладки работало. Мы используем этот рабочий процесс много раз в день, и было бы здорово сэкономить несколько секунд и избежать опечаток.

Конечная цель:

bob start bugfix an<tab>

будет автозаполнение до

bob start bugfix anothermodule

Я попробовал CDPATH но быстро понял, что это не то, что мне нужно, так как это не после команды cd , а только моя специальная команда.

У меня установлена bash_completion но я не очень хорош в bash. Упоминание об этом, хотя в случае, если это может быть частью решения!

2 ответа2

1

Правильно, bash_completion - это решение. Я могу рассказать вам, что у меня есть в моей Ubuntu. Я надеюсь, что на Mac все по крайней мере похоже.

Существует файл /etc/bash_completion который содержит исходники /usr/share/bash-completion/bash_completion .

В каталоге /usr/share/bash-completion есть также подкаталог completions . Это место для сценариев. Давайте посмотрим на скрипт eject :

# bash completion for eject(1)                             -*- shell-script -*-

_eject()
{
    local cur prev words cword
    _init_completion || return

    case $prev in
        -h|--help|-V|--version|-c|--changerslot|-x|--cdspeed)
            return
            ;;
        -a|--auto|-i|--manualeject)
            COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
            return
            ;;
    esac

    if [[ $cur == -* ]]; then
        COMPREPLY=( $( compgen -W '$( _parse_help "$1" )' -- "$cur" ) )
        return
    elif [[ $prev == @(-d|--default) ]]; then
        return
    fi

    _cd_devices
    _dvd_devices
} &&
complete -F _eject eject

# ex: ts=4 sw=4 et filetype=sh

Даже не читая документацию, мы могли бы немного переработать ее и приспособить к вашему случаю. Для нас самая важная часть кода выше, где он говорит , что после -a --auto -i или --manualeject может быть on или off В вашем случае после bugfix вам нужно имя каталога.

(Или нет. У вас есть каталог another-module но вы используете аргумент anothermodule . Сейчас я предполагаю, что это опечатка. Если нет, ответ Энтони , я думаю, укажет вам правильное направление.)

Мы могли бы как-то извлечь эти каталоги, которые вы хотите, и заменить 'on off' , но может быть лучше использовать существующий код. После того, как я ввожу cd , bash автоматически заполняет каталоги, и он работает хорошо, даже если есть пробелы или специальные символы. Итак, давайте посмотрим на _cd() ; он находится в /usr/share/bash-completion/bash_completion , я не буду вставлять его здесь. Затем кажется, что критически важной частью этой функции является вызов _filedir -d . Непосредственно перед тем, как _filedir() определен, мы имеем:

# This function performs file and directory completion. It's better than
# simply using 'compgen -f', because it honours spaces in filenames.

Бинго.

Поэтому я скопировал скрипт eject под именем bob и отредактировал в виде:

# bash completion for bob                             -*- shell-script -*-

_bob()
{
    local cur prev words cword curdir
    _init_completion || return

    case $prev in
        bob)
            COMPREPLY=( $( compgen -W 'start stop foo bar' -- "$cur" ) )
            return
            ;;
        start)
            COMPREPLY=( $( compgen -W 'bugfix' -- "$cur" ) )
            return
            ;;
        bugfix)
            curdir=$(pwd)
            cd public/submodules/ 2>/dev/null && _filedir -d
            cd "$curdir"    
            ;;
    esac

} &&
complete -F _bob bob

Существующие сеансы bash не заметят этот файл, вам нужно запустить новый bash чтобы протестировать его.

Да, это быстрое и грязное программирование вуду, извините.

Обратите внимание, что мы спускаемся в public/submodules/ и возвращаемся. Обычно я бы использовал подоболочку:

export -f _filedir
( cd … && _filedir -d )

но похоже, что _filedir не будет работать таким образом.

1

Это расширение отличного ответа Камиля, которое удаляет дефис из части -module каждого имени подкаталога.

bugfix)
    curdir=$(pwd)
    cd public/submodules/ 2>/dev/null && _filedir -d
    # Strip the hyphen from `-module` in each sub-directory name.
    for ((i=0; i<${#COMPREPLY[@]}; i++)); do
        COMPREPLY[$i]="${COMPREPLY[$i]/-module/module}"
    done
    cd "$curdir"
    ;;

Есть еще возможности для улучшения этого раздела: вам, возможно, придется ввести дефис, т. Е. Набрать a - Tab, чтобы завершить его для amodule вместо выбора между amodule и anothermodule (дефис все еще удаляется функцией завершения).

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .