Existe algo como encerramentos para o zsh?

7

Eu apenas decidi experimentar o zsh (por meio do oh-my-zsh), e agora estou jogando com precmd para emular um prompt de duas linhas que tem prompts corretos em mais do que apenas a última linha.

Então eu clonei o tema padrão, e inspirei este post (que estou usando para aprender muito também) , eu faço algo assim (adicionarei cores mais tarde):

function precmd {
    local cwd="${(%):-[%~]}"
    local who_where="${(%):-%n@%m}"
    local git_info=${(%)$(git_prompt_info)}
    local right_prompt="     $git_info [$who_where]"
    local left_prompt="${(r:(($COLUMNS - ${#${right_prompt}})):: :)cwd}"

    echo "$left_prompt$right_prompt"
}

E isso funciona. Mas não posso deixar de me perguntar: o zsh está definindo todas essas variáveis toda vez que precmd é chamado?

Eu estive pesquisando sobre fechamentos, escopo e namespaces em relação ao zsh, procurando anexar as vars locais como dados para precmd, para que não precise redefinir as variáveis todas as vezes, mas não encontrei nada. Existe alguma maneira de fazer o que eu estou tentando, ou devo apenas deixá-lo cair?

Como nota lateral, e somente se estiver relacionado, o que significa "ter uma função carregada"?

    
por ferhtgoldaraz 08.10.2013 / 19:06

3 respostas

8

O Zsh não tem nada como closures, pacotes ou namespaces. Zsh não tem um monte de coisas necessárias para ter fechamentos verdadeiros:

  • As funções não são de primeira classe. Você não pode passar funções como argumentos para outras funções, e as funções não podem retornar outras funções. (Você pode passar o nome de uma função para chamar, mas isso não é o mesmo que passar a função em si).

  • Você não pode ter funções aninhadas. Todas as funções no zsh são globais. Você deve prefixar seus nomes de função para evitar conflitos. Note especialmente que as funções irão sombrear programas externos com o mesmo nome. Se você tiver uma função chamada ls , ela será chamada em vez do programa ls . Isso pode ser útil, exceto se você fizer isso por acidente.

  • Variáveis são escopadas dinamicamente, não estaticamente escopo como na maioria das linguagens modernas. Mesmo se você pudesse ter funções aninhadas, as funções internas não se aproximariam das variáveis locais das funções externas da maneira que você normalmente esperaria. Você não poderia usá-los para criar módulos da maneira que as pessoas fazem, digamos, em Javascript.

  • Zsh faz ter funções anônimas, mas sem nenhuma dessas outras coisas elas não são muito úteis.

Então, basicamente, o melhor que você pode fazer é prefixar todas as suas funções e variáveis globais.

Também indicarei que você deve definir seu precmd assim:

% autoload -Uz add-zsh-hook
% add-zsh-hook precmd my_precmd_function

add-zsh-hook permite que você conecte sua função em precmd sem sobrescrever quaisquer outras funções que também possam atrapalhar precmd .

O que significa ter uma função carregada é uma questão separada. O Zsh possui um recurso de carregamento automático que carrega apenas funções do disco quando elas são realmente chamadas. Quando você faz autoload -Uz foobar , isso faz com que a função chamada foobar esteja disponível para chamar. Quando você realmente chama foobar , isso carrega a definição do disco.

    
por 08.10.2013 / 20:53
5

Não, os closures são muito sofisticados para o zsh. O Zsh foi projetado para interpretar pequenos scripts que não estão muito distantes da interação direta. Ele não possui recursos sofisticados de linguagem que são muito úteis para programação em grandes, mas menos para o tipo de tarefas pequenas para as quais os shells são normalmente usados.

Note que se houvesse alguma forma de fechamento que permitisse que o valor das variáveis fosse pré-calculado de uma vez por todas e, em seguida, armazenado, os valores não seriam atualizados quando algo fosse alterado para invalidar as informações. / p>

$git_info e as variáveis derivadas podem mudar a qualquer momento devido a uma modificação em um arquivo verificado no git ou no repositório git. Então, eles precisam ser recalculados a cada vez.

Você pode armazenar em cache os valores de cwd e who_where em uma variável global, uma vez que eles não são alterados em operação normal. cwd muda quando o diretório atual muda, portanto, ele precisa ser atualizado de chpwd . No entanto, essas variáveis são extremamente rápidas de serem computadas, portanto, não há motivo para incomodar. A computação cara aqui está executando git_prompt_info , e isso pode mudar a qualquer momento.

Quando você exibe informações entre cada comando, pode ser uma boa ideia colocá-lo como parte do prompt ( PS1 ou psvar array). Zsh sabe que deve reexibir o prompt em várias circunstâncias, enquanto não sabe nada sobre o que você imprime a partir de precmd .

    
por 09.10.2013 / 03:32
1

Sim, essas variáveis são (re) definidas toda vez que você chama a função.

Se você quiser inicializá-los apenas uma vez, poderá simplesmente movê-los para o nível superior, fora da função.

    
por 08.10.2013 / 19:09