Как объединить автозаполнение zsh для аргументов функции-обертки и существующей команды

40

Я работаю в основном в gvim и многих терминалах. Первоначально я предпочитал открывать все мои файлы в одном экземпляре vim. Для этого я использовал псевдоним, чтобы открывать файлы с моих терминалов на текущем «сервере vim».

alias rv="gvim --remote-silent"

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

# main function
rv() {
    local args options server

    options=$(getopt -o hils:t: -l "help,info,list,set:,target:" -- "$@")

    if [[ $? -ne 0 ]]; then
        echo "Failed to parse options."
        return 1
    fi

    # a little magic, necessary when using getopt
    eval set -- "$options"

    # go through the options with a case and use shift to analyze one option at a time.
    while true; do
        case "$1" in
            -h|--help)
                echo "Usage: $0 [-hil] [--help] [--info] [--list]";
                echo "       $0 {-s | --set} <name> [<file1 file2...>]";
                echo "       $0 {-t | --target} <name>] <file1 file2...>";
                return 0;;
            -i|--info)
                gvim_show_info;
                return 0;;
            -l|--list)
                gvim_list_servers;
                return 0;;
            -s|--set)
                gvim_set_server_name ${2:u};
                shift 2;;
            -t|--target)
                server="$2";
                shift 2;;
            --)
                shift;
                break;;
        esac
    done

    if [[ "$#" -eq 0 ]]; then
        # if no files specified...
        if [[ -n "$server" ]]; then
            # throw error if --target option was specified.
            echo "Error!  --target requires one or more filenames."
            return 1;
        fi
    else
        # if files were specified...
        if [[ -n "$server" ]]; then
            # if --target was specified
            gvim_run_remote $server "$@"
        else
            gvim_run_remote $(gvim_get_default_server) "$@"
        fi
    fi

    return 0;
}

Теперь у этого нового rvесть свои варианты. Я могу использовать это, чтобы:

  • список доступных серверов vim (-l --list)
  • установить сервер vim по умолчанию для текущей оболочки (-s --set)
  • показать сервер vim по умолчанию (-i --info)
  • открывать файлы на определенном сервере vim (-t --target)
  • открыть файлы на сервере vim по умолчанию: rv files...

Тем не менее, поскольку я использую функцию rvвместо псевдонима, я теряю завершение zsh, которое ранее мне нравилось. Я прочитал о создании функции завершения _rv, которая покажет rvопции, но я хочу объединить мои варианты завершения с существующими вариантами завершения vim. Я знаю, что могут быть некоторые конфликты с rv's' -sи vim's' -s, но я полагаю, что я могу справиться с этим элегантно с --разделителем.

TLDR; Итак, как мне создать скрипт завершения, который сочетает в себе _argumentsопции для обоих _rvи _vim? Я предпочитаю использовать повторно, _vimесли это возможно, вместо копирования в список своих аргументов _rv.

Вот мой _rv. Обновлено 2014/6/10 16:10

#compdef rv

_rv() {
    typeset -A opt_args
    local alternatives

    alternatives=(
        'args:rv options:_rv_options'
        'files:file:_vim_files'
    )

    _alternative $alternatives && return 0

    return 1
}

_rv_options() {
    local arguments

    arguments=(
        '(-i -l -s -t --info --list --set --target)'{-h,--help}'[Print usage info.]'
        '(-h -l -s -t --help --list --set --target)'{-i,--info}'[Print default vim server. As stored in $GVIM_SERVER.]'
        '(-i -h -s -t --info --help --set --target)'{-l,--list}'[Print list of existing vim servers.]'
        '(-i -h -l -t --info --help --list --target)'{-s,--set}'[Set default vim server for the current shell.]:vim servers:_rv_vim_servers'
        '(-i -h -l -s --info --help --list --set)'{-t,--target}'[Open files in a particular vim server.]:vim servers:_rv_vim_servers'
        )

    _arguments -s -C $arguments && return 0

    return 1
}

_rv_vim_servers() {
    local -a servers
    servers=( ${(f)"$(_call_program servers vim --serverlist 2>/dev/null)"} )
    _wanted servers expl server compadd -M 'm:{a-z}={A-Z}' -a servers && return
}

# invoke the completion command during autoload
_rv "$@"

Текущее поведение

В настоящее время _rvзавершение будет полезным, но не идеальным.

  • Когда я печатаю rv <TAB>, я не вижу опции vim. Отображаются только параметры rv и пути к файлам. _vimзаканчивает пути к файлам для меня, так что ура!
  • Когда я печатаю rv -s <TAB>, я вижу список серверов vim, но также отображаются пути к файлам. Файл не разрешен в этой точке в команде, и не должен появляться в автозаполнении.

Ожидаемое поведение

  • Когда я печатаю rv <TAB>, я ожидаю увидеть: 1) опции rv, 2) опции vim, 3) список путей к файлам
  • Когда я печатаю rv -s <TAB>, я ожидаю увидеть: 1) имена серверов vim (как указано в _rv_vim_servers.
  • Когда я печатаю rv /valid/file/path/<TAB>, я ожидаю увидеть только список путей к файлам. Поскольку _vimтакая возможность уже есть, я бы предпочел на нее положиться.
Джастин С
источник
1
Этот unix.stackexchange.com/questions/128199/… может быть полезен.
Клобрано
1
compdefимеет -nпараметр, который говорит, что «предотвращает перезапись любых завершений, уже определенных для команды или контекста». Итак, вы пытались compdef _vim rvследовать compdev -n _rv rv?
Lqueryvg
3
28 голосов и ответа нет ... и это вопрос о zsh ... Я постараюсь вызвать для вас @ StéphaneChazelas ^^ (Я стараюсь не злоупотреблять этим, но это весело. Пожалуйста, Стефан, скажите мне, если я не должен сделай это ... и я удалю это и больше никогда не сделаю это ...) Если кто-то здесь может знать ответ, это должен быть он
Оливье Дюлак
1
@OlivierDulac Я думаю, что вы будете получать уведомления, только если вы уже разместили в теме. (Допускаются повторяющиеся имена, поэтому это имеет смысл.) Однако вы можете найти его в чате.
Sparhawk
Можно ли было получить исходный _vim файл, но перед этим переписать _argumentsфункцию с помощью локальной функции? Тем самым вы получите аргументы от _vim. Может быть, с отдельным процессом Zsh.
Рафаэль Аренс

Ответы:

1

Я нашел / usr / share / zsh / functions / Completion / Unix / _git, в котором были несколько советов для псевдонимов, подобных этому, и в итоге я определил эти функции для псевдонимов:

_git-ls () {
  # Just return the _git-ls-files autocomplete function
  _git-ls-files
}

Затем выполните прямое compdef g = git. Система автозаполнения увидит, что вы, например, запускаете g ls и используете функцию автозаполнения _git-ls.

Как нашли здесь

Адедойин Аканде
источник
спасибо, но не совсем. Ваше решение предполагает, что я хочу только автозаполнение с _git-ls-files. Этот вопрос имеет git-ls(придерживаться вашего соглашения) свои собственные параметры, и некоторые из этих параметров перекрываются git-ls-files. Вместо того, чтобы писать автозаполнение для всех опций git-ls, как мне написать автозаполнение, которое берет автозаполнение из _git-ls-files(которое покрывает, скажем, 90%), и объединяет их с автозаполнением оставшихся (скажем, 10%) опций?
Джастин C