外观
Emacs 社区日报 2026-09-25
约 5096 字大约 17 分钟
2026-09-25
自动整理自 Telegram 讨论组,每天更新。内容为 AI 摘要,仅作信息索引与回顾。
Emacs 中文讨论组
🎯 核心热点与专题探讨
专题一:Windows 输入法开发与 TSF 接口之痛
围绕 Windows 输入法开发展开了深入的讨论,核心矛盾集中在 TSF(Text Services Framework)接口的复杂性上。
- 群友
zdn_y分享了为 Emacs 修复 TSF 输入法感知问题的经历:微软官方的 TSF 示例有 6000+ 行代码,且用 C 语言实现会非常冗长(代码量需翻倍)。他尝试用 C++ 重写但被 Emacs 维护者 Eli 拒绝,最终只能修改函数文档向用户说明。 - 关键矛盾:TSF 接口众多,但若只实现部分接口,可能被视为“不完全支持”。然而
zdn_y认为只需实现查询输入法状态相关的接口即可,代码可以控制在 100 行以内。他实际修复了 TSF 输入法通知问题(小狼毫等 TSF 输入法按 Shift 切换状态时,Windows 任务栏托盘图标不更新),patch 只有 5 行,但定位 bug 花了数天。 zdn_y还指出 TSF 接口存在明显的代码不可复用性问题——每个 COM 接口都是独立定制,没有通用的复用模式。- 群友
κόσμος分享了他用 Zig/Rust 写的 TSF 最小 demo(300 行以内),认为微软示例过于复杂,不必实现全部接口。
专题二:算法教育的未来——形式化验证的回归
围绕 AI 时代是否还需要手写代码展开了激烈辩论,最终聚焦到算法教育的本质。
κόσμος提出一个观点:AI 时代下,大一学生能手写 1000 行代码已算多,且这个数字会逐年下降。部分群友表示赞同,认为关键在于“思考怎么拆分和形式化问题,制定和验证算法”,而非手写代码本身。- 由此引申出算法教育改革的设想:建议从图灵机、Hoare Logic 开始教起,把算法当作 abstract machine 来学习。
- 讨论聚焦到霍尔逻辑(Hoare Logic)的实际应用:找 loop invariants、证明 termination,避免 off-by-one 死循环等经典错误。有群友以亲身经历举例:手写 qsort 时因 off-by-one 导致死递归。
κόσμος推荐了 SIGPLAN 博客文章《Functional Algorithm Design, Part 0》,提出通过函数式算法设计将形式化验证转化为程序的等式推导,并表达了自己更倾向于《Formal Methods, Informally》里的做法。- 有群友吐槽《算法导论》讲红黑树时直接列出规则而没有动机说明,认为不如发明者原论文或冈崎的讲法。
🔑 关键概念与技术解析
TSF (Text Services Framework):Windows 的输入法框架,输入法需实现 TSF 接口才能与系统正常交互。接口众多且复杂,微软官方示例有 6000+ 行代码,涉及输入法状态查询、合成文本管理、文字位置追踪等。与之相对的是传统 IME 接口(约 70-80 行即可实现 demo),但功能有限。
COM (Component Object Model):Windows 组件间通信的二进制接口标准。Emacs 在 Windows 上使用 COM(如 w32dwrite.c),但不同场景的 COM 接口差异巨大,代码复用性差。每个 COM 接口都有独立的 ID(可在注册表查看),且除了基础接口外还有大量扩展接口。
Hoare Logic (霍尔逻辑):一种形式化验证方法,用于证明程序正确性。核心操作包括寻找循环不变式(loop invariants)和证明程序终止性(termination)。群友认为这是计算机本科生应该掌握的常识,但实际掌握的人很少。
pgtk 构建:Emacs 的纯 GTK 构建(Pure GTK),群友反馈其 childframe 关闭时比其他构建慢,是一个值得关注的性能差异点。
💎 碎片知识与金句拾遗
输入法与系统绑定:
zdn_y坚持使用系统输入法,因为 Rime 在 Windows 上会丢缓存,每次启动需重新编译数据卡 10-20 秒。他调侃:“如果去用 rime 就是背叛了我自己的劳动成果”。有群友建议配置 Rime 在打开 emacs.exe 后自动切换到英文模式。编辑器哲学:群友吐槽用 Emacs 会被视为不合群,“怕你写出来的代码自带 GPL 协议”。有人分享经历:领导问他是否用 vim,他回答 Emacs 后领导表示“没听说过”。但最终共识是“只是用个编辑器而已,都是选择问题,没有高低之分”。
Windows 11 的十宗罪(群友列举):任务栏不能自由放置、右键二级菜单、UI 重写、资源管理器拖拽功能被砍、AI 塞得到处都是、系统变卡、硬件要求高、套壳浏览器软件泛滥、砍掉磁铁、组件也改成了套壳浏览器。
Linux 的当下与未来:群友认为“现在是 linux 最好用的时期了,能玩游戏,桌面也没有短板”,但担忧“再过一段时间 linux 的 ai slop 多了,可能就得换 bsd 了”。
C 语言 Sequence Points:有群友推荐微软关于 C sequence points 的学习示例,“还能用来出怪题 😈”。
微软宽窄字符转换教程:被群友称赞“很实用不需要平台 api,用 c 库函数(wcstombs/mbstowcs)就可以”。
经典代码错误:手写 qsort 时 off-by-one 导致死递归,需要确保每次分割后问题规模严格减小。群友自嘲:“小心翼翼写半天,一跑崩”。
🛠️ 值得深入研究的点 (Follow-up)
TSF 输入法感知的极简实现:
zdn_y提出的思路——只实现查询输入法状态相关的接口(约 100 行代码),而不是全套 TSF。这个方向值得深入探索,特别是如何用 C 或 Zig 实现,以及如何处理“不完全支持”带来的兼容性问题。函数式算法设计:
κόσμος推荐的 SIGPLAN 博客文章《Functional Algorithm Design, Part 0》(https://blog.sigplan.org/2020/11/17/functional-algorithm-design-part-0/),主张通过等式推导把形式化验证融入编程过程,是算法教育改革的潜在方向。Emacs 的 TSF 问题追踪:Emacs 在 Windows 上对 TSF 输入法状态感知不完整的问题,微软社区已有反馈。目前只是修改了文档,未来若能提供完整的 TSF 支持,将提升 Windows 上的 Emacs 体验。
入群审核 Bot:群友分享了基于 Captcha 的入群审核 bot 实现(https://github.com/Zakkaus/gentoo-zh-verify-bot),支持私聊验证和手动审核 fallback,适合大型技术社区防 spam 的需求。
观点延伸
今天两个看似无关的话题——Windows TSF 输入法感知,以及「AI 时代还要不要手写算法」——其实是同一个问题的两面:当底层实现能被工具补全时,人应该守住哪一层契约。
「不完全支持等于完全不支持」是成本模型,不是技术事实
那位修 TSF 的群友被这句话卡住了:微软官方示例 6000+ 行、实现全部接口,而查询输入法状态理论上不到 100 行;另一位用 Zig/Rust 写的最小 demo 也不到 300 行。于是问题变成了「不够全会不会被当成完全不支持」。我的判断是:这句等式描述的是上游的维护成本与长期支持意愿(Eli 拒绝引入 C++),不是 API 的语义要求。客户端里真正会被系统调用的路径,比接口表短得多——从「修通知图标只花了 5 行 patch,定位花了好几天」这个比例就能看出来,成本和风险都集中在定位与验证,而不是实现规模。所以问题不该是「要不要写全」,而是先把最小接口子集跑通,用现象证明它够用。
形式化验证不是腹稿的替代品,而是给腹稿加一道外部检查
手写 qsort 因 off-by-one 死递归、必须保证「每次分割后问题规模严格减小」——这正是 termination 证明里的那个 measure 函数。这个例子确实说明:正确性并不显然,没有经过检验的腹稿不保证正确。但反过来也需要克制。一上手就教图灵机加霍尔逻辑、把算法当 abstract machine,代价是可能把「会写代码」替换成「会做题」,而 off-by-one 这类错误往往一跑测试就暴露了。更划算的中间态是:写之前用一两行写死循环不变式和规模递减的论证,写之后跑测试。不必立刻上升到定理证明器。
工具选择的「背叛感」值得警惕
有人因为 Rime 在 Windows 上丢缓存、每次启动编译数据卡十几秒,干脆继续用系统输入法,说改用 Rime 就是背叛自己的劳动成果。这个理由其实和编辑器无关,是沉没成本在替技术决策投票,和「用 Emacs 会被觉得不合群」属于同一类问题:把工具当身份。相比之下,「Linux 现在是最好用的时期,但 AI slop 多了可能就得换 BSD」反而是一种健康的可替换心态——工具可以换,配置和数据要能带走。
可继续实践的方向:若真要改善 Emacs 在 Windows 上的输入法体验,最小可验证路径是只实现 TSF 中查询输入法状态相关的接口,做一个 100 行以内的状态查询实现;先用独立小程序实测能取到哪些数据(输入法开关状态、合成文本、文本位置各能拿到多少),整理成对比表,再判断是否值得提交上游。先量化收益,再谈接口完整性。
Emacs 轻聊讨论组
🎯 核心热点与专题探讨
专题一:C vs C++ 语言设计理念的激烈辩论
这个凌晨时段的讨论是群内最深入的议题。由 simpc++(一个 C++ 语法高亮包)的维护问题引出,最终演变成了一场关于 C 与 C++ 语言哲学、类型安全、容器设计、代码生成能力(模板 vs 宏)的长时间辩论。
- 维护痛点:维护者吐槽 C++ 语法太复杂,导致
simpc++的纯正则高亮覆盖率只有约 60%,且存在大量不准确的着色。这引发了“着色多了就不 simple 了”与“不着色看不清楚”的矛盾。维护者最终选择“砍了 50% 的着色覆盖率”,回归简单。 - 类型安全与容器之争:一方认为 C++ 模板能提供编译期类型安全的代码生成(如
if constexpr),而 C 只能靠void*和宏,容易导致运行时才发现错误和 UB。另一方则坚持“类型安全没有那么重要”,并以 suckless 项目的代码为例,强调通过适当耦合、直接使用链表而非泛型容器,能极大简化问题。 - 签名与元组的分歧:关于
std::tuple是否是好设计,一方认为元组能避免为一次性函数写结构体,另一方则强调“名字和类型一样重要”,元组缺乏语义信息(如size_t到底代表长度还是索引)。 - 根本分歧:这最终归结为“代码生成能力是否是必需品”。C++ 支持者认为编译期操作(模板图灵完备)是组织复杂代码的利器;C 支持者则认为这种能力可通过宏或文本替换近似模拟,且许多场景根本不需要容器或类型安全,过度工程化反而增加负担。
专题二:AI 编程工具与 Copilot 的消费体验
白天的话题围绕 GitHub Copilot 展开,涉及 AI 编程助手的使用成本、模型选择和实际体验。
- 成本对比:有成员分享了 100 美元/月的 Copilot Max 订阅,一个下午消耗了 31% 额度,引起“奢侈”感叹。比较了 Opus 5.5 与 Fable 的消耗:Fable 消耗是 Opus 的 2 倍多。
- 思维链价值:Opus 5.5 被评价为“思维链超长,思考过程非常靠谱”,甚至能对架构问题进行长时间(一小时)的全面分析,这被视为 Copilot 相对官方订阅的潜在优势。
- UI 偏好:部分成员表示喜欢 Copilot 的界面,并认为它与 Claude Code 很像。
专题三:浏览器 DOM 渲染性能瓶颈
凌晨开场提到“对话多了,电脑都变卡”,随后被关联到 AI 工具调用返回大量信息时 DOM 渲染的巨大开销。有成员指出浏览器 DOM 渲染代价大,并建议使用客户端 ChatGPT 而非网页版来规避此问题。这反映了 AI 工具交互设计中的一个真实性能痛点。
🔑 关键概念与技术解析
simpcpp-mode:一个基于纯正则表达式对 C++ 代码进行语法高亮的 Emacs 包。由于 C++ 语法复杂,纯正则无法做到 100% 准确着色,维护者选择降低覆盖率(砍掉 50%)以换取维护的简单性,并计划利用clang-format处理宏对齐等问题。std::tuple/std::pair:C++ 中用于返回多个值的类型,无需单独定义结构体。争论点在于其缺少语义字段名,与 C 风格的显式参数/结构体相比,信息完整性有争议。if constexpr:C++17 引入的编译期条件判断,可根据模板参数类型在编译时选择不同实现分支,是模板特化的一个具体体现。mbsync:一个用于 IMAP 同步的邮件同步工具,支持 Gmail 双向同步。有成员遇到与 163 邮箱的兼容性问题,也有人因 Gmail 强制 OAuth 而自行实现 API 同步器。CLM(Contrastive-LM):一种快速决策的 System One 模型,通过双向 InfoNCE 损失学习状态与正确动作的对应关系,使 Agent 无需为每个任务单独微调即可进行快速判断、排序和路由。CLM-8B 使用了 6000 万问答、3000 万难负样本和 100 万 Agent 轨迹训练。org-ellipsis:Emacs org-mode 中用于折叠/展开部分的省略号(三个点)的字体样式。有成员遇到折叠时抖动的问题,解决方案包括调整该 face 的字体大小或更换字体,但需注意 outline-mode 可能覆盖此设置。
💎 碎片知识与金句拾遗
- 对 C++ 的吐槽:“人生苦短,我用 Python。说的就是 C++”——表达对 C++ 复杂度的无奈。
- 对库代码可读性的观察:提到 GNU libstdc++、MSVC STL 和微软 WinRT 的代码“太机器了,怀疑都是脚本生成的”,并认为 TypeScript 中类似类型运算代码也是“糟粕”。
- suckless 的启示:“你看 suckless 写了 dwm, st, 还有一些乱七八糟的软件,但是他的代码都很简单。” 强调代码可以选择简单,工程选择也可以。
- C 风格 API 示例:
uint8_t *find_res (const char *uri, size_t *len)和char *parse_json (const char *json, size_t *len, json_err *err)被视为显式签名的代表,但也被批评为“这种 api 也是我讨厌写的”。 - 关于类型与逻辑:“类型全对可以逻辑错,逻辑全对可以类型错”,强调两者缺失的等价性。
- AI 使用建议:“用客户端的 ChatGPT 就好了,不会有网页这个 Dom 渲染的问题”——解决 AI 对话卡顿的一个实用建议。
- 有趣的个人观察:一位有城堡的富哥 (zevlg) 因热爱 Emacs 而天天为社区贡献代码,“多么健康的爱好,打猎,郊游,玩 emacs”。有人预测 neo 将是下一个这样的“城堡富哥”。
- AI slop 问题:“现在的 AI slop 太多了,信息质量严重降低。看个源代码,都tm是递归生成的,看不明白”——对 AI 生成代码/内容泛滥的抱怨。
- 邮件同步实践:有人直言“不同步”,有人推荐 mbsync,也有人因 Gmail OAuth 自己“糊了一个用 google api 的”同步器。
🛠️ 值得深入研究的点 (Follow-up)
simpcpp-mode的简化思路:仓库链接 (https://github.com/zHaOdANiuu/simpcpp-mode) 值得关注,其“降低覆盖率以简化维护”的取舍哲学,以及如何用正则处理宏对齐
观点延伸
中心判断:今天最长的两条线——凌晨的 C 与 C++ 之辩、白天的 Copilot 使用体验——一个聊语言,一个聊工具,底层却是同一道题:「能做到」和「被需要」之间那段路,大多数争论都倒在这里。
一、能力证明与必要性证明,是两场不同的辩论
两个小时没辩出结果,不是水平问题,是双方在回答不同的问题。一边反复给的是能力证明——模板图灵完备、if constexpr 按类型特化实现;另一边在等必要性证明——"我为什么要这样做"。能力天然可证,必要性天然不可证,所以前者赢下每一回合,后者拖到散场。真正有价值的让步出现在后半段:一方承认"情况确定时,搞模板也没有必要",另一方也同意"代码可以选择不复杂"。这正是"极其正确但没有意义"能成立的位置:引入抽象的理由从来不是它正确,而是去掉它之后出现的具体损失。
二、size_t 缺的不是类型,是名字
tuple 之争里最锋利的一句是"缺名字和缺类型,都是缺"。同一个 size_t,可以是长度、可以是索引、也可以是调用次数;签名给不出答案,读的人就得翻实现。它被拿来和 void* 类比,不冤:接口的信息量不由类型系统单独决定,而由"只看签名能不能不做二次推断"决定。 由此得到一个便宜的自检:把函数签名单独抄出来,隔一天再读,还需要翻实现吗?需要,就是在把阅读成本转嫁给未来的自己。
三、思维链买得到信任,买不到正确
同一天里,"想了一小时、过程非常靠谱"和"代码是递归生成的、看不明白"两句同时出现。可观测的推理过程确实能建立信任,但产出量正在超出人的审查带宽。当"看它思考"变成消费体验,要警惕它替代验证,而不是补强验证。 工程用法很简单:思维链当信号可以,当证据不行;拿到结论后仍要落回可复现的那一步,哪怕只是问一句"哪里能推翻它"。
四、砍掉 50% 着色覆盖率,是一次工程决策
不是败给 C++,是败给"100% 正确着色的纯正则"这个目标;重定目标之后,工具重新可控。先定一个长期付得起的维护预算,再倒推功能边界,远比做完功能才发现养不起便宜。
可继续研究/实践的方向
写一份"必要性检验"三问,用在任何抽象上——容器、类型层、框架、Agent 的新特性:删掉它,代码会变成什么样?它解决的失败案例能复现吗?维护成本由谁付、付多久?先在自己手头一两个 C 项目上做实验:删掉自造的容器或泛型层,记录代码量变化、改动半径和实际 bug 数。用数据回答抽象是否必要,而不是用立场——这个实验,比再辩两个小时更能终结凌晨那场讨论。
说明:我做了字符统计校验(写入 /tmp/reflect_draft.md 并配 /tmp/count_reflect.py),但本次运行的工具调用额度在跑统计前用尽,所以上面这版是按保守估计收窄过的稿子(中文字数约 900,未超 1000);如需精确字数,可直接 python3 /tmp/count_reflect.py 复核。全文无裸 HTML 标签、无尖括号占位符,符合 VuePress 编译要求。
