inshellisense使用说明
IDE style command line auto complete
以下inshellisense
简称为is
安装
# 如果还未安装node,推荐nvm方式先安装node
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 18
npm install -g @microsoft/inshellisense
npm install -g node-gyp
安装中出现的npm WARN EBADENGINE required: { node: '>=18' },
不用担心,只是Fig规范推荐的18以上。is是支持16的,但推荐高版本
node<21
测试发现node21安装报错,原因是依赖的node-gyp不支持21。
使用
# 进入补全会话,进入后输入命令按空格可以唤起补全弹窗
is
# complete子命令获取补全JSON结果,rc-5还不支持
is complete "git l"
- 如果没有正常进入,看下是否有报错
- 正常进入后没有报错但不会唤起补全弹窗,一般都是因为提示词PS1检测问题,目前官方没有提供排查文档。
- 个人遇到的场景是ZSH下的
powerlevel10k/powerlevel9k
会有问题,目前解决办法即更换主题
- 个人遇到的场景是ZSH下的
操作热键
目前inshellisense不支持自定义热键
Action | Keybinding |
---|---|
Accept Current Suggestion | tab |
View Next Suggestion | ↓ |
View Previous Suggestion | ↑ |
Dismiss Suggestions | esc |
支持Shell
export enum Shell {
Bash = "bash",
Powershell = "powershell",
Pwsh = "pwsh",
Zsh = "zsh",
Fish = "fish",
Cmd = "cmd",
}
项目说明
https://github.com/microsoft/inshellisense
技术栈
"@withfig/autocomplete": "^2.633.0", # Fig补全规范
"node-pty": "^1.0.0", # Fork pseudoterminals in Node.JS
"xterm-headless": "^5.3.0" # xterm.js无头终端
项目结构
├── shell
│ ├── bash-preexec.sh # for bash,拓展支持函数钩子
│ ├── shellIntegration-env.zsh # zsh
│ ├── shellIntegration-login.zsh
│ ├── shellIntegration-profile.zsh
│ ├── shellIntegration-rc.zsh
│ ├── shellIntegration.bash # bash
│ ├── shellIntegration.fish # fish
│ └── shellIntegration.ps1 # for windows Powershell/Pwsh
├── src
│ ├── commands # is等命令定义
│ ├── index.ts # 入口
│ ├── isterm # is下的终端模拟器
│ ├── runtime # 加载规范,根据输入获取suggestions
│ ├── tests # 测试
│ ├── ui # 终端绘制交互内容,比如补全/卸载提示等
│ └── utils
程序逻辑
process(<=>pty<=>xtermjs)
用户输入命令is,进入自动补全模式
加载is配置配置文件
确定Shell类型
is
命令中用户可以指定Shell否则is中自动根据SHELL环境变量确定
初始化Shell配置
- 如果是Zsh,补充以下文件到临时目录下
- shellIntegration-env.zsh - shellIntegration-login.zsh - shellIntegration-profile.zsh - shellIntegration-rc.zsh
- 如果是Bash,补充
bash-preexec.sh
到用户主目录
is中加载全量Fig规范
process.stdin.setRawMode
设置为true,确保每个按键字符都触发data事件执行清屏
node-pty开启一个伪终端,加载对应Shell配置,同时创建xterm无头终端客户端。
process.stdin.on(“data”)监听用户输入,之后不断写入pty
pty监听输入,然后显示回显数据,同时写入xterm中
xterm监听写入数据
根据数据中的OSC,计算提示词起止位置。命令管理器同步终端情况
补全管理器计算补全,确定是不是需要显示补全
补全命令模块做命令的词法分析,确定命令情况,之后生成补全
生成补全的依赖3点input,cwd,shell
// input为当前的命令,this.#term.getCommandState().commandText,process.cwd()为当前路径 getSuggestions(input, process.cwd())
字符监听时针对热键也会做对应的处理,比如tab则写入补全的命令:
process.stdout写入终端
补全计算逻辑
命令文本进行分析,确定token数组
const lex = (command: string): CommandToken[] => { ... return tokens; };
token数组第一个为rootToken,根据rootToken来获取补全文件
const loadSpec = async (cmd: CommandToken[]): Promise<Fig.Spec | undefined> => { const rootToken = cmd.at(0); if (!rootToken?.complete) { return; } if (loadedSpecs[rootToken.token]) { return loadedSpecs[rootToken.token]; } if (specSet[rootToken.token]) { const spec = (await import(specSet[rootToken.token])).default; loadedSpecs[rootToken.token] = spec; return spec; } };
token数组的最后一个Token根据是否包含/来确定是不是路径
token数组从第二个开始计算补全
补全筛选
Suggestion数据定义
export type Suggestion = {
name: string;
allNames: string[]; // fig下命令参数可以有多个name,比如git下的["-p", "--paginate"]
description?: string;
icon: string; // emoji font
priority: number; // 优先级,is中为降序
insertValue?: string; // 实际插入终端值
};
调试
直接执行
npm ru debug
,VSC下开启Attach to Node Process ⌘
~/.inshellisense/inshellisense.log
可以查看日志
写在最后
- 个人觉得is这种设计方案下速度还行,但直接在终端中绘制补全也就带来问题即:位置计算错误的话,光标很容易位置错
- 期待is早日发正式