before-save-hook中奇奇妙妙的 Error: (wrong-number-of-arguments (2 . 3) 0)

我在我的init.el中是这样写的

  (defun my-indent ()
    "Format all the buffer."
    (interactive)
    (indent-region (point-min) (point-max) nil))
  
  (use-package emacs
    :hook
    (before-save . my-indent))

可重新启动emacs后,保存文件时会报错

Error: (wrong-number-of-arguments (2 . 3) 0)

magical的是,如果我在*scratch*中写这段代码并C-x C-e运行,能够成功执行。

有大佬知道这是怎么回事吗?谢谢

钩子链上的函数要接受参数的, my-indent 函数为零参函数,自然会报错。 你可以把它改成接受 2 个参数的函数,然后不使用这两个参数就可以了。 可以 C-h v 看看 before-save-hook 中的函数都接受几个参数

大佬,我改成了这样:

  (defun my-indent (beg end)
    "Format all the buffer."
    (interactive (list (point-min) (point-max)))
    (indent-region beg end))
  
  (use-package emacs
    :hook
    (before-save . my-indent))

可还是那个错误 Error: (wrong-number-of-arguments (2 . 3) 0) 有什么地方做得不对吗?

抱歉,这个回答的有点想当然了 :joy: 我在我的 emacs 上试了试你的函数:

(add-hook 'before-save-hook 'my-indent)
(run-hooks 'before-save-hook)

这样运行是没有问题的。上面我说的不对,hook 一般都是使用的函数都是没有参数的。

然后我想了想可能和 use-package 有关系,之前还没用过它。我随便试了下:

(macroexpand '(use-package emacs
		:hook (before-save . my-indent)))
=>
(progn
  (defvar use-package--warning1
    #'(lambda (keyword err)
	(let ((msg (format "%s/%s: %s" 'emacs keyword (error-message-string err))))
	  (display-warning 'use-package msg :error))))
  (condition-case-unless-debug err
      (progn (unless (fboundp 'hhh)
	       (autoload #'hhh "emacs" nil t))
	     (add-hook 'before-save-hook #'hhh))
    (error (funcall use-package--warning1 :catch err))))

这个 use-package 的功能就是添加 autoload 和将钩子函数放入钩子中。在运行 use-package 后,我运行了一下钩子,发现也没有问题。

那我猜应该是和 files 中的 save-buffer 函数有关?看源代码的话,它只是使用 run-hooks 调用了 before-save-hook

能不能给出更详细的 debug 信息呢?

(你这解决方案给早了 :rofl:

代码:

  (defun my-indent ()
    "Format all the buffer."
    (interactive)
    (indent-region (point-min) (point-max)))

  (use-package emacs
    :hook
    (before-save . my-indent))

error

Saving file /home/was/.emacs.d/README.org...
Error: (wrong-number-of-arguments (2 . 3) 0)
Wrote /home/was/.emacs.d/README.org

我的before-save-hook的值

(untabify whitespace-cleanup delete-trailing-whitespace my-indent)

能否在 buffer 中运行 (run-hooks 'before-save-hook) ,然后把 edebug Backtrace buffer 中的内容也发一下呢

使用第一版的 my-indent

Debugger entered--Lisp error: (wrong-number-of-arguments (2 . 3) 0)
  untabify()
  run-hooks(before-save-hook)
  (progn (run-hooks 'before-save-hook))
  eval((progn (run-hooks 'before-save-hook)) t)
  elisp--eval-last-sexp(nil)
  eval-last-sexp(nil)
  funcall-interactively(eval-last-sexp nil)
  call-interactively(eval-last-sexp nil nil)
  command-execute(eval-last-sexp)

好了,这下就清楚问题所在了,这不是 my-indent 的锅 :joy:

要解决这个问题的话,最简单粗暴的方式就是 (remove-hook ‘before-save-hook 'untabify) ,把这个函数从钩子链中去掉,这样就应该没有问题了。

另外可以看看 untabify 是从哪里被添加到钩子链中的,它有什么作用。C-h f 看看这个函数的定义和注释之类的消息。

2 个赞

你这一说,我才仔细看这个 backtree(不知道我之前在想什么)

的确是untabify

是我无脑了😂

1 个赞