文本编辑器的基础方程式

前言

我的 Windows 软件之道#推荐 我曾提到代码编辑用的是去除遥测并且使用 Open VSX 的 VSCodium,但实际上我也在使用 Notepad++(下文简称 npp)。由于 npp 作者抱有强烈的政治参与感,三天两头被口诛笔伐。虽然我并不在意这些 1,但时不时看到互撕的也会心烦,早就有了迁移的想法。可惜试来试去,大多都在某些方面差强人意。

前几天在 HackerNews 看到 pragtical,看 commit 记录一直在活跃更新,SDL + Lua + C 的跨平台特点看着也不错,于是尝试和对比了一番,在官方火速修复 LuaJIT 关于 Windows Unicode 路径的 bug 之后彻底迁移,自此告别 npp。

要求

前言说了一堆还没点题,npp 迁移之所以耗时几年,是因为我对文本编辑器的选择很挑剔。下面列举的仅仅是需要满足的 最基本要求

  1. UTF-8/UTF-16-LE 支持,能够打开并修改特定文件编码(至少支持 Shift-JIS / GB-2312 / GBK-5)
  2. 支持转换 EOL(最好支持移除行首/行末多余空格,以及 Tab/Space 相互转换)
  3. 支持 text wrap 和最最基本的文本补全(最好支持 tokenizer)
  4. 支持正则匹配,可以一次性全部替换
  5. 支持深色模式(最好可以自定义主题/配色,支持/内置 monokai)
  6. 打开 100M 以内文件耗时在合理范围(最好 1G 以上文件 100% 加载时间在半分钟以内)
  7. 提供便携版(除非安装包尺寸在 20M 以内)
  8. 支持批量操作文件后缀名关联(绑定与解绑)
  9. 冷启动速度不超过 3 秒(最好是秒启动)
  10. 开源(如果是闭源,必须支持 100 款以上插件)

解释

稍微解释一下几个点:

  • UTF-8 支持看似简单,但实际做起来坑也挺多的,更别提 emoji/Unicode/RTL 文字等等,iOS 三天两头爆个无限重启 bug。Pragtical 虽然支持编码/EOL,但默认的字体显示不了 CJK 字符和 emoji,手动添加字体即可
  • Text wrap (line wrap) 就是如果一行的内容在程序宽度范围写不下,会自动显示成多行,而不用左右拉进度条
  • Tokenizer 即标记器,NLP 里一般就是分词或者特殊的标志词(比如 MoeGoe 里的 [ZH] 等语法标记块),算是 hidden gem
    • 比如在排版的时候,很多时候左对齐、右对齐、居中对齐都很丑,如果有 tokenizer 根据语义分行,就不会出现一个词跨
    • 行这种难受的现象。
    • 又比如双击文本选中,这个功能看似简单,但在不借助 linter 的情况下,如果没有 tokenizer,双击中文词会把旁边一堆英文也选中(比如双击 GBK-5/Shift-JIS编码 中的 编码,会选中整行);或者想要选中 支持深色模式深色,你需要用鼠标准确地选中 深色 两个字,不能太左,也不能太右。而有了分词器,直接双击 字,即可直接选中 深色 这个词语。
  • 正则匹配看似寥寥四字,但是正则标准诸多(Perl/POSIX/PCRE/Vim/ECMAScript/Python/Golang/C#/Rust…),一个隐性要求是正常的正则实现,而不是自己做的莫名其妙的标准
  • 深色模式这点,npp 也花了好多年才做出比较正常的效果,很多开发者自己瞎做的深色模式真是惨不忍睹,对比度低得要死,更别提色弱/色盲模式,甚至支持多种色弱/盲模式。Pragtical 默认配色比 monokai 和 github-dark-dimmed 都好看,就不折腾了
  • 100M/1G 文件测试算是很基本的要求,有的奇葩公司(比如 Facebook)能整出 10G 甚至 100G JSON 文件,为什么不用数据库?我也不造啊🤷 Linux 能用 pager,Windows 虽然有 vim/Gvim,但系统自带的 PowerShell 实在是丑,Windows Terminal 在有的环境又无法正常显示,一般这种情况我就上 hex viewer 了,简单粗暴
  • 便携版的需求应该很自然,毕竟文本编辑器满地都是,配置非常琐碎,不像流行的浏览器内核,一只手都数得过来,还能用 policy template 一劳永逸。尺寸要求就是针对 Electron,别和我说 UI 和开发难度,满地都是的软件不用 Electron/CEF 就不能做,说出来也没人相信。Pragtical 哪怕是 AppImage 也只有 5M 大小
  • 文件关联这点也是出于批量部署的考量 2,其实 pragtical 不支持,但其他方面都做得挺好,就放过了
  • 冷启动速度,嗯,就是针对 Electron 的
    • 3s 的限制太过宽松,哪怕收紧到 1s 绝大多数编辑器也都符合要求。当然,绝大多数编辑器 3 都不能打开 10G JSON,也不能在 30s 内完全加载 1G JSON(内存 32G,系统内存占用 2G,管够),也可以说都不符合要求= =
    • npp 速度不慢,没想到 pragtical 还能更上一层楼。测试方法:AppTimer,检测窗口名称,启动 6 次,间隔 100ms4WM_CLOSE 方法关闭,取平均值
C:\tools\pragtical\pragtical.exe - 6 executions
0.1965
0.1853
0.1850
0.1975
0.1955
0.1774
C:\tools\npp\notepad++.exe - 6 executions
0.2159
0.2182
0.2019
0.2079
0.2005
0.2054

后记

写完感觉有点虎头蛇尾,anyway 就这样吧。之前没怎么接触 Lua,为数不多的经验就是 Pico-8 和 Godot 开发,但 Pico-8 是自己实现的 Lua,很多标准库不能用,而 Godot 的 LuaAPI 隐约记得不是官方支持,还是 GDScript 为主流。在 pragtical 的 Plugin Manager 看很多插件的源码都很简单,后面可能写几个插件练练手,也算是回馈社区。


  1. 我多年来对于写作的观点是,文品与人品毫无关联,纯属后人牵强附会。引申出来的广泛观点也让我对各种撕逼/互锤、饭圈文化、影视剧封杀现象冷眼相看。凯恩斯有句话(虽然关于出处一直有各种看法):When the Facts Change, I Change My Mind. What Do You Do, Sir? 不能通过上帝视角看待问题,总归是有各种偏见和不客观的地方。乔布斯是个人渣,并不妨碍人们欣赏他做的产品。很多娱乐界的明星私生活混乱,何必封死现有文化产品的消费,不让产出新的产品即可。同理,小众文化圈地自萌,哪怕走向偏激都鲜有人管(当然这是有问题的),但搞殖民主义大肆扩展 攻城掠地( qīn lǜe lǐng tǔ ) 我就看不下去了。 ↩︎

  2. 为了方便装机,又搓了个 file-assoc-reg 脚本,根据 config.json 自动生成文件关联相关的注册表,这又是后话 ↩︎

  3. 如果这点是刚需,可以使用 EmEditor,免费版 足够应对类似场景。EE 据说能打开 TB 级别的文件,但真遇到这种情况,感觉可能文件系统先炸了,都没机会抢救= = ↩︎

  4. 这里间隔设置得太短了,后面根本不是冷启动,但反正怎么测都比 npp 快就没有修正。 ↩︎

Vinfall's Geekademy

Sine īrā et studiō