Impossible d'effectuer une recherche de deux mots dans l'achèvement de la tabulation de Zsh pour Man

StackOverflow https://stackoverflow.com/questions/842558

  •  20-08-2019
  •  | 
  •  

Question

Problème: : la complétion par un onglet prend deux mots et en calcule la meilleure correspondance pour Man, puis renvoie les meilleures correspondances

Exemple: Le pseudo-code suivant doit me fournir au moins la commande reverse-menu-complete de Zsh. Pour le moment, je ne peux pas rechercher de manuels dans les manuels sans zgrep.

man zsh:reverse <TAB>

où " " est le séparateur que je veux.

Problème initial: Quels fichiers l'achèvement de la tabulation est-il exécuté lorsque j'appuie sur TAB pour un mot dans la recherche de manuels par Zsh?

Était-ce utile?

La solution

Je vais essayer de donner un aperçu du fonctionnement du système d'achèvement de zsh et de résoudre ce problème de manière incomplète.

Le fichier qui s'exécute lorsque vous utilisez la complétion TAB pour man dans zsh se trouve dans le répertoire /usr/share/zsh/${ZSH_VERSION}/functions. L’arborescence varie d’une distribution à l’autre, mais le fichier s’appelle _man et permet de compléter apropos, whatis et --local-file.

Après l'appel de _man, cela fonctionne comme suit (description approximative):

  1. si terminer pour _files et que manpath était spécifié comme premier indicateur, invoquer l'achèvement des fichiers standard ($MANPATH)
  2. construit zstyle ':completion:*:manuals' separate-sections true une variable à partir d'un ensemble de valeurs par défaut / _man_pages. C’est là que les pages de manuel seront recherchées
  3. détermine si nous avons appelé compfiles -p pages '' '' "$matcher" '' dummy '*' avec un paramètre de numéro de section, si oui, seules les sections faisant l'objet de la recherche seront recherchées
  4. si le pages a été utilisé, séparez les sections en sortie (ne mélangez pas entre elles)
  5. invoque $PREFIX pour fournir une liste de pages de manuel pour la correspondance
  6. compfiles fait maintenant un peu de magie avec *. /usr/share/man/man1 est la variable avec tous les répertoires contenant les pages de manuel des sections demandées. Le modèle de globalisation actuel est construit à partir du paramètre implicite /usr/share/man/man1/foo* et du dernier paramètre à compadd - zsh:foo dans ce cas. Cela se traduit par zsh* transformation en foo
  7. La nouvelle liste de modèles glob est globbed, ce qui permet d'obtenir tous les fichiers correspondant au modèle
  8. : supprime ensuite les suffixes des fichiers et les ajoute à la liste de choix du widget d'achèvement en utilisant #echo "$p matched $manpage_grep"

Comme vous pouvez le constater, la liste des pages de manuel est directement déterminée par la variable <=>. Pour que <=> ne répertorie que les pages de manuel de <=> qui contiennent le mot <=>, il doit être divisé en <=> caractères (le cas échéant).

L'ajout suivant dans <=> résoudre partiellement le problème (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
}

Modifié (recherchez ## mod comments):

_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
}

Cependant, cela ne fonctionne toujours pas complètement (si vous supprimez la mise en commentaire de la ligne <=>, vous pouvez voir qu'elle construit la liste). Je suppose que quelque part en interne, le système d'achèvement voit que, par exemple, & " ; zshcompctl " ne correspond pas au préfixe & "; zsh: foo &"; et n'affiche pas les correspondances résultantes. J'ai essayé de garder <=> tel qu'il est après avoir supprimé la chaîne grep, mais cela ne veut toujours pas fonctionner.

Quoi qu'il en soit, cela devrait au moins vous aider à démarrer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top