切换主模式时保持缓冲面模式

时间:2013-10-17 02:30:13

标签: emacs elisp emacs-faces

偶尔我会手动设置不同于默认值的font-family和size,我使用buffer-face-mode来执行此操作。 (确切地说,我使用鼠标并从对话框中选择一个。)一旦我设置它,我希望它保持为该缓冲区设置,即使我更改模式,所以我尝试了自定义。这个想法是添加一个change-major-mode-hook(它在缓冲区 - 本地被杀之前运行),它将保存缓冲区面(如果已设置),在稍后调用的函数中 - 这似乎很有效。但是那个函数似乎太快被调用了,当模式改变结束时,buffer-face-mode没有激活。

这是我到目前为止所提出的定制

(defun my-preserve-bufface-cmmh ()
  "Keep the state of buffer-face-mode between major-mode changes"
  (if (and (local-variable-p 'buffer-face-mode) buffer-face-mode)
      (delay-mode-hooks
    (message "face is %s" buffer-face-mode-face) ; Just to show me it has the right face
    (let ((my-inner-face buffer-face-mode-face))
      (run-mode-hooks
       (message "inner %s" my-inner-face) ; it still has the right face here
       (setq buffer-face-mode-face my-inner-face)
       (buffer-face-mode))))))

(add-hook 'change-major-mode-hook
      'my-preserve-bufface-cmmh)

当我在缓冲区中使用次模式buffer-face-mode设置更改主模式时,这些消息都会运行并显示自定义面。我原以为delay-mode-hooks ... run-mode-hooks的组合会在新模式设置后运行setq buffer-face-mode-face ... (buffer-face-mode),但显然不会。

这个定制是否“关闭”/可以挽救我的需求?有更清洁的方式吗?

2 个答案:

答案 0 :(得分:1)

首先,delayed-mode-hooks本身就是一个局部变量。 这意味着,如果您在(delay-mode-hooks (run-mode-hooks ...))中按change-major-mode-hook进行设置 这将无效,因为它会立即被杀死。

第二件事是你run-mode-hooks内的东西是 在my-preserve-bufface-cmmh内进行评估。它应该被定义为后引用钩子函数 `(lambda () ...)您要在其中拼接要保留的值。 另一种方法是使用词汇绑定(谷歌)。

第二件事在以下示例中说明(逐步评估):

(defun test (str)
  (let ((mytest (concat "hello " str)))
    (add-hook 'my-own-hook `(lambda () (message "mytest:%S" ,mytest)))))


(test "you")

(run-hooks 'my-own-hook)

(test "world")

(run-hooks 'my-own-hook)

(put  :myface 'test)

如果要保留字体缓冲区 - 本地,则必须使用幸存kill-all-local-variables的本地变量,例如buffer-file-name。你可以在那里挂钩:

编辑:即使符号具有缓冲区本地值,其属性也不是缓冲区本地。因此,先前的方法不起作用。更好:创建自己的永久缓冲区局部变量:

(defvar-local my-preserve-bufface nil
  "Keep the state of buffer-face-mode between major-mode changes")

(put 'my-preserve-bufface 'permanent-local t)

(defun my-preserve-bufface-put ()
  "Keep the state of buffer-face-mode between major-mode changes"
  (and (local-variable-p 'buffer-face-mode)
       buffer-face-mode
       (setq my-preserve-bufface buffer-face-mode-face)))

(defun my-preserve-bufface-get ()
  "Keep the state of buffer-face-mode between major-mode changes"
    (and my-preserve-bufface
         (setq buffer-face-mode-face my-preserve-bufface)
         (buffer-face-mode)))

(add-hook 'change-major-mode-hook 'my-preserve-bufface-put)
(add-hook 'after-change-major-mode-hook 'my-preserve-bufface-get)

答案 1 :(得分:1)

感谢教育评论,特别是来自@ user2708138的答案/示例,我将接受,因为它确实回答了这个问题。

然而,我也将回答我自己的问题,因为我确实提出了一种更通用的解决方案。我发现我还希望保持我的字体大小更改并且它们来自text-scale-mode,还有一个小模式要保留,我走了这条路。此代码读取要保留的次要模式列表,而不必弄清楚它们使用哪些变量。 (对于一个人来说,弄清楚它们并不难,但我想尝试让emacs这样做。)

唉,我知道没有函数来检索次模式使用的变量,但我感兴趣的模式使用约定 minor-mode -var-name,所以这个代码只过滤该模式的缓冲区局部变量。

; Save & restore minor modes I wish to be "permanent" if set
(setq my-preserve-minor-modes '(buffer-face-mode text-scale-mode))

(defun my-preserve-minor-modes-cmmh ()
  "Keep the state of desired-permanent minor modes between major-mode changes. Assumes that associated buffer-local minor-mode variables to save begin with `minor-mode-'"
  (setq my-restore-minor-modes-acmmh nil)
  (dolist (mm my-preserve-minor-modes)
    (when (and (local-variable-p mm) (symbol-value mm))
      (push mm my-restore-minor-modes-acmmh)))
  (when my-restore-minor-modes-acmmh
    (add-hook 'after-change-major-mode-hook 'my-restore-minor-modes-acmmh)
    ; Predicate-list showing if symbol starts with a preserved mode
    (let ((mm-p-l `(lambda (locvar-nm)
             (or ,@(mapcar (lambda (mm)
                     `(and (< ,(length (symbol-name mm))
                          (length locvar-nm))
                       (string-prefix-p ,(symbol-name mm)
                                locvar-nm)))
                   my-restore-minor-modes-acmmh)))))
      ; For each found minor mode, create fn to restore its buf-local variables
      (dolist (locvar (buffer-local-variables))
    (if (and (listp locvar) (funcall mm-p-l (symbol-name (car locvar))))
          (push `(lambda()(setq ,(car locvar) ',(cdr locvar)))
            my-restore-minor-modes-acmmh))))))


(defun my-restore-minor-modes-acmmh ()
  "After major-mode change, restore minor-mode state, and remove self from hook. It restores state by calling the function stored in the variable my-restore-minor-modes-acmmh."
  (remove-hook 'after-change-major-mode-hook 'my-restore-minor-modes-acmmh)
  (dolist (restore-f my-restore-minor-modes-acmmh) (funcall restore-f)))

(add-hook 'change-major-mode-hook 'my-preserve-minor-modes-cmmh)

我确实知道permanent-local属性,但我不确定是否有任何不必要的副作用......我可能是无根据的偏执狂!

如果有办法获得次要模式的变量列表,或者让用户为每个次要模式指定变量列表,我的答案可以得到改善 - 在任何一种情况下我们都不必循环buffer-local-variables再一次,也许只是将所有permanent-local全部放在我们需要的地方,简化代码。无论如何,把这一切都搞清楚(在你的帮助下,看看精美的手册)是非常有教育意义的。