Y at-il quelque chose comme des fermetures pour zsh?

J'ai juste décidé d'essayer zsh (à travers oh-my-zsh), et je suis en train de jouer avec precmd pour émuler une invite de deux lignes qui a droit invites dans plus que juste la dernière ligne.

Donc, je clone le thème par défaut, et je suis inspiré par ce post (que j'utilise pour apprendre beaucoup), je fais un peu comme ça (j'appendai des colors plus tard):

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

Et il fonctionne. Mais je ne peux pas m'empêcher de me requestr: zsh définit-il toutes ces variables à chaque fois que precmd est appelé?

J'ai cherché Google pour les fermetures, la scope et le namespacing par rapport à zsh, en cherchant à attacher les vars locaux en tant que données à precmd, donc il n'a pas besoin de redéfinir les variables à chaque fois, mais je n'ai rien trouvé. Y at-il un moyen de faire ce que j'essaie, ou devrais-je le déposer?

Comme note de côté, et seulement si elle est liée, que signifie "charger une fonction"?

Zsh n'a rien à voir avec des fermetures, des packages ou des namespaces. Zsh manque un tas de choses nécessaires pour avoir de vraies fermetures:

  • Les fonctions ne sont pas de première class. Vous ne pouvez pas passer des fonctions en tant qu'arguments à d'autres fonctions et les fonctions ne peuvent pas renvoyer d'autres fonctions. (Vous pouvez passer le nom d'une fonction à appeler, mais ce n'est pas la même chose que de passer la fonction elle-même).

  • Vous ne pouvez pas avoir de fonctions nestedes. Toutes les fonctions de zsh sont globales. Vous devez préfixer vos noms de fonction pour éviter les conflits. Notez en particulier que les fonctions masquent les programmes externes portant le même nom. Si vous avez une fonction appelée ls , elle sera appelée à la place du programme ls . Cela peut être utile, sauf si vous le faites par accident.

  • Les variables ont une scope dynamic, et non une scope statique comme dans la plupart des langues modernes. Même si vous pouviez avoir des fonctions nestedes, les fonctions internes ne se ferment pas sur les variables locales des fonctions externes comme vous le feriez normalement. Vous ne pouviez pas les utiliser pour créer des modules comme les gens le font, par exemple, Javascript.

  • Zsh a des fonctions anonymes, mais sans aucune de ces autres choses, ils ne sont pas utiles pour beaucoup.

Donc, fondamentalement, le mieux que vous puissiez faire est de préfixer toutes vos fonctions et variables globales.

Je soulignerai aussi que vous devriez définir votre precmd comme ceci:

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

add-zsh-hook vous permet d'accrocher votre fonction dans precmd sans écraser d'autres fonctions qui pourraient aussi vouloir accrocher precmd .

Ce que cela signifie d'avoir une fonction chargée est une question distincte. Zsh a une fonction de chargement automatique qui charge uniquement les fonctions du disque lorsqu'elles sont appelées. Lorsque vous faites autoload -Uz foobar , cela rend la fonction appelée foobar disponible pour appeler. Lorsque vous appelez en fait foobar , cela charge la définition depuis le disque.

Non, les fermetures sont trop sophistiquées pour zsh. Zsh est conçu pour interpréter de petits scripts qui ne sont pas très éloignés de l'interaction directe. Il n'a pas de fonctionnalités de langage de fantaisie qui sont très utiles pour la programmation dans le grand mais less pour le genre de petites tâches que les coquilles sont généralement utilisées.

Notez que s'il existait une forme de fermeture qui permettait de pré-calculer la valeur des variables une fois pour toutes, puis les stocker, les valeurs ne seraient pas mises à jour lorsque quelque chose change, entraînant l'invalidation des informations.

$git_info et les variables dérivées peuvent changer à tout moment en raison d'une modification d'un file vérifié dans git ou dans le référentiel git. Donc, ils doivent être recalculés à chaque fois de toute façon.

Vous pouvez mettre en cache les valeurs de cwd et who_where dans une variable globale, car elles ne changent pas en fonctionnement normal. cwd change quand le directory currrent change donc il devrait être mis à jour à partir de chpwd . Cependant, ces variables sont extrêmement rapides à calculer, donc il ne sert à rien de déranger. Le calcul coûteux est en cours d'exécution git_prompt_info , et cela peut changer à tout moment.

Lorsque vous affichez des informations entre chaque command, il peut être préférable de la placer dans l'invite ( PS1 ou le tableau psvar ). Zsh sait qu'il doit réafficher l'invite dans une variété de circonstances, alors qu'il ne sait rien de ce que vous imprimez à partir de precmd .

Oui, ces variables sont (re) définies à chaque fois que vous appelez la fonction.

Si vous souhaitez les initialiser une seule fois, vous pouvez simplement les déplacer vers le niveau supérieur, hors de la fonction.