Deeson
21
比如在包 doom-modeline 中,函数 doom-modeline-segment--matches
是通过下面这个宏定义的:
(doom-modeline-def-segment matches
"Docstring"
(let ((meta (concat (doom-modeline--macro-recording)
(doom-modeline--anzu)
(doom-modeline--phi-search)
(doom-modeline--evil-substitute)
(doom-modeline--iedit)
(doom-modeline--symbol-overlay)
(doom-modeline--multiple-cursors))))
(or (and (not (string-empty-p meta)) meta)
(doom-modeline--buffer-size))))
我的 patch 代码没有什么特别,比如,就使用:
(psearch-patch doom-modeline-segment--matches
(psearch-replace '`meta
'`meta_))
但最终的结果是:并没有重新定义 doom-modeline-segment--matches
这个函数,而是定义了一个新的函数 doom-modeline-segment--doom-modeline-segment--matches
,而这,就是问题所在。
我明白了。
问题虽然已经明了,但是解决起来有点麻烦。
普通函数和 doom-modeline-def-segment
生成的函数是不一样的:
(psearch-patch--find-function 'doom-modeline-segment--foobar)
;; => (doom-modeline-def-segment foobar "Docstring" body...)
;; | | | |
;; | | | `--- [3]函数体
;; | | `------------ [2]文档
;; | `---------------------- [1]函数名
;; `------------------------------------ [0]声明符
(psearch-patch--find-function 'foobar)
;; => (defun foobar nil "Docstring" body...)
;; | | | | |
;; | | | | `--- [4]函数体
;; | | | `------------ [3]文档
;; | | `-------------------- [2]参数表
;; | `-------------------------- [1]函数名
;; `-------------------------------- [0]声明符
从以上对比可以看出,doom-modeline-def-segment
定义函数是没有参数列表的,所以它的 Docstring
位置和 defun
定义的函数不一样:
而且这个不一样还是 doom-modeline-def-segment
独有的, 换个其它 xxx-def-yyy
有可能就不一样了。有的可能需要参数列表,有的可能不需要 Docstring
。这就导致其生成的结构无法预料。
需要有一种方法,可以让用户指定如何解析 def 生成的结构,这无疑会给用户增加负担。还要考虑到不改变 psearch-patch
的声明格式,不影响旧的 patch 代码,或许可以在外层套个 let
:
(let ((psearch-patch-symbol-definition-pospec
'((symbol-name . 1)
(docstring . 2))))
(psearch-patch doom-modeline-segment--matches
(psearch-replace '`meta
'`meta_)))
让我再想一想,有可能指定一个 (let ((psarch-patch-docpos 2)) ...)
就够了。
1 个赞
Deeson
23
真是很漂亮、精确和简洁的解释!没有认真读过前辈的代码,但是通过这个回答,学到了不少!
再次感谢这个很实用的工具!
同时,我有两个不太相关的小问题:
- 这部分的注释,是怎么排版成这种“图形化”的纯字符呢?有什么小工具吗?
- 我之所以会尝试使用如下“看似没用”的代码:
是因为,我 patch 了 doom-modeline--multiple-cursors
这个函数(它是用 defsubst
定义的),并且被 doom-modeline-segment--matches
调用。
但是仅仅做这个 patch 没有效果(是因为内联?还是 Doom Emacs 的黑魔法?),并且我发现,只要我重新求值一下 doom-modeline-segment--matches
的定义,就有效果了。(并且先 patch 和先重新求值皆可)
这才有了我上面这个“看似没用”的代码。但最终我是通过这个代码来强制重新求值的:
(eval (psearch-patch--find-function 'doom-modeline-segment--matches))
所以,前辈有遇到类似的情况吗?有相关原因和更漂亮的解决方案吗?
手打,没工具。
内联。
最新版本 Add support for macro-generated function · twlz0ne/psearch.el@b027a9d · GitHub 应该可以支持 doom-modeline-segment
函数了,用法:
(let ((psearch-patch-function-definition-docpos 2))
(psearch-patch doom-modeline-segment--matches
(psearch-replace '`MATCH-PATTERN
'`REPLACEMENT)))
1 个赞
Deeson
26
我尝试这个版本发现,可以 patch defun
定义的函数,但是无法 patch defsubst
定义的函数呢(该提交之前,patch 功能是正常的)。
所以是不是把 defsubst
考虑进去比较好:
@@ -797,7 +797,7 @@
`(let ((func-def (psearch-patch--find-function ',orig-func-spec)))
(with-temp-buffer
;; Modifiy function name
- (when (and (eq 'defun (nth 0 func-def)) (not (eq ',name (nth 1 func-def))))
+ (when (and (memq (nth 0 func-def) '(defun defsubst)) (not (eq ',name (nth 1 func-def))))
(setcdr func-def (cons ',name (nthcdr 2 func-def))))
(print func-def (current-buffer))
;; Modify docstring.
@@ -805,7 +805,7 @@
(down-list)
(forward-sexp
(+ ,docpos (if (equal 'lambda (sexp-at-point)) 0
- (if (memq (sexp-at-point) '(defun cl-defgeneric cl-defmethod)) 1
+ (if (memq (sexp-at-point) '(defun defsubst cl-defgeneric cl-defmethod)) 1
0))))
(let ((str "[PATCHED]"))
(goto-char (car (bounds-of-thing-at-point 'sexp)))
LdBeth
27
defubst 本身就算改了定义也没法反映到已经编译的函数里,没啥做的意义
Deeson
28
是这样的,但是有时候确实需要改动一些内联函数,所以我会把某些受影响的函数重新求值一下(假设 FUN
调用了某个被 patch 的内联函数):
(eval (psearch-patch--find-function 'FUN))
能否提一个pr?同时记得修改一下头注释把你的名字加上去:
;; Last-Updated: <当下的时间戳>
;; By: <你的名字>