Nicht imstande, einen Mann Zwei-Wort-Suche in Zsh der TAB Abschluss zu haben
-
20-08-2019 - |
Frage
Problem: ein Tabulatorvervollständigung haben, die zwei Worte nehmen und berechnet die beste Übereinstimmung von ihnen für einen Mann, und gibt dann die besten Übereinstimmungen
Beispiel: Der folgende Pseudo-Code soll mir geben zumindest Zsh des Reverse-Menü-complete -command. Gerade jetzt, ich kann nicht Handbücher innerhalb Handbücher ohne zgrep suchen.
man zsh:reverse <TAB>
Dabei steht ":". Ist das Trennzeichen, das ich will
Initial Problem: Welche Dateien funktioniert die TAB Abschluss laufen, wenn ich TAB für ein Wort drücke in Handbuch von Zsh Suche
Lösung
Ich werde versuchen, einen Einblick zu geben, wie zsh Komplettierungssystem arbeitet und ein unvollständiges gehen auf dieses Problem.
Die Datei, die ausgeführt wird, wenn Sie die TAB-Abschluss für man
in zsh verwenden wird unter dem /usr/share/zsh/${ZSH_VERSION}/functions
Verzeichnis. Der Baum ist je nach Distributionen, aber die Datei wird _man
benannt und bietet Fertigstellung für man
, apropos
und whatis
.
Nach _man aufgerufen wird, funktioniert es wie folgt (grobe Beschreibung):
- , wenn für
man
und--local-file
Abschluss als erster Flag angegeben wurde, rufen Sie Standarddateien Abschluss (_files
) -
manpath
Variable aus einem Satz von defaults /$MANPATH
konstruieren. Hier werden die manpages durchsucht - bestimmen, ob wir
man
mit einer Abschnittsnummer Parameter aufgerufen, wenn ja - nur diese Abschnitte durchsucht werden - , wenn der
zstyle ':completion:*:manuals' separate-sections true
verwendet wurde, separate Abschnitte in der Ausgabe (es zwischen ihnen nicht mische) - aufrufen
_man_pages
eine Liste der Manpages für das Spiel zur Verfügung zu stellen -
_man_pages
hat jetzt ein wenig Magie mitcompfiles -p pages '' '' "$matcher" '' dummy '*'
.pages
ist die Variable mit allen Verzeichnissen manpages für angeforderten Abschnitt (en) enthält. Die tatsächlichen Globbing Muster sind von der impliziten Parameter$PREFIX
und dem letzten Parameter konstruiertcompfiles
-*
in diesem Fall. Dies führt zu/usr/share/man/man1
umgewandelt in/usr/share/man/man1/foo*
werden - Die neue Liste von glob Muster wird globbed, alle Dateien zu erhalten, die das Muster entsprechen
-
_man_pages
Streifen dann alle Suffixe aus den Dateien und fügt sich die Abschluss-Widget Auswahlliste voncompadd
mit
Nun, wie Sie sehen können, wird die Liste der Man-Pages direkt von $PREFIX
Variable bestimmt. Um zsh:foo
zur Liste nur Manpages von zsh*
, die enthalten das Wort foo
zu machen, muss es über :
Charakter (falls vorhanden) aufgeteilt werden.
Der folgende Zusatz in _man_pages
löst teilweise das Problem (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
}
Modified (suchen Sie nach ## mod Kommentare):
_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
}
Es ist jedoch noch nicht vollständig funktioniert (wenn Sie die #echo "$p matched $manpage_grep"
Linie Kommentar-, können Sie sehen, dass es die Liste bauen) - Ich vermute, dass irgendwo intern, das Komplettierungssystem sieht, dass zum Beispiel „zshcompctl“ nicht abgestimmt ist durch Vorsilbe „zsh: foo“, und zeigt nicht die daraus resultierenden Ergebnissen geführt. Ich habe versucht, $PREFIX
zu halten, wie es nach dem Abziehen des grep String ist, aber es will noch nicht arbeiten.
Auf jeden Fall diese zumindest sollten Sie beginnen.