Il contesto
Sto usando l' after-make-frame-functions
hook per caricare correttamente i temi in una configurazione client / server emacs . In particolare questo è lo snippet di codice che utilizzo per farlo (basato su questa risposta 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)))
Il problema
Quando emacsclient -c/t
viene avviata una nuova sessione, l'hook viene eseguito non solo nel nuovo frame, ma in tutti i frame esistenti precedenti (altre sessioni emacsclient ) e produce un effetto visivo molto fastidioso (i temi vengono caricati di nuovo in tutti quei frame) . Ancora peggio, nei terminali i client hanno già aperto il colore del tema che si incasina completamente. Ovviamente ciò accade solo sui client emacs collegati allo stesso server emacs. Il motivo di questo comportamento è chiaro, l'hook viene eseguito sul server e tutti i suoi client ne sono interessati.
La domanda
Esiste un modo per eseguire questa funzione una sola volta o ottenere lo stesso risultato senza usare l'hook?
Una soluzione parziale
Ora ho questo codice, grazie alla risposta di @ Drew. Ma ha ancora un problema, una volta avviata una sessione client nel terminale, la GUI non carica correttamente i temi e viceversa. Dopo molti test, mi sono reso conto che il comportamento dipende da quale emacsclient inizia per primo, e dopo aver scartato varie cose, penso che sia forse correlato alla tavolozza dei colori che viene caricata. Se ricarichi manualmente il tema funziona tutto bene e questo è il motivo per cui questo comportamento non appare quando la funzione viene chiamata dall'hook ogni volta come nella mia configurazione iniziale.
(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 soluzione finale
Finalmente ho un codice totalmente funzionante che risolve il comportamento visto nella soluzione parziale, per raggiungere questo obiettivo eseguo la funzione una volta per modalità (terminale o gui) quando viene quindi avviato emacsclient pertinente per la prima volta, quindi rimuovo la funzione dal gancio perché è non serve più. Ora sono felice! :) Grazie ancora @Drew!
Il codice:
(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)))