El contexto
Estoy usando el after-make-frame-functions
gancho para cargar correctamente los temas en una configuración de cliente / servidor de emacs . Específicamente, este es el fragmento de código que uso 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 emacsclient -c/t
se inicia una nueva sesión, el gancho se ejecuta no solo en el nuevo cuadro, sino en todos los cuadros anteriores existentes (otras sesiones de emacsclient ) y produce un efecto visual muy molesto (los temas se cargan nuevamente en todos esos cuadros) . Peor aún, en la terminal los clientes que ya abrieron el color del tema se desordenaron por completo. Obviamente, eso solo ocurre en los clientes de emacs conectados al mismo servidor de emacs. La razón de este comportamiento es clara, el enlace 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 u obtener el mismo resultado sin usar el gancho?
Una solución parcial
Ahora tengo este código, gracias a la respuesta de @ Drew. Pero aún tiene un problema, una vez que inicia una sesión de cliente en el 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é cliente electrónico comienza 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 el tema, todo funciona bien y esa es la razón por la cual 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 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)))
Respuestas:
Supongo que realmente no estás buscando una forma de " ejecutar el gancho solo una vez ". Supongo que está buscando una manera de ejecutar esa función en particular solo una vez, cada vez que se ejecuta el gancho.
La respuesta convencional y simple a esa pregunta es que su función se retire del gancho, después de llevar a cabo la acción única que desea. En otras palabras, úselo
add-hook
en un contexto en el que sepa que la función debe ejecutarse cuando se ejecuta el gancho, y que la función misma se elimine del gancho, después de que la función haga lo suyo.Si estoy adivinando correctamente lo que realmente quiere, 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
:fuente
Aquí hay una macro que puede usar en lugar de
add-hook
(no ampliamente probada):Nota:
make-symbol
crea un símbolo no intercalado con el nombre dado. Incluí un#
en el nombre para marcar el símbolo como algo inusual, en caso de que lo encuentre mientras mira una variable de gancho.fuente
(void-function gensym)
cl
paquete. Lo siento, olvido que no todos lo usan. Puedes usar(make-symbol "#once")
en su lugar. Actualizaré la respuesta.puedes hacer una hiperfunción
gen-once
para transmitir una función normal a una función que solo podría ejecutarse una vez:entonces, use
(add-hook 'xxx-mode-hook (gen-once your-function-need-to-run-once))
fuente