Gibt es eine Möglichkeit, programmgesteuert auf eine Liste von Abschlusskandidaten in Zsh zuzugreifen und diese zu speichern?

422
John Lunzer

In Zsh ist der tabSchlüssel standardmäßig an gebunden expand-or-complete. Ich möchte programmgesteuert auf die Liste der von press erstellten Abschlusskandidaten zugreifen tab, damit ich meine eigene Funktion schreiben und die Liste selbst filtern kann. Ich verstehe, dass es bei Zsh einen "Abschlussrahmen" gibt, aber ich würde es gerne selbst machen.

Es gibt auch die list-choicesFunktion / das Widget, das die gleiche Ausgabe erzeugt wie expand-or-completedie Tab-Cycling-Funktion.

Ich habe eine ziemlich umfangreiche Suche bei Google durchgeführt und auch durch die Zsh-Quelle gestöbert, war aber trocken. Jede Hilfe wäre dankbar.

2
Interessante Frage. Haben Sie sich diese [Bash-Implementierung desselben Konzepts] (https://brbsix.github.io/2015/11/29/accessing-tab-completion-programmatic-in-bash/) angesehen? JakeGould vor 6 Jahren 0

1 Antwort auf die Frage

2
John Lunzer

Indirekt dank JakeGould stolperte ich über eine Lösung: zsh-capture-completion. Tatsächlich gibt es zwei weitere fast identische Fragen zu den Unix-Stack-Exchange-Sites, beide mit der Antwort, die ich hier gegeben habe.

Skript-Quellcode für zsh-capture-completionfinden Sie hier:

#!/bin/zsh  zmodload zsh/zpty || { echo 'error: missing module zsh/zpty' >&2; exit 1 }  # spawn shell zpty z zsh -f -i  # line buffer for pty output local line  setopt rcquotes () { zpty -w z source $1 repeat 4; do zpty -r z line [[ $line == ok* ]] && return done echo 'error initializing.' >&2 exit 2 } =( <<< ' # no prompt! PROMPT= # load completion system autoload compinit compinit -d ~/.zcompdump_capture # never run a command bindkey ''^M'' undefined bindkey ''^J'' undefined bindkey ''^I'' complete-word # send a line with null-byte at the end before and after completions are output null-line () { echo -E - $''\0'' } compprefuncs=( null-line ) comppostfuncs=( null-line exit ) # never group stuff! zstyle '':completion:*'' list-grouped false # don''t insert tab when attempting completion on empty line zstyle '':completion:*'' insert-tab false # no list separator, this saves some stripping later on zstyle '':completion:*'' list-separator '''' # we use zparseopts zmodload zsh/zutil # override compadd (this our hook) compadd () { # check if any of -O, -A or -D are given if [[ ${@[1,(i)(-|--)]} == *-(O|A|D)\ * ]]; then # if that is the case, just delegate and leave builtin compadd "$@" return $? fi # ok, this concerns us! # echo -E - got this: "$@" # be careful with namespacing here, we don''t want to mess with stuff that # should be passed to compadd! typeset -a __hits __dscr __tmp # do we have a description parameter? # note we don''t use zparseopts here because of combined option parameters # with arguments like -default- confuse it. if (( $@[(I)-d] )); then # kind of a hack, $+@[(r)-d] doesn''t work because of line noise overload # next param after -d __tmp=${@[$[${@[(i)-d]}+1]]} # description can be given as an array parameter name, or inline () array if [[ $__tmp == \(* ]]; then eval "__dscr=$__tmp" else __dscr=( "${(@P)__tmp}" ) fi fi # capture completions by injecting -A parameter into the compadd call. # this takes care of matching for us. builtin compadd -A __hits -D __dscr "$@" setopt localoptions norcexpandparam extendedglob # extract prefixes and suffixes from compadd call. we can''t do zsh''s cool # -r remove-func magic, but it''s better than nothing. typeset -A apre hpre hsuf asuf zparseopts -E P:=apre p:=hpre S:=asuf s:=hsuf # append / to directories? we are only emulating -f in a half-assed way # here, but it''s better than nothing. integer dirsuf=0 # don''t be fooled by -default- >.> if [[ -z $hsuf && "${${@//-default-/}% -# *}" == *-[[:alnum:]]#f* ]]; then dirsuf=1 fi # just drop [[ -n $__hits ]] || return # this is the point where we have all matches in $__hits and all # descriptions in $__dscr! # display all matches local dsuf dscr for i in ; do # add a dir suffix? (( dirsuf )) && [[ -d $__hits[$i] ]] && dsuf=/ || dsuf= # description to be displayed afterwards (( $#__dscr >= $i )) && dscr=" -- ${$##$__hits[$i] #}" || dscr= echo -E - $IPREFIX$apre$hpre$__hits[$i]$dsuf$hsuf$asuf$dscr done } # signal success! echo ok')  zpty -w z "$*"$'\t'  integer tog=0 # read from the pty, and parse linewise while zpty -r z; do :; done | while IFS= read -r line; do if [[ $line == *$'\0\r' ]]; then (( tog++ )) && return 0 || continue fi # display between toggles (( tog )) && echo -E - $line done  return 2 

Hier ist ein Beispiel für die Verwendung von Skripts:

══► % cd ~/.zsh_plugins ══► % zsh ./zsh-capture-completion/capture.zsh 'cd ' zaw/ zsh-capture-completion/ zsh-syntax-highlighting/ zsh-vimode-visual/ 

Beachten Sie das Leerzeichen im obigen Befehl. Mit dem Space stellt das Skript die Liste der Ordner bereit, in die Sie cdaus dem aktuellen Verzeichnis gelangen können. Andernfalls würde das Skript alle Vervollständigungen für Befehle bereitstellen, die mit beginnen cd.

Ich sollte auch beachten, dass selbst der Autor des bereitgestellten Skripts / Plugins seine Lösung als "hacky" betrachtet. Wenn jemand eine kürzere oder einfachere Lösung kennt, würde ich mich freuen, diese als Antwort zu akzeptieren.

Gute Arbeit! Der Quellcode für das Skript selbst wurde hinzugefügt, da der Code am Ende des Tages kurz genug ist. Es ist immer besser, ihn in einer Antwort zu posten, da Links (und deren Inhalt) oft verschwinden können. JakeGould vor 6 Jahren 1
Danke, ich war irgendwie auf dem Zaun, weil ich es hinzugefügt habe. Ich denke, es ist nur am Abgrund "kurz genug" oder "zu lang" zu sein. Aufgrund Ihrer Erfahrung werde ich Ihrem Urteil überlassen. John Lunzer vor 6 Jahren 0
Kein Problem. Beachten Sie, wie der Quellcode in einem Bildlaufelement platziert wird. Länge ist also keine vollständige Sorge, es sei denn, sie ist wirklich lang und außer Kontrolle geraten. JakeGould vor 6 Jahren 0
Außerdem gibt es im Quellcode möglicherweise anstößige / insensitive Sprache. John Lunzer vor 6 Jahren 1
Yikes! Zumindest war es nur ein Kommentar und ich habe es entfernt. JakeGould vor 6 Jahren 0