从 Helm 到 Ivy

发布于 2023-05-06 13:08:31 字数 7746 浏览 82 评论 0

最近,我发现很多 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 为实现最小化,简单化,可定制化,可发现化而努力,这四个形容词告诉我们很多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-swoopswiperhelm-swoop 不分伯仲;对于那些大文件, Counselcounsel-grep-or-swiper,我已经用一些非常非常大的标记语言的文件(一百万行左右)来测试过了,一点问题也没有。

HelmIvyWhat ?
helm-miniivy-switch-buffersearch for currently opened buffers
helm-recentfcounsel-recentfsearch for recently edited files
helm-find-filescounsel-find-filessearch files starting from ./
helm-agcounsel-agsearch regexp occurence in current project
helm-grep-do-git-grepcounsel-git-grepsearch regexp in current project
helm-swoopswipersearch string interactively in current buffer
helm-show-kill-ringcounsel-yank-popsearch copy-paste history
helm-projectilecounsel-projectilesearch project and file in it
helm-ls-git-lscounsel-gitsearch file in current git project
helm-themescounsel-load-themeswitch themes
helm-descbindscounsel-descbindsdescribe keybindings and associated functions
helm-M-xcounsel-M-xenhanced 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,译者注:前者是德国美国的建筑风格,后者是西班牙加泰罗尼亚的建筑风格

这样的争论是非常相似的。

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

佞臣

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

eins

文章 0 评论 0

世界等同你

文章 0 评论 0

毒初莱肆砂笔

文章 0 评论 0

初雪

文章 0 评论 0

miao

文章 0 评论 0

qq_zQQHIW

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文