leaf block
leaf.el 称下面代码块 为一个 leaf block, +unit-test-erro就是他的名字,可以通过函数 leaf-find
找到并跳转到所在的文件(下文会大致讲一下机制细节)
(leaf +unit-test-erro
:ensure nil ;; 因为 +unit-test-erro 毕竟不是包
:config
(sexp ok))
对上面的leaf
宏展开一层(emacs-lisp-macroexpand
)
(prog1 '+unit-test-erro
;; 又一个 leaf 的宏
;; 大致功能:如果执行的文件是 load-path 里的文件就存人一个 leaf block 信息
;; 本文语境下,就认为供 `leaf-find` 用
(leaf-handler-leaf-path +unit-test-erro)
;; :preface :ensure t 本文简单理解为(requrie '包) :init :config
;; 都按顺序放到这里面运行
;; 这个宏里面有类似 java 的 try catch (也是后面测试时报错的信息来源)
(leaf-handler-leaf-protect +unit-test-erro
(sexp ok)
)
)
leaf-find
上面的 +unit-test-erro
就出现在 leaf-find
的候选补全列表里了(但此时只能跳转到所在的 el 文件,并不能正确跳转到所在行,下文解释)
先来看 leaf-find
是怎么实现的
(defun leaf-find (name)
"Find the leaf block of NAME."
;; 利用 `leaf--paths` 里存的数据作为用户的候选列表
;; 而这个 `leaf--paths` 正是上面的
;; `(leaf-handler-leaf-path +unit-test-erro)` 所维护的
(interactive
(let ((candidates (delete-dups (mapcar #'car leaf--paths))))
(if (not candidates)
(error "Leaf has no definition informations")
(list (completing-read "Find leaf: " (delete-dups (mapcar #'car leaf--paths)))))
);;let ends here
);;ineractive ends here
;; 最后一步中用 find-func 的 `(find-function-search-for-symbol name 'leaf path))`
;; 根据 leaf 的 regex 规则(下文讲)匹配到精确行
;; 也就是为什么前面 展开成`(prog1 '+unit-test-erro `)而不是 `(leaf +unit-test-erro`
;; 会找不到 `+unit-test-erro` 这个 leaf block 所在行的原因
(require 'find-func)
;; 现在要一步步从数据中取出 `+unit-test-erro` leaf block
(let* ((name (intern name))
;; 根据名字取出 leaf block 所在文件路径(可能多个)
(paths (mapcan (lambda (elm) (when (eq name (car elm)) (list (cdr elm)))) leaf--paths))
;; 如果多个让用户选一个
(path (if (= (length paths) 1) (car paths) (completing-read "Select one: " paths)))
;; 搜索匹配到 leaf block 所在行
(location (find-function-search-for-symbol name 'leaf path)))
;; 执行跳转
(when location
(prog1 (pop-to-buffer (car location))
(when (cdr location)
(goto-char (cdr location)))
(run-hooks 'find-function-after-hook)))))
看一下 leaf–paths (alist) 里的数据 (cons)
leaf--paths is a variable defined in ‘leaf.el’.
Value:
( (+unit-test-erro . "/Users/ingtshan/.emacs.d/etc/init/init-os.el") )
leaf block 和 leaf-find 总结
对于我这样的初学者来说, leaf-find
特别好用,可以快速跳转到自己的配置里任意地方(前提是用 leaf
装起来),其次 block 里的 require
和 自己的代码都放到 leaf-handler-leaf-protect
里执行,出错时,不用打开 -debug-init
也能看到具体是哪段代码有问题。
而且 leaf.el
的代码可读性很高,不用怕展开后看不懂。
have fun