从 Helm 到 Ivy

译文

Updated on 2017-09-24 03:08 (Created on: 2017-09-24 02:24)

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

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的

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 来管理你的参考书目,你可以浏览你的火狐书签

在Emacs 里面用Helm 进行Google 搜索

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

Helm 配置成正在当前活动的窗口展示数据

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

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

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

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

-- abo-abo, Ivy 的开发者,关于 "为什么不选择Helm" 这个问题的回复

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

让我向你介绍我是怎样用 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 式的建筑就相对于Ivy 之于Emacs

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 并没有那么大的差别。它们都是非常优秀的包,只是以不用的方式去实现相同的目标

原文地址 From Helm to Ivy

在下翻译水平有限,如有错误,还请指出