
Ich verwende die zsh
Shell und habe den folgenden Code darin .zshrc
:
fpath=(~/.zsh/completion $fpath)
autoload -Uz _vc
autoload -Uz compinit
compinit
Die erste Zeile fügt den Pfad ~/.zsh/completion
zum Array hinzu, das in der Umgebungsvariablen gespeichert ist fpath
.
Die zweite Zeile lädt eine Vervollständigungsfunktion namens _vc
für eine benutzerdefinierte Shell-Funktion namens vc
. Der Zweck von vc
besteht einfach darin, eine Datei in einem bestimmten Ordner ( ) zu bearbeiten ~/.cheat
. _vc
ist in der Datei definiert ~/.zsh/completion/_vc
.
Die letzten beiden Zeilen aktivieren ein Vervollständigungssystem.
Hier ist der Code für meine Vervollständigungsfunktion _vc
:
#compdef vc
declare -a cheatsheets
cheatsheets="$(ls ~/.cheat)"
_arguments "1:cheatsheets:(${cheatsheets})" && return 0
Ich habe es hiervon kopiertAdresse, und habe es an meine Bedürfnisse angepasst.
Solange das Verzeichnis ~/.cheat
keine Datei enthält, deren Name ein einfaches Anführungszeichen enthält, funktioniert die Vervollständigung. Wenn jedoch eines vorhanden ist, z. B. foo'bar
, schlägt die Vervollständigung mit dieser Fehlermeldung fehl:
(eval):56: unmatched '
(eval):56: unmatched '
(eval):56: unmatched '
(eval):56: unmatched '
Ich habe eine Lösung gefunden, indem ich die doppelten Anführungszeichen in der Zeile cheatsheets="$(ls ~/.cheat)"
durch einfache Anführungszeichen ersetzt habe cheatsheets='$(ls ~/.cheat)'
.
Tab
Wenn ich jetzt nach meinem Befehl drücke vc
, schlägt zsh darin enthaltene Dateien vor ~/.cheat
, einschließlich foo\'bar
(zsh scheint das einfache Anführungszeichen automatisch maskiert zu haben).
Ich verstehe jedoch nicht, wie oder warum es funktioniert. Mit einfachen Anführungszeichen cheatsheets
sollte die Variable eine wörtliche Zeichenfolge enthalten. Die $(...)
Befehlsersetzung sollte also nicht erweitert werden. Wenn ich beispielsweise die folgenden Befehle ausführe:
myvar='$(ls)'
echo $myvar → outputs `$(ls)` literally
Warum wird also '$(ls ~/.cheat)'
innerhalb erweitert _arguments "1:cheatsheets:(${cheatsheets})" && return 0
? Und warum wird das einfache Anführungszeichen innerhalb automatisch maskiert foo'bar
?
Antwort1
Wenn wir darauf bestehen, die Dinge auf die falsche Art und Weise zu tun™
#compdef vc
declare -a cheatsheets
cheatsheets=(${(f)"$(ls ~/.cheat/)"})
_arguments '1:cheatsheets:(${cheatsheets})' && return 0
Igitt! Das wird natürlich nicht funktionieren, wenn ein Dateiname eine neue Zeile enthält, da (f)
diese aufgeteilt wird.Parsing ls
ist sowieso eine schlechte Idee; ZSH kann Dateien direkt in ein Array globben:
% mkdir ~/.lojban
% touch ~/.lojban/{go\'i,na\ go\'i}
% words=(~/.lojban/*)
% print -l ${words:t}
go'i
na go'i
% words=(~/.lojban/*(On))
% print -l ${words:t}
na go'i
go'i
%
Aber wir brauchen wahrscheinlich kein lokales Array; _files
wir können es auf einem Glob vervollständigen:
#compdef vc
_arguments '1:cheatsheets:_files -g "~/.cheat/*"' && return 0
Dies gibt vollständig qualifizierte Dateipfade zurück. Wenn nur der reine Dateiname aus einem Suchverzeichnis benötigt wird, können wir stattdessen Folgendes verwenden:
#compdef vc
_arguments '1:cheatsheets:_files -W ~/.cheat' && return 0