看到 GitHub 上有一个希望 patch 后能自动关闭打开的 buffer 的 issue,由于我高强度使用前辈的包,所以感觉还是挺需要这个功能的。
我目前初步的实现如上代码:
diff --git a/psearch.el b/psearch.el
index dab0721..1d09e88 100644
--- a/psearch.el
+++ b/psearch.el
@@ -793,11 +793,21 @@ For example:
See `psearch-patch' for explanation on arguments ORIG-FUNC-SPEC and PATCH-FORM."
(declare (indent 2))
- (let ((docpos (or psearch-patch-function-definition-docpos
- (if (symbolp orig-func-spec) 3 (length orig-func-spec)))))
- `(let ((func-def (psearch-patch--find-function ',orig-func-spec)))
+ (let* ((docpos (or psearch-patch-function-definition-docpos
+ (if (symbolp orig-func-spec) 3 (length orig-func-spec))))
+ (lib (cdr (condition-case nil
+ (find-function-library name 'lisp-only t)
+ (void-function nil))))
+ (file (when lib (file-truename (file-name-with-extension (find-library-name lib) "el"))))
+ (buffer (when file (get-file-buffer file))))
+ `(let ((_ (when (and ,file (not ,buffer))
+ (run-with-idle-timer 0 nil (lambda ()
+ (when (get-file-buffer ,file) (kill-buffer (get-file-buffer ,file)))))))
+ (func-def (psearch-patch--find-function ',orig-func-spec))
+ (lb lexical-binding))
(with-temp-buffer
;; Modifiy function name
+ (setq lexical-binding lb)
(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))
@@ -818,10 +828,7 @@ See `psearch-patch' for explanation on arguments ORIG-FUNC-SPEC and PATCH-FORM."
;; Apply patch
(goto-char (point-min))
(if (progn ,@patch-form)
- (let* ((lib (cdr (condition-case nil
- (find-function-library ',name 'lisp-only t)
- (void-function nil))))
- (buffer-file-name (if lib (file-name-sans-extension lib))))
+ (let ((buffer-file-name ,file))
(eval-region (point-min) (point-max)))
(signal 'psearch-patch-failed
(list ',orig-func-spec "PATCH-FORM not applied")))))))
关于 issue 中担心的问题:
- 判断一下 patch 前是否打开了源文件,如果打开了就不关闭;
- 关闭 buffer 只发生在 patch 执行完毕后(idle),所以连着 patch 同一个源文件的函数,不会造成反复打开和关闭的开销。
同时,在我自己的使用实践中,还发现有些代码,必须开启词法绑定才有效果,而 with-temp-buffer
默认是没有词法绑定的。因此我在上面的代码中,增加了词法绑定的设置。
在需要词法绑定的情形,这样即可:
(let ((lexical-binding t))
(psearch-patch FUN
(psearch-replace '`a '`b)))