emacs-覆盖package中的函数
Emacs的一大优点,就是能自由修改、重载elisp函数。我们经常会遇到这样的情况:有的package所提供的函数并不符合自己的需求,或者作者消失了许久,留有一堆issue和pr没有处理。这种时候,我们就可以手动覆盖一些函数、设置一些变量,达到我们想要的效果。
假设你从melpa、elpa或者github手动下载了package相关的 .el 文件,一般有两种方式覆盖函数。后续我们以 org-ql 为例,其有 org-ql.el 和 org-ql-view.el 等子文件。
1. 覆盖当前package主文件中的函数
如果我们要修改和package同名的文件中的函数,就可以直接在 use-package 里设置:
(use-package org-ql
:config
(defun 需要覆盖的函数))
由于「 :config 中的代码会等到包在加载后才会被加载。」(来源: 使用 use-package 管理 emacs 配置),所以我们就在这里放置需要覆盖的函数。
2. 覆盖其他package文件中的函数
有的时候,一个package会拆分成数个函数。假如我们要覆盖的函数不在package主文件中,那么很可能,如果该函数所在文件并未被加载,定义在前一章节的函数就可能因为引用变量不存在或者引用函数不存在而报错。
这里假设需要覆盖的函数在 org-ql-view.el 中(可通过 C-h f 搜索函数名查看所在文件),我们就可采取下列方式:
(use-package org-ql
:config
(with-eval-after-load 'org-ql-view
(defun 需要覆盖的函数)))
这样一来,会在加载 org-ql-view.el 文件后再执行一次重新定义,而这时往往相关变量、函数均已设置完毕。
3. 补充说明
3.1. 为什么不用advice
众所周知,emacs中有强大的 advice 功能,可以对函数进行各种各样的调整。如果仅仅是添加新功能,我也非常建议读者使用 advice 相关函数,可以方便地添加/移除。
这里采用直接覆盖的主要原因还是作者更新不及时,直接覆盖不用担心遇见代码更新导致功能异常,同时还能省一些也许仅存在于精神上的电脑资源吧。
3.2. 有没有更简洁的方式
目前的覆盖方法确实需要将整个函数完整重述一遍,有点繁琐。如果读者有兴趣,可以使用 el-patch 更加精准修改elisp函数。