怎么防止手工添加的 pre-command-hook 被移除

imbot这个输入法自动切换包依赖一个加到 pre-command-hook 的函数 imbot–pre-command-hook,一直有个问题,间隔时间不定(最短半天)地出现 imbot–pre-command-hook 被莫名其秒的移除了,导致自动切换失效,有没有什么办法强制 pre-command-hook 必须包含 imbot–pre-command-hook

可用 add-variable-wather 定位被移除的原因:

1 个赞

先试试 :

(add-variable-watcher 'pre-command-hook #'pre-command-hook-watcher)

(defun pre-command-hook-watcher (sym _newval _op _where)
(unless (member 'imbot--pre-command-hook (default-value 'pre-command-hook))
    (message "imbot--pre-command-hook removed by '%s' at '%s'" _op _where)))

op 和 where 只能告诉你变量是被 setq / let 或其它操作修改,想要更具体的信息,打印 backtrack 比较靠谱。

1 个赞

你加的函数有问题呗,C-h v pre-command-hook

If an unhandled error happens in running this hook, the function in which the error occurred is unconditionally removed, since otherwise the error might happen repeatedly and make Emacs nonfunctional.

这个 hook 最好不要用,起码做尽可能少的事情,用户每次命令都会调用(鼠标 scroll 一下可能就执行了几十次),Emacs 会卡。

嗯,文档应该仔细看,其实就运行了一个 shell-command-to-string ,按理不会出现什么错误吧 不过我之前用ibus那个卡的,失效的次数好像更多,fcitx很快,一点都不卡

(defun imbot--active-p ()
 "Return t when input method is active (in non English state)."
    (not (string-equal
            (string-trim (shell-command-to-string "fcitx-remote")) "1")))

(defun imbot--pre-command-hook ()
 "Update imbot--active-checked in case input state is toggled not via Emacs."
    (setq imbot--active-checked (imbot--active-p))
    (unless imbot--suppressed
        (setq imbot--active-saved imbot--active-checked)))

不能吧,这操作也昂贵了吧,输入个 hello world 就执行 11 次 shell 命令!你的电脑再快也得卡,想想就卡、浪费电:

  1. 需要启动 child processs,耗时
  2. 需要启动 shell,耗时
  3. 需要在 shell 启动其它命令,耗时
  4. shell-command-to-string 本身就做太多事情,耗时

真的不卡呢,不信你试试,用dbus是不是好点 GitHub - clear-code/fcitx-dbus-status

那我直接用call-process吧

(imbot–active-p) 执行一次平均 0.0033742 s

感觉 pre-command-hook 还是成本比较高

狗哥新视频有计划了嘛,哈哈 :smile:

我这旧电脑光开个 shell 就要 23 毫秒,反正是很慢,打个 hello world 得要浪费 0.23 秒

(benchmark-elapse (shell-command ":"))
;; => 0.02315

(benchmark-elapse (call-process "/usr/bin/true"))
;; => 0.013841

是的 pre-command-hook 的成本是非常高的,很多用户觉得lsp-mode卡也是因为它注入了很多函数到pre-command-hook,比如lsp-ui-hide的里的一个 make-frame-invisible 动作就会使得任何字符插入或修改以及光标移动的卡顿, 于是我统一把它们都放刀idle-timer里,于是快到飞起,没有任何功能损失。