Como combinar o preenchimento automático do zsh para argumentos de função do wrapper e comando existente

40

Eu trabalho principalmente no gvim e em muitos terminais. Originalmente, eu preferia abrir todos os meus arquivos em uma única instância do vim. Para esse fim, usei um alias para abrir arquivos dos meus terminais no atual 'servidor vim'.

alias rv="gvim --remote-silent"

Mas ter muitos arquivos de vários projetos abertos em uma única instância do vim afeta minha produtividade, por isso estou atualizando meu alias para uma função.

# 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;
}

Agora, este novo rvpossui suas próprias opções. Eu posso usá-lo para:

  • lista servidores vim disponíveis (-l --list)
  • defina o servidor vim padrão para o shell atual (-s --set)
  • mostre o servidor vim padrão (-i --info)
  • abrir arquivos em um servidor vim específico (-t --target)
  • abra arquivos no servidor vim padrão: rv files...

No entanto, como estou usando uma função para, em rvvez de um alias, perco a conclusão do zsh de que desfrutei anteriormente. Eu li sobre a criação de uma função de conclusão,, _rvque mostrará rvas opções, mas quero combinar minhas opções de conclusão com as opções de conclusão do vim existentes. Eu sei que pode haver alguns conflitos com rv's' -se vim's -s, mas acho que posso lidar com isso de maneira elegante com o --separador.

TLDR; Então, como crio um script de conclusão que combina as _argumentsopções para ambos _rve _vim? Prefiro reutilizar, _vimse possível, em vez de copiar e colar sua lista de argumentos _rv.

Aqui está o meu _rv. Atualizado 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 "$@"

Comportamento Atual

Atualmente, a _rvconclusão é utilizável, mas não ideal.

  • Quando digito rv <TAB>, não vejo as opções do vim. Apenas opções de rv e caminhos de arquivo são exibidos. _vimestá completando caminhos de arquivos para mim, então viva isso!
  • Quando digito rv -s <TAB>, vejo a lista de servidores vim, mas também os caminhos dos arquivos são exibidos. Um arquivo não é permitido neste momento no comando e não deve aparecer no preenchimento automático.

Comportamento esperado

  • Quando digito rv <TAB>, espero ver: 1) opções rv, 2) opções vim, 3) lista de caminhos de arquivos
  • Quando digito rv -s <TAB>, espero ver: 1) nomes de servidores vim (conforme fornecido por _rv_vim_servers.
  • Quando digito rv /valid/file/path/<TAB>, espero ver apenas uma lista de caminhos de arquivos. Como _vimjá tem esse recurso, eu preferiria confiar nele.
Justin C
fonte
11
Esse arquivo unix.stackexchange.com/questions/128199/… pode ser útil.
Clobrano
11
compdefpossui uma -nopção que diz "impede que quaisquer conclusões já definidas para o comando ou contexto sejam substituídas". Então, você já tentou compdef _vim rvseguir compdev -n _rv rv?
precisa saber é o seguinte
3
28 votos positivos e nenhuma resposta ... e é uma pergunta sobre zsh ... vou tentar invocar @ StéphaneChazelas para você ^^ (eu tento não abusar disso, mas é divertido. Por favor, Stephane, me diga se não devo fazer isso ... e eu vou apagar isso e nunca fazê-lo novamente) ... Se alguém aqui pode saber a resposta, deve ser ele
Olivier Dulac
11
@OlivierDulac Acho que você só recebe notificações se já tiver postado no tópico. (Nomes duplicados são permitidos, portanto, isso faz sentido.) Você pode encontrá-lo no bate-papo.
Sparhawk #
Poderia ser possível obter o _vim arquivo original , mas antes de substituir a _argumentsfunção por uma função local personalizada? Ao fazer isso, você obteria os argumentos _vim. Talvez com um processo zsh separado.
Raphael Ahrens

Respostas:

1

Eu encontrei / usr / share / zsh / functions / Completion / Unix / _git que tinha algumas dicas para aliases como este e acabei definindo essas funções para os aliases:

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

Então, faça um compdef direto g = git. O sistema de preenchimento automático verá que você está executando, por exemplo, g ls e usará a função de preenchimento automático _git-ls.

Como encontrado aqui

Adedoyin Akande
fonte
obrigado, mas não exatamente. sua solução assume que eu só quero o preenchimento automático _git-ls-files. Esta pergunta tem um git-ls(para manter sua convenção) com suas próprias opções, e algumas dessas opções se sobrepõem git-ls-files. Em vez de escrever o preenchimento automático para todas as opções de git-ls, como eu escrevo um preenchimento automático que retira o preenchimento automático _git-ls-files(que abrange cerca de 90%) e os combina com o preenchimento automático das demais opções (digamos 10%)?
Justin C