Ito:用 Lua 写终端 UI,两个 Neovim 重度玩家搞出来的新库|Show HN

Hacker News 上这两天有个「Show HN」帖子有点意思:两个自称 Neovim 重度玩家的作者,发了个叫 Ito 的库,让开发者能用 Lua 来搭终端 UI。帖子 37 个赞、9 条评论,不算多高的热度,但评论区里围绕「这算不算地道的 Lua 写法」吵得还挺实在,值得拆一拆。

作者的原话是,他们喜欢「rice」终端和编辑器——就是那种把终端主题、配色、布局折腾到极致的行为艺术。折腾来折腾去,发现现有的 terminal harness 大多是 JavaScript 底层,比如 Pi。作者不是对 JS 有意见,只是觉得 Lua 更对味,而且「基座用 Rust 的话还能更快」。于是两个人就自己开搞了一个 Lua 写的终端 UI 库,核心很精简,所有内置抽象、provider 的定义方式、乃至整个「rice」过程,全都能在 Lua 里完成。

有个细节我觉得挺有诚意:作者说本想「照着 Ratatui 那套来」,但朋友不同意,非要做出「能用 Lua 构建 TUI」的东西。结果就是现在这个 Ito。为了让人能直接上手试,作者还写了一个自定义 canvas 实现(而不是通常的 terminal adaptor),导出成 wasm,做了个网页,你可以在浏览器里直接实验用 Lua 搭 UI。顺带还给「vibe coders」准备了一个 llms.txt。库在 github.com/uji-labs/ito,对应的 harness 在 github.com/uji-labs/uji。

真正引发讨论的,是评论区质疑「这代码不像 Lua」。有位评论者举了个例子:ui.Button "Button Text" { on_click = function() ... end }——利用 Lua 的「免括号调用」特性,会更简洁也更地道。另一位则说得更细,指出现在 ito.TextField(draft) 先建对象、再用 :label("Name")、:focused()、:on_submit(...) 这种链式方法调用去改它,读起来像是「一个习惯 Rust Builder 模式的人,把那套思路一字不差地翻译进 Lua」。他建议直接传一个 table 进去:ito.TextField(draft, { label = "Name", focused = true, ... }),之后要改再直接赋值字段就行。

作者自己回应得挺坦诚:他承认现在的设计确实是「更激进」的,并且已经挂了个 issue 讨论这个方向,还自嘲「maybe it's a bad idea :X」。同时他也坚持,自己是 Ratatui 那种「组合性」的粉丝,想把它搬到 Lua 上。这个点其实值得留意——Ratatui 是 Rust 生态里很成熟的 TUI 框架,把它的组合思路套到 Lua,自然会带出「语言习惯水土不服」的问题。这不是 Ito 一家的问题,但凡有人想把一个框架的哲学移植到另一种语言,多半都会撞上这堵墙。

评论区氛围整体是友好的,「declarative API 看起来很爽」「我会试试」这类声音不少,作者也回话说欢迎提 issue,目标是把它做成「适合 rice 的 harness」(还打了个字,把「right」打成了「rice」,挺可爱)。目前这还是个很早期的项目,作者自己也不避讳设计上有争议的地方。能不能真把 Lua 的 TUI 生态做起来,还不好说,但至少这两个人给出了一个能跑、能试、能让人在浏览器里折腾的入口。

如果你也是没事就把终端主题调到半夜、纠结配色到不想写代码的那种人,可以去 uji.sh/ito 看一眼,或者在浏览器里试试那套 wasm 版。至于「像不像地道 Lua」这个问题,留给评论区继续吵,反正作者已经主动开 issue 了。

相关链接:
- Ito 官网:https://uji.sh/ito/
- Ito 仓库:https://github.com/uji-labs/ito
- Uji harness 仓库:https://github.com/uji-labs/uji
- 关于 API 设计的讨论 issue:https://github.com/uji-labs/ito/issues/4