문맥
emacs 클라이언트 / 서버 구성after-make-frame-functions
에서 테마를 올바르게로드하기 위해 후크를 사용하고 있습니다 . 특히 이것은 이것을 만드는 데 사용하는 코드 스 니펫입니다 (이 SO answer 기반 ).
(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의 답변 덕분에 이제이 코드가 있습니다. 그러나 여전히 문제가 있습니다. 일단 터미널에서 클라이언트 세션을 시작하면 GUI가 테마를 올바르게로드하지 않으며 그 반대도 마찬가지입니다. 많은 테스트를 거친 후에는 어떤 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가 처음 시작될 때 모드 (터미널 또는 GUI)로 함수를 한 번 실행 한 다음 후크에서 함수를 제거합니다. 더 이상 필요하지 않습니다. 이제 나는 행복하다! 🙂 다시 감사합니다 @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
.
(defun facemenu-set-self-insert-face (face)
"Arrange for the next self-inserted char to have face `face'."
(setq facemenu-self-insert-data (cons face this-command))
(add-hook 'post-self-insert-hook 'facemenu-post-self-insert-function))
(defun facemenu-post-self-insert-function ()
(when (and (car facemenu-self-insert-data)
(eq last-command (cdr facemenu-self-insert-data)))
(put-text-property (1- (point)) (point)
'face (car facemenu-self-insert-data))
(setq facemenu-self-insert-data nil))
(remove-hook 'post-self-insert-hook 'facemenu-post-self-insert-function))
답변
다음은 add-hook
광범위하게 테스트되지 않은 대신 사용할 수있는 매크로입니다 .
(defmacro add-hook-run-once (hook function &optional append local)
"Like add-hook, but remove the hook after it is called"
(let ((sym (make-symbol "#once")))
`(progn
(defun ,sym ()
(remove-hook ,hook ',sym ,local)
(funcall ,function))
(add-hook ,hook ',sym ,append ,local))))
참고 : make-symbol
주어진 이름으로 언 인턴 심볼을 만듭니다. 나는 포함 #
후크 변수를 보면서 경우에 당신이 그것을 건너, 플래그 이름 다소 특이한로 기호에.
답변
하이퍼 함수 gen-once
를 사용하여 일반 함수를 한 번만 실행할 수있는 함수로 변환 할 수 있습니다.
(setq lexical-binding t)
(defun gen-once (fn)
(let ((done nil))
(lambda () (if (not done)
(progn (setq done t)
(funcall fn))))))
(setq test (gen-once (lambda () (message "runs"))))
;;;;---following is test----;;;;
((lambda () (funcall test))) ;; first time, message "runs"
((lambda () (funcall test))) ;; nil
((lambda () (funcall test))) ;; nil
그런 다음 사용 (add-hook 'xxx-mode-hook (gen-once your-function-need-to-run-once))