【问题标题】:Emacs executes `c-mode-hook` twiceEmacs 执行 `c-mode-hook` 两次
【发布时间】:2023-07-29 03:57:01
【问题描述】:

这是我的 emacs 配置

(require 'cc-mode)

(defun ffy-c-mode-hook ()
  "This is settings for the C/C++ mode"
  (message "ffy-c-mode-hook executed")
  (electric-pair-mode +1)
  (electric-indent-local-mode +1)
  (if electric-indent-mode
      (let ((binding (key-binding (kbd "RET"))))
        (local-set-key (kbd "RET") (key-binding (kbd "C-j")))
        (local-set-key (kbd "C-j") binding)))
  (c-toggle-hungry-state +1)
  (c-set-style "gnu")
  (setq c-basic-offset 4))

(add-hook 'c-mode-hook #'ffy-c-mode-hook)

显然c-mode-hook 被执行了两次,因为当我打开一个 C 文件时,我看到了:

user-error: Beginning of history; no preceding item
ffy-c-mode-hook executed [2 times]

这是一个特性还是一个错误?没有其他钩子多次执行AFAIK。另外,现在我似乎无法在挂钩中切换功能。

我查看了变量c-mode-hook,它的值是(ffy-c-mode-hook)

Emacs 和 CC-mode 的版本是

GNU Emacs 24.5.1 (i686-pc-mingw32) of 2015-04-11 on LEG570
Using CC Mode version 5.32.5

ffy-c-mode-hook 上的堆栈跟踪

ffy-c-mode-hook()
run-hooks(change-major-mode-after-body-hook prog-mode-hook c-mode-common-hook c-mode-hook c-mode-hook)
apply(run-hooks (change-major-mode-after-body-hook prog-mode-hook c-mode-common-hook c-mode-hook c-mode-hook))
run-mode-hooks(c-mode-hook)
c-mode()
set-auto-mode-0(c-mode nil)
set-auto-mode()

【问题讨论】:

  • 如果您使用emacs -Q 调用 Emacs,然后评估上面的 sn-p,然后加载 C 文件,是否还会发生这种情况?
  • @Chris 是的。它发生了。我在问题中添加了堆栈跟踪。
  • 我认为这是 emacs 中的一个错误。这里有一个讨论:debbugs.gnu.org/cgi/bugreport.cgi?bug=16759
  • 有趣。所以它已经存在了一段时间。

标签: c emacs


【解决方案1】:

在我对错误报告http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16759 发表评论后,我认为语言挂钩不能保证在多种语言模式下执行一次。我怀疑这个问题是由于使用define-derived-mode 造成的,这是一个 lisp 宏,用于定义已经包含对钩子的调用的模式,这意味着在该模式中调用的钩子将是一个额外的执行。

您可能想尝试初始化挂钩。手册说:

变量:c-initialization-hook

在初始化 CC 模式时,每个 Emacs 会话只运行一次挂钩。这是一个改变的好地方 任何 CC 模式键映射中的键绑定(或添加新的)。看 示例初始化文件。

它提供的示例在这里:https://www.gnu.org/software/emacs/manual/html_node/ccmode/Sample-Init-File.html#Sample-Init-File

【讨论】:

  • 使用define-derived-mode 定义的模式也显式运行其模式挂钩是非常不寻常的。在(绝大多数)大多数情况下,这取决于宏生成的代码(并且可以始终依赖未使用宏定义的模式来模拟涉及挂钩的功能)。您可能会发现这里的文章很有用:*.com/a/19295380/324105
  • 你的意思是如果这样做会是一个错误?
  • 我当然会主张将其视为一个错误-但看起来它已经在您链接到的讨论中被接受,并且已经提出了如何解决的想法用更干净的东西替换意外的调用(大概可以对任何其他实例执行相同的操作,如果存在的话)。