Emacs高度统一的插件设计哲学
Emacs是我计算机的启蒙老师,RMS多年在自由软件奋斗的故事一直激励着我,通过阅读Emacs插件的Lisp代码,我能看到地球另一边那些天才们的影子:熬夜弄懂每一个API的细节、反复打磨每行代码、天马行空的想象力、代码大厦建成后和构想分毫不差的满足感…
很多人只看到Emacs的高效率和指尖的魔法(其实就是没看懂这些人按了啥工作就完成了,哈哈哈哈), 我最欣赏Emacs背后的 “高度统一的插件设计哲学”,你会发现,虽然不同插件作者的文化底蕴和技术水平有巨大差异,但是插件都具备一些共同特性:
- 尊重习惯:每个插件都会对一些基本的按键 (C-n、C-p、C-c C-c、C-c C-k 等) 行为提供一致性的表达,尽最大让用户直觉化操作
- 传递懒癌:你会发现越是流行的Emacs插件,已经把懒癌文化发挥到极致,能按一下按键的绝不按两下按键,能不按键的自动化处理
- 细节设计:很多插件用的时候会有一种行云流水般的爽,这些都来源于作者深入研究了编程时每一个卡手事件的原因,他们才是编程界的交互设计大师
而这些设计哲学最让我吃惊的是,没有任何一个人或组织定制需要强制遵守的规范,上面这些设计细节就像宗教文化一样在一代又一代的黑客之间传递,社区共识力量之伟大,造就了世界上最庞大的编程插件生态。
为什么创建 Emacs Application Framework?
用Emacs习惯了,Emacs和外界的通用图形应用(比如Chrome、终端、文件管理器等)的反复切换给每个Emacser带来强烈的分裂感:
- 在Emacs中,所有操作都可以通过快捷键、链接跳转、搜索来快速完成,效率是传统软件的10倍以上
- 外界通用图形软件,因为创建之初就基于普通大众的视角去设计的,大多数操作都是鼠标优先的,一个软件能配套10%的快捷键就已经非常不错了
对于效率至上的黑客和键盘流信仰者,用外部图形应用就像让现代人放弃科技回到古代那般无奈和不爽…
我创建EAF的目标不是要把天下的软件都重新造一遍,而是希望基于现有开源社区丰盛的基础组件,构建一系列符合全键盘操作的工作环境。
Live in Emacs背后的理想是,顶尖黑客需要一整套面向黑客设计的工作环境,当大多数黑客用的软件都可以被EAF满足后,最终就可以实现 “人剑合一” 的心流状态。
这种心流状态的好处是,你不再会因为普通应用的鼠标点击和不统一的操作习惯而打断创作思路,当创作思绪在 “构想、实验和指尖跳动” 之间流淌,天马行空的想象力和肌肉记忆的指尖魔法会让每个计算机艺术家们创作出更伟大的作品。
Emacs Application Framework 当前的进度
EAF目前已经支持大多数操作系统和Linux发行版,包括Windows、macOS、FreeBSD、Linux(Arch、Fedora、Gentoo、Debian、OpenSuse等)。
- 浏览器: 基于Chromium渲染引擎, 内置包括Vimium、Caret、EmacsEdit等一系列键盘效率插件
- PDF阅读器:基于PyMupdf库实现PDF文件连续查看、高性能滚动、笔记标注和导出等功能,是Emacs生态中最快的PDF阅读应用,没有之一
- 视频播放器:直接在Emacs看视频,不需要和外部播放器来回切换
- 图片浏览器:图片支持任意倍速快速缩放,甚至包括触摸板缩放手势
- 终端模拟器:基于Xterm.js来实现的全功能终端模拟器,支持终端环境所有图形渲染能力,同时不用像vterm那样还需要编译后才能使用
- 文件管理器:兼具ranger文件快速预览的双栏设计以及Dired的键盘操作习惯,甚至内置多线程文件递归搜索功能
- 音乐播放器:作为CJK的用户,如果音乐播放列表连最基本的多列对齐都做不到,我宁愿不用
- 文件预览:支持Markdown、Org-Mode、Office等文件的实时预览
- 其他应用:包括思维导图、Jupyter、摄像头、文件分享、网易云音乐、系统监视器都是一些贴心的小应用…
Emacs Application Framework 架构设计
EAF本质上和手机贴膜的原理差不多,EAF整体架构设计本质上只有三个关键技术:
- 利用QWindow的Reparent技术来实现PyQt应用进程的窗口粘贴到Emacs对应的Buffer区域
- 通过Python EPC来实现Emacs进程和Python进程的控制指令和跨进程消息通讯
- 通过Qt5的QGraphicsScene来实现镜像窗口,以对应Emacs的Buffer/Window模型
Emacs Application Framework 多语言调用接口
目前为止,EAF具备的协同开发能力有:
- Elisp <-> Python 相互调用,借助Python,Emacs可以获取多线程、二三维绘制和调用Python系统库等能力
- Elisp <-> NodeJS 相互调用,借助NodeJS,Emacs可以直接调用丰富的NPM库
- Elisp <-> Vue.js 相互调用,借助Vue.js,Emacs可以开发富媒体的图形应用
通过EAF多语言调用接口,形成了多脚本语言快速协作的开发模式:
- Elisp提供Emacs状态访问和交互反馈
- Python提供多线程能力以及给浏览器提供系统底层库访问的能力
- JavaScript提供图形绘制能力
基于上述多语言调用能力,所有VSCode能做的事情,现在Emacs都可以做,而且不破坏Emacs现有的插件生态和黑客文化。
Emacs Application Framework 应用开发
EAF现在已经支持Core核心框架和应用独立的开发模式,开发方式很简单:
- Qt应用直接 fork eaf-demo 项目后,添加自己的Qt控件即可
- Vue.js应用直接 fork eaf-vue-demo, 添加自己的Vue控件即可
关键函数主要有几个:
-
Emacs同步调用Python函数并返回结果:
(eaf-call-sync "call_function" eaf--buffer-id "python_function_name")
-
Emacs异步调用Python函数,不返回结果:
(eaf-call-async "execute_function" eaf--buffer-id "toggle_fullscreen" args)
-
Emacs同步调用JavaScript函数,并返回结果:
(eaf-call-sync "execute_js_function" eaf--buffer-id "js_function_name" args)
-
Emacs异步调用JavaScript函数,不返回结果:
(eaf-call-async "eval_js_function" eaf--buffer-id "js_function_name" args)
-
Python端直接向Emacs打印消息:
message_to_emacs("message")
-
Python端读取Emacs变量值:
get_emacs_vars["var1", "var2", "var3"]
-
Python端执行Elisp函数, 不返回结果:
eval_in_emacs("elisp_function", [args])
-
Python端执行Elisp函数,并返回结果:
get_emacs_func_result("elisp_function", [args])
-
JavaScript调用Python函数foo:
window.pyobject.foo(args)
-
JavaScript调用Elisp函数:
window.pyobject.eval_emacs_function("elisp_function_name", [])
其实只要掌握了上述语言间互调用的方法,剩下的就是阅读现有EAF应用的代码,依葫芦画瓢就可以了。
Emacs Application Framework 未来规划
EAF全球已经有61位开发者,目前的架构已经可以支持各应用独立于Core快速开发。
未来的一些规划包括:
- EAF核心支持DND拖拽事件
- 浏览器支持代理规则定义,而不是现在全局代理模式
- 支持更多应用,包括邮件客户端、新闻阅读器、原创的思维导图框架…
- 自动安装脚本支持更多的Linux发行版
我觉得每一个Emacser都是身怀绝技的艺术家,管它什么狗屁UNIX哲学和KISS原则,只要我们自己用的爽就行了,来吧,一起创造和打磨属于我们自己的完美工作环境!