elisp – ¿Hay alguna forma de ejecutar una función de enlace solo una vez?

Pregunta:

El contexto

Estoy usando el gancho after-make-frame-functions para cargar correctamente los temas en una configuración de cliente / servidor emacs . Específicamente, este es el fragmento de código que utilizo para hacer eso (basado en esta respuesta SO ):

 (if (daemonp)
      (add-hook 'after-make-frame-functions
          (lambda (frame)
              (select-frame frame)
              (load-theme 'monokai t)
              ;; setup the smart-mode-line and its theme
              (sml/setup))) 
      (progn (load-theme 'monokai t)
             (sml/setup)))

El problema

Cuando se inicia una nueva sesión emacsclient -c/t , el hook se ejecuta no solo en el nuevo frame, sino en todos los frames previos existentes (otras sesiones emacsclient ) y produce un efecto visual muy molesto (los temas se cargan de nuevo en todos esos marcos) . Peor aún, en la terminal los clientes ya abiertos el color del tema se estropea por completo. Obviamente, eso ocurre solo en los clientes emacs conectados al mismo servidor emacs. La razón de este comportamiento es clara, el gancho se ejecuta en el servidor y todos sus clientes se ven afectados.

La pregunta

¿Hay alguna forma de ejecutar esta función solo una vez o de obtener el mismo resultado sin usar el gancho?


Una solucion parcial

Ahora tengo este código, gracias a la respuesta de @ Drew. Pero todavía tiene un problema, una vez que inicia una sesión de cliente en la terminal, la GUI no carga los temas correctamente y viceversa. Después de muchas pruebas, me di cuenta de que el comportamiento depende de qué emacsclient comience primero, y después de descartar varias cosas, creo que tal vez esté relacionado con la paleta de colores que se carga. Si vuelve a cargar manualmente, todo el tema funciona bien y esa es la razón por la que este comportamiento no aparece cuando el gancho llama a la función cada vez, como en mi configuración inicial.

(defun emacsclient-setup-theme-function (frame)
  (progn
    (select-frame frame)
    (load-theme 'monokai t)
    ;; setup the smart-mode-line and its theme
    (sml/setup)
    (remove-hook 'after-make-frame-functions 'emacsclient-setup-theme-function)))

(if (daemonp)
    (add-hook 'after-make-frame-functions 'emacsclient-setup-theme-function)
    (progn (load-theme 'monokai t)
           (sml/setup)))

La solución definitiva

Finalmente tengo un código totalmente funcional que resuelve el comportamiento visto en la solución parcial, para lograr esto ejecuto la función una vez por modo (terminal o gui) cuando luego se inicia emacsclient pertinente por primera vez, luego elimino la función del gancho porque es no se necesita más. ¡Ahora soy feliz! 🙂 ¡Gracias de nuevo @Drew!

El código:

(setq myGraphicModeHash (make-hash-table :test 'equal :size 2))
(puthash "gui" t myGraphicModeHash)
(puthash "term" t myGraphicModeHash)

(defun emacsclient-setup-theme-function (frame)
  (let ((gui (gethash "gui" myGraphicModeHash))
        (ter (gethash "term" myGraphicModeHash)))
    (progn
      (select-frame frame)
      (when (or gui ter) 
        (progn
          (load-theme 'monokai t)
          ;; setup the smart-mode-line and its theme
          (sml/setup)
          (sml/apply-theme 'dark)
          (if (display-graphic-p)
              (puthash "gui" nil myGraphicModeHash)
            (puthash "term" nil myGraphicModeHash))))
      (when (not (and gui ter))
        (remove-hook 'after-make-frame-functions 'emacsclient-setup-theme-function)))))

(if (daemonp)
    (add-hook 'after-make-frame-functions 'emacsclient-setup-theme-function)
  (progn (load-theme 'monokai t)
         (sml/setup)))

Respuesta:

Supongo que en realidad no está buscando una forma de " ejecutar el gancho solo una vez ". Supongo que está buscando una forma de ejecutar esa función en particular solo una vez, siempre que se ejecute el gancho.

La respuesta convencional y simple a esa pregunta es que su función se retire del anzuelo, después de realizar la acción única que desea. En otras palabras, use add-hook en un contexto en el que sepa que la función debe ejecutarse cuando se ejecuta el gancho, y haga que la función se elimine del gancho, después de que la función haga lo suyo.

Si estoy adivinando correctamente sobre lo que realmente desea, considere editar su pregunta a algo como " ¿Hay alguna forma de ejecutar una función de enlace solo una vez?

Aquí hay un ejemplo, de la biblioteca estándar facemenu.el :

(defun facemenu-set-self-insert-face (face)
  "Arrange for the next self-inserted char to have face `face'."
  (setq facemenu-self-insert-data (cons face this-command))
  (add-hook 'post-self-insert-hook 'facemenu-post-self-insert-function))

(defun facemenu-post-self-insert-function ()
  (when (and (car facemenu-self-insert-data)
             (eq last-command (cdr facemenu-self-insert-data)))
    (put-text-property (1- (point)) (point)
                       'face (car facemenu-self-insert-data))
    (setq facemenu-self-insert-data nil))
  (remove-hook 'post-self-insert-hook 'facemenu-post-self-insert-function))

Leave a Comment

Your email address will not be published. Required fields are marked *

web tasarım