sobrescreve e reutiliza a função existente no zsh

1

Eu gostaria de estender um pouco a função de conclusão do zsh.

Eu gostaria de evitar colocar o corpo da função completa no meu homedir com apenas uma linha alterada. Em vez disso, gostaria de interceptar a chamada e, em seguida, chamar a função original. Em quase código:

<make sure _the_original_function is loaded>
_backup_of_original_function=_the_original_function

_the_original_function() {
   _arguments "-superduper[that one option I always need]"
   _backup_of_originial_function $@
}

No meu caso concreto, eu tenho uma propriedade cmake em praticamente todos os meus projetos, de forma que eu gostaria de modificar a conclusão do cmake. Não ter essa opção na conclusão me incomodaria muito mais do que tê-la em projetos em que a opção não pertence. Então, em vez de copiar _cmake em algum lugar, eu apenas redefiniria _cmake_define_common_property_names() em meu .zshrc :

_cmake_define_common_property_names() {
  local properties; properties=(
    'MY_GREAT_OPTION:be awesome'
  )                    

  _describe -t 'my-property-names' 'my property name' properties $@

  **call original _cmake_define_common_property_names here
}  

Então, o que está faltando é carregar _cmake_define_common_property_names e atribuir um novo nome de função a ele.

De aqui , tentei

autoload -Uz +X _cmake_define_common_property_names

mas isso falha (a função não está definida em seu próprio arquivo, mas sim em _cmake .

NB: Eu não atribuo um novo nome de função para evitar ter que modificar o local de onde a função é chamada em sua versão original.

O que funciona parcialmente é autoload -Uz +X _cmake , MAS isso só garante que _cmake seja carregado (o que eu verifico chamando functions _cmake ). Não carrega a função auxiliar _cmake_define_common_property_names .

Então minhas duas perguntas são

  1. como carrego uma função de um arquivo $fpath
  2. Quando eu tiver uma função carregada. Como faço para copiá-lo em um script / Atribuir um novo nome de função?
por pseyfert 15.06.2018 / 18:48

1 resposta

1

Como corrigir uma função

O código de uma função é armazenado na matriz associativa functions . Esse é o código-fonte com espaço em branco normalizado e nenhum comentário (zsh fez análise lexical e imprime bastante os tokens). Você pode alterar o código de uma função modificando a entrada da matriz functions . Por exemplo, para adicionar código extra no começo:

functions[_cmake_define_common_property_names]="
    … # your extra code here
    $functions[_cmake_define_common_property_names]"

Você também pode usar a matriz functions para copiar uma função para outro nome. Essa é a maneira mais fácil de envolver uma função existente.

functions[_cmake_define_common_property_names_orig]=$functions[_cmake_define_common_property_names]
_cmake_define_common_property_names () {
    …
    _cmake_define_common_property_names_orig "$@"
}

Carregando todas as funções

A única maneira infalível de carregar todas as funções de um arquivo feito para o carregamento automático é executar a função, se você puder fazer isso sem efeitos colaterais. Para uma função de conclusão, basta executar a função com erros redirecionados para o depósito de bits. Não fará nada além de reclamar que não está sendo executado em um contexto de conclusão.

_cmake 2>/dev/null
# Now _cmake_xxx is defined

A razão autoload -Uz +X _cmake não funciona é que as definições das funções auxiliares estão na própria função _cmake .

% echo $functions[_cmake]
builtin autoload -XU
% autoload -Uz +X _cmake
% echo $functions[_cmake]
…
        (( $+functions[_cmake_define_property_names] )) || _cmake_define_property_names () {
…
}
…
        local cmake_command_actions
        cmake_command_actions=('-E[CMake command mode]:*:command') 
        _cmake_command () {
                _arguments -C -s - command "$cmake_command_actions[@]"
        }
        local cmake_suggest_build
        cmake_suggest_build=('--build[build]') 
        if [ $CURRENT -eq 2 ]
        then
                _arguments -C -s - help "$cmake_help_actions[@]" - command "$cmake_command_actions[@]" - build_opts "$cmake_build_options[@]" - build_cmds "$cmake_suggest_build[@]" && return 0
        elif [[ $words[2] = --help* ]]
        then
                _cmake_help
        elif [[ $words[2] != -E ]]
        then
                _cmake_on_build
        else
                _cmake_command
        fi

Se você realmente não quer executar a função de nível superior, você tem várias opções:

  • Corrigir a definição de _cmake_define_common_property_names dentro da definição de _cmake .
  • Extraia a definição de _cmake_define_common_property_names da definição de _cmake e use-a para definir _cmake_define_common_property_names_orig ou _cmake_define_common_property_names .
  • Corrigir a definição de _cmake para remover as partes que não sejam as definições da função e depois executá-las. Não é realmente viável com _cmake , mas algumas outras funções de conclusão são melhor estruturadas. Por exemplo _cvs consiste puramente em definições de funções condicionais (por exemplo, (( $+functions[_cvs_command] )) || _cvs_command () { … } ), uma definição da função titular e uma chamada da função titular como a última coisa, assim você pode definir toda a função mas não executar nada por removendo a última linha.

    autoload -Uz +X _cvs
    functions[_cvs]=${functions_cvs%'$\n'*}
    _cvs
    # Patch auxiliary functions here
    
por 16.06.2018 / 11:27

Tags