2009-05-09 5 views
0

Problème: d'avoir une touche de tabulation qui prend deux mots et calcule le meilleur match de leur part pour l'homme, puis retourne les meilleurs matchsImpossible d'avoir deux mots-recherche dans l'achèvement TAB de zsh Man

Exemple: Le pseudo-code suivant devrait me donner au moins la commande-reverse-complete -command de Zsh. En ce moment, je ne peux pas rechercher des manuels dans les manuels sans zgrep.

man zsh:reverse <TAB> 

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

Problème initial: Quels sont les fichiers qui finissent l'exécution de TAB lorsque j'appuie sur TAB pour un mot dans la recherche de manuels par Zsh?

Répondre

2

Je vais essayer de fournir un aperçu de la façon dont le système de complétion zsh fonctionne et un aller incomplet à ce problème.

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 porte le numéro _man et indique l'achèvement pour man, apropos et whatis.

Après _man est invoqué, il fonctionne comme suit (description sommaire):

  1. si vous remplissez pour man et --local-file a été spécifié comme premier drapeau, appelez fichiers standard d'achèvement (_files)
  2. construire manpath variable à partir un ensemble de valeurs par défaut/$MANPATH. C'est là que les pages de manuel seront recherchées
  3. déterminer si nous invoquions man avec un paramètre de numéro de section, si oui - que ces sections seront recherchées
  4. si le zstyle ':completion:*:manuals' separate-sections true a été utilisé, des sections distinctes de la production (ne se mélangent pas entre les)
  5. invoquez _man_pages pour fournir une liste des pages de manuel pour le match
  6. _man_pages fait maintenant un peu de magie avec compfiles -p pages '' '' "$matcher" '' dummy '*'. pages est la variable avec tous les répertoires contenant des pages de manuel pour les sections demandées. Le modèle de globulation réel est construit à partir du paramètre implicite $PREFIX et le dernier paramètre à compfiles - * dans ce cas. Il en résulte /usr/share/man/man1 être transformé en /usr/share/man/man1/foo*
  7. La nouvelle liste des modèles glob est globbed, obtenir tous les fichiers qui correspondent au modèle
  8. _man_pages les bandes puis tous les suffixes des fichiers et les ajoute à la liste des widgets d'achèvement des choix par maintenant, en utilisant compadd

, comme vous pouvez le voir, la liste des pages de manuel est déterminée directement par $PREFIX variable. Afin de faire zsh:foo pour ne répertorier que les pages man de zsh* qui contiennent le mot foo, il doit être divisé en : caractère (le cas échéant).

L'ajout suivant à _man_pages 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 "[email protected]" - ${pages%.(?|<->*(|.gz|.bz2|.Z))} 
    else 
    compadd "[email protected]" -P "$sopt$sect " - ${pages%.(?|<->*(|.gz|.bz2|.Z))} 
    fi 
} 

Modifiés (rechercher ## commentaires 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 "[email protected]" - ${pages%.(?|<->*(|.gz|.bz2|.Z))} 
    else 
    compadd "[email protected]" -P "$sopt$sect " - ${pages%.(?|<->*(|.gz|.bz2|.Z))} 
    fi 
} 

Cependant, il ne fonctionne pas encore complètement (si vous décommentez la ligne #echo "$p matched $manpage_grep", vous pouvez voir qu'il construit la liste) - Je suppose que quelque part en interne, la co Le système mpletion voit que, par exemple, "zshcompctl" ne correspond pas au préfixe "zsh: foo", et n'affiche pas les résultats obtenus. J'ai essayé de garder $PREFIX comme il est après avoir dépouillé la chaîne grep, mais il ne veut toujours pas travailler.

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

+0

Merci pour votre réponse! –

Questions connexes