Контекст
Я использую after-make-frame-functions
хук для правильной загрузки тем в конфигурации клиент / сервер emacs . В частности, это фрагмент кода, который я использую для этого (на основе этого 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)))
Проблема
Когда начинается новый emacsclient -c/t
сеанс, ловушка выполняется не только в новом кадре, но и во всех предыдущих существующих кадрах (другие сеансы emacsclient ), и это создает очень раздражающий визуальный эффект (темы снова загружаются во все эти кадры) . Хуже того, в терминале клиенты уже открыли тему, цвет которой полностью испортился. Очевидно, что это происходит только на клиентах emacs, подключенных к тому же серверу emacs. Причина такого поведения ясна: ловушка запускается на сервере и затрагиваются все его клиенты.
Вопрос
Есть ли способ выполнить эту функцию только один раз или получить тот же результат без использования ловушки?
Частичное решение
Теперь у меня есть этот код, благодаря ответу @ Drew. Но все же есть проблема: после запуска клиентского сеанса в терминале графический интерфейс не загружает темы должным образом и наоборот. После многих испытаний я понял, что поведение зависит от того, какой emacsclient запускается первым, и после отбрасывания различных вещей, я думаю, что это может быть связано с загруженной цветовой палитрой. Если вы перезагружаете вручную тему, все работает нормально, и это причина, почему это поведение не появляется, когда функция вызывается ловушкой каждый раз, как в моей начальной конфигурации.
(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)))
Окончательное решение
Наконец, у меня есть полностью рабочий код, который решает поведение, наблюдаемое в частичном решении, для достижения этого я запускаю функцию один раз в режиме (терминал или графический интерфейс), когда затем запускается соответствующий emacsclient, затем удаляю функцию из ловушки, потому что больше не нужно. Теперь я счастлив! :) Еще раз спасибо @Drew!
Код:
(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)))
Ответы:
Я предполагаю, что вы на самом деле не ищете способ « выполнить хук только один раз ». Я предполагаю, что вы ищете способ выполнить эту конкретную функцию только один раз, когда запускается ловушка.
Обычный и простой ответ на этот вопрос заключается в том, что ваша функция снимает себя с крючка после выполнения единовременного действия, которое вы хотите. Другими словами, используйте
add-hook
в контексте, когда вы знаете, что функция должна выполняться при запуске ловушки, и чтобы сама функция удаляла себя из ловушки после того, как функция сделает свое дело.Если я правильно о том, что вы действительно хотите, то , пожалуйста , рассмотреть вопрос редактирования , чтобы что - то вроде угадывания " Есть ли способ запустить крючок функцию только один раз?
Вот пример из стандартной библиотеки
facemenu.el
:источник
Вот макрос, который вы можете использовать вместо
add-hook
(не всесторонне протестированный):Примечание:
make-symbol
создает непостоянный символ с заданным именем. Я включил#
в имя символ, чтобы пометить символ как несколько необычный, на случай, если вы встретите его, глядя на переменную хука.источник
(void-function gensym)
cl
пакета. Извините за это - я забыл, что не все используют это. Вы можете использовать(make-symbol "#once")
вместо этого. Я обновлю ответ.Вы можете создать гиперфункцию
gen-once
для преобразования нормальной функции в функцию, которая может выполняться только один раз:затем используйте
(add-hook 'xxx-mode-hook (gen-once your-function-need-to-run-once))
источник