Skip to content

Latest commit

 

History

History
411 lines (250 loc) · 16.6 KB

introduction-to-ivy.md

File metadata and controls

411 lines (250 loc) · 16.6 KB

ivy 新手教程

ivy 是什么

ivy是一个交互式补全工具,可以应用在如M-x命令列表,find-file打开文件等场景。

当然提到了ivy肯定会提到counselswiperswiper功能比较单一,类似于 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是什么。

minibufferEmacs命令读取参数的地方,如C-x C-f (find-file) 会打开一个文件选项列表供选择,C-x * q (calc quick mode) 可以打开一个计算器,让用户输入算术表达式计算。

quick calc

quick calc result

ivy minibuffer 按键绑定

ivy-minibuffer-map提供了6个比较基础的移动方式绑定:

  • C-n下一个选项
  • C-p上一行选项
  • M-<第一个选项
  • M->最后一个选项
  • C-v向下翻一页,一页内的候选项数目由ivy-height确定
  • M-v向上翻一页,同上

可以看见,这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 + 11 行当前输入,9行其他选项。

ivy-height

ivy action

ivyincremental completion完成之后,还可以再执行action操作,每个可选择的选项都有所谓的action操作。例如find-file的默认action是打开文件,M-x的默认action是执行命令。

单纯的列出命令并说明比较无趣,因此下面会结合场景来介绍各种action的作用。

ivy-done

ivy-done默认绑定在C-mRET上。

它是最常用的操作方式,如find-file的默认action是打开文件,触发ivy-done之后就会 执行这个默认action打开对应文件。

ivy-alt-done

ivy-alt-done默认绑定在C-j上。

find-file的场景下,例如当前光标停在auto-save-list选项上

before-ivy-alt-done

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

after-ivy-alt-done

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

ivy-alt-done-open-file

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

ivy-alt-done-open-dir

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

ivy-alt-done-alternative

在上面这种情况下,直接按/ivy-alt-done效果一致。

ivy-partial-or-done

ivy-partial-or-done默认绑定在TAB上。

它的功能是尽可能的补全当前的输入,以达到最长前缀状态,也就是当前输入的字符串是剩余选项的最长公共前缀

如图所示, 当前最长的公共前缀应该是evil-for

before-ivy-partial-or-done

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

after-ivy-partial-or-done

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里的 候选项。

new-file

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

another-way

注意,这里的光标已经上移至用户输入口了。此时直接RET确定就可以打开abc文件了。

相关问题

ivy-avy

ivy-avy默认绑定在C-'上。

ivy-height设置得比较大时,通过avy来直接跳转选择结果会是一个比较快速的办法。

ivy-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-x想执行evil-forward-char这个命令,但是我想知道这个命令是如何实现的。那 么接下来就通过按M-o触发ivy-dispatching-done,之后再输入d执行查看这个函数的 定义。

ivy-dispatching-done definition

可以看到,它已经确定跳转至evil-forward-char这个命令处了。

h所对应的帮助action实际就是describe-function的效果。

ivy-dispatching-done help

ivy-call

ivy-call默认绑定在C-M-m上,它可以看做不退出minibufferivy-done操作。

还是以evil-forward-char举例

before-ivy-call

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

after-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-dispatching-call

ivy-next-line-and-call 和 ivy-previous-line-and-call

他们两个分别默认绑定在C-M-nC-M-p上,主要功能是把移动和action执行合在一起。

一个比较有用的场景是,find-file找到了许多相似的文件,需要一次性都把他们打开。这个时候,ivy-next-line-and-call的用处就来了。

before-ivy-next-line-and-call

这里想一次性打开ace-window的这3个文件,连续3次使用C-M-n就行。

after-ivy-next-line-and-call

ivy-resume

ivy-resume默认没有提供按键绑定。如同它名字一样,提供resume功能,继续上一次的ivy操作。

M-x执行evil-forward-char,但是不小心按快了,执行了evil-forward-word-end. 这时,ivy-resume会恢复M-x的最后状态,保留着用户输入的内容、光标位置。

ivy-resume

ivy-next-history-element 和 ivy-previous-history-element

他们两个分别默认绑定在M-nM-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-yank-word

ivy-restrict-to-matches

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

before-ivy-restrict-to-matches

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

after-ivy-restrict-to-matches

注:显示候选集合大小通过设置(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上,会弹出一个ivyhydra菜单供用户调用。

hydra使用说明见这个

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扩展性很强,下文会单独开一节描述。

注: 如果是evil用户,可能会需要手工将 normal 状态变为 insert 状态才能使用对应的按键绑定。

(use-package ivy
  :ensure t
  :diminish ivy-mode
  :definines (evil-insert-status-cursor)
  :hook ((after-init . ivy-mode)
         (ivy-occur-mode . (lambda ()
                             (setq-local evil-insert-status-cursor 'box)
                             (evil-insert-state)))))

ivy-occur-dispatch

ivy-occur-mode下,ivy-occur-dispatch如同ivy-dispatching-done一样,将会读 取一个action,然后在当前光标停留的候选项上执行对应的action

ivy-occur

ivy completion style

ivy总共提供了5种补全方式:

  • ivy--regex
  • ivy--regex-plus
  • ivy--regex-ignore-order
  • ivy--regex-fuzzy
  • regexp-quote

默认配置为

(setq ivy-re-builders-alist
      '((t . ivy--regex-plus)))

t是用来保证每个操作都有一个对应的re-builder可以使用。

ivy--regex-plus

ivy--regex-plusivy的默认补全方式,它是这样工作的:

例如用户搜索的是"foo bar", 它会将"foo bar"里的多个连续的空格中的第1个空格转 换成正则里的通项匹配,即正则表达式foo.*bar。如果用户想匹配空格,那么需要额外的 多输入一个空格。如想匹配"foo bar", 那么用户实际应该输入的是foo bar(注意这里 要有2个空格).ivy会把它转换为foo .*bar(注意foo后面有个空格)。论坛会压缩空 格,效果下文见图片。

ivy--regex-plus

此外它还支持正则的取非操作,通过!来完成。

例如"foo bar !example"会先得到匹配foo.*bar的结果,然后再将结果里匹配 example的候选项删除。

ivy--regex

弱化版的ivy--regex-plus,不支持取非操作。

ivy--regex-ignore-order

如名字所示,它会忽略正则的顺序,就好比多次grep一样。

  • foo 会匹配 foo
  • foo bar 会匹配 foo bar bar foo
  • foo !bar 会匹配 foo baz 但是不会 foo barbar 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"))

custom-action