$ cat pa[Tab]
# 场景A:唯一匹配
$ cat package.json # 立即补全,光标在末尾
# 场景B:多个匹配
$ cat p[Tab]
# 无反应,需要按第二次Tab$ cat p[Tab][Tab]
package.json package-lock.json public/
$ cat p█ # 光标保持原位,显示所有可能选项$ cat pac[Tab]
$ cat package # 补全到公共前缀 "package"
$ cat package[Tab][Tab]
package.json package-lock.json# 自动添加斜杠
$ cd src[Tab]
$ cd src/ # 目录自动加斜杠
# 连续补全
$ cd src/[Tab]
components/ hooks/ utils/ # 显示目录内容
# 隐藏文件
$ ls .[Tab][Tab] # 需要以.开头才显示隐藏文件
.env .gitignore .npmrc# 命令后的第一个参数
$ git [Tab][Tab]
add commit push pull status # 显示git子命令
# 不同命令的不同行为
$ cd [Tab] # 只显示目录
$ cat [Tab] # 显示文件
$ chmod [Tab] # 显示可执行文件# 空格转义
$ cat My\ Documents/[Tab]
$ cat "My Documents/"[Tab]
# 通配符
$ cat *.js[Tab] # 展开所有.js文件
$ cat test*[Tab] # 展开所有test开头的文件$ cat p
$ cat package.json # 灰色显示建议
# 右箭头接受,Tab完成$ npm run
$ npm run dev # 基于历史的建议$ cat pjs[Tab]
$ cat package.json # 模糊匹配p...j...s$ cat existing.txt # 绿色,文件存在
$ cat missing.txt # 红色,文件不存在-
双击Tab显示所有选项
- 当前:第一次Tab就显示菜单
- 应该:第一次Tab尝试补全,第二次显示选项
-
公共前缀补全
- 当前:直接显示菜单
- 应该:先补全到公共前缀
-
无需显式触发
- 当前:必须Tab才触发
- 应该:输入时就准备好建议
-
连续路径补全
- 当前:补全后停止
- 应该:目录补全后继续等待下一次Tab
-
通配符展开
- 当前:不支持
- 应该:*.js展开为所有js文件
-
上下文检测
- 有基础实现,但不够智能
-
文件类型区分
- 有图标,但行为未区分
-
即时响应
- 已实现,但交互模式不对
用户输入: cat pa
内部状态: 准备suggestions ["package.json", "package-lock.json"]
显示: 无变化(或灰色提示)
用户操作: [Tab]
判断逻辑:
- 唯一匹配 → 直接补全
- 多个匹配但有公共前缀 → 补全到公共前缀
- 多个匹配无公共前缀 → 蜂鸣/无反应
用户操作: [Tab][Tab]
行为: 显示所有可能的补全选项
格式: 水平排列,按列对齐
继续输入: 缩小范围
方向键: 选择(可选)
Tab: 循环选择(可选)
Enter: 确认选择
- 双Tab机制 - 第一次补全,第二次显示
- 公共前缀 - 智能补全到最长公共前缀
- 连续补全 - 目录后继续补全
- 更智能的上下文 - 命令感知
- 灰色建议 - 输入时显示
- 历史感知 - 基于使用频率排序
- 模糊匹配 - 支持简写
- 路径缓存 - 提升性能
- 语法高亮 - 文件存在性
- 自定义补全 - 用户定义规则
- 异步加载 - 大目录优化
- 补全预览 - 显示文件内容预览
interface TabState {
lastTabTime: number
tabCount: number
lastContext: string
}
// 双击检测:300ms内的第二次Tab
if (Date.now() - lastTabTime < 300) {
tabCount++
} else {
tabCount = 1
}function findCommonPrefix(strings: string[]): string {
if (!strings.length) return ''
return strings.reduce((prefix, str) => {
while (!str.startsWith(prefix)) {
prefix = prefix.slice(0, -1)
}
return prefix
})
}function handleTab(suggestions: string[]): Action {
if (suggestions.length === 0) {
return 'beep'
}
if (suggestions.length === 1) {
return 'complete'
}
const prefix = findCommonPrefix(suggestions)
if (prefix.length > currentWord.length) {
return 'complete-to-prefix'
}
if (isSecondTab()) {
return 'show-menu'
}
return 'beep'
}- 双Tab机制
- 公共前缀补全
- 连续路径补全
- 更准确的上下文检测
- 实时灰色建议
- 历史/频率排序
- 模糊匹配支持
- 通配符展开
- 自定义补全规则
- 异步性能优化