# 调试 EOF 异常问题

## 问题现象

用户操作序列：
1. 启动程序 ✅
2. 输入"你是谁" ✅  
3. 看到 Thinking... ✅
4. 按 ESC 取消 ✅
5. 按 Ctrl+D → **异常** ❌

```
Exception: Read bytes 4294967295 != Expected bytes 1
at cli.io.Readline::readline(...)
```

## 关键发现

### 1. 修复已应用但仍有异常

- ✅ 源代码已修复（`if (len <= 0)`）
- ✅ 最新编译（2025-11-07 10:07）
- ✅ 空输入测试通过（`echo "" | cjpm run`）
- ❌ 取消后 Ctrl+D 仍然异常

### 2. 可能的原因

#### A. Terminal 状态问题

取消操作后，terminal 可能处于不稳定状态：
- ESC 键处理可能留下残留数据
- 输入缓冲区未正确清理
- Raw mode 状态异常

#### B. 竞态条件

取消操作涉及多线程：
- 主线程处理输入
- 响应线程被取消
- 可能存在竞态条件

#### C. 错误处理路径

可能还有其他代码路径调用读取但没有正确处理 EOF。

## 调试步骤

### 步骤 1: 验证编译版本

```bash
cd /Users/louloulin/Documents/linchong/cjproject/codelin
ls -lh target/release/bin/cli
md5 target/release/bin/cli
```

### 步骤 2: 添加调试日志

在 `raw_input_utils_unix.cj` 的 `rawGetRune()` 中添加日志：

```cangjie
static func rawGetRune(): Option<Rune> {
    var buffer: VArray<Byte, $4> = [0, 0, 0, 0]
    let len: IntNative = unsafe { getRawUtf8(inout buffer) }

    // 添加调试日志
    LogUtils.debug("rawGetRune: len = ${len}")

    if (len <= 0) {
        LogUtils.debug("rawGetRune: EOF or error, returning None")
        return None
    }

    // ... rest of code
}
```

### 步骤 3: 测试特定场景

```bash
# 场景 1: 简单 Ctrl+D
echo "" | cjpm run --name cli

# 场景 2: 输入后 Ctrl+D
echo "你好" | cjpm run --name cli

# 场景 3: 交互式测试
cjpm run --name cli
# 然后按 Ctrl+D
```

## 可能的解决方案

### 方案 1: 增强错误处理

在所有读取点添加 try-catch：

```cangjie
try {
    let rune = RawInputUtils.rawGetRune()
    // ... 处理
} catch (ex: Exception) {
    LogUtils.error("Error reading input: ${ex.message}")
    return None
}
```

### 方案 2: 清理输入缓冲区

在取消后清理输入缓冲区：

```cangjie
func clearInputBuffer(): Unit {
    // Flush any pending input
    while (RawInputUtils.rawGetRune() != None) {
        // Discard
    }
}
```

### 方案 3: 重置 Terminal 状态

在取消后重置 terminal：

```cangjie
func handleCancel(): Unit {
    // ... 现有代码
    
    // Reset terminal state
    InputUtils.exitRawMode()
    InputUtils.enterRawMode()
}
```

### 方案 4: 添加防护检查

在调用 `Rune.fromUtf8()` 前验证数据：

```cangjie
if (len > 0 && len <= 4) {
    let bytes = [buffer[0], buffer[1], buffer[2], buffer[3]]
    let (r, size) = Rune.fromUtf8(bytes, 0)
    // ... 处理
} else {
    return None
}
```

## 下一步行动

1. 添加详细的调试日志
2. 重新编译并测试
3. 收集日志输出
4. 根据日志确定问题根因
5. 实施正确的修复方案

## 临时解决方法

用户可以：
- 使用 `exit` 命令退出（而不是 Ctrl+D）
- 避免在取消后立即按 Ctrl+D
- 如遇异常，重新启动程序

