Gibt es so etwas wie Verschlüsse für zsh?

7

Ich habe gerade beschlossen, zsh (über oh-my-zsh) auszuprobieren, und spiele jetzt mit precmd, um eine zweizeilige Eingabeaufforderung zu emulieren, die in mehr als nur der letzten Zeile die richtigen Eingabeaufforderungen enthält.

Also klone ich das Standardthema und inspiriere mich an diesem Beitrag (mit dem ich auch viel lerne). Ich mache so etwas (ich werde später Farben hinzufügen):

function precmd {
    local cwd="${(%):-[%~]}"
    local who_where="${(%):-%n@%m}"
    local git_info=${(%)$(git_prompt_info)}
    local right_prompt="     $git_info [$who_where]"
    local left_prompt="${(r:(($COLUMNS - ${#${right_prompt}})):: :)cwd}"

    echo "$left_prompt$right_prompt"
}

Und es funktioniert. Aber ich frage mich: Definiert zsh jedes Mal, wenn precmd aufgerufen wird, all diese Variablen?

Ich habe nach Abschlüssen, Umfang und Namespace in Bezug auf zsh gegoogelt und versucht, die lokalen Variablen als Daten an precmd anzuhängen, damit die Variablen nicht jedes Mal neu definiert werden müssen, aber ich habe nichts gefunden. Gibt es eine Möglichkeit, das zu tun, was ich versuche, oder sollte ich es einfach fallen lassen?

Als Randnotiz und nur wenn es verwandt ist, was bedeutet "eine Funktion laden lassen"?

ferhtgoldaraz
quelle

Antworten:

10

Zsh hat nichts wie Verschlüsse oder Pakete oder Namespaces. Zsh fehlt eine Reihe von Dingen, die für echte Abschlüsse erforderlich sind:

  • Funktionen sind nicht erstklassig. Sie können Funktionen nicht als Argumente an andere Funktionen weitergeben, und Funktionen können keine anderen Funktionen zurückgeben. (Sie können den Namen einer aufzurufenden Funktion übergeben, dies entspricht jedoch nicht der Übergabe der Funktion selbst).

  • Sie können keine verschachtelten Funktionen haben. Alle Funktionen in zsh sind global. Sie müssen Ihren Funktionsnamen ein Präfix voranstellen, um Konflikte zu vermeiden. Beachten Sie insbesondere, dass Funktionen externe Programme mit demselben Namen beschatten. Wenn Sie eine Funktion aufgerufen haben ls, wird diese anstelle des Programms aufgerufen ls. Dies kann nützlich sein, es sei denn, Sie tun dies versehentlich.

  • Variablen haben einen dynamischen Gültigkeitsbereich und keinen statischen Gültigkeitsbereich wie in den meisten modernen Sprachen. Selbst wenn Sie verschachtelte Funktionen hätten, würden innere Funktionen die lokalen Variablen der äußeren Funktionen nicht so schließen, wie Sie es normalerweise erwarten würden. Sie können sie nicht verwenden, um Module so zu erstellen, wie es beispielsweise in Javascript der Fall ist.

  • Zsh hat zwar anonyme Funktionen, aber ohne diese anderen Dinge sind sie für vieles nicht nützlich.

Das Beste, was Sie tun können, ist, all Ihren Funktionen und globalen Variablen ein Präfix zu setzen.

Ich werde auch darauf hinweisen, dass Sie Ihre precmdso definieren sollten :

% autoload -Uz add-zsh-hook
% add-zsh-hook precmd my_precmd_function

add-zsh-hookMit dieser Funktion können Sie Ihre Funktion precmdeinbinden, ohne andere Funktionen zu überschreiben, die möglicherweise ebenfalls eingebunden werden sollen precmd.

Was es bedeutet, eine Funktion geladen zu haben, ist eine separate Frage. Zsh verfügt über eine Autoloading-Funktion, die Funktionen nur dann von der Festplatte lädt, wenn sie tatsächlich aufgerufen werden. Wenn Sie dies tun autoload -Uz foobar, steht die genannte Funktion foobarzum Aufrufen zur Verfügung. Wenn Sie tatsächlich aufrufen foobar, wird die Definition von der Festplatte geladen.

Matt
quelle
1
Das habe ich gesucht. Ich kann noch nicht abstimmen, aber ein großes Lob.
Ferhtgoldaraz
@Matt, zusätzliche Gutschrift für die Erwähnung des Add-Zsh-Hooks.
SuperMagic
Für Punkt 1 können Sie die Definition einer Funktion als Argument übergeben: myfunc $functions[otherfunction]das myfunckann beispielsweise als aufgerufen werden () {eval $1} args(nicht, dass ich dies empfehlen würde).
Stéphane Chazelas
Für Punkt 3 können Sie mithilfe von privateVariablen (im zsh/param/privateModul) einen statischen Bereich haben .
Stéphane Chazelas
Ich hatte gerade diese verrückte Idee und es scheint nicht nur mit Bash zu funktionieren, sondern auch mit zsh: gist.github.com/pinkeen/287ad64d951f7bf138afce975d3bce7b
pinkeen
5

Nein, Verschlüsse sind für zsh zu raffiniert. Zsh wurde entwickelt, um kleine Skripte zu interpretieren, die nicht weit von der direkten Interaktion entfernt sind. Es gibt keine ausgefallenen Sprachfunktionen, die für die Programmierung im großen Stil sehr nützlich sind, aber weniger für die Art kleiner Aufgaben, für die Shells normalerweise verwendet werden.

Beachten Sie, dass bei einer Form des Abschlusses, bei der der Wert der Variablen ein für alle Mal vorberechnet und dann gespeichert werden konnte, die Werte nicht aktualisiert werden, wenn sich etwas ändert, das dazu führt, dass die Informationen ungültig werden.

$git_infound die abgeleiteten Variablen können sich jederzeit aufgrund einer Änderung an einer in git oder im git-Repository eingecheckten Datei ändern. Sie müssen also sowieso jedes Mal neu berechnet werden.

Sie können die Werte von cwdund who_wherein einer globalen Variablen zwischenspeichern, da sie sich im normalen Betrieb nicht ändern. cwdändert sich, wenn sich das aktuelle Verzeichnis ändert, sodass es aktualisiert werden muss chpwd. Diese Variablen lassen sich jedoch sehr schnell berechnen, sodass es keinen Sinn macht, sich darum zu kümmern. Die teure Berechnung läuft hier git_prompt_infound das kann sich jederzeit ändern.

Wenn Sie Informationen zwischen den einzelnen Befehlen anzeigen, ist es möglicherweise besser, sie als Teil der Eingabeaufforderung ( PS1oder des psvarArrays) einzufügen. Zsh weiß, dass die Eingabeaufforderung unter verschiedenen Umständen erneut angezeigt werden muss, während es nichts darüber weiß, von was Sie drucken precmd.

Gilles 'SO - hör auf böse zu sein'
quelle
+1, um die Notwendigkeit zu beheben, die Werte jedes Mal neu zu berechnen.
Chepper
1

Ja, diese Variablen werden bei jedem Aufruf der Funktion (neu) definiert.

Wenn Sie sie nur einmal initialisieren möchten, können Sie sie einfach aus der Funktion auf die oberste Ebene verschieben.

Ben
quelle
Danke für die Antwort. Obwohl ich versuche, Alternativen zur Nutzung des globalen Anwendungsbereichs zu finden, damit ich die Umweltverschmutzung in Zukunft bekämpfen kann, wenn dies erforderlich ist. Vielleicht gibt es eine Alternative dazu?
Ferhtgoldaraz
1
Nicht wirklich. Sie können ein Präfix für Ihre Variablen verwenden, z. B. LRPROMPT_, um mögliche Namenskollisionen / Verschmutzungen zu begrenzen. Dies ist jedoch weiterhin möglich. Außerdem ist es nur Ihre Shell und Eingabeaufforderung. Kollisionen können passieren, aber es ist keine so große Sache, wenn Sie nicht viel mehr in der Shell tun, als wahrscheinlich vernünftig ist. Ich benutze oh-my-zsh UND habe mehr als 2000 Zeilen in einer benutzerdefinierten zsh-Konfiguration (über omz hinaus) und Kollisionen sind wirklich kein Problem. Ich verwende jedoch Präfixe.
SuperMagic
Wenn Ihre Shell-Startdateien so groß sind, dass Namenskollisionen wirklich ein Problem darstellen, werden Sie mit ziemlicher Sicherheit auch andere, schwerwiegendere Probleme haben :)
Ben
@Ben, diese Zahl enthält Funktionen mit beträchtlichem Leerraum und lokalen Variablen. Wenn ich 2000 globale Aliase und Variablen hätte ... wäre das ein Problem.
SuperMagic