Emacs Helm: 使用关键字搜索、获取、执行任何东西

Helm 是一个emacs的软件包,定义了一个通用框架,交互式地、动态缩减式地使用关键字选择、获取、执行任何东西。比如:

  • 执行emacs 命令
  • 打开文件
  • 查看man文档
  • 执行grep操作
  • 执行apt命令
  • 相看imenu函数定义
  • 切换buffer

Helm软件包本身包含两部分,框架本身及应用。以上列表均为应用。基于框架,可以轻松创建新的应用。

基本原理

Helm的三个重要概念:candidate, narrowing, action.

Candidate

Candidate即候选值,是一个列表,保存所有可供选择的条目。对于打开文件的命令,candidate是所有的文件名称的列表。

Narrowing

Helm命令启动后,用户未输入任何关键字前,会将candidate中的所有条目显示出来,每行显示一个项,可通过'C-n', 'C-p'上下移动光标选择当前条目。

如果candidate的数目较少,此时没必要输入关键字,通过上下移动光标选择就行了;但如果candidate数目较多,目标条目没有被显示在第一页,可输入关键字,对candidate的条目进行筛选,只有匹配到关键字的条目才会被显示出来。这就是narrowing。

值得一提的是,这个过程是动态的,即每输入一个字符,candidate的条目都会被重新筛选。有时只输入了一个字符,目标条目已经显示在第一页,则可停止输入,通过移动光标选择当前条目;有时输入了一个关键字,目标条目仍然没有出现,则可按空格,继续输入另一个关键字,进行更精确的筛选,直到目标条目出现为止。

输入的关键字越多,candidate的数目会越少,目标条目出现在第一页第一个条目位置的机率就越大,进而选择也就越方便。

Action

当一个candidate被选中后,按下Enter后,就会有一个action被执行。对于打开文件,其action对应到emacs命令就是'find-file'。可以为一个条目定义多个action,如对于文件条目action可以为打开文件、重命令文件、删除文件等。 通过TAB键从多个action中选择,如果直接按Enter会执行第一个action.

定义一个新的helm应用

基本例子

要定义一个新的helm命令,只需定义一个变量指定candidate及对应的action,然后将其作为参数传给helm就可以了,以下为一个例子。

(setq some-helm-source
      '((name . "HELM at the Emacs")
        (candidates . (1 2 3 4))
        (action . (lambda (candidate)
                    (message-box "%s" candidate)))))

(helm :sources '(some-helm-source))

其中定义candidate、action的变量叫做source, 是一个assoc list。candidates是一个list, action是一个函数,action函数被调用时,当前选择的candidate会被作为参数传入。

定义多个action

上面的例子中action的值为一个匿名函数,如果要定义多个action,则需要将action的值设置为一个list,list的元素是一个cons:(说明 . 函数)。如下所示,定义了两个action。

(setq some-helm-source
      '((name . "HELM at the Emacs")
        (candidates . (1 2 3 4))
        (action .
                (("Display" .  (lambda (candidate)
                                 (message-box "%s" candidate)))
                 ("None" . identify)
                 ))
        ))
(helm :sources '(some-helm-source))

将candidate的选择值与真实值分离

有时候需要通过不同的值选择candidate,此时可将candidates设置为cons (KEY . VALUE)的list。其中KEY将用于选择,VALUE将作为action函数的输入参数值。

(setq some-helm-source
      '((name . "HELM at the Emacs")
        (candidates . (("one" . 1) 2 ("three" . 3) 4))
        (action .
                (("Display" .  (lambda (candidate)
                                 (message-box "%s" candidate)))
                 ("None" . identify)
                 ))
        ))
(helm :sources '(some-helm-source))

动态candidate

有时candidates需要动态计算,或者静态计算量会很大,此时可将candidates设置为一个函数,这个函数将被用于计算所有candidates的值。

(defun random-candidates ()
  "Return a list of 4 random numbers from 0 to 10"
  (loop for i below 4 collect (random 10)))

(setq some-helm-source
      '((name . "HELM at the Emacs")
        (candidates . random-candidates)
        (action . (lambda (candidate)
                    (message "%s" candidate)))))

(helm :sources '(some-helm-source))

添加一个persistent action

Persistent action是指执行action后,不退出helm,类似于预览功能,默认绑定在\C-z。通过'persistent-action'来指定,如果未指定,则与第一个action一样。

(setq some-helm-source
      '((name . "HELM at the Emacs")
        (candidates . (1 2 3 4))
        (persistent-action . (lambda (candidate) (message "%s" candidate)))
        (action . (lambda (candidate)
                    (message-box "%s" candidate)))))

(helm :sources '(some-helm-source))

helm-org-headlines的定义

这个命令由helm默认提供,其定义如下,可为实现新的命令提供参考。

(setq helm-source-org-headline
      `((name . "Org Headline")
        (headline
         ,@(mapcar
            (lambda (num)
              (format "^\\*\\{%d\\} \\(.+?\\)\\([ \t]*:[a-zA-Z0-9_@:]+:\\)?[ \t]*$"
                      num))
            (number-sequence 1 8)))
        (condition . (eq major-mode 'org-mode))
        (migemo)
        (subexp . 1)
        (persistent-action . (lambda (elm)
                               (helm-action-line-goto elm)
                               (org-cycle)))
        (action-transformer
         . (lambda (actions candidate)
             '(("Go to line" . helm-action-line-goto)
               ("Refile to this headline" . helm-org-headline-refile)
               ("Insert link to this headline"
                . helm-org-headline-insert-link-to-headline))))))

(defun helm-org-headlines ()
  "Preconfigured helm to show org headlines."
  (interactive)
  (helm-other-buffer 'helm-source-org-headline "*org headlines*"))

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏有趣的Python

2018.2最新-Scrapy+elasticSearch+Django打造搜索引擎直至部署上线(四)伯乐在线爬取所有文章

最终项目上线演示地址: http://search.mtianyan.cn 第四节:开工啦,开工啦。这节我们爬点数据试试手,并且存起来。存到json,mysql...

4949
来自专栏前端架构与工程

Node.js建站笔记-使用react和react-router取代Backbone

斟酌之后,决定在《嗨猫》项目中引入react,整体项目偏重spa模式,舍弃部分server端的模板渲染,将一部分渲染工作交给前端react实现。 react拥有...

2039
来自专栏猿人谷

grep命令

Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。grep全称是Global Regular Expre...

1717
来自专栏彭湖湾的编程世界

【PHP】文件写入和读取详解

文章提纲: 一.实现文件读取和写入的基本思路 二.使用fopen方法打开文件 三.文件读取和文件写入操作 四.使用fclose方法关闭文件 五.文件指针的移动 ...

2487
来自专栏王磊的博客

ASP.NET页面的字符编码设置

在用ASP.NET写网上支付的接口程序时,遇到一个奇怪问题,通过表单提交过去的中文全是乱码,英文正常。而用asp程序进行测试,可以正常提交中文,asp页面中有这...

3396
来自专栏北京马哥教育

ansible之playbook功能简述

playbooks剧本简介 playbooks是ansible更为强大的配置管理组件,实现基于文本文件编排执行的多个任务,且多次重复执行。其是使用YAML(Ye...

2825
来自专栏大内老A

深入剖析ASP.NET的编译原理之一:动态编译(Dynamical Compilation)

Microsoft 的Visual Studio为我们在应用开发中提供的强大功能,我们是有目共睹。借助该工具,是我们的开发 显得更加高效而轻松。从Microso...

1735
来自专栏社区的朋友们

深入浅出 Nodejs( 三 ):Nodejs 核心模块机制

本篇教程关于Nodejs的核心模块机制,具体讲Nodejs核心模块的原理、C/C++扩展模块的原理、包、模块调用栈以及NPM。

6810
来自专栏macOS 开发学习

Mac开发之 Cocoa 绑定 入门

从iOS开发转为Mac OSX应用开发的过程中,cocoa 绑定算是比较大的一个差异,也是OSX上比较实用的技术,cocoa 绑定让开发者节省了大量的代码,可以...

652
来自专栏程序你好

JavaScript调试和优化,深入研究谷歌Chrome浏览器开发工具(一)

Chrome DevTools集成了许多子工具,用于在客户端上调试web应用程序,比如记录性能配置文件和检查动画——主要是通过DevTools控制台来学习web...

725

扫码关注云+社区