为 Emacs 增加新语言支持
能否编写一个 major mode 是是否能称为 elisp hacker 的分水岭. 你早晚都会遇到一种编程语言或者一种配置格式是 Emacs 尚不支持的.原因可能是它们是才出现不久,也可能是因为它们太小众了。
最终,你会决定卷起袖子开始填坑. 那么你该如何编写一个 major mode 呢?怎样才算是一个好的 major mode 呢?
入门
创建一个最少功能的 major mode,你只需要设置 syntax table 即可,只要你的 mode 能高亮出注释和字符串,那就是有用的
下面是一个最简化的 JS mode:
(defconst my-js-mode-syntax-table
(let ((table (make-syntax-table)))
;; ' is a string delimiter
(modify-syntax-entry ?' "\"" table)
;; " is a string delimiter too
(modify-syntax-entry ?\" "\"" table)
;; / is punctuation, but // is a comment starter
(modify-syntax-entry ?/ ". 12" table)
;; \n is a comment ender
(modify-syntax-entry ?\n ">" table)
table))
(define-derived-mode my-js-mode prog-mode "Simple JS Mode"
:syntax-table my-js-mode-syntax-table
(font-lock-fontify-buffer))
Here’s the result:
看起来并没有作什么工作,但对于配置文件来说,一般够用了。恭喜你,你现在已经是一名 elisp hacker 了! 将你的 major mode 发布到 MELPA 上吧,这样大家可以使用并贡献給你的新 mode。
完全的语法高亮
从这里开始,存在一个很大的扩展空间了,你需要看一下 sophisticated syntax highlighting,这篇文章囊括了一门语言的所有语法说明。
随着你的 major mode 变得越来越复杂,你应该开始考虑如何对它进行测试了,虽说许多 major mode 确实都没有测试,但是像你这么一位自重的 hacker 是很乐意看到 bug 被修复的 (but a self-respecting hacker like you likes bugs to stay fixed).
第一步是创建一个包含各种特殊语法情况的案例文件然后打开它,这种方式很繁杂,最终你会想用程序来进行测试。puppet-mode 就是一个很好的例子 .
缩进
下一步该处理缩进的问题了. 用于希望 Emacs 在任何状态下都能正确地缩进代码,你需要检查光标附近的语法然后计算出当前的嵌套层级。
为了计算当前的嵌套层级,你往往需要从光标当前位置向后搜索整个 buffer,并计算出现 {
(或其他等价的作用域分隔符) 的次数. 然后再根据嵌套层级调整当前行的缩进位置(一般是将嵌套层级乘于 my-mode-tab-width
),若你仔细的处理了字符串和注释中的 {
,这种方式往往能行。
还有一种方法,Emacs 提供了 Simple Minded Indentation Engine (SMIE). 你只需要写好 BNF 语法,然后你就能生成基础的缩进与移动命令了。
You could be a total lunatic, and Emacs has to make you happy.
– Steve Yegge on indentation
在实际中,对什么才是正确的缩进是有争议的,因此为了适应不同的缩进风格,你可以需要提供一些配置项供用户自己调整. 若一切正常的话,你应该能做: 到从一个现存的项目中打开一个大文件,然后运行 (indent-region (point-min) (point-max))
, 结果缩进并不会有什么改变。
缩进的逻辑测试起来很简单,你可以参见 julia-mode 中的例子. 你还需要测试在大文件中缩进是否足够快速,因为一不小心就可能应用了缓慢的算法。
实时检查
若能为 flycheck
添加一个 linter 那必是极好的. 然而即使尚没有成熟的 lint 工具,能够实时高亮语法错误也不错。
flycheck-pyflakes 标示出未用的变量
补全
一个好的 major mode 能够提供自动补全的功能. 你可以通过编写 company 后端来为 major mode 提供补全的能力. 下面这些例子也许能给你一些灵感:
company-clang
( company
的一部分) 使用 Clang
来发现结构体成员:
company-c-headers 搜索本地文件系统来提供补全 C 头文件的建议
pip-requirements 在 internet 上搜索可用的 package 列表
Eldoc
Eldoc 是一个在 minibuffer 显示光标所在内容相关信息的 minor mode,一般被用于提示函数前面或变量类型,但你可以用它来提示任何一样东西。
假设你你的 major mode 能进行一些静态分析,使用 eldoc 来显示上下文相关信息是一种很好的方式。
用 eldoc 显示 elisp 中的 docstrings:
用 c-eldoc 显示光标所在函数的函数原型:
整合 REPL
最后,最完美的 major mode 会允许你直接在 Emacs 中以交互的方式运行代码。
Emacs 提供了一个 comint-mode
,该 mode 允许你自定义解析器,并在 Emacs 中运行该解析器. 许多 major modes,尤其那些 Emacs 自带的 major mode,都是继承自 comint-mode 的。
像 cider 和 sly 这样的项目整合 REPL 的程序甚至比 comint-mode 还要高. 这些包允许你通过解释器进程查询文档字符串,进行自动补全,宏扩展等等其他很多内容。
cider 将 Emacs 和 Clojure REPL 完美的整合在一起了:
Polish
Emacs 一开始就内建支持 C 语言编程,而且 这种支持直到 2015 年还在不断的改进 ! 尽早发布,经常发布,你会创造精品。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论