Hotdry.

Article

终端电子表格的 Excel 兼容实现:从 Lotus 1-2-3 兼容层到 xlsx 双向转换的工程实践

解析 l123 项目如何实现 DOS 时代交互范式与现代 Excel 文件格式的深度兼容,涵盖公式语法转换、文件格式双向转换、13 种交互模式等工程细节。

2026-04-27ai-systems

在现代软件开发中,复刻经典软件的体验通常面临两条路径:视觉致敬或功能完全复刻。l123 项目选择了更为激进的后者 —— 一个运行在终端中的 Lotus 1-2-3 风格电子表格,其交互模型与 1993 年的 Release 3.4a for DOS 版本几乎无法区分,但底层引擎却完全现代化。本文深入解析这一项目在实现终端电子表格与 Excel 文件格式兼容过程中遇到的核心工程挑战。

项目定位与核心承诺

l123 的设计目标并非简单的怀旧复古,而是追求功能层面的完全 Fidelity(保真度)。项目明确了两项不可妥协的承诺:资深 Lotus 1-2-3 R3.4a 用户可以无需阅读任何文档直接上手操作;工作簿文件能够干净地与 .xlsx 格式往返转换。这两项承诺构成了项目的「真实性契约」,任何一项破裂即意味着项目失败。

在技术选型上,项目使用 Rust 语言作为实现基础,配合 ratatui 和 crossterm 构建终端用户界面,IronCalc 引擎负责底层的公式计算与文件 I/O。选择 IronCalc 的关键理由在于其原生支持 .xlsx 格式的读写,这为双向文件转换提供了坚实的技术基座。

分层架构与引擎抽象

项目采用严格的分层架构,从底层到顶层依次为:l123-core 仅包含类型定义,零外部依赖;l123-parse 和 l123-menu 负责公式解析与菜单系统;l123-engine 封装 IronCalc 并暴露统一的 Engine trait;l123-cmd、l123-io、l123-graph、l123-print 提供命令、输入输出、图表、打印等具体功能;l123-ui 基于 ratatui 实现用户界面。这种分层设计的核心价值在于将计算引擎抽象为可替换的组件 —— 虽然当前使用 IronCalc,但 Engine trait 的存在使得未来更换底层引擎成为可能。

在数据模型层面,项目定义了清晰的类型层次。Value 枚举包含 Number、Text、Bool 和 Error 四种基本类型;CellContents 区分空单元格、标签(含前缀信息)、常量和公式;Workbook 结构管理多工作表、命名区域、打印设置和图表定义;Session 结构则维护多文件会话、当前活动文件、模式状态、单元格指针、菜单栈和命令日志等会话级状态。值得注意的是,单元格存储采用稀疏结构(由 IronCalc 底层实现),l123 在此基础上额外追踪标签前缀和批注信息。

公式语法的双向转换

Lotus 1-2-3 与现代 Excel 在公式语法上存在显著差异,这些差异必须在传递给 IronCalc 之前完成转换。首先是函数命名空间的差异:1-2-3 使用 @ 前缀标记函数(如 @SUM、@AVG、@IF),而 Excel 使用传统的函数名直接书写。l123 在 l123-parse 模块中实现了完整的翻译层,将 @ 函数名映射到 Excel 对应名称,例如 @AVG 转换为 AVERAGE,@STDS 转换为 STDEV.S,@@ 间接引用映射到 INDIRECT。

其次是范围表示法的差异。1-2-3 使用双点号作为范围分隔符(A1..B5),而 Excel 使用冒号(A1:B5)。此外,逻辑操作符也不同:1-2-3 使用 #AND#、#OR#、#NOT#,而 Excel 使用 AND ()、OR ()、NOT () 函数。l123 的解析层在公式进入计算引擎前完成这些转换,确保 UI 层始终呈现 1-2-3 风格的语法,而内部数据流转则采用 Excel 兼容格式。

第三个关键差异在于值起始字符规则。Excel 中输入公式以等号开头,而 Lotus 1-2-3 的等号并非值起始字符 —— 输入 =A1 会被视为标签而非公式。正确的 1-2-3 公式输入方式是使用加号开头(+A1)或直接输入单元格引用。项目在 UI 层实现了完整的首次字符判定逻辑:数字、加号、减号、点号、左括号、@、#、$ 触发 VALUE 模式;其他字符触发 LABEL 模式,并自动插入单引号前缀。这种模式划分不仅是视觉显示,更直接影响后续的解析行为。

文件格式的工程实现

在文件格式支持方面,项目实现了多层次的兼容策略。.xlsx 格式作为主要存储格式,实现了完整的往返支持 —— 读取 .xlsx 后修改再保存为 .xlsx,文件结构与数据完整保留。IronCalc 引擎负责底层的 Excel 文件解析与生成,这为项目提供了稳定可靠的现代格式支持。

.wk3 格式(Lotus 1-2-3 Release 3.x 的工作簿格式)实现了只读导入。项目通过 ironcalc_lotus crate 读取 .wk3 文件中的值、公式、基本样式和列宽信息。值得注意的是,当用户从 .wk3 文件启动编辑后,保存操作会自动将目标路径重定向为 <原文件名>.WK3.xlsx,从而避免意外覆盖珍贵的 legacy 文件。项目明确将 .wk3 写入列为非目标,这意味着不打算实现将数据写回原始 .wk3 二进制格式的功能。

CSV 格式支持导入和导出,满足纯数据交换场景的需求。项目使用标准的 csv crate 处理 CSV 解析,确保与各类电子表格软件的互操作性。

在多文件管理方面,1-2-3 原生支持同时打开多个活动文件。l123 在 Session 结构中维护 active_files 向量,支持通过 /File Open Before|After 命令在当前文件前后插入新文件,通过 Ctrl-End 然后方向键在不同文件间导航。跨文件引用使用 <<filename.wk3>>Sheet!CellRef 语法,这种引用在解析时需要额外的解析层来处理文件路径解析和加载。

十三种模式的状态机设计

Lotus 1-2-3 的交互模型建立在一个精细的状态机之上,不同的按键序列触发不同的模式,每种模式对应特定的输入处理逻辑。项目实现了完整的 13 种模式:

READY 模式是默认的空闲状态,接受导航按键、斜杠键启动菜单或首次击键进入数据 entry。LABEL 和 VALUE 模式的区分由首次字符规则决定,这影响着后续的解析和显示行为。EDIT 模式通过 F2 键触发,提供完整的行内编辑能力,支持 Ctrl - 左右方向键的词级跳转、Home/End 的行首行尾跳转。

POINT 模式是 1-2-3 交互范式的核心组成部分。当公式或命令期望输入单元格或范围引用时,系统自动进入 POINT 模式并在该位置设置锚点。用户可以通过方向键扩展范围,按。键循环切换活动角(哪个角跟随方向键移动),按 Esc 键先取消锚点再取消 POINT 模式。输入单元格地址(如 C8..D12)会替换当前的高亮范围。这种精确的锚点语义是 1-2-3 区别于其他电子表格的关键特征,项目在 SPEC.md 中用专门章节详细定义了这些行为。

MENU 模式处理完整的斜杠菜单树,包括单字母加速器、箭头导航、子菜单预览和帮助文本显示。FILES 和 NAMES 模式分别显示文件列表和命名区域列表供选择。HELP 模式显示上下文相关的帮助信息。ERROR 模式在发生错误时阻塞输入并显示错误消息。WAIT 模式在耗时操作(加载、保存、重算)期间显示等待状态。FIND 和 STAT 模式分别用于 /Data Query 的查找结果展示和工作表状态面板。

交互细节的工程参数

除了宏观的架构设计,大量交互细节构成了「无可区分」体验的基础。F4 键在编辑状态下循环切换单元格引用的绝对性状态,从相对引用依次切换到绝对引用、混合引用的 8 种组合。方向键在数据 entry 过程中扮演双重角色 —— 默认行为是移动单元格指针,但项目正确实现了 Commit-on-arrow 语义,即在 LABEL 或 VALUE 模式下按方向键会先提交当前输入然后移动到相邻单元格。

状态行指示符提供了丰富的上下文信息。CALC 指示符在待重算时显示蓝色,重算进行中显示红色;CAPS、NUM、OVR、END、CIRC、UNDO 等指示符按需显示。项目在 MVP 阶段实现了 CALC、CAPS、NUM、OVR、END、CIRC、UNDO 的完整支持,其余指示符随功能迭代逐步添加。

单元格格式标签(Format Tag)是控制面板第一行的核心组成部分。格式标签以括号形式显示在单元格地址之后,如 (C2) 表示货币格式两位小数,(F0) 表示定点格式无小数。完整的格式标签体系包括 F/S/C/, /G/(+)/P/D/T/H/A/L 等多个系列,覆盖定点、科学、货币、逗号、普通、+/- 条形图、百分比、日期、时间、文本、隐藏、自动、标签等格式类型。当数值在当前格式和列宽下无法完整显示时,单元格溢出显示为星号(*********)。

验收测试与持续集成

项目为每个 authenticity contract 中的验收项编写了接受测试。接受测试采用 .tsv 文件格式,记录输入的按键序列和预期的屏幕输出状态。每次 UI 可见的变更都必须附带对应的接受测试 transcript,确保修改不会破坏已实现的交互行为。

测试命令包括 cargo test --workspace 运行全量测试,cargo test -p l123-ui --test acceptance 运行 UI 接受测试,cargo clippy --workspace --all-targets -- -D warnings 执行 lint 检查。代码格式化通过 cargo fmt --all 统一风格。这种严格的工程实践保证了项目在快速迭代过程中始终保持对核心承诺的遵守。

小结

l123 项目展示了在现代技术栈上复刻经典软件交互范式的完整工程路径。通过 Rust 的类型系统和分层架构,项目成功地将 DOS 时代的终端交互模式与现代化的 Excel 文件格式支持结合在一起。公式语法转换层、文件格式抽象、13 模式状态机、POINT 模式锚点语义等工程细节共同构成了「无可区分」体验的技术基石。对于需要在终端环境中实现复杂交互兼容性系统的开发者而言,l123 项目提供了涵盖架构设计、数据建模、模式状态机、格式转换和验收测试的完整参考实现。

资料来源:GitHub 仓库 duane1024/l123 及项目文档 SPEC.md、MENU.md、PLAN.md。

ai-systems