ivy 是什么
ivy是一个交互式补全工具,可以应用在如M-x命令列表,find-file打开文件等场景。
当然提到了ivy肯定会提到counsel、swiper。swiper功能比较单一,类似于
isearch的搜索工具,而counsel集成功能较多,如counsel-M-x,
counsel-find-file等等。可以通过M-x搜索counsel-前缀获得更加比较完整的列表。
ivy功能非常强大,因此推荐全局打开。
(use-package ivy
:ensure t
:diminish ivy-mode
:hook (after-init . ivy-mode))
一旦这样打开之后,ivy默认会重新映射这2个全局操作至ivy的对应版本: C-x b
(switch-to-buffer) 和 C-x 4 b (switch-to-buffer-other-window)。
关于use-package的配置说明,请参阅这
接下来的内容可以算是ivy manual的翻译 + 一些图片
辅助说明。
以下图片示例由这份配置操作完成。因为已
经开启了counsel-mode,所以find-file映射到了counsel-find-file,M-x映射到
了counsel-M-x。
ivy minibuffer
因为ivy大多数时候基本都工作在minibuffer上,因此先介绍一下minibuffer是什么。
minibuffer 是什么
minibuffer是Emacs命令读取参数的地方,如C-x C-f (find-file) 会打开一个文
件选项列表供选择,C-x * q (calc quick mode) 可以打开一个计算器,让用户输入算术表达式计算。
ivy minibuffer 按键绑定
ivy-minibuffer-map提供了6个比较基础的移动方式绑定:
C-n下一个选项C-p上一行选项M-<第一个选项M->最后一个选项C-v向下翻页,页数由ivy-height确定M-v向上翻页,同样页数由ivy-height确定
可以看见,这6个移动方式与Emacs在编辑文本时的操作是一致的。
同时,ivy也提供了2个与历史操作有关的按键。
M-p上一条历史记录M-n下一条历史记录
除此之外,C-a (move-beginning-of-line)、C-e (move-end-of-line) 等操作方
式一样在minibuffer下同样受用。
ivy-height同它名字显示一样,是指ivy minibuffer展开的高度,默认值为9 +
1。1 行当前输入,9 行其他选项。

ivy action
ivy在incremental completion完成之后,还可以再执行action操作,每个可选择的
选项都有所谓的action操作。例如find-file的默认action是打开文件,M-x的默认
action是执行命令。
单纯的列出命令并说明比较无趣,因此下面会结合场景来介绍各种action的作用。
ivy-done
ivy-done默认绑定在C-m和RET上。
它是最常用的操作方式,如find-file的默认action是打开文件,触发ivy-done之后就会
执行这个默认action打开对应文件。
ivy-alt-done
ivy-alt-done默认绑定在C-j上。
在find-file的场景下,例如当前光标停在auto-save-list选项上

然后触发ivy-alt-done就会将当前的目录路径补全。

如果接下来的补全选项是要打开的文件,那么再触发ivy-alt-done实际的效果跟手工按
RET没区别,都会执行打开操作。

如果当前补全选项是.或者..目录,那么再次触发ivy-alt-done实际也跟手工按
RET没区别,虽然执行的是dired。

这里还有一个比较简便方法。如果当前路径确定是目录,可以通过直接按/来补全目录路径。

在上面这种情况下,直接按/与ivy-alt-done效果一致。
ivy-partial-or-done
ivy-partial-or-done默认绑定在TAB上。
它的功能是尽可能的补全当前的输入,以达到最长前缀状态,也就是当前输入的字符串是剩余选项的最长公共前缀。
如图所示, 当前最长的公共前缀应该是evil-for

这里触发ivy-partial-or-done之后,可以看到当前输入已补全变成了evil-for了

TAB TAB的效果与ivy-alt-done效果一致,不再赘述。
ivy-immediate-done
ivy-immediate-done默认绑定在C-M-j上。
它的作用是以当前用户输入作为结果而不是当前minibuffer里的候选项,在
find-file的时候特别有用。当要打开一个名为abc的文件,但是当前目录下已存在
abc.pdf文件。这时候find-file的候选项只有一个abc.pdf。这个时候通过
ivy-immediate-done来告诉ivy使用当前的输入abc作为结果而不是minibuffer里的
候选项。

如果是为了解决上述的find-file问题,也可以通过设置ivy-use-selectable-prompt为t来
曲线救国。

注意,这里的光标已经上移至用户输入口了。此时直接RET确定就可以打开abc文件了。
相关问题:
ivy-avy
ivy-avy默认绑定在C-'上。
当ivy-height设置得比较大时,通过avy来直接跳转选择结果会是一个比较快速的办法。

ivy-dispatching-done
ivy-dispatching-done默认绑定在M-o上。
当触发ivy-dispatching-done之后,它会要求用户输入对应的action操作。默认提供的
action非常之多,可以使用describe-variable查看ivy--actions-list得到完整列表。
下面以counsel-M-x的为例子说明:
counsel-M-x下提供了 2 个 action分别是:
d查看定义h帮助

这里M-x想执行evil-forward-char这个命令,但是我想知道这个命令是如何实现的。那
么接下来就通过按M-o触发ivy-dispatching-done,之后再输入d执行查看这个函数的
定义。
可以看到,它已经确定跳转至evil-forward-char这个命令处了。
而h所对应的帮助action实际就是describe-function的效果。
ivy-call
ivy-call默认绑定在C-M-m上,它可以看做不退出minibuffer的ivy-done操作。
还是以evil-forward-char举例

初始光标停留在行首,然后连续3次C-M-m触发ivy-call可以得到如下结果。

这时,光标已经向前移动了3个字符,且minibuffer还处于打开的状态,颇有hydra的味道。
ivy-dispatching-call
ivy-dispatching-call默认绑定在C-M-o上,对应为ivy-dispatching-done的不关闭
minibuffer版本。
M-x输入evil-forward-char之后, C-M-o d C-M-o h 可以分别打开函数定义处、
函数帮助页面。
ivy-next-line-and-call 和 ivy-previous-line-and-call
他们两个分别默认绑定在C-M-n和C-M-p上,主要功能是把移动和action执行合在一起。
一个比较有用的场景是,find-file找到了许多相似的文件,需要一次性都把他们打开。
这个时候,ivy-next-line-and-call的用处就来了。
这里想一次性打开ace-window的这 3 个文件,连续 3 次使用C-M-n就行。
ivy-resume
ivy-resume默认没有提供按键绑定。如同它名字一样,提供resume功能,继续上一次的
ivy操作。
如M-x执行evil-forward-char,但是不小心按快了,执行了evil-forward-word-end.
这时,ivy-resume会恢复M-x的最后状态,保留着用户输入的内容、光标位置。

ivy-next-history-element 和 ivy-previous-history-element
他们两个分别默认绑定在M-n和M-p上,可方便地查看历史命令。
ivy-insert-current
ivy-insert-current默认绑定在M-i上。
不会用,待我再研究一下…
ivy-yank-word
ivy-yank-word默认绑定在M-j上。它的功能跟C-s C-w (isearch-mode-map 下的
isearch-yank-word-or-char) 类似。
例如,当前光标后面有apple boy cat这3个单词。打开M-x,然后M-j触发
ivy-yank-word会将第1个单词apple输入至minibuffer中。然后光标会移动至boy单
词前。再次M-j即会将boy单词输入至minibuffer中。

ivy-restrict-to-matches
ivy-restrict-to-matches默认绑定在S-SPC上,可以当成一种二次过滤的手段来使用。
它会清空用户输入、将搜索集合设置为当前的候选集合,这样用户可以慢慢地减少干扰项,
缩小查找范围。

默认M-x可执行的命令数量为 6247。输入evil再S-SPC触发
ivy-restrict-to-matches。此时,当前集合大小仅为 378。可见确实起到了二次过
滤的作用。

注: 显示候选集合大小通过设置(setq ivy-count-format "%d/%d")实现。
相关问题:
ivy-reverse-i-search
ivy-reverse-i-search默认绑定在C-r上,其功能类似bash的反向搜索历史。
ivy-kill-ring-save
ivy-kill-ring-save默认绑定在M-w上,它会复制当前搜索集合内所有元素。如果集合
过多,可以配合上述的ivy-restrict-to-matches减小集合大小。
hydra-ivy/body
hydra-ivy/body默认绑定在C-o上,会弹出一个ivy的hydra菜单供用户调用。
hydra使用说明见 GitHub - abo-abo/hydra: make Emacs bindings that stick around
| Short | Normal | Command name |
|---|---|---|
o |
C-g |
keyboard-escape-quit |
j |
C-n |
ivy-next-line |
k |
C-p |
ivy-previous-line |
h |
M-< |
ivy-beginning-of-buffer |
l |
M-> |
ivy-end-of-buffer |
d |
C-m |
ivy-done |
f |
C-j |
ivy-alt-done |
g |
C-M-m |
ivy-call |
u |
C-c C-o |
ivy-occur |
由于我本人也不使用hydra,就不截图了。
ivy-occur
ivy-occur默认绑定在C-c C-o上,它可以将当前的候选集合保存至buffer内并退出
minibuffer
ivy-occur-mode下所提供的按键绑定(完整列表的可以describe-variable查看
ivy-occur-mode-map得到)为:
| key | command |
|---|---|
RET or f |
ivy-occur-press |
| 鼠标左键点击 | ivy-occur-click |
j |
next-line |
k |
previous-line |
a |
ivy-occur-read-action |
o |
ivy-occur-dispatch |
q |
quit-window |
主要是使用 j k 来向下、向上移动,q 来退出。
ivy-occur-dispatch
在ivy-occur-mode下,ivy-occur-dispatch如同ivy-dispatching-done一样,将会读
取一个action,然后在当前光标停留的候选项上执行对应的action。
ivy completion style
ivy completion style
ivy总共提供了5种补全方式:
ivy--regexivy--regex-plusivy--regex-ignore-orderivy--regex-fuzzyregexp-quote
ivy–regex-plus
ivy--regex-plus是ivy的默认补全方式,它是这样工作的:
例如用户搜索的是"foo bar", 它会将"foo bar"里的多个连续的空格中的第1个空格转
换成正则里的通项匹配,即正则表达式foo.*bar。如果用户想匹配空格,那么需要额外的
多输入一个空格。如想匹配"foo bar", 那么用户实际应该输入的是foo bar(注意这里
要有2个空格).ivy会把它转换为foo .*bar(注意foo后面有个空格)。论坛会压缩空格,效果下文见图片。

此外它还支持正则的取非操作,通过!来完成。
例如"foo bar !example"会先得到匹配foo.*bar的结果,然后再将结果里匹配
example的候选项删除。
ivy–regex-ignore-order
如名字所示,它会忽略正则的顺序,就好比多次grep一样。
foo会匹配foofoo bar会匹配foo barbar foofoo !bar会匹配foo baz但是不会foo bar和bar foofoo[0-9]会匹配foo1foo2等等后面是数字的情况
如果想要匹配!号,需要转义一下:
foo\\!bar 将会匹配 foo!bar
此外,空格也可以转义:
foo\\ bar 将会匹配 foo bar
ivy–regex-fuzzy
它会在每个字符后面都插入.*, 如 abc 对应的正则是 a.*b.*c.*。
regexp-quote
自带的,见官方文档.
增加自己的 ivy action
以counsel-find-file为例,有如下场景:
如果想要在查找文件的同时,发现有些文件命名不合适,有些文件需要删除还有些文件没有
权限打开需要使用root。最好是在find-file里就能实现而不用再去调用dired。此时
可以为counsel-find-file添加action.
(ivy-set-actions
'counsel-find-file
'(("d" delete-file "delete")
("r" rename-file "rename"))
("x" counsel-find-file-as-root "open as root"))







,为了能够直观看到效果,就直接在论坛里写好了。