EMACS-DOCUMENT

=============>集思广益

从Helm到Ivy

最近,我发现很多Emacs 用户对Ivy 很感兴趣;而且大部份用户都是已经了解过Helm 或者Ido的 当有人在Reddit 上面问 选择Helm 还是Ido这类问题的时候,我觉得我会给出我自己的选择: Ivy,即使我是一个前Helm 的狂热用户 miimalism-vs.-maximilasim-700x334.jpg 最大或者最小

Helm 和Ivy 都是补全框架.这意味着它们都是Emacs 生态系统中用来在用户输入后缩窄可供 选择选项的范围的工具。很自然而然想起的通用例子就是搜索文件。Helm 和Ivy 都可以帮助 用户快速搜索文件

它们两者都是框架,这意味着它们都可以用在那些需要补全或者缩窄范围的复杂命令。例如 Helm 有一个命令(helm-google-suggest)可以模拟Goole 的搜索框,并在你输入时给出相应 的google 提示

Ivy 和Helm 都有相同的目标,但是它们实现的方法却是迥然不同

现在我想站在用户的角度来比较一下这两个工具。我这里指的用户观点是我在不需要了解 Helm 和Ivy 的内部工作原理的前提下对这两个工具进行比较。其实,因为我对 elisp 还谈不上精通,所以也没办法就两者实现细节来进行比较。但是这两个工具我都使用过, 所以我可以从用户的角度,跟你分享我使用它们的不同感受。最后,我从Helm 切换到了Ivy

我想先谈Helm.当我使用Spacemacs 的时候,我学会了怎么使用Helm,以Helm 的方式思考 ,如何自定义Helm,怎么把Helm 配置得称心如意。我想我应该算得上是一个中级的Helm 用户吧。 我有读过这篇文章 还有这篇文章 以及Wiki 此外,在长达一年的时间里,我每天都是使用Helm的 swiss_knife.jpg Helm 是Emacs 的瑞士军刀

Helm 是一个非常成熟的工具.根据git 的提交历史,Helm 的开发工作是在2009年左右开始的。 在写这篇文章的时候,Helm 官方的git 仓库有超过26000行elisp 代码

git clone https://github.com/emacs-helm/helm.git
cd helm
cat *.el | wc -l
# => 26431

这还是没有把在MELPA 上查询到跟Helm 有关的包有142个的情况考虑在内的呢。你可以用Helm 来完成任何事情 它主要的强大之处在于你可以把Helm 和很多Emacs 的行为整合在一起。你可以以Helm 为 中心构造接口,就像Spacemacs 做的那样。Helm 支持非常一致的接口,你可以通过Helm 来 做任何事

你可以搜索文件,搜索缓冲区,搜索颜色,搜索项目,搜索你最近编辑过的文件,搜索系统进程 搜索音乐,搜索网络资源,搜索补全,搜索代码片段,搜索正则表达式,搜索命令,文档 相关描述,手册…. 你可以用Helm-projectile(一个Helm 对projectile 非常好的包装) 来管理你的项目。你可以用gitignore.io 来生成gitignore文件,你可以用Helm-bibtex 来管理你的参考书目,你可以浏览你的火狐书签 helm_google_suggest.gif 在Emacs 里面用Helm 进行Google 搜索 你可以用Helm 来完成任何事。

基于 tuhdo 对我在Reddit 上面问题的回复,我想指出的一个特性就是Helm 是不使用 minibuffer ,但是Ivy 是使用的。所以它可以被配置成总是在当前打开的窗口展示。对于那些大屏幕显示器 的用户而言,这个特性真的非常有用,因为你的目光不用在 minibuffer 来回切换:补全 结果总是显示在同一个窗口 g1Oz9JY.png Helm 配置成正在当前活动的窗口展示数据

最终的比较结果是Helm 是非常便利的工具,相信会有数量非常多的Spacemacs 用户告诉你 同样的看法。而Helm 主要的缺点就是它的代码量太大了。我想虽然Helm 的代码量很大,但是 它的开发者利用 elisp 成功把它打造成了一个相当快的工具了

而且有些时候,Helm 似乎把简单的问题复杂化了;它配置起来也感觉相当臃肿;有时它也会 有一些很奇怪的表现,然后导致卡顿,或者让Emacs 过载,即使你做的只是很简单的查询。 或许那些Helm 的高手用户看到这里,会觉得如果我也是个 elisp 高手,就不会 出现上述问题了。虽然我已经使用Helm 超过一年了,我还是没有找到方法让可以Helm 更加稳定。我觉得Helm 在用自己做例子来讲述了什么是化简为繁吧

你可以用Helm 来做任何事;但事实上你并不需要。你可以这样做并不意味着你应该这样做。 在使用Helm 一年以后,我可以告诉你我只是使用了Helm 三分之一或者更小的功能。有些 功能我觉得真的很棒,昨天在读了这篇文章 之后,我又发现了一些新的东西。大部分时间,我 都是使用简单的命令来切换缓冲区,或者列举文件

Helm 只是一个用来补全的包,就好像Ido 或者Ivy.它可能很容易使用,一旦有人经历过 配置它的困难,就会发现它很难做到让你随心所欲。有些人觉得只要可以让他们使用好的工具 ,即使他们完全不了解这些工具也无所谓。但是我就做不到 –abo-abo,Ivy 的开发者,回答"为什么不选择Helm" 这个问题

opinel.jpg Ivy 只完成一件事,以及….

Ivy 为实现最小化,简单化,可定制化,可发现化而努力.这四个形容词告诉我们很多Helm 和Ivy 这两个工具间不同的设计理念。阅读Ivy介绍 以便更好了解Ivy的理念。

在写这篇文章的时候,Ivy 只有大概3400行代码,为Ivy 所打造的生态系统:即Swipter 和 Counsel 也只有7500 行代码

git clone https://github.com/abo-abo/swiper.git
cd swiper
## Only ivy ?
cat ivy.el | wc -l
# => 3442

## count lines of code into the whole swiper ecosystem
cat *.el | wc -l
# => 7526

Ivy 真的是很容易上手,下面就是我的全部配置:

(use-package ivy :ensure t
  :diminish (ivy-mode . "")
  :bind
  (:map ivy-mode-map
        ("C-'" . ivy-avy))
  :config
  (ivy-mode 1)
  ;; add ‘recentf-mode’ and bookmarks to ‘ivy-switch-buffer’.
  (setq ivy-use-virtual-buffers t)
  ;; number of result lines to display
  (setq ivy-height 10)
  ;; does not count candidates
  (setq ivy-count-format "")
  ;; no regexp by default
  (setq ivy-initial-inputs-alist nil)
  ;; configure regexp engine.
  (setq ivy-re-builders-alist
  ;; allow input not in order
        '((t   . ivy--regex-ignore-order))))

Ivy 是很低调的;它不想让你把一切都整合到Ivy去。它仅仅是提供你必需的补全。你不能像 Helm 那样用Ivy 来做任何事;那为什么我还要切换到Ivy 去呢?

虽然Ivy 已经最小化,但是我依然可以用Ivy 来代替我绝大部分日常使用的Helm命令。因为 Ivy是如此简洁, abo-abo 在它上开发了一个叫 Counsel 的包; Counsel 可以 为你提供非常非常多像你在Helm使用的命令

你可以切换缓冲区,搜索文件,在项目级别进行搜索和替换,与Projectile 整合,搜索你最近 编辑过的文件,搜索Emacs 命令,搜索文档,搜索按键绑定,浏览 kill-ring swiper.gif

让我向你介绍我是怎样用Ivy 代替Helm 的。下面是我对那些我需要使用Ivy 来代替Helm的最 常用命令的总结。这些基本是我一直以来最常用的方法。我每分钟会使用三次的 ivy-switch-buffer ,我一天会使用五次的 helm-swoop, swiperhelm-swoop 不分伯仲;对于 那些大文件, Counselcounsel-grep-or-swiper.我已经用一些非常非常大的 标记语言的文件(一百万行左右)来测试过了,一点问题也没有。

Helm Ivy What ?
helm-mini ivy-switch-buffer search for currently opened buffers
helm-recentf counsel-recentf search for recently edited files
helm-find-files counsel-find-files search files starting from ./
helm-ag counsel-ag search regexp occurence in current project
helm-grep-do-git-grep counsel-git-grep search regexp in current project
helm-swoop swiper search string interactively in current buffer
helm-show-kill-ring counsel-yank-pop search copy-paste history
helm-projectile counsel-projectile search project and file in it
helm-ls-git-ls counsel-git search file in current git project
helm-themes counsel-load-theme switch themes
helm-descbinds counsel-descbinds describe keybindings and associated functions
helm-M-x counsel-M-x enhanced M-x command

我觉得你可以看到Ivy 基本的命令对比Helm 的命令也是毫不逊色的。它们可以代替你日常 使用的每一条Helm命令。我不是说你可以像Helm 那样用Ivy 来做任何事,但是它已经足够 好用了,正如我说的那样,你也不需要任何事都使用Helm 来完成。

说到补全理念这个话题上,Helm 和Ivy 之间的差异并没有那么大。作为一个用户,我可以 告诉你的是:Ivy 会让你感觉到更少的臃肿,更加的直观,更加地容易理解。每一次的补全 都是可以预见的。

最后,这真的跟个人的品味有关。对于我自己来说,"Ivy 还是Helm" 这样的争论跟 "Emacs 还是Spacemacs" "Emacs 还是Ide" "C 还是Java" "简洁还是全能" "Thelonious 还是 Duke" (译者注,两者都是爵士乐作曲家),"Van Der Rohe 还是 Gaudi."(译者注:前者是德国美国 的建筑风格,后者是西班牙加泰罗尼亚的建筑风格)这样的争论是非常相似的。 van_der_rohe.png Van Der Rohe 式的建筑就相对于Ivy 之于Emacs

gaudi.jpg Gaudi 就相当与Helm 之于Emacs

你选择Helm 呢,你会得到一个巨型的包,一系列你不会用到的特性,一堆你可能只是偶尔 用一下的功能,一些你会一个小时使用50次的特性。如果你选择Ivy,你会得到一个只拥有 那些让你顺心的必要特性的精简的包,你可以很容易地通过 Counsel 或者简单的函数 对它进行扩展

(ivy-read "Pick:" (mapcar #'number-to-string (number-sequence 1 10)))

如果你想要通过Helm 来扩展:

(helm
 :sources
 (helm-build-sync-source "one-to-ten"
                         :candidates
                         (mapcar #'number-to-string (number-sequence 1 10))
                         :fuzzy-match t)
 :buffer
 "*helm one-to-ten*")

或者简单的列表:

(helm-comp-read "Pick:" (mapcar #'number-to-string (number-sequence 1 10)))

Helm 为用户作了非常多的决定,Ivy 让用户按需求进行定制;Helm 通过耗费非常多的内存来 变得快速,Ivy 通过保持简洁来实现快速;Helm 很成熟,Ivy 很青涩;Helm 为Emacs 提供 一致性,Ivy 为Emacs 提供简洁性和可预见性;Helm 需要你进行一定的配置,Ivy 开箱即用

我自己是稍偏向Ivy 的,因为我正在使用它;它更符合我的口味。但是作为一个用户,Helm 和Ivy 并没有那么大的差别。它们都是非常优秀的包,只是以不用的方式去实现相同的目标