Kontekst
Korzystam z after-make-frame-functions
haka, aby poprawnie załadować motywy w konfiguracji klient / serwer emacs . W szczególności jest to fragment kodu, którego używam do tego (na podstawie tej odpowiedzi 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)))
Problem
Po uruchomieniu nowej emacsclient -c/t
sesji zaczep jest wykonywany nie tylko w nowej ramce, ale we wszystkich poprzednich istniejących ramkach (inne sesje emacsclient ) i daje bardzo irytujący efekt wizualny (motywy są ładowane ponownie we wszystkich tych ramkach) . Co gorsza, w terminalu klienci, którzy już otworzyli, kolor motywu jest całkowicie pomieszany. Oczywiście dzieje się tak tylko na klientach emacs podłączonych do tego samego serwera emacs. Przyczyna tego zachowania jest jasna, hak jest uruchamiany na serwerze i dotyczy to wszystkich jego klientów.
Pytanie
Czy jest jakiś sposób na wykonanie tej funkcji tylko raz lub uzyskanie tego samego wyniku bez użycia haka?
Częściowe rozwiązanie
Mam teraz ten kod, dzięki odpowiedzi @ Drew. Ale nadal ma problem, gdy rozpoczniesz sesję klienta w terminalu, GUI nie ładuje poprawnie motywów i odwrotnie. Po wielu testach zdałem sobie sprawę, że zachowanie zależy od tego, który emacsclient zaczyna się jako pierwszy, a po odrzuceniu różnych rzeczy myślę, że może być związany z załadowaną paletą kolorów. Jeśli przeładujesz ręcznie kompozycję, wszystko działa dobrze i dlatego to zachowanie nie pojawia się, gdy funkcja jest wywoływana przez hak za każdym razem, jak w mojej początkowej konfiguracji.
(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)))
Ostateczne rozwiązanie
Wreszcie mam całkowicie działający kod, który rozwiązuje zachowanie widoczne w rozwiązaniu częściowym. Aby to osiągnąć, uruchamiam funkcję jeden raz w trybie (terminal lub GUI), kiedy po raz pierwszy uruchamiany jest odpowiedni emacsclient, a następnie usuwam funkcję z zaczepu, ponieważ jest nie jest już potrzebny. Teraz jestem szczęśliwy! :) Jeszcze raz dziękuję @Drew!
Kod:
(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)))
Odpowiedzi:
Zgaduję, że tak naprawdę nie szukasz sposobu na „ wykonanie haka tylko raz ”. Zgaduję, że szukasz sposobu na wykonanie tej konkretnej funkcji tylko raz, za każdym razem, gdy uruchamiany jest hak.
Konwencjonalna i prosta odpowiedź na to pytanie polega na tym, że Twoja funkcja usuwa się z zaczepu po wykonaniu jednorazowego działania, które chcesz. Innymi słowy, użyj
add-hook
w kontekście, w którym wiesz, że funkcja powinna zostać wykonana po uruchomieniu haka, i niech sama funkcja zdejmie się z haka, gdy funkcja zrobi swoje.Jeśli mam zgadywać prawidłowo, co naprawdę chcesz, to proszę rozważyć edycji pytanie coś takiego jak " Czy istnieje jakiś sposób, aby uruchomić hak funkcję tylko raz?
Oto przykład ze standardowej biblioteki
facemenu.el
:źródło
Oto makro, którego możesz użyć zamiast
add-hook
(nie jest dokładnie testowany):Uwaga:
make-symbol
tworzy nienaruszony symbol o podanej nazwie. W#
nazwie umieściłem symbol, aby oznaczyć symbol jako nieco nietypowy, na wypadek, gdybyś go spotkał patrząc na zmienną hook.źródło
(void-function gensym)
cl
paczki. Przepraszam za to - zapominam, że nie wszyscy go używają. Zamiast tego możesz użyć(make-symbol "#once")
. Zaktualizuję odpowiedź.możesz wykonać funkcję hiper,
gen-once
aby przekształcić normalną funkcję w funkcję, która może działać tylko raz:następnie użyj
(add-hook 'xxx-mode-hook (gen-once your-function-need-to-run-once))
źródło