在 Embark 中,标记 candidates 并应用 embark-act-all
是通过 embark-collect
来完成的,具体的步骤如下:
- run
embark-act
embark-collect
- 在 collect buffer 中,按
m
标记
- 按
A
(embark-act-all)
- 选择命令
这个方案有一个明显的问题:操作太繁琐了。前三步的目的是标记 candidates ,那为什么不直接在 minibuffer 中标记呢?然后对标记的对象应用 embark ,这样即节省了操作步数,也免去了 buffer 切换等容易打乱工作流的操作。
基于以上想法,下面是我的解决方案:
(defvar eli/vertico-marked-list nil
"List of marked candidates in minibuffer.")
(defun eli/vertico-mark ()
"Mark candidates in minibuffer"
(interactive)
(let*
((selected (embark--vertico-selected))
(target (cdr selected)))
(if (member target eli/vertico-marked-list)
(setq eli/vertico-marked-list (delete target eli/vertico-marked-list))
(push target eli/vertico-marked-list))))
(defun eli/vertico-marked-p (candidate)
"Return t if CANDIDATE is in `eli/vertico-marked-list'."
(member (concat vertico--base candidate) eli/vertico-marked-list))
(defun eli/vertico--format-candidate-hl-marked (args)
"Highlight marked vertico items."
(let* ((cand (car args)))
(if (eli/vertico-marked-p cand)
(add-face-text-property 0 (length cand) 'embark-collect-marked nil cand)
(vertico--remove-face 0 (length cand) 'embark-collect-marked cand))
args))
(advice-add #'vertico--format-candidate :filter-args #'eli/vertico--format-candidate-hl-marked)
(defun eli/vertico-marked-list-clean ()
"Initialize `eli/vertico-marked-list' and `eli/vertico-mark-type'."
(setq eli/vertico-marked-list nil))
(add-hook 'minibuffer-setup-hook #'eli/vertico-marked-list-clean)
(defun eli/embark-vertico-marked-list ()
(when eli/vertico-marked-list
(cons (car (embark--vertico-selected)) (reverse eli/vertico-marked-list))))
(add-hook 'embark-candidate-collectors #'eli/embark-vertico-marked-list -100)
(setq embark-confirm-act-all nil)
(keymap-set vertico-map "C-SPC" #'eli/vertico-mark)
(keymap-set vertico-map "C-," #'embark-act-all)
效果如下
Edit :修复一些 Bug 使其更通用。
7 个赞
重新修改了下逻辑,使用 embark-act-all
而不是 embark-act
SPQR
4
草,原来标记 candidates 的默认方法这么复杂 ,楼主的这个hack太好用了
几个建议哈
-
vertico--format-candidate
可以不必 override, 可以改成 filter-args , 通过 advice 来更改第一个
参数,这样可以更多复用 vertico 原来的代码。
-
embark--maybe-transform-candidates
也可以不用 override 来覆盖,可以简单地向
embark-candidate-collectors
添加个函数即可:
(defun eli/embark-vertico-marked-list ()
(when eli/vertico-marked-list
(cons (car (embark--vertico-selected)) eli/vertico-marked-list)))
(pushnew! embark-candidate-collectors #'eli/embark-vertico-marked-list)
1 个赞
好长的讨论。简单来说,就是在做,还没有进主干 :)
SPQR
12
已经进master了,不过目前embark的实现方式是需要embark-act再embark-select,不能直接一步embark-select
这和作者讨论过,一是不这么做实现起来比较困难,二是用户可以自己定义键盘宏,比如
(global-set-key (kbd "C-;") (kbd "C-. SPC"))
3 个赞
zqso
15
@aqua0210
默认 C-. SPC
→ embark-select
这儿有个changelog (作者把时间写成2020年了,内容没有错):
@VagrantJoker
前后选择了好几个,但怎么一键取消呢?
1 个赞
默认是 C-. A SPC
,也可以自己绑定个宏,不过这种做法在我这有时会有 bug ,就先自己写了个函数来取消选择
(defun eli/embark-deselect ()
"Deselect all selected candidates."
(interactive)
(when embark--selection
(dolist (target embark--selection)
(when-let ((overlay (cdr target)))
(delete-overlay overlay)))
(setq embark--selection nil)))
1 个赞
作者已经在 README 中更新使用方法。默认是通过 embark-act
来调用 embark-select
,选择完成后调用 embark-act-all
就好了
1 个赞