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--regex
ivy--regex-plus
ivy--regex-ignore-order
ivy--regex-fuzzy
regexp-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
会匹配foo
foo bar
会匹配foo bar
bar foo
foo !bar
会匹配foo baz
但是不会foo bar
和bar foo
foo[0-9]
会匹配foo1
foo2
等等后面是数字的情况
如果想要匹配!
号,需要转义一下:
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"))