inshellisense Usage Guide
IDE style command line auto complete
Hereafter, inshellisense
will be abbreviated as is
Installation
# If Node.js is not installed yet, recommended to install via nvm
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
Don’t worry about the npm WARN EBADENGINE required: { node: '>=18' }
warning during installation - it’s just the Fig specification recommending Node 18+. inshellisense supports Node 16, but higher versions are recommended.
Node <21
Testing revealed that Node 21 installation fails because the dependency node-gyp doesn’t support version 21 yet.
Usage
# Enter completion session, press space after typing commands to trigger completion popup
is
# Use complete subcommand to get JSON completion results (not supported in rc-5 yet)
is complete "git l"
- If it doesn’t enter normally, check for any error messages
- If it enters without errors but doesn’t trigger completion popup, it’s usually due to PS1 prompt detection issues. Official troubleshooting documentation is not yet available.
- Personally encountered issues with
powerlevel10k/powerlevel9k
themes in ZSH. Current solution is to switch themes.
- Personally encountered issues with
Key Bindings
Currently, inshellisense does not support custom key bindings
Action | Keybinding |
---|---|
Accept Current Suggestion | tab |
View Next Suggestion | ↓ |
View Previous Suggestion | ↑ |
Dismiss Suggestions | esc |
Supported Shells
export enum Shell {
Bash = "bash",
Powershell = "powershell",
Pwsh = "pwsh",
Zsh = "zsh",
Fish = "fish",
Cmd = "cmd",
}
Project Overview
https://github.com/microsoft/inshellisense
Tech Stack
"@withfig/autocomplete": "^2.633.0", # Fig completion specification
"node-pty": "^1.0.0", # Fork pseudoterminals in Node.JS
"xterm-headless": "^5.3.0" # xterm.js headless terminal
Project Structure
├── shell
│ ├── bash-preexec.sh # for bash, extended function hook support
│ ├── 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 command definitions
│ ├── index.ts # entry point
│ ├── isterm # terminal emulator for is
│ ├── runtime # load specifications, get suggestions based on input
│ ├── tests # tests
│ ├── ui # terminal rendering and interaction (completion/uninstall prompts, etc.)
│ └── utils
Program Logic
process(<=>pty<=>xtermjs)
User enters command
is
to enter auto-completion modeLoad is configuration files
Determine shell type
- User can specify shell in
is
command, otherwise automatically determined from SHELL environment variable
- User can specify shell in
Initialize shell configuration
- For Zsh, add the following files to temporary directory:
- shellIntegration-env.zsh - shellIntegration-login.zsh - shellIntegration-profile.zsh - shellIntegration-rc.zsh
- For Bash, add
bash-preexec.sh
to user home directory
Load full Fig specification in is
Set
process.stdin.setRawMode
to true to ensure each keypress triggers data eventsExecute clear screen
node-pty opens a pseudo terminal, loads corresponding shell configuration, and creates xterm headless terminal client
process.stdin.on(“data”) listens for user input and continuously writes to pty
pty listens for input, displays echo data, and writes to xterm
xterm listens for written data
Calculate prompt start/end positions based on OSC in data. Command manager synchronizes terminal state
Completion manager calculates completions and determines whether to display them
Completion command module performs lexical analysis of commands, determines command context, and generates completions
Completion generation depends on 3 factors: input, cwd, shell
// input is current command: this.#term.getCommandState().commandText, process.cwd() is current path getSuggestions(input, process.cwd())
Key bindings are also handled during character listening, e.g., tab writes completed command:
process.stdout writes to terminal
Completion Calculation Logic
Analyze command text to determine token array
const lex = (command: string): CommandToken[] => { ... return tokens; };
First token in array is rootToken, used to fetch completion files
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; } };
Determine if last token in array is a path based on whether it contains /
Calculate completions starting from second token in array
Completion filtering
Suggestion Data Definition
export type Suggestion = {
name: string;
allNames: string[]; // command parameters in Fig can have multiple names, e.g., ["-p", "--paginate"] in git
description?: string;
icon: string; // emoji font
priority: number; // priority, descending order in is
insertValue?: string; // actual value inserted into terminal
};
Debugging
Directly execute
npm ru debug
, then enableAttach to Node Process ⌘
in VSCodeCheck logs at
~/.inshellisense/inshellisense.log
Final Thoughts
- Personally, I think the performance of this design approach for is is acceptable, but drawing completions directly in the terminal brings issues: if position calculation is incorrect, the cursor position can easily become misaligned
- Looking forward to is being officially released soon