因为想找点适合 Emacs 的工作(指 C++/Rust 开发),我给自己没事找事:洛谷,顺便研究了求大数质数的方法(好吧,那道题暴力就能拿满分),Rust 用 static 和 const fn 的打表法,还有最好玩的:给 Emacs 写动态模块(也就是 ffi)。
早前知道有大佬写了分词插件,但用了 swift 和 MacOS 的库;我知道 WinRT 有分词 API(虽然我也不知道我怎么知道的),觉得可以照猫画虎,就开工了。
发现如下:
* 高级的 rs binding 新版本无法加载,又遇到依赖不遵守 semver,花了一晚上 rebase + bisect,定位、提交问题之后放弃
* 从 C 头文件自动生成的 Rust binding 还蛮好用,可变可变指针的类型也不难猜构造方法
* VSC 的 inlay 极丑,Emacs 能改字体大小的“富文本渲染器”优势就体现了
* Emacs 的性能奇差,某些常见功能不知道如何形容但就是比 vsc 麻烦,还有 code action 不知道是 eglot 不支持还是 emacs 就没有
* lto 对二进制体积影响极大,1M+ -> 270k
* 条件编译的宏不太好用,只适合重写函数定义,内联变量定义直接写方括号注解即可
* 不处理字符簇没有任何问题,elisp 那边会只针对汉字调用 helper 函数的
* 第一次领略了 Rusult 的用法:try_fold,可以打断的 fold,ts 这种情况只能老老实实写循环(
此处写了人生第一个 Ok 应当 panic 而 Error 应当返回的回调,方知 Either = Left a | Right b 的合理(
* ICU 坏事做尽,二进制体积大,字典不合格,分词结果荒唐,API 还是最麻烦的——竟然只能返回字节分界,我还得先切片再数数?不过跨平台的最优解就是它,用了它我们可以保证结果不差于浏览器(逃)
* Iterator 是惰性的,应该在作用块结束前消耗掉,否则就出悬垂指针啦。
* cppwinrt 的头文件有类型推导错误,不知为何编译不了
写完之后给原作者发了 issue(草,第一次用这个动词搭配),凌晨四点过没有消息,但看到点了赞同回应,又一刷新看见拿到一颗 star。一连串一个邮件都没有,大佬这么不喜欢骚扰别人。
动态模块 API 总体还算清晰,高级数据结构一律在 elisp 端构造并取得指针。不过我没写过 VSC 插件,就无从比较了。有人写了 MacOS 下分享多个文件、还有在 Finder 中打开选中的多个文件的 API,想象力丰富。
https://xenodium.com/native-emacsmacos-ux-integrations-via-swift-modules/Lisp 的链表的最后一项原来可以不是 nil 而是真的值。这是学 Haskell 时没有见过的。
我真希望未来有什么点子。毕竟我是老 ffi 仙人了,贡献从 CPython(ada)WASM(划掉,这个是计划)到 Emacs 不等。引入另一个世界的能力老有趣了。
因为 Emacs 30 预装了两个我最喜欢的包的改进版,也因为无聊,改了改 PKGBUILD 就自己编译去了,痛苦的“补丁 Hunk 应用失败”被我肮脏解决后,成功拿到 arch=native 并且 ELN AOT 正常的二进制。(话说为什么 ELN 不能 march=native 啊!这是带缓存的 JIT!)顺便看了看 control flow protection 和 control flow guard 编译参数。Rust gnullvm 总是编译不出 cfg 二进制,翻了许久找到一个合并的 pr,稳定版本是明年第一版,笑。GCC 那边没有大型浏览器之类需求,不知何时能支持。