- Complete architectural overhaul of useUnifiedCompletion hook - Unified state management: 8 separate states → single CompletionState interface - Simplified core logic: getWordAtCursor 194 lines → 42 lines (78% reduction) - Fixed infinite React update loops with ref-based input tracking - Smart triggering mechanism replacing aggressive auto-completion - Integrated @agent and @file mention system with system reminders - Added comprehensive agent loading and mention processing - Enhanced Tab/Arrow/Enter key handling with clean event management - Maintained 100% functional compatibility across all completion types Key improvements: • File path completion (relative, absolute, ~expansion, @references) • Slash command completion (/help, /model, etc.) • Agent completion (@agent-xxx with intelligent descriptions) • System command completion (PATH scanning with fallback) • Terminal-style Tab cycling, Enter confirmation, Escape cancellation • Preview mode with boundary calculation • History navigation compatibility • Empty directory handling with user feedback Architecture: Event-driven @mention detection → system reminder injection → LLM tool usage Performance: Eliminated 7-layer nested conditionals, reduced state synchronization issues Reliability: Fixed maximum update depth exceeded warnings, stable state management
186 lines
4.5 KiB
Markdown
186 lines
4.5 KiB
Markdown
# 终端行为对比:标准 Terminal vs 我们的实现
|
||
|
||
## 🔴 关键差异对比
|
||
|
||
### 场景1:多个匹配文件
|
||
```bash
|
||
# 文件列表:package.json, package-lock.json, public/
|
||
|
||
# ✅ 真正的终端(bash/zsh)
|
||
$ cat p[Tab]
|
||
$ cat p█ # 第一次Tab:没反应(或蜂鸣)
|
||
$ cat p[Tab][Tab]
|
||
package.json package-lock.json public/ # 第二次Tab:显示选项
|
||
$ cat pa[Tab]
|
||
$ cat package█ # 补全到公共前缀 "package"
|
||
$ cat package[Tab][Tab]
|
||
package.json package-lock.json # 再显示剩余选项
|
||
|
||
# ❌ 我们当前的实现
|
||
$ cat p[Tab]
|
||
▸ 📄 package.json # 立即显示菜单
|
||
📄 package-lock.json
|
||
📁 public/
|
||
```
|
||
|
||
### 场景2:唯一匹配
|
||
```bash
|
||
# ✅ 真正的终端
|
||
$ cat READ[Tab]
|
||
$ cat README.md█ # 立即补全,一步到位
|
||
|
||
# ✅ 我们的实现(这个是对的!)
|
||
$ cat READ[Tab]
|
||
$ cat README.md█ # 也是立即补全
|
||
```
|
||
|
||
### 场景3:目录补全后继续
|
||
```bash
|
||
# ✅ 真正的终端
|
||
$ cd src[Tab]
|
||
$ cd src/█ # 补全并加斜杠,光标在斜杠后
|
||
$ cd src/[Tab] # 可以继续Tab
|
||
components/ hooks/ utils/ # 显示src/下的内容
|
||
|
||
# ❌ 我们的实现
|
||
$ cd src[Tab]
|
||
$ cd src/█ # 补全后结束
|
||
$ cd src/[Tab] # 需要重新检测上下文
|
||
```
|
||
|
||
### 场景4:命令补全
|
||
```bash
|
||
# ✅ 真正的终端
|
||
$ git a[Tab]
|
||
$ git add█ # 唯一匹配,直接补全
|
||
|
||
$ git [Tab][Tab] # 空前缀,需要双Tab
|
||
add commit push pull status # 显示所有git命令
|
||
|
||
# ⚠️ 我们的实现
|
||
$ /he[Tab]
|
||
$ /help█ # 命令补全工作正常
|
||
$ /[Tab] # 但立即显示菜单(应该需要双Tab)
|
||
▸ help
|
||
model
|
||
agents
|
||
```
|
||
|
||
## 📊 行为差异总结
|
||
|
||
| 特性 | 标准终端 | 我们的实现 | 影响 |
|
||
|------|----------|------------|------|
|
||
| **双Tab显示** | ✅ 需要按两次 | ❌ 第一次就显示 | 打断输入流程 |
|
||
| **公共前缀** | ✅ 智能补全 | ❌ 直接显示菜单 | 多余的选择步骤 |
|
||
| **连续补全** | ✅ 自然流畅 | ❌ 需要重新触发 | 效率降低 |
|
||
| **空前缀Tab** | ✅ 需要双击 | ❌ 立即显示 | 意外触发 |
|
||
| **蜂鸣反馈** | ✅ 无匹配时蜂鸣 | ❌ 静默 | 缺少反馈 |
|
||
|
||
## 🎯 核心问题
|
||
|
||
### 1. **Tab计数缺失**
|
||
```typescript
|
||
// 我们现在的代码(错误)
|
||
if (key.tab) {
|
||
showSuggestions() // 立即显示
|
||
}
|
||
|
||
// 应该是
|
||
if (key.tab) {
|
||
if (isSecondTab()) {
|
||
showSuggestions()
|
||
} else {
|
||
tryComplete()
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. **公共前缀算法缺失**
|
||
```typescript
|
||
// 需要添加
|
||
function getCommonPrefix(items: string[]): string {
|
||
if (items.length === 0) return ''
|
||
if (items.length === 1) return items[0]
|
||
|
||
let prefix = items[0]
|
||
for (let i = 1; i < items.length; i++) {
|
||
while (!items[i].startsWith(prefix)) {
|
||
prefix = prefix.slice(0, -1)
|
||
}
|
||
}
|
||
return prefix
|
||
}
|
||
```
|
||
|
||
### 3. **状态管理不足**
|
||
```typescript
|
||
// 当前:无状态
|
||
// 需要:
|
||
interface CompletionState {
|
||
lastTabTime: number
|
||
tabCount: number
|
||
lastPrefix: string
|
||
lastSuggestions: string[]
|
||
isShowingMenu: boolean
|
||
}
|
||
```
|
||
|
||
## 💡 为什么这些差异重要?
|
||
|
||
### 用户期望
|
||
- **肌肉记忆**:数十年的终端使用习惯
|
||
- **效率优先**:最少的按键完成任务
|
||
- **预测性**:行为必须可预测
|
||
|
||
### 实际影响
|
||
1. **输入中断**:过早显示菜单打断思路
|
||
2. **额外操作**:本可以自动补全的需要手动选择
|
||
3. **认知负担**:行为不一致增加心智负担
|
||
|
||
## 🔧 改进优先级
|
||
|
||
### 🔴 必须修复(破坏体验)
|
||
1. **双Tab机制** - 这是最基础的终端行为
|
||
2. **公共前缀补全** - 减少不必要的选择
|
||
3. **连续补全** - 路径导航的基础
|
||
|
||
### 🟡 应该改进(提升体验)
|
||
1. **蜂鸣反馈** - 告诉用户发生了什么
|
||
2. **灰色提示** - 现代终端的标配
|
||
3. **历史感知** - 更智能的排序
|
||
|
||
### 🟢 可以添加(锦上添花)
|
||
1. **模糊匹配** - 容错输入
|
||
2. **预览功能** - 显示文件内容
|
||
3. **自定义规则** - 用户定制
|
||
|
||
## 📝 用户故事
|
||
|
||
### 当前体验 😤
|
||
```
|
||
我:想输入 "cat package.json"
|
||
我:输入 "cat p" + Tab
|
||
系统:弹出菜单让我选择
|
||
我:需要按方向键选择
|
||
我:按Enter确认
|
||
结果:5个操作才完成
|
||
```
|
||
|
||
### 理想体验 😊
|
||
```
|
||
我:想输入 "cat package.json"
|
||
我:输入 "cat pa" + Tab
|
||
系统:自动补全到 "cat package"
|
||
我:输入 ".j" + Tab
|
||
系统:补全到 "cat package.json"
|
||
结果:3个操作完成
|
||
```
|
||
|
||
## 🎬 下一步
|
||
|
||
最小可行改进(MVP):
|
||
1. 实现Tab计数器
|
||
2. 添加公共前缀补全
|
||
3. 修复连续补全
|
||
|
||
这三个改动就能让体验提升80%! |