# CodeLin TUI Raw Input Rust 改造方案（v0.1）

> 目标：用 Rust 重写 `/ffi/raw_input_{win,linux}.c`，保留现有 C ABI，统一跨平台行为，并为后续 TUI/CLI 交互提供可扩展的事件流接口，对标 Claude Code / Augment Code 的可维护性与可靠性。

---

## 1. 背景与约束

1. 现状
   - Windows 使用 Win32 API（`ReadConsoleInputW`）+ 手动编码。
   - Linux 使用 `termios` + `poll`，逻辑分散、重复。
   - CLI 通过 FFI（静态库/动态库）调用 `enterRaw` / `exitRaw` / `getRawUtf8` / `getByte`。
2. 痛点
   - C 代码缺少单元测试与现代依赖管理。
   - 扩展（如鼠标、组合键、IME）成本高。
   - 缺少统一事件模型，难以对接未来的 Rust/TUI 组件。
3. 约束
   - 暂不大改 Cangjie 代码，只替换底层实现。
   - 继续输出 C ABI（`extern "C"`）以保持 CLI 无缝使用。
   - 编译流程需兼容 `cjpm build`（Mac/Linux）与 Windows 交付。

---

## 2. Rust 生态调研

| 类别 | 候选库 | 亮点 | 风险/说明 |
|------|--------|------|-----------|
| 终端控制 | [`crossterm`](https://crates.io/crates/crossterm) | 跨平台（Windows Console + UNIX Termios），支持 RawMode、事件流、屏幕绘制。 | 依赖层较厚，但可仅使用 `crossterm::terminal` 与 `crossterm::event` 子模块。 |
| 终端行编辑 | [`rustyline`](https://crates.io/crates/rustyline) | 自带 raw mode + 输入编辑，可参考其 raw 部分；可选。 | 与我们需求重叠但较重，当前聚焦底层输入即可。 |
| 轻量终端 | [`termion`](https://crates.io/crates/termion) | 纯 UNIX，API 简洁，易读参考。 | Windows 支持弱，需要额外桥接。 |
| IO/事件 | [`mio`](https://crates.io/crates/mio) | 统一的非阻塞 IO 模型，可实现更灵活的超时/多路复用。 | 需要自建控制台驱动，初期可以先用 `crossterm` 封装。 |

结论：优先采用 `crossterm`（稳定、跨平台、事件模型成熟），必要时辅以：
- `windows` crate（Win32 特性，如原生 code page、快路径）。
- `libc` crate（UNIX termios 细节）。

---

## 3. 总体架构

```
ffi/
  rust_rawinput/
    Cargo.toml
    src/lib.rs          # 暴露 C ABI
    src/backend/mod.rs  # trait RawInputBackend
    src/backend/win.rs  # Windows 实现（crossterm + windows）
    src/backend/unix.rs # Linux/macOS 实现（crossterm + termios 调整）
    build.rs            # 生成 .a / .dylib / .dll
    include/raw_input.h # （可选）由 cbindgen 生成
```

- `RawInputBackend` trait：定义 `enter_raw`, `exit_raw`, `read_utf8`, `read_byte_with_timeout`。
- `RawInputService`：面向 C ABI 的单例，内部持有后端实例。
- `#[no_mangle] extern "C"` 函数：保持与现有 C 函数签名兼容（参数、返回值、错误码）。
- 构建：
  - `cargo build --release --target` 输出 `librust_rawinput.a` / `.dylib` / `.dll`.
  - `build.rs` + `cbindgen` 生成 `raw_input.h`，供 Cangjie 引用。
  - `ffi/` 目录同时保留老库，支持快速回滚。

---

## 4. 实施阶段（建议 3 Sprint）

### Phase 0：预研验证
1. 搭建 Rust crate，使用 `crossterm::terminal::enable_raw_mode/disable_raw_mode` 验证 RawMode 开关。
2. 用 `crossterm::event::read()` 映射方向键、Home/End、Delete，确保 UTF-8 输出一致（自带 `KeyEventKind`、`KeyCode`）。
3. 测量延迟、确认 Windows/Linux 下的 code page/UTF-8 行为。

### Phase 1：核心 API 替换
1. 定义 C ABI：
   ```rust
   #[no_mangle]
   pub extern "C" fn enterRaw() -> bool;
   #[no_mangle]
   pub extern "C" fn exitRaw();
   #[no_mangle]
   pub extern "C" fn getRawUtf8(buf: *mut u8, len: usize) -> i32;
   #[no_mangle]
   pub extern "C" fn getByte(timeout_ms: u32, key_code: *mut u16) -> i32;
   ```
2. `getRawUtf8`：
   - `match KeyEvent` → 映射到与现有 C 代码相同的 UTF-8 字节序列（包含 ESC、箭头、Ctrl 组合）。
   - 普通字符直接写入缓冲区，返回字节数。
3. `getByte`：
   - 利用 `crossterm::event::poll(Duration)` + `read()`，实现阻塞/超时。
   - 兼容 surrogate / 多字节：Rust 本身 UTF-8，直接转换为 `char` 再编码。
4. 编译生成静态库 + 头文件，替换 `librawinput.*`。

### Phase 2：兼容性 & 扩展
1. 行为一致性测试：
   - 编写 `cargo test` + 端到端 `cjpm build`（Mac/Linux），Windows 通过 GitHub Actions 或本地验证。
   - 对比旧/新库：输入序列 diff（可编写脚本录制键入）。
2. 性能 & 稳定性：
   - 监控 CPU 使用、并发情况下的 poll 行为。
   - 处理控制台重尺寸、Ctrl+C、SIGHUP 等信号。
3. 扩展点：
   - 提供新的 API（例如 `peek_event`, `flush_input`）备用，但先不在 C ABI 中暴露。

### Phase 3：落地与文档
1. 更新 `ffi/README.md`、`tui/README.md` 说明如何构建 Rust FFI。
2. 在 `cjpm build` 流程中新增 `cargo build` 步骤（或缓存构建产物）。
3. 在 `cangjie1.md` / `codelin15.md` 标记完成阶段。

---

## 5. 关键难点与对策

| 风险 | 描述 | 对策 |
|------|------|------|
| Windows 控制台 code page | 需要维持 UTF-8（65001）和原生行为一致。 | 使用 `crossterm` + `windows` crate 设置 CP，同时保留备选手动 `SetConsoleCP`。 |
| 性能/延迟 | Rust 层事件循环可能带来额外包装。 | `event::poll` + `event::read` 本身为阻塞调用，内部调用 Win32/termios；必要时直接绑定 Win32 API。 |
| C ABI 稳定 | 现有 Cangjie 代码依赖具体返回值。 | 通过 `bindgen`/`cbindgen` 确保签名一致，并保留详细的兼容测试。 |
| 构建系统 | 需要在 `cjpm` 环境中构建 Rust 库。 | 提供脚本（如 `scripts/build_rawinput.sh`）在 `cjpm` 前执行；CI 加入 `cargo` 缓存。 |

---

## 6. 交付物清单（写入 `tui1.md` 即本文）

1. `ffi/rust_rawinput/` Rust crate + 构建脚本。
2. `librawinput.a/.dylib/.dll` 全平台产物。
3. 自动化测试：
   - Rust 单测：键值映射、UTF-8 转码。
   - 集成测试：Cangjie CLI 在 Linux/macOS/Windows 下的 smoke test。
4. 文档：
   - 新 `tui1.md`（本文件）作为改造计划。
   - `ffi/README.md` 构建说明。
   - `cangjie1.md` / `codelin15.md` 状态更新（实施后执行）。

---

> 下一步：进入 Phase 0，创建 `ffi/rust_rawinput` 原型，验证 `crossterm` 行为并输出最小可行的 `enterRaw` / `exitRaw` / `getRawUtf8`。验证通过后再推进 Phase 1 的 C ABI 替换。 

