w3m的小bug: w3m-auto-show

好久没去上水木了, 今天上去瞧瞧. 本来以为几天不去了, 会有好多帖子, 上去之后, 只有一点帖子, 有点失望, 呵呵.
废话少说, 看到一个网友的问题:
求帮看看这句话为什么老有错误信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | (define-prefix-command 'f9-map) (global-set-key (kbd "<f9>") 'f9-map) (global-set-key (kbd "<f9> 3") (lambda() (interactive) (w3m-goto-url "http://www.tianya.cn/publicforum/articleslist/0/no05.shtml"))) 目的是想按f9 3, Emacs会调w3m去打开某个页面. 现在能work, 但老是提示error 出错信息是: Error in post-command-hook: (wrong-type-argument symbolp (lambda nil (interactive) (w3m-goto-url http://www.tianya.cn/publicforum/articleslist/0/no05.shtml))) 不知哪个兄弟有时间帮看下, 谢了~ |
我去emacs scratch下eval:
1 2 3 4 5 6 | (define-prefix-command 'f9-map) (global-set-key (kbd "<f9>") 'f9-map) (global-set-key (kbd "<f9> 3") (lambda() (interactive) (w3m-goto-url "http://www.tianya.cn/publicforum/articleslist/0/no05.shtml"))) |
然后按了F9 3, 果然如这位网友所说, 能打开那个网页, 但是出现那个post-command-hook那个错误.
很奇怪, 这段代码没问题啊, 怎么会出错呢?
我抱着试试的态度, 看把那个lambda表达式改为命令行不行, 即把
1 2 3 | (lambda() (interactive) (w3m-goto-url "http://www.tianya.cn/publicforum/articleslist/0/no05.shtml")) |
改为
1 2 3 | (defun test() (interactive) (w3m-goto-url "http://www.tianya.cn/publicforum/articleslist/0/no05.shtml")) |
然后再:
(global-set-key (kbd "<f9> 3") 'test) |
这时, 再按F9 3已经可以正确运行了. 我再这样:
(global-set-key (kbd "C-x M-p") 'test) |
然后按C-x M-p也没有错误, 看来很有可能是那个lambda表达式惹的祸.
还有, 报错是与post-command-hook相关的. post-command-hook作用如下(C-h v post-command-hook):
Normal hook run after each command is executed. If an unhandled error happens in running this hook, the hook value is set to nil, since otherwise the error might happen repeatedly and make Emacs nonfunctional. |
这个hook就是每个命令执行完之后都会运行这个hook中的函数, 如果某个函数运行出错后, 这个hook讲被置为nil.(与其对应的pre-command-hook, 即每个命令执行前执行的hook)
按F9 3出错后, 我去那个w3m buffer去查看了一下post-command-hook的值, 确实已经变为nil了, 看来错误应该与它有关. 所以我就去w3m的代码里搜索了一下post-command-hook, 结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | -*- mode: grep; default-directory: "~/emacs/trunk/lisps/emacs-w3m/" -*- Grep started at Thu Dec 24 22:51:38 find . -type f ! -wholename "*/.svn*" ! -wholename "*~" -print0 | xargs -0 -e grep -nH -e post-command-hook ./doc/emacs-w3m-ja.texi:3753:of @code{post-command-hook}. ./doc/emacs-w3m.texi:3699:of @code{post-command-hook}. ./w3m.el:1023:way of `post-command-hook'." ./w3m.el:8767:`post-command-hook' by `w3m-buffer-setup'." ./w3m.el:8788: (w3m-add-local-hook 'post-command-hook 'w3m-check-current-position) ./mime-w3m.el:90:by way of `post-command-hook'." ./mime-w3m.el:190: (w3m-add-local-hook 'post-command-hook ./ChangeLog.1:192: `post-command-hook', instead of `w3m-print-this-url-after-command'. Grep finished (matches found) at Thu Dec 24 22:51:39 |
打开那些文件对应行, 与post-command-hook有关系的也只有w3m-after-cursor-move-hook,w3m-check-current-position, mime-w3m-after-cursor-move-hook和mime-w3m-check-current-position了. w3m-after-cursor-move-hook的值为:
1 2 3 | '(w3m-highlight-current-anchor w3m-print-this-url w3m-auto-show) |
mime-w3m-after-cursor-move-hook的值为:
'(w3m-print-this-url) |
我大致看了下这几个函数, 没看出什么问题来. 关键也没看出与刚才那个lambda表达式相关的信息, 太奇怪了, 遂决定调试一下那个w3m-goto-url命令, 看它有没有问题.
在w3m-goto-url命令里面执行M-x edebug-defun, 对w3m-goto-url命令设置断点. 然后按F9 3, 在w3m-goto-url里面短住, 我不停的按n, 一步一步的调, 始终没出错, 等运行完这个命令才出错, 看来是与w3m-goto-url无关, 还是那个post-command-hook的问题.
我现在没辙了, 突然想到, 刚才不是说可能与那个w3m-after-cursor-move-hook有关嘛, 这个hook是在w3m-check-current-position这个函数中调用的, 而w3m-check-current-position又是在w3m-buffer-setup中调用的, 而w3m-goto-url里面又调用了w3m-buffer-setup, 看来确实有可能与w3m-after-cursor-move-hook这个hook有关. 那么我先把它置为nil试试, 一试, 太好了, 果然不出错了, 看来肯定是它的问题了, 它的默认值是:
1 2 3 | '(w3m-highlight-current-anchor w3m-print-this-url w3m-auto-show) |
我一个一个的试, 最后发现只要加上w3m-auto-show, 就出错, 看来问题在w3m-auto-show这个函数, 我们来看看它的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | (defun w3m-auto-show () "Scroll horizontally so that the point is visible." (when (and truncate-lines w3m-auto-show (not w3m-horizontal-scroll-done) (not (and (eq last-command this-command) (or (eq (point) (point-min)) (eq (point) (point-max))))) (or (memq this-command '(beginning-of-buffer end-of-buffer)) (string-match "\\`i?search-" (symbol-name this-command)) (and (markerp (nth 1 w3m-current-position)) (markerp (nth 2 w3m-current-position)) (>= (point) (marker-position (nth 1 w3m-current-position))) (<= (point) (marker-position (nth 2 w3m-current-position)))))) (w3m-horizontal-on-screen)) (setq w3m-horizontal-scroll-done nil)) |
咋看上去没啥问题, 那么调试吧. M-x edebug-defun设置断点, 然后按F9 3, 停在w3m-auto-show这个函数里, 按n单步前进, 当运行到这行代码:
(string-match "\\`i?search-" (symbol-name this-command)) |
出错了. 这句话有什么问题吗? this-command是当前运行的命令, 我看了一下它的值是:
(lambda nil (interactive) (w3m-goto-url "http://www.tianya.cn/publicforum/articleslist/0/no05.shtml")) |
然后我们再回头来看看那个错误提示:
1 | Error in post-command-hook: (wrong-type-argument symbolp (lambda nil (interactive) (w3m-goto-url http://www.tianya.cn/publicforum/articleslist/0/no05.shtml))) |
你发现了什么没? 错误提示的意思说那个lambda表达式不是一个符号. 真的是这样吗? 我们来试试. 在”*scratch*”里输入:
(symbolp (lambda (message ""))) |
然后在上面行尾按C-x C-e进行计算, 返回nil, 果然如此.
终于真相大白了, 因为那个lambda表达式不是一个符号, 而symbol-name的参数要求为符号, 所以才产生了那个错误. 看来这是w3m的一个小小的bug.
那么我们怎么来fix这个小bug呢?
很简单, 在调用symbol-name之前判断一下即可, 即把
(string-match "\\`i?search-" (symbol-name this-command)) |
改为
1 2 | (string-match "\\`i?search-" (if (symbolp this-command) (symbol-name this-command) "")) |
就可以了. 很简单吧.

loading...
赞,现在emacs-lisp水平精进啊。
[回复]
ahei 回复:
一月 25th, 2010 at 7:13 上午
呵呵,谢谢。说你还是说我呢?:)
[回复]
好文,又学了一招edebug-defun ,这玩意儿真是强大,调试的时候太好用了。这几天认真学了学elisp,碰到一个疑惑想请教您。elisp中跳出循环,比如while ,dolist ,dotimes 等, 应该怎么做,有没有类似c的break 语句。(我现在只会在while之前加一个block ,通过return-form 来退出block ,进而退出循环,感觉很麻烦,我也看到有用catch的,但也感觉不直观)
[回复]
ahei 回复:
六月 12th, 2010 at 12:08 下午
@xilbert, 你说对了,就那么多方法,没有break或者return
[回复]
org-mode 中有同样的问题。。。
[回复]
ahei 回复:
十月 11th, 2010 at 10:47 上午
啥同样的问题?
[回复]
ngn 回复:
十月 11th, 2010 at 10:46 下午
@ahei,
和这个页面的描述一样,http://www.mail-archive.com/emacs-orgmode@gnu.org/msg25105.html
要翻墙,
就是在一个entry里加入deadline(C-c Cd)之后,再(C-x b),就报error in post-command-hoot.
我的环境和上面提到的一样。
上班没多少时间,所以上次回复没有说清楚, 你能回复到我的twitter么,方便交流。
[回复]
ngn 回复:
十月 11th, 2010 at 10:47 下午
@ngn,
再补充一下,我用的ido
[回复]
ahei 回复:
十月 12th, 2010 at 11:12 上午
@ngn, ….我上班太忙了,额,等以后吧
[回复]