Emacs Application Framework 的折腾之路
用了Emacs将近13年了, Emacs的使用时间几乎等于我的编程生涯, 可以说这么多年的编程能力和专注力都是靠Emacs来帮我提升的.
Emacs最大的威力是, 一旦你配置好了编程所需的一切, 它可以让你完全生活在里面, 打开电脑只用Emacs, 关闭Emacs就直接睡觉, 所有的专注力都放在高效的编程环境中, 只需要思考, 条件反射式的动手指, 运行即可.
使用Emacs时间长了, 就希望所有的事情都能够让Emacs完成, 不仅仅是编程.
其实Emacs几十年的发展, 除了编程以外, 还可以听音乐(EMMS), IRC聊天(ERC), 甚至是终端(Multi-Term) 等等, 如果你是一个 old-school 风格的黑客, 其实Emacs内置的功能已经够你使用了.
但是我这十几年的折腾 ( https://www.emacswiki.org/emacs/AndyStewart ), 完全不满足于此, 我希望Emacs能编程程序员的操作系统, 没有过多的界面装饰, 只用最简洁的设计, 全键盘操作程序员希望的一切程序, 比如图形化浏览器, 视频播放器, Markdown实时阅读器, 邮件客户端等等.
这个小小的梦想, 十几年前就有了, 但是限于当时的编程能力, 走了很多弯路:
第一次尝试: 2007年, 使用了Haskell编写了一个类似 Emacs 的操作系统: Manatee & 截图, 当时一口气写了编辑器, 终端, 浏览器, 音乐播放器, 文件管理器, 新闻阅读器等十几个应用, 几乎就要达到我梦想中的样子了, 但是最后放弃了, 有两个重要的原因: 第一、因为不知道怎么使用图形混合技术, 导致多个浏览器窗口无法共用一个buffer, 最直接的问题就是一个视频浏览器页面一旦分屏以后就会有两个进度和两个声音; 第二、编辑器模块怎么写也不可能有Emacs那么强大 (Manatee这个项目最大的贡献就是, 因为Manatee要使用很多Gtk+控件库, Gtk2hs 都没有, 我贡献了几万行代码给Gtk2hs, 使得Gtk2hs成为当年为数不多的Gtk+ Language Binding)
第二次尝试, 2015年, 我用Vala写了一个类似 Manatee 的项目: MrKeyboard, 但是最后也放弃了, 最主要的原因是曹哥的 Deepin-WM 窗口管理器专克我的 Xlib Reparent 黑科技, 导致我没法在 deepin 操作系统中运行 MrKeyboard, 加之当时工作也非常忙, 没有时间写图形混合器, 画面同步都是在 XClient 端拷贝图像实现的, 导致看视频的时候非常卡.
第三次尝试, 2018年, 从 deepin 退休后, 花了一个月的时间用 PyQt5 编写了一个新的框架 EAF, EAF使用了 DBus/QtGraphicsView/XReparent 三种技术实现了多进程通讯, 图形混合器和粘贴窗口到Emacs, 利用这三种技术, EAF可以让任何图形化的程序都可以直接在Emacs中运行, 包括浏览器, PDF阅读器, 图片查看器, 视频播放器, 摄像头, Org/Markdown实时预览, 文件传输等等应用. 这个项目彻底的实现了十几年前我期望改造Emacs的小目标.
Emacs Application Framework 的目标
- 增强Emacs的图形化能力, 所有需要高性能图形绘制的功能都用EAF来实现
- 让Emacs专注于文本编程环境的开发, 并保持 Elisp 现有的生态不会因为引入图形化功能发生重大的变化
- 通过增强Emacs的图形化插件来获得现代IDE的很多能力, 使得Emacser能够永久的生活在Emacs中.
Emacs Application Framework 的架构设计
用最通俗的话来讲, EAF其实做的工作和手机贴膜差不多, 就是先把 PyQt5 的图形程序运行起来, 然后通过 XReparent 的技术把PyQt5的窗口粘贴到Emacs窗口对应的位置.
EAF整体架构的关键技术有以下几点:
- 通过 QtGraphicsView/QtGraphicsSence 来实现实时图形混合, 多个窗口可以共用一个进程的绘制内容, 这样就可以适应 Emacs 的 Window/Buffer 架构设计, 从而最终让 PyQt5 窗口可以像 Emacs Elisp Buffer 那样集成和切换, 顺利的解决了当年 Manatee 两个浏览器窗口有多重音视频的问题.
- 通过 X11 Reparent 技术, 粘贴 PyQt5 的窗口到 Emacs EAF Buffer 的坐标上, 实现多个进程的窗口看起来是一个程序里面的不同部分, 不清楚 X11 技术的同学, 可以想象一下 Chrome 的多进程架构设计. X11 Reparent 的技术除了达到贴膜的作用外, 还变相的实现了多进程沙箱的设计, EAF图形化的程序运行在单独的进程中, 即使出现了意外情况, 也不会影响Emacs本身的稳定性.
- 在Emacs端实现了一个事件监听循环, 当用户在 EAF Buffer按下任何按键, 都会通过 DBus 发送事件消息给 Python 进程, Python 进程再伪造相应的事件来模拟Emacs端用户的键盘输入.
通过这种简单粗狂的设计, EAF已经实现了包括浏览器, 图片浏览器, PDF阅读器, 视频播放器, 摄像程序, Org/Markdown实时预览器, 文件共享程序等模块.
5分钟就可以写好一个插件
只要你会基本的 Python 和 Qt 编程, 5分钟就可以写一个 EAF插件
如果你不会 Qt 也没有关系, 看这个Qt教程, 几天就会了.
未来的目标
- 完善浏览器插件
- 实现更多的插件, 比如邮件客户端, 新闻阅读器, 终端模拟器等
- 移植EAF到 MacOS 平台 (主要的障碍是 MacOS 平台上怎么实现 X11 XReparent 类似的技术)
- 面向社区开发更友好的架构设计和文档工作