Função Bash não funciona no Zsh

6

Eu tenho migrado lentamente do Bash para o Zsh e cheguei ao ponto em que tudo em que me mudei está funcionando bem, com uma exceção.

Eu tenho algumas funções no meu .bashrc que eu uso dezenas de vezes por dia e duas delas não funcionam no Zsh. As três funções compreendem uma facilidade de anotação básica.

Eles estão atualmente em .config/zsh/functions :

function n() { 
local arg files=(); for arg; do files+=( ~/".notes/$arg" ); done
${EDITOR:-vi} "${files[@]}" 
}

function nls() {
tree -CR --noreport $HOME/.notes | awk '{ 
    if (NF==1) print $1; 
    else if (NF==2) print $2; 
    else if (NF==3) printf "  %s\n", $3 
    }'
}

# TAB completion for notes
function _notes() {
local files=($HOME/.notes/**/"$2"*)
    [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]##~/.notes/}" )
}
complete -o default -F _notes n

Qual eu origem de .zshrc da seguinte forma:

autoload bashcompinit
bashcompinit
# source zshrc functions file
source "$HOME/.config/zsh/functions"

nls funciona como esperado, mas nem o trabalho de conclusão do n nem Tab .

Eu leio man zshcompsys onde diz:

The function bashcompinit provides compatibility with bash's programmable completion system. When run it will define the functions, compgen and complete which correspond to the bash builtins with the same names. It will then be possible to use completion specifications and functions written for bash.

No entanto, quando eu tento concluir o Tab , nada acontece e quando eu digito n notename , o Vim abre meu /home no modo de navegador de arquivos - não exatamente o comportamento esperado.

Todas as outras funções definidas funcionam bem. Como faço para migrar essas funções para trabalhar com o Zsh?

    
por jasonwryan 30.12.2012 / 21:38

2 respostas

5
  • local é uma palavra-chave embutida, não uma palavra-chave, portanto, local files=(…) não é analisado como uma atribuição de matriz, mas como uma atribuição de sequência de caracteres. Escreva a tarefa separadamente da declaração. (Já encontrado por llua , mas observe que você precisa inicializar files na matriz vazia ou declarar a variável com typeset -a , caso contrário, a matriz começa com um elemento vazio falso.)
  • As matrizes Zsh são numeradas de 1, não de 0 como em bash e ksh, portanto, ${files[0]} deve ser escrito $files[1] . Como alternativa, diga ao zsh para se comportar de uma maneira mais compatível com o ksh e o bash: coloque emulate -L ksh no início da função.
  • A menos que você use a emulate route, sua função _notes imprimirá zsh: no matches found: foo* se não houver conclusão para foo , porque, por padrão, globs não correspondentes acionam um erro. Adicione o qualificador N para obter uma matriz vazia se não houver correspondência, e testar se a matriz está vazia.
  • Há outro erro na sua função _notes que afeta as anotações nos subdiretórios: você deve remover o prefixo até a conclusão, de modo que, se, por exemplo, ~/notes/foo/bar existe e você digita n b<TAB> , COMPREPLY está definido para conter b , não foo/b .

Se você deseja manter um arquivo legível por bash e zsh:

type emulate >/dev/null 2>/dev/null || alias emulate=true
function n() {
  emulate -L ksh
  local arg; typeset -a files
  for arg; do files+=( ~/".notes/$arg" ); done
  ${EDITOR:-vi} "${files[@]}" 
}

function nls() {
  tree -CR --noreport $HOME/.notes | awk '{ 
      if (NF==1) print $1; 
      else if (NF==2) print $2; 
      else if (NF==3) printf "  %s\n", $3 
    }'
}

# TAB completion for notes
function _notes() {
  emulate -L ksh
  local x files
  files=($HOME/.notes/**/"$2"*)
  [[ -e ${files[0]} ]] || return 1
  COMPREPLY=()
  for x in "${files[@]}"; do
    COMPREPLY+=("$2${x#$HOME/.notes*/$2}")
  done
}
complete -o default -F _notes n

Se você quiser portar seu código para zsh:

function n() {
  local files
  files=(${@/#/~/.notes/})
  ${EDITOR:-vi} $files
}

function nls() {
  tree -CR --noreport $HOME/.notes | awk '{ 
      if (NF==1) print $1; 
      else if (NF==2) print $2; 
      else if (NF==3) printf "  %s\n", $3 
    }'
}

# TAB completion for notes
function _notes() {
  setopt local_options bare_glob_qual
  local files
  files=(~/.notes/**/$2*(N))
  ((#files)) && COMPREPLY=($2${^files##~/.notes*/$2})
}
complete -o default -F _notes n
    
por 01.01.2013 / 02:06
2

O comando typeset (local) do zsh não pode definir matrizes com sua sintaxe. Você pode criar matrizes, mas também não pode definir valores em um único comando.

function n() {                                                         
local arg files; for arg; do files+=( ~/.notes/$arg ); done
vim ${files[@]}
}

é uma maneira de corrigir isso.

    
por 31.12.2012 / 03:00