Pergunta

Problema: para ter uma conclusão de tabulação que leva duas palavras e calcula o melhor jogo a partir deles para o homem, e retorna os melhores jogos

Exemplo: O pseudo-código a seguir deve me dar pelo menos -command-reverse-menu completo do Zsh. Agora, eu não posso procurar manuais dentro manuais sem zgrep.

man zsh:reverse <TAB>

onde ":". É o separador que eu quero

Problema inicial:? Quais arquivos não a conclusão TAB prazo quando eu pressionar TAB para uma palavra na busca manuais por Zsh

Foi útil?

Solução

vou tentar fornecer uma visão de como zsh funciona o sistema de conclusão e uma incompleta ir a este problema.

O arquivo que é executado quando você usar a conclusão de TAB para man em zsh está localizado sob o diretório /usr/share/zsh/${ZSH_VERSION}/functions. A árvore varia entre as distribuições, mas o arquivo é chamado _man, e fornece conclusão para man, apropos e whatis.

Depois de _man é invocado, ele funciona da seguinte forma (descrição aproximada):

  1. se completando para man e --local-file foi especificado como primeira bandeira, chamar a conclusão de arquivos padrão (_files)
  2. variável construção manpath a partir de um conjunto de defaults / $MANPATH. Este é o local onde as páginas de manual será procurado
  3. determinar se invocado man com um parâmetro número da seção, se sim - apenas as seções serão pesquisados ??
  4. Se foi utilizado o zstyle ':completion:*:manuals' separate-sections true, seções separadas em saída (não se misturam entre eles)
  5. invoke _man_pages para fornecer uma lista de páginas de manual para o jogo
  6. _man_pages agora faz um pouco de magia com compfiles -p pages '' '' "$matcher" '' dummy '*'. pages é a variável com todas as pastas contendo manpages para secção requerido (s). O padrão de englobamento real é construído a partir do $PREFIX parâmetro implícito eo último parâmetro para compfiles - * neste caso. Isso resulta em /usr/share/man/man1 para ser transformado em /usr/share/man/man1/foo*
  7. A nova lista de padrões glob é globbed, a obtenção de todos os arquivos que correspondem ao padrão
  8. _man_pages seguida, retira quaisquer sufixos dos arquivos e os adiciona à lista de widget de conclusão de opções usando compadd

Agora, como você pode ver, a lista de manpages está diretamente determinada pela variável $PREFIX. A fim de fazer zsh:foo a lista apenas as páginas homem de zsh* que contêm a palavra foo, ele precisa ser dividida entre caráter : (se houver).

O seguinte aditamento no _man_pages parcialmente resolver a questão (zsh 4.3.4):

Original:

_man_pages() {
  local matcher pages dummy sopt

  zparseopts -E M+:=matcher

  if (( $#matcher )); then
    matcher=( ${matcher:#-M} )
    matcher="$matcher"
  else
    matcher=
  fi

  pages=( ${(M)dirs:#*$sect/} )

  compfiles -p pages '' '' "$matcher" '' dummy '*'
  pages=( ${^~pages}(N:t) )

  (($#mrd)) && pages[$#pages+1]=($(awk $awk $mrd))

  # Remove any compression suffix, then remove the minimum possible string
  # beginning with .<->: that handles problem cases like files called
  # `POSIX.1.5'.

  [[ $OSTYPE = solaris* ]] && sopt='-s '
  if ((CURRENT > 2)) ||
      ! zstyle -t ":completion:${curcontext}:manuals.$sect" insert-sections
  then
    compadd "$@" - ${pages%.(?|<->*(|.gz|.bz2|.Z))}
  else
    compadd "$@" -P "$sopt$sect " - ${pages%.(?|<->*(|.gz|.bz2|.Z))}
  fi
}

Modificado (olhar para ## comentários mod):

_man_pages() {
  local matcher pages dummy sopt

  zparseopts -E M+:=matcher

  if (( $#matcher )); then
    matcher=( ${matcher:#-M} )
    matcher="$matcher"
  else
    matcher=
  fi

  pages=( ${(M)dirs:#*$sect/} )

  ##mod
  # split components by the ":" character
  local pref_words manpage_grep orig_prefix
  # save original prefix (just in case)
  orig_prefix=${PREFIX}
  # split $PREFIX by ':' and make it an array
  pref_words=${PREFIX//:/ }
  set -A pref_words ${=pref_words}
  # if there are both manpage name and grep string, use both
  if (( $#pref_words == 2 )); then
      manpage_grep=$pref_words[2]
      # PREFIX is used internally by compfiles
      PREFIX=$pref_words[1]
  elif (( $#pref_words == 1 )) && [[ ${PREFIX[1,1]} == ":" ]]; then
      # otherwise, prefix is empty and only grep string exists
      PREFIX=
      manpage_grep=$pref_words[1]
  fi


  compfiles -p pages '' '' "$matcher" '' dummy '*'
  ##mod: complete, but don't strip path names
  pages=( ${^~pages} )

  (($#mrd)) && pages[$#pages+1]=($(awk $awk $mrd))

  ##mod: grep pages
  # Build a list of matching pages that pass the grep
  local matching_pages
  typeset -a matching_pages

  # manpage_grep exists and not empty 
  if (( ${#manpage_grep} > 0 )); then
      for p in ${pages}; do
          zgrep "${manpage_grep}" $p > /dev/null
          if (( $? == 0 )); then
              #echo "$p matched $manpage_grep"
              matching_pages+=($p)
          fi
      done
  else
  # there's no manpage_grep, so all pages match
      matching_pages=( ${pages} )
  fi

  #echo "\nmatching manpages: "${matching_pages}
  pages=( ${matching_pages}(N:t) )
  # keep the stripped prefix for now
  #PREFIX=${orig_prefix}


  # Remove any compression suffix, then remove the minimum possible string
  # beginning with .<->: that handles problem cases like files called
  # `POSIX.1.5'.


  [[ $OSTYPE = solaris* ]] && sopt='-s '
  if ((CURRENT > 2)) ||
      ! zstyle -t ":completion:${curcontext}:manuals.$sect" insert-sections
  then
    compadd "$@" - ${pages%.(?|<->*(|.gz|.bz2|.Z))}
  else
    compadd "$@" -P "$sopt$sect " - ${pages%.(?|<->*(|.gz|.bz2|.Z))}
  fi
}

No entanto, é ainda não totalmente funcional (se você remover o comentário da linha #echo "$p matched $manpage_grep", você pode ver que ele não criar a lista de) - Eu suspeito que em algum lugar internamente, o sistema de conclusão vê que, por exemplo, "zshcompctl" não é correspondida pelo prefixo "zsh: foo", e não exibir as correspondências resultantes. Eu tentei manter $PREFIX como é após a remoção da cadeia de grep, mas ainda não quer trabalho.

De qualquer forma, isso pelo menos deve começar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top