Welcome

个人博客

用 Scheme 给 Helix 写 Wakatime 插件

我日常用的编辑器是 Helix。我从来没深入用过 Vim,所以转到 Helix 并没有什么适应成本——反而更自然:Helix 开箱即用的体验很好,而且"先选择再操作"(select-then-act)的编辑模型比 Vim 的"先动词再名词"对我来说更直觉。 Helix 主线目前没有插件系统,这一直是社区里最大的痛点之一。不过 mattwparas 维护了一个 fork(steel-event-system 分支),集成了 Steel——一个嵌入式 Scheme 实现——作为插件运行时。Scheme 是 Lisp 的一个方言,而 Steel 是 Scheme 的一个方言,所以你大概能猜到写插件的体验是什么画风:很多括号。 我在 AUR 上打包了这个 fork:helix-steel-git,Arch 用户可以直接装。 其实我很早就知道这个 fork 的存在,但一直没有真正去用——原因很简单,我是真的怕括号。然而最近我彻底抛弃了 VSCode,全面转向 Helix 作为唯一的编辑器,随之而来的问题是:对插件的需求越来越强烈。而 Steel 生态目前能用的插件屈指可数,想要什么功能基本只能自己动手。于是我终于硬着头皮开始写 Scheme 了。 第一版:让 LLM 来 第一步是从社区已有的插件里复制了一套模板,建好 wakatime.hx 仓库,然后直接把需求丢给 Claude,让它生成第一版代码。毕竟我对 Lisp 一无所知,连基本语法都得现查。 Claude 确实给了我一个能跑的版本。问题是——LLM 生成的 Lisp 代码,人类读起来比手写的还要痛苦。比如获取编辑器版本号这段: (define (editor-version) (if *wakatime-editor-version* *wakatime-editor-version* (begin (let ([spawned (spawn-process (with-stdout-piped (command "hx" (list "--version"))))]) (if (Ok? spawned) (let ([output (wait->stdout (Ok->value spawned))]) (if (Ok? output) (let ([version (extract-version (Ok->value output))]) (set! *wakatime-editor-version* version) version) "unknown")) "unknown"))))) 嵌套的 if-let-if-let-if,层层剥洋葱式地处理 Ok? 结果——典型的"LLM 不知道这门语言的惯用写法,只好用最保守的方式堆逻辑"。能跑,但读起来让人头大。 ...

2026年5月3日 · 3 分钟

Oracle Cloud Ubuntu VM 从 ext4 原地转换到 Btrfs

记录一下把 Oracle Cloud 上的 Ubuntu 26.04 ARM VM 从 ext4 原地转换为 Btrfs 的过程。 WARNING: 本文操作涉及文件系统级别的原地转换,一旦出错数据将无法恢复。我的 VM 是一台空白机器,没有任何重要数据,所以才敢这么操作。如果你的机器上有任何你不想丢的东西,请务必先做好完整备份(Oracle Cloud 的 Boot Volume Backup、rsync 到远端、dd 镜像等),确认备份可恢复之后再动手。文件系统转换失败 + 没有备份 = 数据全灭,没有后悔药。 背景 Oracle Cloud 免费 ARM 实例,150G 磁盘,系统盘只有一个 ext4 根分区。想用上 Btrfs 的透明压缩、快照和子卷管理,但不想重装系统。 方案:initramfs 钩子 + btrfs-convert 核心思路:根分区在挂载状态下无法转换,所以利用 initramfs 的 local-premount 阶段——此时根分区尚未挂载——执行 btrfs-convert。 1. 安装 btrfs-progs sudo apt install btrfs-progs 2. 创建 initramfs 钩子 将 btrfs-convert 和 btrfs 二进制打包进 initramfs: # /etc/initramfs-tools/hooks/btrfs-convert #!/bin/sh set -e PREREQ="" prereqs() { echo "$PREREQ"; } case $1 in prereqs) prereqs; exit 0;; esac . /usr/share/initramfs-tools/hook-functions copy_exec /usr/bin/btrfs-convert /usr/bin copy_exec /usr/bin/btrfs /usr/bin 在 root 挂载前执行转换。注意 btrfs-convert 会生成新的 UUID,所以脚本里需要同时更新 GRUB 配置,否则重启后内核找不到 root 会掉进 initramfs shell: ...

2026年4月6日 · 3 分钟

我是怎么改善 Rust 编译体验的

Rust 编译慢、target/ 目录大,这是老生常谈了。这篇记录一下我目前在用的几个改善手段,以我的项目 ClewdR(394 个 crate 依赖的异步 Web 服务)为例。 环境:Rust 1.94.1,CachyOS (Arch-based),NVMe SSD,Btrfs。 rust-lld 链接是 Rust 编译的最后一步,也是传统上最慢的一步。GNU ld 在这里表现很差,特别是开了 LTO 的时候。 以前的做法是手动装 lld 或 mold,然后在 .cargo/config.toml 里配: [target.x86_64-unknown-linux-gnu] linker = "clang" rustflags = ["-C", "link-arg=-fuse-ld=lld"] 但从 Rust 1.85(2025-02-20)开始,rust-lld 在 x86_64-unknown-linux-gnu 上已经是默认链接器了,不需要任何配置: $ readelf -p .comment target/release/clewdr String dump of section '.comment': [ 1] Linker: LLD 21.1.8 [ 5f] rustc version 1.94.1 (e408947bf 2026-03-25) 升级 Rust 就行,免费午餐。 顺带一提,社区里还有两个值得关注的替代链接器: mold:以速度为卖点的链接器,在非 LTO 场景下通常比 lld 更快,不过对 LTO 的支持有限。 wild:一个用 Rust 写的实验性链接器,目标是成为最快的 Linux ELF 链接器,做了大量多线程优化。目前还在活跃开发中,有兴趣可以关注。 对于大多数人来说,默认的 rust-lld 已经够用了。 ...

2026年4月6日 · 2 分钟

用 cargo-zigbuild 交叉编译 Rust 项目到 FreeBSD

记录一下在 Linux (x86_64) 上用 cargo-zigbuild 交叉编译 Rust 项目到 FreeBSD x86_64 的踩坑过程。项目是一个 Discord bot,依赖了 sysinfo、tikv-jemallocator、sea-orm(SQLite) 等 crate。 背景 Zig 自带了多平台的 libc 和交叉编译工具链,cargo-zigbuild 利用 Zig 作为 linker 来实现 Rust 的交叉编译,通常比自己配置交叉工具链方便很多。但 FreeBSD 作为目标平台时会遇到一些特殊问题。 准备 # 安装 FreeBSD 目标 rustup target add x86_64-unknown-freebsd # 安装 cargo-zigbuild(如果还没有) cargo install cargo-zigbuild 问题一:缺少 FreeBSD 系统库 编译本身顺利通过,但链接阶段报错: error: unable to find dynamic system library 'geom' using strategy 'no_fallback' sysinfo crate 在 FreeBSD 上需要链接 libkvm、libprocstat、libgeom、libdevstat 等 FreeBSD base system 的库。Zig 的工具链只提供 libc,不包含这些系统库。 ...

2026年4月6日 · 4 分钟