caasi
1
环境为macOS 10.15.2; GNU Emacs 26.3。以下是完整的~/.emacs.d/init.el
文件内容:
(setq package-archives
'(("gnu" . "http://elpa.emacs-china.org/gnu/")
("melpa" . "http://elpa.emacs-china.org/melpa/")
("org" . "http://elpa.emacs-china.org/org/")))
(package-initialize)
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile (require 'use-package))
(setq use-package-always-ensure t)
(use-package evil
:config (evil-mode))
通过该配置文件可以正常开启图形界面的Emacs并正确启用Evil模式。但是,如果是在终端下运行emacs --batch --load="~/.emacs.d/init.el"
就会报以下的错误:
Wrong type argument: number-or-marker-p, nil
有没有知道原因的,还有,这种情况应该怎么调试?谢过!
意思:参数类型不匹配,预期一个数字,却收到 nil
。
打开 Lisp Debugger,查看出错时的 Backtrace(就是导致该错误的一系列函数调用),如:
~ $ emacs -Q --batch -f toggle-debug-on-error --eval '(+ 1 (car 2))'
Debug on Error enabled globally
Debugger entered--Lisp error: (wrong-type-argument listp 2)
car(2)
(+ 1 (car 2))
eval((+ 1 (car 2)))
command-line-1(("-f" "toggle-debug-on-error" "--eval" "(+ 1 (car 2))"))
command-line()
normal-top-level()
Backtrace 从上往下一行一行看
Debugger entered--Lisp error: (wrong-type-argument listp 2)
报错,参数类型不匹配,要求 list,获得 2。这是哪来的呢?
car(2)
原来代码执行了 (car 2)
,这又是哪来的呢?
(+ 1 (car 2))
原来是这里。
用 M-x toggle-debug-on-error 或 (setq debug-on-error t) 开启 Lisp Debugger。
caasi
3
多谢回复!不幸的是如此执行仍然无法得到更多的错误消息,在Evil的Repo上提了Issue #1243,开发者回复说是undo-tree的问题。
可复现该问题的最小化init.el
:
(require 'package)
(package-initialize)
(unless (package-installed-p 'undo-tree)
(package-refresh-contents)
(package-install 'undo-tree))
(require 'undo-tree)
(global-undo-tree-mode)
执行emacs -Q --batch -f toggle-debug-on-error --load="~/.emacs.d/init.el"
后提示错误:Wrong type argument: number-or-marker-p, nil
。
想到最近确实更新了undo-tree(2020-01-09)。
为什么要在 batch 模式下加载 evil 呢?可以只加载那些你用到的包,写一个专门用于 batch 模式的 init.el 很简单的。
caasi
6
解决问题了,是新版undo-tree的bug,邮件联系了开发者,目前该问题已经解决了。
P.S. 我也奇怪,但是使用前文提供的init.el,再运行emacs -Q --batch -f toggle-debug-on-error --load="~/.emacs.d/init.el"
确实只产生了如下两行输出:
Debug on Error enabled globally
Wrong type argument: number-or-marker-p, nil
caasi
7
嗯,场景是比较特殊,搜索引擎上也搜索不到相关问题。比较好奇为什么同样的配置文件,batch模式和正常模式下会产生不同的结果。
我也遇到这个问题,undo-tree最近老出问题,正在尝试undo-fu。
没看到 backtrace,说明没有触发 debugger,试试清空 debug-ignored-errors
。
~ $ emacs -Q --batch -f toggle-debug-on-error --eval '(user-error "hello")'
Debug on Error enabled globally
hello
~ $ emacs -Q --batch -f toggle-debug-on-error --eval '(setq debug-ignored-errors nil)' --eval '(user-error "hello")'
Debug on Error enabled globally
Debugger entered--Lisp error: (user-error "hello")
signal(user-error ("hello"))
user-error("hello")
eval((user-error "hello"))
command-line-1(("-f" "toggle-debug-on-error" "--eval" "(setq debug-ignored-errors nil)" "--eval" "(user-error \"hello\")"))
command-line()
normal-top-level()
2 个赞
源文件编译之后往往会掩盖/造成一些问题。
把 .elc
文件删掉之后,错误信息就更明确一些了:
Debug on Error enabled globally
Package cl is deprecated
Error: (error (void-function undo-tree-save-history-from-hook))
(undo-tree-save-history-from-hook)
(kill-buffer #<buffer *temp*-191149>)
...
先不纠结 undo-tree-save-history-from-hook
为什么这个函数不存在,因为它看起来跟最早的 number-or-marker-p
错误不太相干。所以定义一个空的,让其执行通过看看会发生什么:
(when noninteractive
(defun undo-tree-save-history-from-hook ()
(message "==> undo-tree-save-history-from-hook")))
再次运行,可以看到 message 打印出来了,出错信息进一步明确:
Debug on Error enabled globally
Package cl is deprecated
==> undo-tree-save-history-from-hook
Error: (error (wrong-type-argument number-or-marker-p nil))
(max nil 360000000)
(if undo-tree-limit (max undo-outer-limit undo-tree-outer-limit) most-positive-fixnum)
(set (make-local-variable 'undo-outer-limit) (if undo-tree-limit (max undo-outer-limit undo-tree-outer-limit) most-positive-fixnum))
...
真正出错的位置就是 undo-tree-mode
函数里的第三条 (max ...)
语句:
(set (make-local-variable 'undo-outer-limit)
(if undo-tree-limit
(max undo-outer-limit undo-tree-outer-limit)
most-positive-fixnum))
undo-outer-limit
是在 undo.c
里面定义的变量,并且初始值为 24000000
。但是 emacs.c
又把它置为了 nil
,这也许就是 batch 模式下报错的原因:
我不知道你是不是要在 batch 模式下做什么测试,是否真的会用到 undo-tree
的功能。如果只是单纯的想让 init.el
通过,可以这样修复:
(when noninteractive
(defun undo-tree-save-history-from-hook ())
(setq undo-outer-limit 24000000))
既然 emacs.c
有意把 undo-outer-limit
置为 nil
,就是为了不让在 batch 模式下使用。虽然强行设置可以使得 init.el
通过,但此时如果去调用 undo-tree
的函数依然可能会有问题。
4 个赞
caasi
11
多谢,这个调试技巧学习到了!
其实是有个脚本要运行一些elisp代码,但是又不想多维护一份init.el,就直接载入了原来的init.el,所以并不是用undo-tree的功能,只是想让它完成载入。这个脚本之前运行得一直挺好的,最近突然出现就想问一下。
FYI,在undo-tree的新版本中,这个问题是这样解决的: Undo-tree bug-fix release.
caasi
12
还未测试,不过猜想极有可能是 twlz0ne 说的,编译后的elc文件导致没有产生backtrace。