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-fileM-x映射到 了counsel-M-x

ivy minibuffer

因为ivy大多数时候基本都工作在minibuffer上,因此先介绍一下minibuffer是什么。

minibuffer 是什么

minibufferEmacs命令读取参数的地方,如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-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选项上

ivy-alt-done-1

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

ivy-alt-done-2

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

ivy-alt-done-3

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

ivy-alt-done-4

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

ivy-alt-done-5

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

ivy-partial-or-done

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

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

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

ivy-partial-or-done-1

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

ivy-partial-or-done-2

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

ivy-immediate-done

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

2020-03-03_16-13

注意,这里的光标已经上移至用户输入口了。此时直接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

这里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上,它可以看做不退出minibufferivy-done操作。

还是以evil-forward-char举例

ivy-call

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

ivy-call-3

这时,光标已经向前移动了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-nC-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-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上,可以当成一种二次过滤的手段来使用。 它会清空用户输入、将搜索集合设置为当前的候选集合,这样用户可以慢慢地减少干扰项, 缩小查找范围。

M-x

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

M-x-restricted

注: 显示候选集合大小通过设置(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使用说明见 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-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-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

45 个赞

如果是给新手的,更建议用vanilla emacs。

期待完工,希望能更详细些,既然是给新手的,门槛越低越好。

能给一个简短的理由吗?

何必在人家的教程下面谈论工具本身好不好,合不合适的问题呢?

3 个赞

很多 manual 中的内容,很棒。

既然是写给新手的,建议:

  1. 不要用use-package做配置例子,或者讲清楚怎么用use-package
  2. 用 Vanilla Emacs,或者贴出配置路径或 说明。因为新手用户最容易的错觉是,为什么我的 Emacs 跟你的不一样?

仅供参考。

2 个赞

楼主有心了,期待大作的完工。

也用了一段时间ivy了,但只是随便用用,想到啥需求去查查,从没系统了解过…

我是说,不要多余的配置,干净的emacs只装个ivy。配图什么的看起来会更少干扰,不是说不要用ivy。

1 个赞

我觉得楼主可以放个github的链接

可以用org 也可以用md

楼主的前一个帖子 关于内置mode的 也可以放在一起

这样别人可以提issue和pr

1 个赞

手动点赞!!

如果放在github可能就不会有人点进来了 :pensive:,为了能够直观看到效果,就直接在论坛里写好了。

2 个赞

针对第1点,use-package用法太多了,如果要说明的话,可能会有点重点偏颇了。

已经参考建议,贴上了配置路径了

对,所以要看针对的用户群。如果是初学者很可能搞不清楚 use-package。针对初学者,其实直接用 require 之类的配置最合适了。

1 个赞

在论坛里写 和 同时放在GitHub里 并不冲突

你将来还会有其他插件的介绍 github只是作为一个集合

ivy-occur是大杀器,因为接下来就可以C-x C-q进入wgrep-mode了。这当中有很多技巧可以拓展。关键是懂Emacs Lisp。

现在ivy的弱点是某些命令反模式如!keyword1 keyword2到occur这一步会丢失。我在ec179db中曾经修正过部分command。

6 个赞

还没玩过 wgrep……我学习一下之后再来丰富一下这个教程

这个提议可以,明后天可以搬到 github 上

github上有些作者很nice的,也会在issue里面和大家聊的。

可以介绍一下 yasnippet

或者可以开个投票 看看哪个用的最多

然后是 company 因为需要company-yasnippet

:pensive: 惭愧,我还没用过 yasnippet,要不你来介绍一下吧

1 个赞

还没用过 可能是没有需求 那就按照你的顺序来吧

我觉得一个包得有一个应用场景

比如说ivy 其实就是从一个列表中选择

yasnippet 就是让你少打几个字

company 和ivy相似 只不过是显示在光标的位置

1 个赞