用 embark 挺长时间了,深感其对效率提升之大。因此想深入研究一下,看看它有什么奇技淫巧,但是发现除了 FIFTEEN WAYS TO USE EMBARK ,论坛关于 embark 的讨论并不是很多,因此开帖来请教一下大家。
抛砖引玉,我先来分享一下我的一些配置:
- consult-org-heading
(defun consult-heading-insert-backlink (target)
(let* ((marker (plist-get
(text-properties-at 0 target)
'consult--candidate))
(headline-name (substring (org-no-properties target)
0 -1))
(headline-id (save-excursion
(with-current-buffer
(marker-buffer marker)
(goto-char marker)
(org-id-get-create)))))
(org-insert-link
nil (concat "id:" headline-id) headline-name)))
(embark-define-keymap embark-org-heading-map
"Keymap for Embark heading actions."
("i" embark-insert)
("b" consult-heading-insert-backlink)
("w" embark-copy-as-kill)
("q" embark-toggle-quit)
("E" embark-export)
("S" embark-collect)
("L" embark-live)
("B" embark-become)
("A" embark-act-all)
("C-s" embark-isearch)
("SPC" mark)
("DEL" delete-region))
(add-to-list 'embark-keymap-alist '(consult-org-heading . embark-org-heading-map))
主要增加了"快速插入 headline 链接" 的功能, 效果如下
- org-roam support
(defun org-roam-backlinks-query* (NODE)
"Gets the backlinks of NODE with `org-roam-db-query'."
(org-roam-db-query
[:select [source dest]
:from links
:where (= dest $s1)
:and (= type "id")]
(org-roam-node-id NODE)))
(defun org-roam-backlinks-p (SOURCE NODE)
"Predicate function that checks if NODE is a backlink of SOURCE."
(let* ((source-id (org-roam-node-id SOURCE))
(backlinks (org-roam-backlinks-query* SOURCE))
(id (org-roam-node-id NODE))
(id-list (list id source-id)))
(member id-list backlinks)))
(defun org-roam-backlinks--read-node-backlinks (source)
"Runs `org-roam-node-read' on the backlinks of SOURCE.
The predicate used as `org-roam-node-read''s filter-fn is
`org-roam-backlinks-p'."
(org-roam-node-read nil (apply-partially #'org-roam-backlinks-p source)))
(defun org-roam-backlinks-node-read (entry)
"Read a NODE and run `org-roam-backlinks--read-node-backlinks'."
(let* ((node (get-text-property 0 'node entry))
(backlink (org-roam-backlinks--read-node-backlinks node)))
(find-file (org-roam-node-file backlink))))
(embark-define-keymap embark-org-roam-map
"Keymap for Embark org roam actions."
("i" org-roam-node-insert)
("s" embark-collect)
("b" eli-org-roam-backlinks-node-read))
(add-to-list 'embark-keymap-alist '(org-roam-node . embark-org-roam-map))
在 org-roam-node-find
界面,可以使用 embark 来查看所选节点的反向链接节点和插入此节点,也可以批量操作节点。和节点有关操作用统一入口 org-roam-node-find
就能解决,减少记忆和快捷键负担。
edit: 根据reddit 的一篇帖子优化了 embark 代码
不知道大家还有什么小技巧或者 hack ?
18 个赞
插入图片我一般有两种方式:一是用 org-download 截图,二是从本地目录选择插入。由于我的本地图片文件名都是日期格式,所以有一个不方便的地方就是不好确定目标图片,所以结合 embark 和 posframe 做了个图片预览:
(require 'posframe)
(require 'embark)
(defun eli-image-preview (&rest _args)
(let* ((target (embark--targets))
(file-path (plist-get (car target) :target))
(name (file-name-nondirectory file-path))
(mode (assoc-default name auto-mode-alist #'string-match)))
(posframe-hide-all)
(when (memq mode '(image-mode))
(with-current-buffer (get-buffer-create "*image*")
(setq inhibit-read-only t)
(erase-buffer)
(insert-file-contents file-path)
(set-auto-mode-0 mode))
(when (posframe-workable-p)
(posframe-show "*image*"
:poshandler #'posframe-poshandler-frame-center)))))
(defun eli-select-images ()
(interactive)
(let ((default-directory "/path-to-images/"))
(call-interactively 'find-file)))
(advice-add 'eli-select-images
:before (lambda ()
(add-hook 'post-command-hook #'eli-image-preview)))
(add-hook 'minibuffer-exit-hook
(lambda ()
(remove-hook 'post-command-hook #'eli-image-preview)
(posframe-delete-all)))
这个函数还可以扩展,变成预览所有类型的文件。
效果如下:
18 个赞
(add-to-list 'embark-keymap-alist '(consult-org-heading . embark-org-heading-map))
这个对 consult-org-heading
的确起作用了, 但为啥对下面这个就完全不起作用呢? 执行 consult-outline
时 embark 菜单里还是没有 b 这个快捷键?
(add-to-list 'embark-keymap-alist '(consult-outline . embark-org-heading-map))
embark 的原理是根据光标附近对象的类型来选择对应的操作集,embark-keymap-alist
中的元素是 (对象类型 . 对象类型对应的操作集)
, 而不是特定的命令。比如说在 buffer 里面,光标下是 link ,那就去 embark-keymap-alist
里面找有没有对应的操作,如果没有就用默认的。(当然这是最基本逻辑,还有数据传递之类的细节)
而在 minibuffer 里面,candidates 的类型是由 metadata 里的 category(Programmed Completion )设置的,在 consult 里面,由 consult--read
中的 CATEGORY
参数来设置。
consult-outline
的 :category
是默认的 consult-location
,embark-keymap-alist
中找不到就会用默认的操作集。
哦哦, 可是我执行了下面这一行以后执行 consult-outline, embark 菜单中还是找不到 embark-org-heading-map
定义的动作, 这是为啥呢?
(add-to-list 'embark-keymap-alist '(consult-location . embark-org-heading-map))
因为它被 override 了,见变量 embark-default-action-overrides
:
((imenu . consult-imenu)
(consult-info . embark-consult-info)
(consult-man . embark-consult-man)
((file . consult-locate)
. find-file)
((file . consult-find)
. find-file)
(consult-grep . embark-consult-goto-grep)
(consult-location . embark-consult-goto-location))
当然 embark-org-heading-map
里的函数可能不适用于 consult-location
的对象,因为你平时用 consult-line
之类的操作,其候选的对象也是这个,所以要注意不在 org-mode 中,不是 headline 等情况,还是挺复杂的,总之不推荐修改
感谢, 可是,
(setq embark-default-action-overrides (assoc-delete-all 'consult-location embark-default-action-overrides))
我都从中去除了 consult-location
, 还是不行
我不知道你的具体配置,但是我这里是可以的,建议给个最小可复现配置
(defun consult-outline-insert-heading (target)
(let* ((marker (plist-get
(text-properties-at 0 target)
'consult--candidate))
(headline-name (substring (org-no-properties target)
2 nil)))
(org-insert-link nil headline-name)))
(with-eval-after-load 'embark
(define-key embark-general-map (kbd "h") #'consult-outline-insert-heading))
我这样设置的,也可以用。
谢谢您~ 时隔几个月终于破案了, 原因是我用的最新版的 embark, 在 embark-org.el 中已经定义了 embark-org-heading-map
, 而我也用 defvar-keymap
定义, 在已经存在的情况下就是不起作用的, 我把 embark-org-heading-map
重命名为 my/embark-org-heading-map
后, 问题解决.
1 个赞
最近也在玩 embark, 想请教个用法,我现在有一堆 pod 名字,现在我想检查每个pod的日志里是否出现了,error 日志,如果出现了则输出pod的名字。我现在通过 embark-collect 收集到了一个buffer。
变成了这个样子,那么我如何提取 pod 名字,并执行接下来的操作呢?
我想问, 如何快速确定一个命令的 :category
呢? 就比如 consult-org-heading 这个例子还好, 我在 consult 包里找到它的定义即可, 但比如随便一个命令, 比如 cd
命令, 我怎么能知道它的 category 是什么呢? 我在意这个问题是我想要对 cd 命令添加动作, 就是把某个变量设定为 cd 的补全结果.
哦, 没事, 解决了, marginalia 包的 marginalia-cycle 能显示出这个信息.
可以贴出您更新后的配置参考一下吗?我重命名了之后,还是无法插入link
; 根据 target 类型返回 target 对应的 marker
(defun my/embark-get-marker(target)
(let* ((embark-plist (text-properties-at 0 target)) (embark-type (car embark-plist)))
(cond
((eq embark-type 'consult-org--heading) (plist-get embark-plist 'consult--candidate))
((eq embark-type 'consult--outline-level) (car (plist-get embark-plist 'consult-location)))
)
))
; 根据 target 类型返回 target 对应的 heading
(defun my/embark-headname(target)
(let* ((embark-plist (text-properties-at 0 target)) (embark-type (car embark-plist)))
(cond
((eq embark-type 'consult-org--heading) (substring (org-no-properties target)
0 -1))
((eq embark-type 'consult--outline-level) (replace-regexp-in-string "^\*+ " "" (org-no-properties target)) )
)
)
)
(defun embark-heading-insert-link (target)
(let* ((marker (my/embark-get-marker target))
(headline-name (my/embark-headname target))
(headline-id (save-excursion
(marker-buffer marker)
(goto-char marker)
(org-id-get-create))))
(org-insert-link
nil (concat "id:" headline-id) headline-name)))
(defvar-keymap my/embark-org-heading-map
:doc "Keymap for Embark heading actions."
:parent embark-org-heading-map
"l" 'embark-heading-insert-link
)
(add-to-list 'embark-keymap-alist '(consult-org-heading . my/embark-org-heading-map))
我删了一些与链接无关的行, 可能会影响运行, 意思就是这个意思
1 个赞