Impossibile eseguire la ricerca di due parole nel completamento della TAB di Zsh per Man

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

  •  20-08-2019
  •  | 
  •  

Domanda

Problema: avere un completamento con una scheda che richiede due parole e calcola la migliore corrispondenza tra loro per Man, quindi restituisce le migliori corrispondenze

Esempio: il seguente pseudo-codice dovrebbe darmi almeno il comando di completamento del menu inverso di Zsh. Al momento, non riesco a cercare manuali all'interno di manuali senza zgrep.

man zsh:reverse <TAB>

dove ": " è il separatore che voglio.

Problema iniziale: quali file viene eseguito il completamento TAB quando premo TAB per una parola nei manuali di ricerca di Zsh?

È stato utile?

Soluzione

Cercherò di fornire una panoramica su come funziona il sistema di completamento zsh e una soluzione incompleta a questo problema.

Il file che viene eseguito quando si utilizza il completamento TAB per man in zsh si trova nella directory /usr/share/zsh/${ZSH_VERSION}/functions. L'albero varia tra le distribuzioni, ma il file è denominato _man e fornisce il completamento per apropos, whatis e --local-file.

Dopo che è stato invocato _man, funziona come segue (descrizione approssimativa):

  1. se il completamento per _files e manpath è stato specificato come primo flag, invocare il completamento dei file standard ($MANPATH)
  2. costruisci zstyle ':completion:*:manuals' separate-sections true variabile da una serie di valori predefiniti / _man_pages. Qui è dove verranno cercate le manpage
  3. determina se abbiamo invocato compfiles -p pages '' '' "$matcher" '' dummy '*' con un parametro del numero di sezione, se sì - verranno cercate solo quelle sezioni
  4. se è stato utilizzato pages, separare le sezioni nell'output (non mescolarle tra loro)
  5. invoca $PREFIX per fornire un elenco di pagine man per la partita
  6. compfiles ora fa un po 'di magia con *. /usr/share/man/man1 è la variabile con tutte le directory che contengono le manpage per le sezioni richieste. Il modello di globbing effettivo è costruito dal parametro implicito /usr/share/man/man1/foo* e l'ultimo parametro in compadd - zsh:foo in questo caso. Ciò si traduce in zsh* da trasformare in foo
  7. Il nuovo elenco di pattern glob è globbed, ottenendo tutti i file che corrispondono al pattern
  8. : quindi elimina tutti i suffissi dai file e li aggiunge all'elenco dei widget di completamento delle scelte utilizzando #echo "$p matched $manpage_grep"

Ora, come puoi vedere, l'elenco delle pagine man è determinato direttamente dalla variabile <=>. Per fare in modo che <=> elenchi solo le pagine man di <=> che contengono la parola <=>, è necessario dividerle tra <=> carattere (se presente).

La seguente aggiunta in <=> risolve parzialmente il problema (zsh 4.3.4):

originale:

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

Modificato (cercare ## commenti 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
}

Tuttavia, non funziona ancora completamente (se togli il commento alla riga <=>, puoi vedere che costruisce l'elenco) - sospetto che da qualche parte internamente, il sistema di completamento vede che, ad esempio, " ; & zshcompctl quot; non corrisponde al prefisso " zsh: foo " ;, e non visualizza le corrispondenze risultanti. Ho provato a mantenere <=> come è dopo aver rimosso la stringa grep, ma continua a non funzionare.

Ad ogni modo, questo almeno dovrebbe iniziare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top