¿Existe algo así como cierres para zsh?

¿Existe algo así como cierres para zsh?

Decidí probar zsh (a través de oh-my-zsh) y ahora estoy jugando para precmdemular un mensaje de dos líneas que tiene mensajes correctos en más de la última línea.

Entonces cloné el tema predeterminado y me inspiré enesta publicación(que también estoy usando para aprender mucho), hago algo como esto (agregaré colores más adelante):

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

Y funciona. Pero no puedo evitar preguntarme: ¿zsh define todas esas variables cada vez que se llama a precmd?

He estado buscando en Google cierres, alcance y espacios de nombres en relación con zsh, buscando adjuntar las variables locales como datos a precmd, para que no sea necesario redefinir las variables cada vez, pero no encontré nada. ¿Hay alguna forma de hacer lo que estoy intentando o debería simplemente dejarlo?

Como nota al margen, y sólo si está relacionada, ¿qué significa "tener una función cargada"?

Respuesta1

Zsh no tiene nada parecido a cierres, paquetes o espacios de nombres. Zsh carece de un montón de cosas necesarias para tener cierres verdaderos:

  • Las funciones no son de primera clase. No puede pasar funciones como argumentos a otras funciones y las funciones no pueden devolver otras funciones. (Puedes pasar elnombrede una función a llamar, pero eso no es lo mismo que pasar la función en sí).

  • No puedes tener funciones anidadas. Todas las funciones en zsh son globales. Debe anteponer los nombres de sus funciones para evitar conflictos. Tenga en cuenta especialmente que las funciones seguirán los programas externos con el mismo nombre. Si tiene una función llamada ls, se llamará a ella en lugar del programa ls. Esto puede resultar útil, excepto si lo haces por accidente.

  • Las variables tienen un alcance dinámico, no estático como en la mayoría de los lenguajes modernos. Incluso si pudiera tener funciones anidadas, las funciones internas no se cerrarían sobre las variables locales de las funciones externas de la forma que normalmente se esperaría. No se podían utilizar para crear módulos como lo hace la gente, por ejemplo, en Javascript.

  • Zshhacetienen funciones anónimas, pero sin ninguna de estas otras cosas no son útiles para mucho.

Básicamente, lo mejor que puedes hacer es anteponer todas tus funciones y variables globales.

También señalaré que debes definirlo precmdasí:

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

add-zsh-hookle permite conectar su función precmdsin que sobrescriba otras funciones que también quieran conectarse precmd.

Lo que significa tener una función cargada es una cuestión aparte. Zsh tiene una función de carga automática que solo carga funciones desde el disco cuando realmente se llaman. Cuando lo haga autoload -Uz foobar, la función nombrada estará foobardisponible para llamar. Cuando realmente llamas foobar, se carga la definición desde el disco.

Respuesta2

No, los cierres son demasiado sofisticados para zsh. Zsh está diseñado para interpretar pequeños guiones que no se alejan mucho de la interacción directa. No tiene características de lenguaje sofisticadas que sean muy útiles para la programación a gran escala, pero menos para el tipo de tareas pequeñas para las que normalmente se utilizan los shells.

Tenga en cuenta que si hubiera alguna forma de cierre que permitiera calcular previamente el valor de las variables de una vez por todas y luego almacenarlo, los valores no se actualizarían cuando algo cambie y provoque que la información deje de ser válida.

$git_infoy las variables derivadas pueden cambiar en cualquier momento debido a una modificación de un archivo registrado en git o en el repositorio de git. Por lo tanto, de todos modos es necesario volver a calcularlos cada vez.

Puede almacenar en caché los valores de cwdy who_whereen una variable global, ya que no cambian durante el funcionamiento normal. cwdcambia cuando cambia el directorio actual, por lo que será necesario actualizarlo desde chpwd. Sin embargo, estas variables son extremadamente rápidas de calcular, por lo que no tiene sentido molestarse. El costoso cálculo aquí se está ejecutando git_prompt_infoy eso puede cambiar en cualquier momento.

Cuando muestra información entre cada comando, puede ser una mejor idea ponerla como parte del mensaje ( PS1o la psvarmatriz). Zsh sabe que debe volver a mostrar el mensaje en una variedad de circunstancias, mientras que no sabe nada sobre desde qué imprime precmd.

Respuesta3

Sí, esas variables se (re)definen cada vez que llamas a la función.

Si desea inicializarlos solo una vez, simplemente puede moverlos al nivel superior, fuera de la función.

Respuesta4

Para tener cierres, el lenguaje debe poder manipular funciones como elementos u objetos, lo cual no es posible en zsh, excepto a través de cadenas y el evalincorporado (como en los otros shells). Pero eso es muy limitado ya que usted mismo necesita manejar todas las cosas de bajo nivel (por ejemplo, cotizaciones). Sin embargo, cuando los argumentos no tienen caracteres especiales (por lo tanto, no es necesario manejar las comillas), es fácil hacer algunas cosas simples usando esta idea, y en zsh, las funciones anónimas pueden ayudar un poco. Por ejemplo, para definir funciones que calculan a*x+b*y, donde ay bson constantes proporcionadas en la definición de la función xy yson los argumentos de la función:

mk_ax_plus_by() { echo "() { echo \$((($1)*(\$1)+($2)*(\$2))) }" }

fct_2x_plus_3y=$(mk_ax_plus_by 2 3)
fct_5x_plus_7y=$(mk_ax_plus_by 5 7)

Entonces, uno tiene una función fct_2x_plus_3yque calcula 2*x+3*yy una función fct_5x_plus_7yque calcula 5*x+7*y(tenga en cuenta que he elegido los nombres de las funciones solo para facilitar la lectura, estos pueden ser cualquier nombre y ni siquiera necesita almacenar el contenido en variables). Tenga en cuenta también que en realidad son cadenas (no funciones en la terminología del shell), pero se comportarán como funciones con el evalcomando incorporado. Un ejemplo de uso:

% eval $fct_2x_plus_3y 4 9
35
% eval $fct_5x_plus_7y 4 9
83

como 2*4+3*9da 35 y 5*4+7*9da 83.

Tenga en cuenta que, a diferencia de los lenguajes funcionales, aquí es necesario diferenciar los parámetros que provienen del entorno (sin comillas) y los parámetros de la función definida (entre comillas), es decir, que se evaluarán solo en la llamada a la función. Pero es posible cambiar la implementación para que se parezca más a lenguajes funcionales, y el uso será el mismo:

mk_ax_plus_by()
{
  local x='$1' y='$2'
  echo "() { echo \$((($1)*($x)+($2)*($y))) }"
}

información relacionada