O contexto
Estou usando o after-make-frame-functions
gancho para carregar corretamente os temas em uma configuração de cliente / servidor do emacs . Especificamente, este é o trecho de código que eu uso para fazer isso (com base nesta resposta do 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)))
O problema
Quando uma nova emacsclient -c/t
sessão é iniciada, o gancho é executado não apenas no novo quadro, mas em todos os quadros existentes anteriores (outras sessões do emacsclient ) e produz um efeito visual muito irritante (os temas são carregados novamente em todos esses quadros) . Pior ainda, nos clientes do terminal já abertos, a cor do tema fica completamente bagunçada. Obviamente, isso acontece apenas nos clientes emacs conectados ao mesmo servidor emacs. O motivo desse comportamento é claro, o gancho é executado no servidor e todos os seus clientes são afetados.
A questão
Existe alguma maneira de executar essa função apenas uma vez ou obter o mesmo resultado sem usar o gancho?
Uma solução parcial
Agora tenho esse código, graças à resposta do @ Drew. Mas ainda tem um problema: depois de iniciar uma sessão do cliente no terminal, a GUI não carrega os temas corretamente e vice-versa. Depois de muitos testes, percebi que o comportamento depende de qual emacsclient é iniciado primeiro e, depois de descartar várias coisas, acho que talvez esteja relacionado à paleta de cores carregada. Se você recarregar manualmente, o tema funcionará bem e essa é a razão pela qual esse comportamento não aparece quando a função é chamada pelo gancho sempre, como na minha configuração 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)))
A solução final
Finalmente, tenho um código totalmente funcional que resolve o comportamento visto na solução parcial. Para conseguir isso, eu executo a função uma vez por modo (terminal ou gui), quando o emacsclient pertinente é iniciado pela primeira vez e, em seguida, remova a função do gancho, porque é não é mais necessário. Agora estou feliz! :) Mais uma vez obrigado @Drew!
O 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)))