[READ-ONLY] Mirror of https://github.com/bombshell-dev/docs. bomb.sh/docs
0

Configure Feed

Select the types of activity you want to include in your feed.

docs(tab): convert docs to a single-page layout (#22)

* chore(docs): update tab docs

* Update index.mdx

Signed-off-by: AmirHossein Sakhravi <amirhosseinpr184@gmail.com>

---------

Signed-off-by: AmirHossein Sakhravi <amirhosseinpr184@gmail.com>

authored by

AmirHossein Sakhravi and committed by
GitHub
(Oct 13, 2025, 2:39 PM +0330) 95f136be 6d73d212

+198 -2209
-402
src/content/docs/tab/api/core.mdx
··· 1 - --- 2 - title: Core API 3 - description: Complete API reference for the Tab core package 4 - --- 5 - 6 - This page provides the complete API reference for the Tab core package, including all classes, methods, types, and interfaces. 7 - 8 - ## Classes 9 - 10 - ### RootCommand 11 - 12 - The main class for managing command and option completions. This is the primary entry point for defining your CLI structure. 13 - 14 - ```ts 15 - import { RootCommand } from '@bomb.sh/tab'; 16 - 17 - const t = new RootCommand(); 18 - ``` 19 - 20 - #### Methods 21 - 22 - ##### command 23 - 24 - Adds a command with optional description and returns a Command instance for further configuration. 25 - 26 - **Parameters:** 27 - - `name` (string): The command name 28 - - `description` (string, optional): Command description 29 - 30 - **Returns:** Command - A Command instance for chaining 31 - 32 - **Example:** 33 - ```ts 34 - // Simple command 35 - const devCmd = t.command('dev', 'Start development server'); 36 - 37 - // Nested command 38 - const buildCmd = t.command('dev build', 'Build project'); 39 - ``` 40 - 41 - ##### option 42 - 43 - Adds a global option to the root command. 44 - 45 - **Parameters:** 46 - - `name` (string): The option name (e.g., 'config' for '--config') 47 - - `description` (string): Option description 48 - - `handler` (OptionHandler, optional): Function that provides completion suggestions 49 - - `alias` (string, optional): Short flag alias (e.g., 'c' for '--config') 50 - 51 - **Returns:** RootCommand - For method chaining 52 - 53 - **Example:** 54 - ```ts 55 - t.option('config', 'Use specified config file', function(complete) { 56 - complete('vite.config.ts', 'Vite config file'); 57 - complete('vite.config.js', 'Vite config file'); 58 - }, 'c'); 59 - ``` 60 - 61 - ##### argument 62 - 63 - Adds a positional argument to the root command. 64 - 65 - **Parameters:** 66 - - `name` (string): The argument name 67 - - `handler` (ArgumentHandler, optional): Function that provides completion suggestions 68 - - `variadic` (boolean, optional): Whether this is a variadic argument (default: false) 69 - 70 - **Returns:** RootCommand - For method chaining 71 - 72 - **Example:** 73 - ```ts 74 - t.argument('project', function(complete) { 75 - complete('my-app', 'My application'); 76 - complete('my-lib', 'My library'); 77 - }); 78 - ``` 79 - 80 - ##### parse 81 - 82 - Parses command line arguments and outputs completion suggestions to stdout. 83 - 84 - **Parameters:** 85 - - `args` (string[]): Command line arguments 86 - 87 - **Example:** 88 - ```ts 89 - const separatorIndex = process.argv.indexOf('--'); 90 - const completionArgs = separatorIndex !== -1 ? process.argv.slice(separatorIndex + 1) : []; 91 - t.parse(completionArgs); 92 - ``` 93 - 94 - ##### setup 95 - 96 - Generates shell completion scripts. 97 - 98 - **Parameters:** 99 - - `name` (string): CLI tool name 100 - - `executable` (string): Executable path for the CLI tool 101 - - `shell` (string): Target shell ('zsh', 'bash', 'fish', 'powershell') 102 - 103 - **Example:** 104 - ```ts 105 - t.setup('my-cli', process.execPath, 'zsh'); 106 - ``` 107 - 108 - ### Command 109 - 110 - Represents a command with its options and arguments. 111 - 112 - ```ts 113 - const cmd = t.command('dev', 'Start development server'); 114 - ``` 115 - 116 - #### Methods 117 - 118 - ##### option 119 - 120 - Adds an option to this command. 121 - 122 - **Parameters:** 123 - - `name` (string): The option name (e.g., 'p' for '--port') 124 - - `description` (string): Option description 125 - - `handler` (OptionHandler, optional): Function that provides completion suggestions 126 - - `alias` (string, optional): Short flag alias (e.g., 'p' for '--port') 127 - 128 - **Returns:** Command - For method chaining 129 - 130 - **Example:** 131 - ```ts 132 - cmd.option('port', 'Port number', function(complete) { 133 - complete('3000', 'Development port'); 134 - complete('8080', 'Production port'); 135 - }, 'p'); 136 - ``` 137 - 138 - ##### argument 139 - 140 - Adds a positional argument to this command. 141 - 142 - **Parameters:** 143 - - `name` (string): The argument name 144 - - `handler` (ArgumentHandler, optional): Function that provides completion suggestions 145 - - `variadic` (boolean, optional): Whether this is a variadic argument (default: false) 146 - 147 - **Returns:** Command - For method chaining 148 - 149 - **Example:** 150 - ```ts 151 - cmd.argument('entry', function(complete) { 152 - complete('src/main.ts', 'Main entry point'); 153 - complete('src/index.ts', 'Index entry point'); 154 - }); 155 - ``` 156 - 157 - ## Types 158 - 159 - ### OptionHandler 160 - 161 - Function type for option completion handlers. 162 - 163 - ```ts 164 - type OptionHandler = ( 165 - this: Option, 166 - complete: Complete, 167 - options: OptionsMap 168 - ) => void; 169 - ``` 170 - 171 - **Parameters:** 172 - - `this`: The Option instance 173 - - `complete`: Function to call with completion suggestions 174 - - `options`: Map of all options for this command 175 - 176 - **Example:** 177 - ```ts 178 - const handler: OptionHandler = function(complete) { 179 - complete('3000', 'Development port'); 180 - complete('8080', 'Production port'); 181 - }; 182 - ``` 183 - 184 - ### ArgumentHandler 185 - 186 - Function type for argument completion handlers. 187 - 188 - ```ts 189 - type ArgumentHandler = ( 190 - this: Argument, 191 - complete: Complete, 192 - options: OptionsMap 193 - ) => void; 194 - ``` 195 - 196 - **Parameters:** 197 - - `this`: The Argument instance 198 - - `complete`: Function to call with completion suggestions 199 - - `options`: Map of all options for this command 200 - 201 - **Example:** 202 - ```ts 203 - const handler: ArgumentHandler = function(complete) { 204 - complete('src/main.ts', 'Main entry point'); 205 - complete('src/index.ts', 'Index entry point'); 206 - }; 207 - ``` 208 - 209 - ### Complete 210 - 211 - Function type for providing completion suggestions. 212 - 213 - ```ts 214 - type Complete = (value: string, description: string) => void; 215 - ``` 216 - 217 - **Parameters:** 218 - - `value` (string): The completion value 219 - - `description` (string): Description of the completion 220 - 221 - **Example:** 222 - ```ts 223 - function(complete) { 224 - complete('3000', 'Development port'); 225 - complete('8080', 'Production port'); 226 - } 227 - ``` 228 - 229 - ### Completion 230 - 231 - Object representing a completion suggestion. 232 - 233 - ```ts 234 - type Completion = { 235 - value: string; 236 - description?: string; 237 - }; 238 - ``` 239 - 240 - **Properties:** 241 - - `value` (string): The completion value 242 - - `description` (string, optional): Description of the completion 243 - 244 - **Example:** 245 - ```ts 246 - const completion: Completion = { 247 - value: '3000', 248 - description: 'Development port' 249 - }; 250 - ``` 251 - 252 - ## Constants 253 - 254 - ### ShellCompDirective 255 - 256 - Bit map representing different behaviors the shell can be instructed to have. 257 - 258 - ```ts 259 - export const ShellCompDirective = { 260 - ShellCompDirectiveError: 1 << 0, 261 - ShellCompDirectiveNoSpace: 1 << 1, 262 - ShellCompDirectiveNoFileComp: 1 << 2, 263 - ShellCompDirectiveFilterFileExt: 1 << 3, 264 - ShellCompDirectiveFilterDirs: 1 << 4, 265 - ShellCompDirectiveKeepOrder: 1 << 5, 266 - shellCompDirectiveMaxValue: 1 << 6, 267 - ShellCompDirectiveDefault: 0, 268 - }; 269 - ``` 270 - 271 - ## Complete Example 272 - 273 - Here's a complete example showing all the core API features: 274 - 275 - ```ts 276 - #!/usr/bin/env node 277 - import { RootCommand } from '@bomb.sh/tab'; 278 - 279 - const t = new RootCommand(); 280 - 281 - // Add global options 282 - t.option('config', 'Use specified config file', function(complete) { 283 - complete('vite.config.ts', 'Vite config file'); 284 - complete('vite.config.js', 'Vite config file'); 285 - }, 'c'); 286 - 287 - t.option('mode', 'Set env mode', function(complete) { 288 - complete('development', 'Development mode'); 289 - complete('production', 'Production mode'); 290 - }, 'm'); 291 - 292 - // Add root command argument 293 - t.argument('project', function(complete) { 294 - complete('my-app', 'My application'); 295 - complete('my-lib', 'My library'); 296 - }); 297 - 298 - // Add commands with completions 299 - const devCmd = t.command('dev', 'Start development server'); 300 - devCmd.option('port', 'Port number', function(complete) { 301 - complete('3000', 'Development port'); 302 - complete('8080', 'Production port'); 303 - }, 'p'); 304 - 305 - devCmd.option('host', 'Hostname', function(complete) { 306 - complete('localhost', 'Localhost'); 307 - complete('0.0.0.0', 'All interfaces'); 308 - }, 'H'); 309 - 310 - devCmd.option('verbose', 'Enable verbose logging', 'v'); 311 - 312 - // Add nested commands 313 - t.command('dev build', 'Build project'); 314 - t.command('dev start', 'Start development server'); 315 - 316 - // Add command with arguments 317 - t.command('copy', 'Copy files') 318 - .argument('source', function(complete) { 319 - complete('src/', 'Source directory'); 320 - complete('dist/', 'Distribution directory'); 321 - }) 322 - .argument('destination', function(complete) { 323 - complete('build/', 'Build output'); 324 - complete('release/', 'Release directory'); 325 - }); 326 - 327 - // Add command with variadic arguments 328 - t.command('lint', 'Lint project') 329 - .argument('files', function(complete) { 330 - complete('main.ts', 'Main file'); 331 - complete('src/', 'Source directory'); 332 - }, true); // true = variadic argument 333 - 334 - // Handle completion requests 335 - if (process.argv[2] === 'complete') { 336 - const shell = process.argv[3]; 337 - if (shell && ['zsh', 'bash', 'fish', 'powershell'].includes(shell)) { 338 - t.setup('my-cli', process.execPath, shell); 339 - } else { 340 - // Parse completion arguments (everything after --) 341 - const separatorIndex = process.argv.indexOf('--'); 342 - const completionArgs = separatorIndex !== -1 ? process.argv.slice(separatorIndex + 1) : []; 343 - t.parse(completionArgs); 344 - } 345 - } else { 346 - // Regular CLI usage 347 - console.log('My CLI Tool'); 348 - console.log('Use "complete" command for shell completion'); 349 - } 350 - ``` 351 - 352 - ## Advanced Usage 353 - 354 - ### Context-Aware Completions 355 - 356 - Make your completions responsive to what the user is typing: 357 - 358 - ```ts 359 - devCmd.option('port', 'Port number', function(complete) { 360 - // Check if user is typing a specific port 361 - if (this.toComplete?.startsWith('30')) { 362 - complete('3000', 'Development port'); 363 - return; 364 - } 365 - 366 - complete('3000', 'Development port'); 367 - complete('8080', 'Production port'); 368 - complete('9000', 'Alternative port'); 369 - }, 'p'); 370 - ``` 371 - 372 - ### Dynamic Completions 373 - 374 - Load completions from external sources: 375 - 376 - ```ts 377 - devCmd.option('config', 'Config file', async function(complete) { 378 - try { 379 - const files = await fs.readdir('.'); 380 - const configFiles = files.filter(f => f.includes('config')); 381 - configFiles.forEach(file => complete(file, `Config file: ${file}`)); 382 - } catch (error) { 383 - // Fallback completions 384 - complete('vite.config.ts', 'Vite config file'); 385 - } 386 - }); 387 - ``` 388 - 389 - ### Boolean Options 390 - 391 - For boolean flags, you don't need a handler: 392 - 393 - ```ts 394 - devCmd.option('verbose', 'Enable verbose logging', 'v'); 395 - devCmd.option('quiet', 'Suppress output'); 396 - ``` 397 - 398 - ## Next Steps 399 - 400 - - Learn about [Framework Adapters](/docs/tab/guides/adapters/) for easier integration 401 - - Check out [Examples](/docs/tab/guides/examples/) for practical use cases 402 - - Explore [Best Practices](/docs/tab/guides/best-practices/) for effective implementations
-233
src/content/docs/tab/basics/getting-started.mdx
··· 1 - --- 2 - title: Getting Started 3 - description: Learn how to add shell autocompletions to your CLI with Tab 4 - --- 5 - 6 - import { Tabs, TabItem } from '@astrojs/starlight/components'; 7 - 8 - Tab provides shell autocompletions for JavaScript CLI tools, making your CLI feel as polished as native tools like git. This guide will walk you through adding autocompletions to your CLI tool. 9 - 10 - ## Installation 11 - 12 - Install Tab using your preferred package manager: 13 - 14 - <Tabs> 15 - <TabItem label="npm" icon="seti:npm"> 16 - ```bash 17 - npm install @bomb.sh/tab 18 - ``` 19 - </TabItem> 20 - <TabItem label="pnpm" icon="pnpm"> 21 - ```bash 22 - pnpm add @bomb.sh/tab 23 - ``` 24 - </TabItem> 25 - <TabItem label="Yarn" icon="seti:yarn"> 26 - ```bash 27 - yarn add @bomb.sh/tab 28 - ``` 29 - </TabItem> 30 - </Tabs> 31 - 32 - ## Basic Usage 33 - 34 - Here's a simple example of how to add autocompletions to your CLI: 35 - 36 - ```ts 37 - import { RootCommand } from '@bomb.sh/tab'; 38 - 39 - const t = new RootCommand(); 40 - 41 - // Add global options 42 - t.option('config', 'Use specified config file', function(complete) { 43 - complete('vite.config.ts', 'Vite config file'); 44 - complete('vite.config.js', 'Vite config file'); 45 - }, 'c'); 46 - 47 - // Add commands with completions 48 - const devCmd = t.command('dev', 'Start development server'); 49 - devCmd.option('port', 'Port number', function(complete) { 50 - complete('3000', 'Development port'); 51 - complete('8080', 'Production port'); 52 - }, 'p'); 53 - 54 - devCmd.option('host', 'Hostname', function(complete) { 55 - complete('localhost', 'Localhost'); 56 - complete('0.0.0.0', 'All interfaces'); 57 - }, 'H'); 58 - 59 - // Add positional arguments 60 - t.command('copy', 'Copy files') 61 - .argument('source', function(complete) { 62 - complete('src/', 'Source directory'); 63 - complete('dist/', 'Distribution directory'); 64 - }) 65 - .argument('destination', function(complete) { 66 - complete('build/', 'Build output'); 67 - complete('release/', 'Release directory'); 68 - }); 69 - 70 - // Handle completion requests 71 - if (process.argv[2] === 'complete') { 72 - const shell = process.argv[3]; 73 - if (shell && ['zsh', 'bash', 'fish', 'powershell'].includes(shell)) { 74 - t.setup('my-cli', process.execPath, shell); 75 - } else { 76 - // Parse completion arguments (everything after --) 77 - const separatorIndex = process.argv.indexOf('--'); 78 - const completionArgs = separatorIndex !== -1 ? process.argv.slice(separatorIndex + 1) : []; 79 - t.parse(completionArgs); 80 - } 81 - } else { 82 - // Regular CLI usage 83 - console.log('My CLI Tool'); 84 - console.log('Use "complete" command for shell completion'); 85 - } 86 - ``` 87 - 88 - ## Understanding the API 89 - 90 - ### RootCommand Class 91 - 92 - The `RootCommand` class is the main entry point for defining your CLI structure: 93 - 94 - ```ts 95 - const t = new RootCommand(); 96 - ``` 97 - 98 - ### Adding Commands 99 - 100 - Use the `command()` method to add commands with descriptions: 101 - 102 - ```ts 103 - const devCmd = t.command('dev', 'Start development server'); 104 - ``` 105 - 106 - ### Adding Options 107 - 108 - Add options to commands with completion handlers: 109 - 110 - ```ts 111 - devCmd.option('port', 'Port number', function(complete) { 112 - complete('3000', 'Development port'); 113 - complete('8080', 'Production port'); 114 - }, 'p'); // Short flag alias 115 - ``` 116 - 117 - ### Adding Arguments 118 - 119 - Add positional arguments with completion handlers: 120 - 121 - ```ts 122 - t.command('copy', 'Copy files') 123 - .argument('source', function(complete) { 124 - complete('src/', 'Source directory'); 125 - complete('dist/', 'Distribution directory'); 126 - }); 127 - ``` 128 - 129 - ### Variadic Arguments 130 - 131 - For commands that accept multiple arguments: 132 - 133 - ```ts 134 - t.command('lint', 'Lint project') 135 - .argument('files', function(complete) { 136 - complete('main.ts', 'Main file'); 137 - complete('src/', 'Source directory'); 138 - }, true); // true = variadic argument 139 - ``` 140 - 141 - ## Shell Setup 142 - 143 - After adding Tab to your CLI, users need to set up shell completion. Here are the recommended approaches for different shells: 144 - 145 - ### Zsh 146 - 147 - ```bash 148 - # Generate completion script 149 - my-cli complete zsh > ~/completion-for-my-cli.zsh 150 - 151 - # Add to your .zshrc 152 - echo 'source ~/completion-for-my-cli.zsh' >> ~/.zshrc 153 - ``` 154 - 155 - ### Bash 156 - 157 - ```bash 158 - # Generate completion script 159 - my-cli complete bash > ~/.bash_completion.d/my-cli 160 - 161 - # Add to your .bashrc 162 - echo 'source ~/.bash_completion.d/my-cli' >> ~/.bashrc 163 - ``` 164 - 165 - ### Fish 166 - 167 - ```bash 168 - # Generate completion script 169 - my-cli complete fish > ~/.config/fish/completions/my-cli.fish 170 - ``` 171 - 172 - ### PowerShell 173 - 174 - ```powershell 175 - # Generate completion script 176 - my-cli complete powershell > $PROFILE.CurrentUserAllHosts 177 - ``` 178 - 179 - ## Package Manager Integration 180 - 181 - Tab also provides a standalone CLI tool that enhances package manager completions with automatic CLI discovery: 182 - 183 - ### Installing the Tab CLI 184 - 185 - ```bash 186 - npm install -g @bomb.sh/tab 187 - ``` 188 - 189 - ### Setting Up Package Manager Completions 190 - 191 - ```bash 192 - # For pnpm 193 - tab pnpm zsh > ~/.zsh_completions/tab-pnpm.zsh 194 - echo 'source ~/.zsh_completions/tab-pnpm.zsh' >> ~/.zshrc 195 - 196 - # For npm 197 - tab npm zsh > ~/.zsh_completions/tab-npm.zsh 198 - echo 'source ~/.zsh_completions/tab-npm.zsh' >> ~/.zshrc 199 - 200 - # For yarn 201 - tab yarn zsh > ~/.zsh_completions/tab-yarn.zsh 202 - echo 'source ~/.zsh_completions/tab-yarn.zsh' >> ~/.zshrc 203 - 204 - # For bun 205 - tab bun zsh > ~/.zsh_completions/tab-bun.zsh 206 - echo 'source ~/.zsh_completions/tab-bun.zsh' >> ~/.zshrc 207 - ``` 208 - 209 - This provides enhanced completions for all CLI tools that support Tab completions, automatically detecting and providing completions for tools like Vite, TypeScript, and any other Tab-compatible CLI. 210 - 211 - ## How It Works 212 - 213 - Tab works by adding a `complete` command to your CLI that generates shell-specific completion scripts. When users type `my-cli complete zsh`, Tab generates a completion script that the shell can source. 214 - 215 - The completion script communicates with your CLI through the autocompletion server. When users press Tab, the shell calls your CLI with special arguments, and Tab returns the appropriate completions. 216 - 217 - ### Autocompletion Server 218 - 219 - Your CLI becomes an autocompletion server when you add Tab. The server responds to completion requests with suggestions and ends its output with `:{Number}` to indicate the number of completions. 220 - 221 - For example: 222 - ```bash 223 - my-cli complete -- --po 224 - --port Port number 225 - :0 226 - ``` 227 - 228 - ## Next Steps 229 - 230 - - Learn about [Framework Adapters](/docs/tab/guides/adapters/) for easier integration with CAC, Citty, and Commander.js 231 - - Explore [Package Manager Integration](/docs/tab/guides/package-managers/) for enhanced completions 232 - - Check out [Best Practices](/docs/tab/guides/best-practices/) for implementing effective autocompletions 233 - - Check out the [API Reference](/docs/tab/api/core/) for detailed documentation
-327
src/content/docs/tab/guides/adapters.mdx
··· 1 - --- 2 - title: Adapters 3 - description: Use Tab with popular CLI frameworks like CAC, Citty, and Commander.js 4 - --- 5 - 6 - Tab provides adapters for popular CLI frameworks to make integration even easier. These adapters automatically extract commands and options from your CLI framework and allow you to add custom completion handlers. 7 - 8 - ## CAC Adapter 9 - 10 - The CAC adapter automatically detects commands and options from your CAC instance and provides completion handlers for customization. 11 - 12 - ```ts 13 - import cac from 'cac'; 14 - import tab from '@bomb.sh/tab/cac'; 15 - 16 - const cli = cac('my-cli'); 17 - 18 - cli.command('dev', 'Start dev server').option('port <port>', 'Specify port'); 19 - cli.command('build', 'Build for production').option('mode <mode>', 'Build mode'); 20 - 21 - const completion = await tab(cli); 22 - 23 - // Get the dev command completion handler 24 - const devCommandCompletion = completion.commands.get('dev'); 25 - 26 - // Get and configure the port option completion handler 27 - const portOptionCompletion = devCommandCompletion.options.get('port'); 28 - portOptionCompletion.handler = (complete) => { 29 - complete('3000', 'Development port'); 30 - complete('8080', 'Production port'); 31 - }; 32 - 33 - // Configure build mode completions 34 - const buildCommandCompletion = completion.commands.get('build'); 35 - const modeOptionCompletion = buildCommandCompletion.options.get('mode'); 36 - modeOptionCompletion.handler = (complete) => { 37 - complete('development', 'Development build'); 38 - complete('production', 'Production build'); 39 - }; 40 - 41 - cli.parse(); 42 - ``` 43 - 44 - ### How the CAC Adapter Works 45 - 46 - The CAC adapter: 47 - 48 - 1. **Extracts Commands**: Automatically detects all commands defined with `cli.command()` 49 - 2. **Extracts Options**: Identifies options defined with `.option()` for each command 50 - 3. **Provides Handlers**: Gives you access to completion handlers for each command and option 51 - 4. **Maintains Structure**: Preserves the command hierarchy and option relationships 52 - 53 - ## Citty Adapter 54 - 55 - The Citty adapter works with Citty's command definitions and provides a similar interface for adding completions. 56 - 57 - ```ts 58 - import { defineCommand, createMain } from 'citty'; 59 - import tab from '@bomb.sh/tab/citty'; 60 - 61 - const main = defineCommand({ 62 - meta: { 63 - name: 'my-cli', 64 - description: 'My CLI tool', 65 - }, 66 - }); 67 - 68 - const devCommand = defineCommand({ 69 - meta: { 70 - name: 'dev', 71 - description: 'Start dev server', 72 - }, 73 - args: { 74 - port: { type: 'string', description: 'Specify port' }, 75 - host: { type: 'string', description: 'Specify host' }, 76 - }, 77 - }); 78 - 79 - const buildCommand = defineCommand({ 80 - meta: { 81 - name: 'build', 82 - description: 'Build for production', 83 - }, 84 - args: { 85 - mode: { type: 'string', description: 'Build mode' }, 86 - }, 87 - }); 88 - 89 - main.subCommands = { 90 - dev: devCommand, 91 - build: buildCommand, 92 - }; 93 - 94 - const completion = await tab(main); 95 - 96 - // Configure completions 97 - const devCommandCompletion = completion.commands.get('dev'); 98 - if (devCommandCompletion) { 99 - const portOptionCompletion = devCommandCompletion.options.get('port'); 100 - if (portOptionCompletion) { 101 - portOptionCompletion.handler = (complete) => { 102 - complete('3000', 'Development port'); 103 - complete('8080', 'Production port'); 104 - }; 105 - } 106 - } 107 - 108 - const cli = createMain(main); 109 - cli(); 110 - ``` 111 - 112 - ### How the Citty Adapter Works 113 - 114 - The Citty adapter: 115 - 116 - 1. **Processes Command Definitions**: Analyzes the command structure defined with `defineCommand()` 117 - 2. **Extracts Arguments**: Identifies arguments defined in the `args` object 118 - 3. **Handles Subcommands**: Recursively processes nested subcommands 119 - 4. **Provides Type Safety**: Leverages Citty's type system for better completion accuracy 120 - 121 - ## Commander Adapter 122 - 123 - The Commander adapter works with Commander.js and provides completion handlers for its command structure. 124 - 125 - ```ts 126 - import { Command } from 'commander'; 127 - import tab from '@bomb.sh/tab/commander'; 128 - 129 - const program = new Command(); 130 - 131 - program 132 - .name('my-cli') 133 - .description('My CLI tool'); 134 - 135 - program 136 - .command('dev') 137 - .description('Start development server') 138 - .option('-p, --port <port>', 'Specify port') 139 - .option('-h, --host <host>', 'Specify host'); 140 - 141 - program 142 - .command('build') 143 - .description('Build for production') 144 - .option('-m, --mode <mode>', 'Build mode'); 145 - 146 - const completion = tab(program); 147 - 148 - // Configure completions 149 - const devCommandCompletion = completion.commands.get('dev'); 150 - if (devCommandCompletion) { 151 - const portOptionCompletion = devCommandCompletion.options.get('port'); 152 - if (portOptionCompletion) { 153 - portOptionCompletion.handler = (complete) => { 154 - complete('3000', 'Development port'); 155 - complete('8080', 'Production port'); 156 - }; 157 - } 158 - } 159 - 160 - program.parse(); 161 - ``` 162 - 163 - ### How the Commander Adapter Works 164 - 165 - The Commander adapter: 166 - 167 - 1. **Processes Commands**: Analyzes the command structure defined with `program.command()` 168 - 2. **Extracts Options**: Identifies options defined with `.option()` 169 - 3. **Handles Aliases**: Automatically processes short and long option aliases 170 - 4. **Maintains Hierarchy**: Preserves the command hierarchy and option relationships 171 - 172 - ## Configuration 173 - 174 - All adapters support a configuration object to customize completion behavior: 175 - 176 - ```ts 177 - import { CompletionConfig } from '@bomb.sh/tab'; 178 - 179 - const config: CompletionConfig = { 180 - handler: async (previousArgs, toComplete, endsWithSpace) => { 181 - // Default handler for all commands 182 - return []; 183 - }, 184 - options: { 185 - port: { 186 - handler: async () => { 187 - return [ 188 - { value: '3000', description: 'Development port' }, 189 - { value: '8080', description: 'Production port' }, 190 - ]; 191 - }, 192 - }, 193 - }, 194 - subCommands: { 195 - dev: { 196 - handler: async () => { 197 - return [ 198 - { value: 'dev', description: 'Development mode' }, 199 - ]; 200 - }, 201 - options: { 202 - port: { 203 - handler: async () => { 204 - return [ 205 - { value: '3000', description: 'Dev port' }, 206 - ]; 207 - }, 208 - }, 209 - }, 210 - }, 211 - }, 212 - }; 213 - 214 - // Use with any adapter 215 - const completion = await tab(cli, config); 216 - ``` 217 - 218 - ## Best Practices 219 - 220 - ### 1. Error Handling 221 - 222 - Always handle errors gracefully in your completion handlers: 223 - 224 - ```ts 225 - portOptionCompletion.handler = async () => { 226 - try { 227 - // Expensive operation 228 - const results = await getPorts(); 229 - return results.map(port => ({ 230 - value: port.toString(), 231 - description: `Port ${port}` 232 - })); 233 - } catch (error) { 234 - // Return empty array instead of throwing 235 - console.error('Error in completion handler:', error); 236 - return []; 237 - } 238 - }; 239 - ``` 240 - 241 - ### 2. Context-Aware Completions 242 - 243 - Make your completions responsive to what the user is typing: 244 - 245 - ```ts 246 - portOptionCompletion.handler = async (previousArgs, toComplete, endsWithSpace) => { 247 - if (toComplete.startsWith('30')) { 248 - return [ 249 - { value: '3000', description: 'Development port' }, 250 - ]; 251 - } 252 - 253 - return [ 254 - { value: '3000', description: 'Development port' }, 255 - { value: '8080', description: 'Production port' }, 256 - { value: '9000', description: 'Alternative port' }, 257 - ]; 258 - }; 259 - ``` 260 - 261 - ### 3. Performance Optimization 262 - 263 - Cache expensive operations and limit results: 264 - 265 - ```ts 266 - let cachedPorts: Item[] | null = null; 267 - 268 - portOptionCompletion.handler = async () => { 269 - if (cachedPorts) { 270 - return cachedPorts; 271 - } 272 - 273 - const ports = await getAvailablePorts(); 274 - cachedPorts = ports.slice(0, 20).map(port => ({ 275 - value: port.toString(), 276 - description: `Port ${port}` 277 - })); 278 - 279 - return cachedPorts; 280 - }; 281 - ``` 282 - 283 - ### 4. Framework-Specific Considerations 284 - 285 - #### CAC 286 - 287 - - CAC automatically handles option parsing, so your completion handlers should focus on providing relevant suggestions 288 - - Use the option name as defined in your CAC command (e.g., `--port <port>` becomes `--port`) 289 - 290 - #### Citty 291 - 292 - - Citty's type system provides better type safety for completions 293 - - Arguments defined in the `args` object are automatically converted to options 294 - - Subcommands are processed recursively 295 - 296 - #### Commander.js 297 - 298 - - Commander.js supports both short and long option aliases 299 - - The adapter automatically handles both forms 300 - - Commands can have multiple aliases 301 - 302 - ## Integration with Shell Setup 303 - 304 - After setting up your adapter, you still need to handle shell completion setup: 305 - 306 - ```ts 307 - // Add this to your CLI entry point 308 - if (process.argv[2] === 'complete') { 309 - const shell = process.argv[3]; 310 - if (shell && ['zsh', 'bash', 'fish', 'powershell'].includes(shell)) { 311 - // Generate shell completion script 312 - const script = generateCompletionScript(shell, 'my-cli', process.execPath); 313 - console.log(script); 314 - } else { 315 - // Handle completion requests 316 - const separatorIndex = process.argv.indexOf('--'); 317 - const completionArgs = separatorIndex !== -1 ? process.argv.slice(separatorIndex + 1) : []; 318 - await completion.parse(completionArgs); 319 - } 320 - } 321 - ``` 322 - 323 - ## Next Steps 324 - 325 - - Learn about [Best Practices](/docs/tab/guides/best-practices/) for effective autocompletions 326 - - Check out [Examples](/docs/tab/guides/examples/) for practical use cases 327 - - Explore the [API Reference](/docs/tab/api/core/) for advanced usage
-485
src/content/docs/tab/guides/best-practices.mdx
··· 1 - --- 2 - title: Best Practices 3 - description: Learn best practices for implementing effective autocompletions with Tab 4 - --- 5 - 6 - This guide covers best practices for implementing effective autocompletions with Tab, including performance optimization, user experience considerations, and common patterns. 7 - 8 - ## General Best Practices 9 - 10 - ### 1. Provide Meaningful Descriptions 11 - 12 - Always include descriptive text for your completions to help users understand what each option does: 13 - 14 - ```ts 15 - // Good 16 - devCmd.option('port', 'Port number', function(complete) { 17 - complete('3000', 'Development port (default)'); 18 - complete('8080', 'Production port'); 19 - complete('9000', 'Alternative port'); 20 - }, 'p'); 21 - 22 - // Avoid 23 - devCmd.option('port', 'Port number', function(complete) { 24 - complete('3000', ''); 25 - complete('8080', ''); 26 - }, 'p'); 27 - ``` 28 - 29 - ### 2. Use Context-Aware Completions 30 - 31 - Make your completions responsive to what the user is typing: 32 - 33 - ```ts 34 - devCmd.option('mode', 'Build mode', function(complete) { 35 - // If user is typing 'dev', suggest development 36 - if (this.toComplete?.startsWith('dev')) { 37 - complete('development', 'Development mode'); 38 - return; 39 - } 40 - 41 - // If user is typing 'prod', suggest production 42 - if (this.toComplete?.startsWith('prod')) { 43 - complete('production', 'Production mode'); 44 - return; 45 - } 46 - 47 - // Default suggestions 48 - complete('development', 'Development mode'); 49 - complete('production', 'Production mode'); 50 - complete('staging', 'Staging mode'); 51 - }); 52 - ``` 53 - 54 - ### 3. Handle Errors Gracefully 55 - 56 - Always handle errors in your completion handlers to prevent crashes: 57 - 58 - ```ts 59 - devCmd.option('config', 'Config file', async function(complete) { 60 - try { 61 - const files = await fs.readdir('.'); 62 - const configFiles = files.filter(f => f.includes('config')); 63 - configFiles.forEach(file => complete(file, `Config file: ${file}`)); 64 - } catch (error) { 65 - // Provide fallback completions instead of failing 66 - complete('vite.config.ts', 'Vite config file'); 67 - complete('vite.config.js', 'Vite config file'); 68 - } 69 - }); 70 - ``` 71 - 72 - ### 4. Optimize Performance 73 - 74 - Cache expensive operations and limit results to maintain responsiveness: 75 - 76 - ```ts 77 - let cachedScripts: string[] | null = null; 78 - 79 - t.command('run', 'Run scripts') 80 - .argument('script', async function(complete) { 81 - if (cachedScripts) { 82 - cachedScripts.forEach(script => complete(script, `Run ${script} script`)); 83 - return; 84 - } 85 - 86 - try { 87 - const packageJson = JSON.parse(await fs.readFile('package.json', 'utf8')); 88 - const scripts = Object.keys(packageJson.scripts || {}); 89 - cachedScripts = scripts.slice(0, 20); // Limit to 20 scripts 90 - cachedScripts.forEach(script => complete(script, `Run ${script} script`)); 91 - } catch (error) { 92 - // Fallback completions 93 - complete('dev', 'Start development server'); 94 - complete('build', 'Build for production'); 95 - } 96 - }); 97 - ``` 98 - 99 - ## Command Structure Best Practices 100 - 101 - ### 1. Use Consistent Naming 102 - 103 - Follow consistent naming conventions for commands and options: 104 - 105 - ```ts 106 - // Good - consistent with common CLI patterns 107 - t.command('dev', 'Start development server'); 108 - t.command('build', 'Build for production'); 109 - t.command('deploy', 'Deploy application'); 110 - 111 - // Avoid - inconsistent naming 112 - t.command('start-dev', 'Start development server'); 113 - t.command('build-prod', 'Build for production'); 114 - t.command('deploy-app', 'Deploy application'); 115 - ``` 116 - 117 - ### 2. Group Related Commands 118 - 119 - Organize related commands logically: 120 - 121 - ```ts 122 - // Development commands 123 - t.command('dev', 'Start development server'); 124 - t.command('dev build', 'Build in development mode'); 125 - t.command('dev test', 'Run tests in development mode'); 126 - 127 - // Production commands 128 - t.command('build', 'Build for production'); 129 - t.command('deploy', 'Deploy to production'); 130 - t.command('deploy staging', 'Deploy to staging'); 131 - ``` 132 - 133 - ### 3. Use Short Aliases Sparingly 134 - 135 - Provide short aliases only for commonly used options: 136 - 137 - ```ts 138 - // Good - short aliases for common options 139 - devCmd.option('port', 'Port number', handler, 'p'); 140 - devCmd.option('host', 'Host address', handler, 'h'); 141 - devCmd.option('verbose', 'Enable verbose logging', 'v'); 142 - 143 - // Avoid - too many short aliases 144 - devCmd.option('config', 'Config file', handler, 'c'); 145 - devCmd.option('mode', 'Build mode', handler, 'm'); 146 - devCmd.option('output', 'Output directory', handler, 'o'); 147 - devCmd.option('source', 'Source directory', handler, 's'); 148 - ``` 149 - 150 - ## Option Design Best Practices 151 - 152 - ### 1. Use Boolean Flags Appropriately 153 - 154 - Use boolean flags for simple on/off options: 155 - 156 - ```ts 157 - // Good - boolean flags for simple options 158 - devCmd.option('verbose', 'Enable verbose logging', 'v'); 159 - devCmd.option('quiet', 'Suppress output', 'q'); 160 - devCmd.option('watch', 'Watch for changes', 'w'); 161 - 162 - // Good - value options for complex data 163 - devCmd.option('port', 'Port number', function(complete) { 164 - complete('3000', 'Development port'); 165 - complete('8080', 'Production port'); 166 - }, 'p'); 167 - ``` 168 - 169 - ### 2. Provide Sensible Defaults 170 - 171 - When possible, provide sensible default values in your suggestions: 172 - 173 - ```ts 174 - devCmd.option('port', 'Port number', function(complete) { 175 - complete('3000', 'Development port (default)'); 176 - complete('8080', 'Production port'); 177 - complete('9000', 'Alternative port'); 178 - }, 'p'); 179 - ``` 180 - 181 - ### 3. Use Descriptive Option Names 182 - 183 - Choose option names that clearly indicate their purpose: 184 - 185 - ```ts 186 - // Good - descriptive names 187 - devCmd.option('output-dir', 'Output directory', handler); 188 - devCmd.option('source-map', 'Generate source maps', handler); 189 - 190 - // Avoid - ambiguous names 191 - devCmd.option('output', 'Output directory', handler); 192 - devCmd.option('map', 'Generate source maps', handler); 193 - ``` 194 - 195 - ## Argument Design Best Practices 196 - 197 - ### 1. Use Variadic Arguments for File Lists 198 - 199 - Use variadic arguments when users might want to specify multiple files: 200 - 201 - ```ts 202 - // Good - variadic argument for multiple files 203 - t.command('lint', 'Lint files') 204 - .argument('files', function(complete) { 205 - complete('src/', 'Source directory'); 206 - complete('tests/', 'Tests directory'); 207 - complete('*.ts', 'TypeScript files'); 208 - }, true); // true = variadic argument 209 - ``` 210 - 211 - ### 2. Provide Contextual Suggestions 212 - 213 - Make argument suggestions contextual to the command: 214 - 215 - ```ts 216 - t.command('copy', 'Copy files') 217 - .argument('source', function(complete) { 218 - // Suggest source locations 219 - complete('src/', 'Source directory'); 220 - complete('dist/', 'Distribution directory'); 221 - complete('public/', 'Public assets'); 222 - }) 223 - .argument('destination', function(complete) { 224 - // Suggest destination locations 225 - complete('build/', 'Build output'); 226 - complete('release/', 'Release directory'); 227 - complete('backup/', 'Backup location'); 228 - }); 229 - ``` 230 - 231 - ## Package Manager Integration Best Practices 232 - 233 - ### 1. Test CLI Compatibility 234 - 235 - When building CLI tools, test that they work with Tab's package manager integration: 236 - 237 - ```bash 238 - # Test if your CLI supports Tab completions 239 - my-cli complete -- --help 240 - 241 - # Expected output format: 242 - --help Show help information 243 - :0 244 - ``` 245 - 246 - ### 2. Follow the Tab Protocol 247 - 248 - Ensure your CLI follows the Tab completion protocol: 249 - 250 - ```ts 251 - // In your CLI entry point 252 - if (process.argv[2] === 'complete') { 253 - const shell = process.argv[3]; 254 - if (shell && ['zsh', 'bash', 'fish', 'powershell'].includes(shell)) { 255 - t.setup('my-cli', process.execPath, shell); 256 - } else { 257 - const separatorIndex = process.argv.indexOf('--'); 258 - const completionArgs = separatorIndex !== -1 ? process.argv.slice(separatorIndex + 1) : []; 259 - t.parse(completionArgs); 260 - } 261 - } 262 - ``` 263 - 264 - ### 3. Provide Comprehensive Completions 265 - 266 - For package manager integration, provide completions for all major commands: 267 - 268 - ```ts 269 - // Example: Comprehensive pnpm completions 270 - const addCmd = t.command('add', 'Install packages'); 271 - addCmd.option('save-dev', 'Save to devDependencies', 'D'); 272 - addCmd.option('save-optional', 'Save to optionalDependencies', 'O'); 273 - addCmd.option('global', 'Install globally', 'g'); 274 - 275 - const runCmd = t.command('run', 'Run scripts'); 276 - runCmd.argument('script', async function(complete) { 277 - try { 278 - const packageJson = JSON.parse(await fs.readFile('package.json', 'utf8')); 279 - const scripts = Object.keys(packageJson.scripts || {}); 280 - scripts.forEach(script => complete(script, `Run ${script} script`)); 281 - } catch (error) { 282 - // Fallback completions 283 - complete('dev', 'Start development server'); 284 - complete('build', 'Build for production'); 285 - } 286 - }, true); 287 - ``` 288 - 289 - ## Performance Best Practices 290 - 291 - ### 1. Cache Expensive Operations 292 - 293 - Cache results of expensive operations to improve responsiveness: 294 - 295 - ```ts 296 - let cachedDependencies: string[] | null = null; 297 - 298 - t.command('remove', 'Remove packages') 299 - .argument('package', async function(complete) { 300 - if (cachedDependencies) { 301 - cachedDependencies.forEach(dep => complete(dep, 'Installed package')); 302 - return; 303 - } 304 - 305 - try { 306 - const packageJson = JSON.parse(await fs.readFile('package.json', 'utf8')); 307 - const deps = { 308 - ...packageJson.dependencies, 309 - ...packageJson.devDependencies, 310 - }; 311 - cachedDependencies = Object.keys(deps); 312 - cachedDependencies.forEach(dep => complete(dep, 'Installed package')); 313 - } catch (error) { 314 - // Fallback completions 315 - complete('react', 'React library'); 316 - complete('typescript', 'TypeScript compiler'); 317 - } 318 - }); 319 - ``` 320 - 321 - ### 2. Limit Result Sets 322 - 323 - Limit the number of completions to maintain performance: 324 - 325 - ```ts 326 - devCmd.option('config', 'Config file', async function(complete) { 327 - try { 328 - const files = await fs.readdir('.'); 329 - const configFiles = files.filter(f => f.includes('config')); 330 - // Limit to 10 results for performance 331 - configFiles.slice(0, 10).forEach(file => complete(file, `Config file: ${file}`)); 332 - } catch (error) { 333 - complete('vite.config.ts', 'Vite config file'); 334 - } 335 - }); 336 - ``` 337 - 338 - ### 3. Use Async Operations Sparingly 339 - 340 - Only use async operations when necessary: 341 - 342 - ```ts 343 - // Good - sync operations for simple completions 344 - devCmd.option('mode', 'Build mode', function(complete) { 345 - complete('development', 'Development mode'); 346 - complete('production', 'Production mode'); 347 - complete('staging', 'Staging mode'); 348 - }); 349 - 350 - // Good - async operations for dynamic data 351 - devCmd.option('config', 'Config file', async function(complete) { 352 - const files = await fs.readdir('.'); 353 - const configFiles = files.filter(f => f.includes('config')); 354 - configFiles.forEach(file => complete(file, `Config file: ${file}`)); 355 - }); 356 - ``` 357 - 358 - ## User Experience Best Practices 359 - 360 - ### 1. Provide Progressive Disclosure 361 - 362 - Start with common options and provide more specific ones as users type: 363 - 364 - ```ts 365 - devCmd.option('mode', 'Build mode', function(complete) { 366 - if (this.toComplete?.startsWith('dev')) { 367 - complete('development', 'Development mode'); 368 - return; 369 - } 370 - 371 - if (this.toComplete?.startsWith('prod')) { 372 - complete('production', 'Production mode'); 373 - return; 374 - } 375 - 376 - // Show all options initially 377 - complete('development', 'Development mode'); 378 - complete('production', 'Production mode'); 379 - complete('staging', 'Staging mode'); 380 - complete('test', 'Test mode'); 381 - }); 382 - ``` 383 - 384 - ### 2. Use Consistent Descriptions 385 - 386 - Maintain consistent description formatting: 387 - 388 - ```ts 389 - // Good - consistent formatting 390 - devCmd.option('port', 'Port number', function(complete) { 391 - complete('3000', 'Development port (default)'); 392 - complete('8080', 'Production port'); 393 - complete('9000', 'Alternative port'); 394 - }, 'p'); 395 - 396 - // Avoid - inconsistent formatting 397 - devCmd.option('port', 'Port number', function(complete) { 398 - complete('3000', 'dev port'); 399 - complete('8080', 'Production port'); 400 - complete('9000', 'alt port'); 401 - }, 'p'); 402 - ``` 403 - 404 - ### 3. Provide Helpful Defaults 405 - 406 - Include default values in descriptions when helpful: 407 - 408 - ```ts 409 - devCmd.option('port', 'Port number', function(complete) { 410 - complete('3000', 'Development port (default)'); 411 - complete('8080', 'Production port'); 412 - }, 'p'); 413 - 414 - devCmd.option('host', 'Host address', function(complete) { 415 - complete('localhost', 'Localhost (default)'); 416 - complete('0.0.0.0', 'All interfaces'); 417 - }, 'h'); 418 - ``` 419 - 420 - ## Testing Best Practices 421 - 422 - ### 1. Test Completions Manually 423 - 424 - Regularly test your completions to ensure they work correctly: 425 - 426 - ```bash 427 - # Test command completions 428 - my-cli complete -- "dev" 429 - 430 - # Test option completions 431 - my-cli complete -- "dev --port" 432 - 433 - # Test argument completions 434 - my-cli complete -- "copy src/" 435 - 436 - # Test with package managers 437 - pnpm my-cli complete -- "dev --port" 438 - ``` 439 - 440 - ### 2. Test Error Scenarios 441 - 442 - Test how your completions handle error conditions: 443 - 444 - ```ts 445 - // Test with missing files 446 - devCmd.option('config', 'Config file', async function(complete) { 447 - try { 448 - const files = await fs.readdir('.'); 449 - const configFiles = files.filter(f => f.includes('config')); 450 - configFiles.forEach(file => complete(file, `Config file: ${file}`)); 451 - } catch (error) { 452 - // Ensure fallback completions work 453 - complete('vite.config.ts', 'Vite config file'); 454 - complete('vite.config.js', 'Vite config file'); 455 - } 456 - }); 457 - ``` 458 - 459 - ### 3. Test Performance 460 - 461 - Monitor completion performance, especially for async operations: 462 - 463 - ```ts 464 - // Add timing for performance monitoring 465 - devCmd.option('config', 'Config file', async function(complete) { 466 - const start = Date.now(); 467 - try { 468 - const files = await fs.readdir('.'); 469 - const configFiles = files.filter(f => f.includes('config')); 470 - configFiles.forEach(file => complete(file, `Config file: ${file}`)); 471 - } catch (error) { 472 - complete('vite.config.ts', 'Vite config file'); 473 - } 474 - const duration = Date.now() - start; 475 - if (duration > 100) { 476 - console.warn(`Slow completion: ${duration}ms`); 477 - } 478 - }); 479 - ``` 480 - 481 - ## Next Steps 482 - 483 - - Check out [Examples](/docs/tab/guides/examples/) for practical use cases 484 - - Explore the [API Reference](/docs/tab/api/core/) for advanced usage 485 - - Learn about [Package Manager Integration](/docs/tab/guides/package-managers/) for enhanced completions
-443
src/content/docs/tab/guides/examples.mdx
··· 1 - --- 2 - title: Examples 3 - description: Practical examples of using Tab with different CLI frameworks and scenarios 4 - --- 5 - 6 - This guide provides practical examples of using Tab with different CLI frameworks and common scenarios you might encounter when building CLI tools. 7 - 8 - ## Basic CLI with Core API 9 - 10 - A simple CLI tool with basic autocompletions: 11 - 12 - ```ts 13 - #!/usr/bin/env node 14 - import { RootCommand } from '@bomb.sh/tab'; 15 - 16 - const t = new RootCommand(); 17 - 18 - // Add global options 19 - t.option('config', 'Use specified config file', function(complete) { 20 - complete('vite.config.ts', 'Vite config file'); 21 - complete('vite.config.js', 'Vite config file'); 22 - }, 'c'); 23 - 24 - t.option('mode', 'Set env mode', function(complete) { 25 - complete('development', 'Development mode'); 26 - complete('production', 'Production mode'); 27 - }, 'm'); 28 - 29 - // Add root command argument 30 - t.argument('project', function(complete) { 31 - complete('my-app', 'My application'); 32 - complete('my-lib', 'My library'); 33 - }); 34 - 35 - // Add commands with completions 36 - const devCmd = t.command('dev', 'Start development server'); 37 - devCmd.option('port', 'Port number', function(complete) { 38 - complete('3000', 'Development port'); 39 - complete('8080', 'Production port'); 40 - }, 'p'); 41 - 42 - devCmd.option('host', 'Host address', function(complete) { 43 - complete('localhost', 'Local development'); 44 - complete('0.0.0.0', 'All interfaces'); 45 - }, 'h'); 46 - 47 - devCmd.option('verbose', 'Enable verbose logging', 'v'); 48 - 49 - // Add build command 50 - const buildCmd = t.command('build', 'Build for production'); 51 - buildCmd.option('mode', 'Build mode', function(complete) { 52 - complete('development', 'Development build'); 53 - complete('production', 'Production build'); 54 - }); 55 - 56 - buildCmd.option('out-dir', 'Output directory', function(complete) { 57 - complete('dist/', 'Distribution directory'); 58 - complete('build/', 'Build directory'); 59 - }); 60 - 61 - // Add command with arguments 62 - t.command('copy', 'Copy files') 63 - .argument('source', function(complete) { 64 - complete('src/', 'Source directory'); 65 - complete('dist/', 'Distribution directory'); 66 - }) 67 - .argument('destination', function(complete) { 68 - complete('build/', 'Build output'); 69 - complete('release/', 'Release directory'); 70 - }); 71 - 72 - // Handle completion requests 73 - if (process.argv[2] === 'complete') { 74 - const shell = process.argv[3]; 75 - if (shell && ['zsh', 'bash', 'fish', 'powershell'].includes(shell)) { 76 - t.setup('my-cli', process.execPath, shell); 77 - } else { 78 - // Parse completion arguments (everything after --) 79 - const separatorIndex = process.argv.indexOf('--'); 80 - const completionArgs = separatorIndex !== -1 ? process.argv.slice(separatorIndex + 1) : []; 81 - t.parse(completionArgs); 82 - } 83 - } else { 84 - // Regular CLI usage 85 - console.log('My CLI Tool'); 86 - console.log('Use "complete" command for shell completion'); 87 - } 88 - ``` 89 - 90 - ## CAC Framework Example 91 - 92 - A more complex CLI using CAC with Tab integration: 93 - 94 - ```ts 95 - #!/usr/bin/env node 96 - import cac from 'cac'; 97 - import tab from '@bomb.sh/tab/cac'; 98 - 99 - const cli = cac('my-cli'); 100 - 101 - // Define commands 102 - cli.command('dev', 'Start development server') 103 - .option('--port <port>', 'Specify port', { default: 3000 }) 104 - .option('--host <host>', 'Specify host', { default: 'localhost' }) 105 - .option('--config <file>', 'Config file') 106 - .action((options) => { 107 - console.log('Starting dev server...', options); 108 - }); 109 - 110 - cli.command('build', 'Build for production') 111 - .option('--mode <mode>', 'Build mode', { default: 'production' }) 112 - .option('--out-dir <dir>', 'Output directory') 113 - .action((options) => { 114 - console.log('Building...', options); 115 - }); 116 - 117 - cli.command('deploy', 'Deploy application') 118 - .option('--env <environment>', 'Deployment environment') 119 - .option('--region <region>', 'Deployment region') 120 - .action((options) => { 121 - console.log('Deploying...', options); 122 - }); 123 - 124 - // Initialize Tab completion 125 - const completion = await tab(cli); 126 - 127 - // Configure custom completions 128 - const devCommandCompletion = completion.commands.get('dev'); 129 - if (devCommandCompletion) { 130 - const portOptionCompletion = devCommandCompletion.options.get('port'); 131 - if (portOptionCompletion) { 132 - portOptionCompletion.handler = (complete) => { 133 - complete('3000', 'Development port'); 134 - complete('8080', 'Production port'); 135 - }; 136 - } 137 - 138 - const configOptionCompletion = devCommandCompletion.options.get('config'); 139 - if (configOptionCompletion) { 140 - configOptionCompletion.handler = (complete) => { 141 - complete('vite.config.ts', 'Vite config file'); 142 - complete('vite.config.js', 'Vite config file'); 143 - }; 144 - } 145 - } 146 - 147 - const buildCommandCompletion = completion.commands.get('build'); 148 - if (buildCommandCompletion) { 149 - const modeOptionCompletion = buildCommandCompletion.options.get('mode'); 150 - if (modeOptionCompletion) { 151 - modeOptionCompletion.handler = (complete) => { 152 - complete('development', 'Development build'); 153 - complete('production', 'Production build'); 154 - }; 155 - } 156 - } 157 - 158 - cli.parse(); 159 - ``` 160 - 161 - ## Citty Framework Example 162 - 163 - A CLI using Citty with Tab integration: 164 - 165 - ```ts 166 - #!/usr/bin/env node 167 - import { defineCommand, createMain } from 'citty'; 168 - import tab from '@bomb.sh/tab/citty'; 169 - 170 - const main = defineCommand({ 171 - meta: { 172 - name: 'my-cli', 173 - description: 'My CLI tool', 174 - }, 175 - }); 176 - 177 - const devCommand = defineCommand({ 178 - meta: { 179 - name: 'dev', 180 - description: 'Start development server', 181 - }, 182 - args: { 183 - port: { type: 'string', description: 'Specify port' }, 184 - host: { type: 'string', description: 'Specify host' }, 185 - config: { type: 'string', description: 'Config file' }, 186 - }, 187 - }); 188 - 189 - const buildCommand = defineCommand({ 190 - meta: { 191 - name: 'build', 192 - description: 'Build for production', 193 - }, 194 - args: { 195 - mode: { type: 'string', description: 'Build mode' }, 196 - outDir: { type: 'string', description: 'Output directory' }, 197 - }, 198 - }); 199 - 200 - const deployCommand = defineCommand({ 201 - meta: { 202 - name: 'deploy', 203 - description: 'Deploy application', 204 - }, 205 - args: { 206 - env: { type: 'string', description: 'Deployment environment' }, 207 - region: { type: 'string', description: 'Deployment region' }, 208 - }, 209 - }); 210 - 211 - main.subCommands = { 212 - dev: devCommand, 213 - build: buildCommand, 214 - deploy: deployCommand, 215 - }; 216 - 217 - const completion = await tab(main); 218 - 219 - // Configure completions 220 - const devCommandCompletion = completion.commands.get('dev'); 221 - if (devCommandCompletion) { 222 - const portOptionCompletion = devCommandCompletion.options.get('port'); 223 - if (portOptionCompletion) { 224 - portOptionCompletion.handler = (complete) => { 225 - complete('3000', 'Development port'); 226 - complete('8080', 'Production port'); 227 - }; 228 - } 229 - } 230 - 231 - const cli = createMain(main); 232 - cli(); 233 - ``` 234 - 235 - ## Commander.js Example 236 - 237 - A CLI using Commander.js with Tab integration: 238 - 239 - ```ts 240 - #!/usr/bin/env node 241 - import { Command } from 'commander'; 242 - import tab from '@bomb.sh/tab/commander'; 243 - 244 - const program = new Command(); 245 - 246 - program 247 - .name('my-cli') 248 - .description('My CLI tool') 249 - .version('1.0.0'); 250 - 251 - program 252 - .command('dev') 253 - .description('Start development server') 254 - .option('-p, --port <port>', 'Specify port') 255 - .option('-h, --host <host>', 'Specify host') 256 - .option('-c, --config <file>', 'Config file') 257 - .action((options) => { 258 - console.log('Starting dev server...', options); 259 - }); 260 - 261 - program 262 - .command('build') 263 - .description('Build for production') 264 - .option('-m, --mode <mode>', 'Build mode') 265 - .option('-o, --out-dir <dir>', 'Output directory') 266 - .action((options) => { 267 - console.log('Building...', options); 268 - }); 269 - 270 - program 271 - .command('deploy') 272 - .description('Deploy application') 273 - .option('-e, --env <environment>', 'Deployment environment') 274 - .option('-r, --region <region>', 'Deployment region') 275 - .action((options) => { 276 - console.log('Deploying...', options); 277 - }); 278 - 279 - const completion = tab(program); 280 - 281 - // Configure completions 282 - const devCommandCompletion = completion.commands.get('dev'); 283 - if (devCommandCompletion) { 284 - const portOptionCompletion = devCommandCompletion.options.get('port'); 285 - if (portOptionCompletion) { 286 - portOptionCompletion.handler = (complete) => { 287 - complete('3000', 'Development port'); 288 - complete('8080', 'Production port'); 289 - }; 290 - } 291 - } 292 - 293 - program.parse(); 294 - ``` 295 - 296 - ## Advanced Examples 297 - 298 - ### Dynamic File Completions 299 - 300 - Load completions from the file system: 301 - 302 - ```ts 303 - import { readdir } from 'fs/promises'; 304 - import { RootCommand } from '@bomb.sh/tab'; 305 - 306 - const t = new RootCommand(); 307 - 308 - t.command('build', 'Build project') 309 - .option('config', 'Config file', async function(complete) { 310 - try { 311 - const files = await readdir('.'); 312 - const configFiles = files.filter(f => 313 - f.includes('config') && (f.endsWith('.js') || f.endsWith('.ts')) 314 - ); 315 - configFiles.forEach(file => complete(file, `Config file: ${file}`)); 316 - } catch (error) { 317 - // Fallback completions 318 - complete('vite.config.ts', 'Vite config file'); 319 - complete('vite.config.js', 'Vite config file'); 320 - } 321 - }); 322 - ``` 323 - 324 - ### Context-Aware Completions 325 - 326 - Provide different completions based on context: 327 - 328 - ```ts 329 - const t = new RootCommand(); 330 - 331 - t.command('deploy', 'Deploy application') 332 - .option('env', 'Environment', function(complete) { 333 - // Check if user is typing a specific environment 334 - if (this.toComplete?.startsWith('prod')) { 335 - complete('production', 'Production environment'); 336 - return; 337 - } 338 - 339 - complete('development', 'Development environment'); 340 - complete('staging', 'Staging environment'); 341 - complete('production', 'Production environment'); 342 - }) 343 - .option('region', 'Region', function(complete) { 344 - // Provide region completions based on environment 345 - const env = this.command?.options?.get('--env')?.value; 346 - 347 - if (env === 'production') { 348 - complete('us-east-1', 'US East (N. Virginia)'); 349 - complete('us-west-2', 'US West (Oregon)'); 350 - complete('eu-west-1', 'Europe (Ireland)'); 351 - } else { 352 - complete('us-east-1', 'US East (N. Virginia)'); 353 - complete('eu-west-1', 'Europe (Ireland)'); 354 - } 355 - }); 356 - ``` 357 - 358 - ### Package.json Script Completions 359 - 360 - Dynamically load completions from package.json: 361 - 362 - ```ts 363 - import { readFile } from 'fs/promises'; 364 - import { RootCommand } from '@bomb.sh/tab'; 365 - 366 - const t = new RootCommand(); 367 - 368 - t.command('run', 'Run scripts') 369 - .argument('script', async function(complete) { 370 - try { 371 - const packageJson = JSON.parse(await readFile('package.json', 'utf8')); 372 - const scripts = Object.keys(packageJson.scripts || {}); 373 - scripts.forEach(script => complete(script, `Run ${script} script`)); 374 - } catch (error) { 375 - // Fallback completions 376 - complete('dev', 'Start development server'); 377 - complete('build', 'Build for production'); 378 - complete('test', 'Run tests'); 379 - } 380 - }); 381 - ``` 382 - 383 - ### Workspace Completions 384 - 385 - Handle monorepo workspace completions: 386 - 387 - ```ts 388 - import { readFile, readdir } from 'fs/promises'; 389 - import { RootCommand } from '@bomb.sh/tab'; 390 - 391 - const t = new RootCommand(); 392 - 393 - t.command('workspace', 'Workspace commands') 394 - .option('filter', 'Filter workspaces', async function(complete) { 395 - try { 396 - const packageJson = JSON.parse(await readFile('package.json', 'utf8')); 397 - const workspaces = packageJson.workspaces || []; 398 - 399 - // Get workspace names 400 - const workspaceNames = []; 401 - for (const workspace of workspaces) { 402 - if (workspace.includes('*')) { 403 - // Handle glob patterns 404 - const dir = workspace.replace('/*', ''); 405 - const items = await readdir(dir); 406 - workspaceNames.push(...items); 407 - } else { 408 - workspaceNames.push(workspace); 409 - } 410 - } 411 - 412 - workspaceNames.forEach(name => complete(name, `Workspace: ${name}`)); 413 - } catch (error) { 414 - // Fallback completions 415 - complete('packages/*', 'All packages'); 416 - complete('apps/*', 'All applications'); 417 - } 418 - }); 419 - ``` 420 - 421 - ## Testing Completions 422 - 423 - Test your completions manually: 424 - 425 - ```bash 426 - # Test command completions 427 - my-cli complete -- "dev" 428 - 429 - # Test option completions 430 - my-cli complete -- "dev --port" 431 - 432 - # Test argument completions 433 - my-cli complete -- "copy src/" 434 - 435 - # Generate shell completion script 436 - my-cli complete zsh 437 - ``` 438 - 439 - ## Next Steps 440 - 441 - - Learn about [Framework Adapters](/docs/tab/guides/adapters/) for easier integration 442 - - Check out [Best Practices](/docs/tab/guides/best-practices/) for effective autocompletions 443 - - Explore the [API Reference](/docs/tab/api/core/) for advanced usage
-261
src/content/docs/tab/guides/package-managers.mdx
··· 1 - --- 2 - title: Package Manager Integration 3 - description: Enhanced completions for npm, pnpm, yarn, and bun with automatic CLI discovery 4 - --- 5 - 6 - Tab provides a standalone CLI tool that enhances package manager completions with automatic discovery of CLI tools that support Tab completions. This guide focuses on the advanced features and unique capabilities of Tab's package manager integration. 7 - 8 - ## Quick Setup 9 - 10 - For basic setup instructions, see the [Getting Started](/docs/tab/basics/getting-started/) guide. Here's the minimal setup: 11 - 12 - ```bash 13 - # Install and configure 14 - npm install -g @bomb.sh/tab 15 - tab pnpm zsh > ~/.zsh_completions/tab-pnpm.zsh 16 - echo 'source ~/.zsh_completions/tab-pnpm.zsh' >> ~/.zshrc 17 - ``` 18 - 19 - ## Advanced Features 20 - 21 - ### Automatic CLI Discovery 22 - 23 - Tab automatically detects and provides completions for CLI tools in your project: 24 - 25 - ```bash 26 - # Tab automatically discovers and provides completions for: 27 - pnpm vite dev --port # ← Vite completions 28 - pnpm tsc --target # ← TypeScript completions 29 - pnpm eslint --ext # ← ESLint completions 30 - pnpm jest --config # ← Jest completions 31 - ``` 32 - 33 - The discovery process: 34 - 1. **Scans** `node_modules/.bin/` for available CLI tools 35 - 2. **Tests** each tool for Tab compatibility (has a `complete` command) 36 - 3. **Provides** completions automatically for compatible tools 37 - 38 - ### Tab-Compatible CLIs 39 - 40 - A CLI tool is "Tab-compatible" if it follows the Tab protocol: 41 - 42 - ```bash 43 - # Test compatibility 44 - my-cli complete -- --help 45 - 46 - # Expected output: 47 - --help Show help information 48 - :0 49 - ``` 50 - 51 - ### Dynamic Script Completions 52 - 53 - Tab reads your `package.json` to provide intelligent completions: 54 - 55 - ```bash 56 - # Automatically suggests scripts from package.json 57 - pnpm run <TAB> # Shows: dev, build, test, lint, etc. 58 - 59 - # Suggests dependencies for add/remove commands 60 - pnpm add <TAB> # Shows installed packages 61 - pnpm remove <TAB> # Shows installed packages 62 - ``` 63 - 64 - ### Workspace Support 65 - 66 - Enhanced completions for monorepo setups: 67 - 68 - ```bash 69 - # Workspace filtering 70 - pnpm --filter my-app run build 71 - pnpm --filter "packages/*" run test 72 - pnpm --filter "!packages/docs" run lint 73 - 74 - # Tab provides workspace-aware completions for: 75 - # - Workspace names 76 - # - Workspace patterns 77 - # - Workspace-specific scripts 78 - ``` 79 - 80 - ### Context-Aware Completions 81 - 82 - Completions adapt based on your project context: 83 - 84 - ```bash 85 - # In a TypeScript project 86 - pnpm tsc --target <TAB> # Shows: es2020, es2021, es2022, etc. 87 - 88 - # In a Vite project 89 - pnpm vite build --mode <TAB> # Shows: development, production, etc. 90 - 91 - # In a React project 92 - pnpm create-react-app <TAB> # Shows: my-app, my-component, etc. 93 - ``` 94 - 95 - ## Package Manager Specific Features 96 - 97 - ### pnpm Enhancements 98 - 99 - ```bash 100 - # Enhanced workspace commands 101 - pnpm workspace <TAB> # Shows workspace commands 102 - pnpm --filter <TAB> # Shows workspace names and patterns 103 - 104 - # Advanced install options 105 - pnpm add --save-dev <TAB> # Shows dependency types 106 - pnpm install --frozen-lockfile # Shows install options 107 - ``` 108 - 109 - ### npm Enhancements 110 - 111 - ```bash 112 - # Config management 113 - npm config get <TAB> # Shows config keys 114 - npm config set <TAB> # Shows config keys 115 - 116 - # Package management 117 - npm install --save-dev <TAB> # Shows dependency types 118 - npm run <TAB> # Shows scripts with descriptions 119 - ``` 120 - 121 - ### yarn Enhancements 122 - 123 - ```bash 124 - # Workspace operations 125 - yarn workspace <TAB> # Shows workspace commands 126 - yarn workspaces <TAB> # Shows workspace operations 127 - 128 - # Cache management 129 - yarn cache <TAB> # Shows cache operations 130 - yarn cache list # Shows cached packages 131 - ``` 132 - 133 - ### bun Enhancements 134 - 135 - ```bash 136 - # Runtime commands 137 - bun run <TAB> # Shows scripts 138 - bun x <TAB> # Shows available binaries 139 - 140 - # Development features 141 - bun dev <TAB> # Shows dev commands 142 - bun test <TAB> # Shows test options 143 - ``` 144 - 145 - ## Configuration 146 - 147 - ### Environment Variables 148 - 149 - ```bash 150 - # Debug mode for troubleshooting 151 - export DEBUG=1 152 - 153 - # Custom timeout for slow completions 154 - export TAB_COMPLETION_TIMEOUT=3000 155 - 156 - # Disable automatic discovery (fallback to basic completions) 157 - export TAB_DISABLE_DISCOVERY=1 158 - ``` 159 - 160 - ### Performance Optimization 161 - 162 - For large projects, you can optimize performance: 163 - 164 - ```bash 165 - # Increase timeout for projects with many dependencies 166 - export TAB_COMPLETION_TIMEOUT=5000 167 - 168 - # Cache completions (experimental) 169 - export TAB_CACHE_COMPLETIONS=1 170 - ``` 171 - 172 - ## Troubleshooting 173 - 174 - ### Common Issues 175 - 176 - #### Completions are slow 177 - ```bash 178 - # Increase timeout 179 - export TAB_COMPLETION_TIMEOUT=3000 180 - 181 - # Check for slow CLI tools 182 - DEBUG=1 tab pnpm complete -- --help 183 - ``` 184 - 185 - #### Some CLIs don't show completions 186 - ```bash 187 - # Test CLI compatibility 188 - my-cli complete -- --help 189 - 190 - # Check if CLI follows Tab protocol 191 - # Should output completions ending with :{number} 192 - ``` 193 - 194 - #### Workspace completions not working 195 - ```bash 196 - # Verify workspace configuration 197 - cat package.json | grep workspaces 198 - 199 - # Check workspace structure 200 - ls packages/ # Should show workspace directories 201 - ``` 202 - 203 - ### Debug Mode 204 - 205 - Enable detailed logging: 206 - 207 - ```bash 208 - # Full debug output 209 - DEBUG=1 tab pnpm complete -- --help 210 - 211 - # Check discovery process 212 - DEBUG=1 tab pnpm complete -- vite dev 213 - ``` 214 - 215 - ## Advanced Usage 216 - 217 - ### Custom Completion Handlers 218 - 219 - For advanced users, you can extend Tab's completion handlers by modifying the source: 220 - 221 - ```bash 222 - # The completion handlers are in: 223 - # tab/bin/completion-handlers.ts 224 - # tab/bin/package-manager-completion.ts 225 - ``` 226 - 227 - ### Integration with Other Tools 228 - 229 - Tab works alongside other completion tools: 230 - 231 - ```bash 232 - # Use with existing pnpm completions 233 - source <(pnpm completion) 234 - 235 - # Tab enhances existing completions 236 - # rather than replacing them 237 - ``` 238 - 239 - ## Best Practices 240 - 241 - ### 1. Use Consistent Package Manager 242 - Stick to one package manager per project for the best experience. 243 - 244 - ### 2. Keep CLI Tools Updated 245 - Regularly update your CLI tools to ensure Tab compatibility. 246 - 247 - ### 3. Test in Your Projects 248 - ```bash 249 - # Test completions in your specific projects 250 - tab pnpm complete -- --help 251 - pnpm vite complete -- --help 252 - ``` 253 - 254 - ### 4. Share with Team 255 - Share your Tab setup to ensure consistent experience across your team. 256 - 257 - ## Next Steps 258 - 259 - - Learn about [Framework Adapters](/docs/tab/guides/adapters/) for building Tab-compatible CLIs 260 - - Check out [Best Practices](/docs/tab/guides/best-practices/) for effective autocompletions 261 - - Explore the [API Reference](/docs/tab/api/core/) for building your own CLI tools
+198 -58
src/content/docs/tab/index.mdx
··· 3 3 description: Shell autocompletions for JavaScript CLI tools 4 4 --- 5 5 6 - import { CardGrid, Card } from '@astrojs/starlight/components'; 6 + Shell autocompletions are largely missing in the JavaScript CLI ecosystem. tab provides a simple API for adding autocompletions to any JavaScript CLI tool. 7 7 8 - Tab is a powerful tool that brings shell autocompletions to JavaScript CLI tools. Inspired by tools like git and their excellent autocompletion experience, Tab makes the same functionality available for any JavaScript CLI project. 8 + Additionally, tab supports autocompletions for `pnpm`, `npm`, `yarn`, and `bun`. 9 9 10 - ## Features 10 + Modern CLI libraries like [Gunshi](https://github.com/kazupon/gunshi) include tab completion natively in their core. 11 11 12 - <CardGrid> 12 + As CLI tooling authors, if we can spare our users a second or two by not checking documentation or writing the `-h` flag, we're doing them a huge favor. The unconscious mind loves hitting the [TAB] key and always expects feedback. When nothing happens, it breaks the user's flow - a frustration apparent across the whole JavaScript CLI tooling ecosystem. 13 13 14 - <Card title="Shell Integration" icon="seti:shell"> 15 - Seamless integration with zsh, bash, fish, and PowerShell. Get native autocompletion experience for your CLI tools. 16 - </Card> 14 + tab solves this complexity by providing autocompletions that work consistently across `zsh`, `bash`, `fish`, and `powershell`. 17 15 18 - <Card title="Framework Adapters" icon="seti:smarty"> 19 - Built-in adapters for popular CLI frameworks including CAC, Citty, and Commander.js for easy integration. 20 - </Card> 16 + ## Installation 21 17 22 - <Card title="Package Manager Support" icon="seti:npm"> 23 - Built-in completions for npm, pnpm, yarn, and bun with automatic CLI discovery and completion detection. 24 - </Card> 18 + ```bash 19 + npm install @bomb.sh/tab 20 + # or 21 + pnpm add @bomb.sh/tab 22 + # or 23 + yarn add @bomb.sh/tab 24 + # or 25 + bun add @bomb.sh/tab 26 + ``` 25 27 26 - <Card title="Type-Safe" icon="rocket"> 27 - Full TypeScript support with type-safe completion handlers and autocomplete suggestions. 28 - </Card> 28 + ## Quick Start 29 29 30 - <Card title="Custom Completions" icon="approve-check"> 31 - Define custom completion logic for commands and options with dynamic suggestions based on context. 32 - </Card> 30 + Add autocompletions to your CLI tool: 33 31 34 - <Card title="Easy Setup" icon="sun"> 35 - Simple installation and configuration with minimal code changes to add autocompletion to your CLI. 36 - </Card> 32 + ```typescript 33 + import t from '@bomb.sh/tab'; 37 34 38 - </CardGrid> 35 + // Define your CLI structure 36 + const devCmd = t.command('dev', 'Start development server'); 37 + devCmd.option('port', 'Specify port', (complete) => { 38 + complete('3000', 'Development port'); 39 + complete('8080', 'Production port'); 40 + }); 39 41 40 - ## Quick Start 42 + // Handle completion requests 43 + if (process.argv[2] === 'complete') { 44 + const shell = process.argv[3]; 45 + if (shell === '--') { 46 + const args = process.argv.slice(4); 47 + t.parse(args); 48 + } else { 49 + t.setup('my-cli', 'node my-cli.js', shell); 50 + } 51 + } 52 + ``` 41 53 42 - ### For CLI Tool Authors 54 + Test your completions: 43 55 44 - Add shell autocompletions to your CLI in just a few lines: 56 + ```bash 57 + node my-cli.js complete -- dev --port=<TAB> 58 + # Output: --port=3000 Development port 59 + # --port=8080 Production port 60 + ``` 45 61 46 - ```ts 47 - import { RootCommand, script } from '@bomb.sh/tab'; 62 + Install for users: 48 63 49 - const t = new RootCommand(); 64 + ```bash 65 + # One-time setup 66 + source <(my-cli complete zsh) 50 67 51 - // Add commands with completions 52 - t.command('dev', 'Start development server') 53 - .option('port', 'Port number', function(complete) { 68 + # Permanent setup 69 + my-cli complete zsh > ~/.my-cli-completion.zsh 70 + echo 'source ~/.my-cli-completion.zsh' >> ~/.zshrc 71 + ``` 72 + 73 + ## Package Manager Completions 74 + 75 + As mentioned earlier, tab provides completions for package managers as well: 76 + 77 + ```bash 78 + # Generate and install completion scripts 79 + npx @bomb.sh/tab pnpm zsh > ~/.pnpm-completion.zsh && echo 'source ~/.pnpm-completion.zsh' >> ~/.zshrc 80 + npx @bomb.sh/tab npm bash > ~/.npm-completion.bash && echo 'source ~/.npm-completion.bash' >> ~/.bashrc 81 + npx @bomb.sh/tab yarn fish > ~/.config/fish/completions/yarn.fish 82 + npx @bomb.sh/tab bun powershell > ~/.bun-completion.ps1 && echo '. ~/.bun-completion.ps1' >> $PROFILE 83 + ``` 84 + 85 + Example in action: 86 + 87 + ```bash 88 + pnpm install --reporter=<TAB> 89 + # Shows: append-only, default, ndjson, silent 90 + 91 + yarn add --emoji=<TAB> 92 + # Shows: true, false 93 + ``` 94 + 95 + ## Framework Adapters 96 + 97 + tab provides adapters for popular JavaScript CLI frameworks. 98 + 99 + ### CAC Integration 100 + 101 + ```typescript 102 + import cac from 'cac'; 103 + import tab from '@bomb.sh/tab/cac'; 104 + 105 + const cli = cac('my-cli'); 106 + 107 + // Define your CLI 108 + cli 109 + .command('dev', 'Start dev server') 110 + .option('--port <port>', 'Specify port') 111 + .option('--host <host>', 'Specify host'); 112 + 113 + // Initialize tab completions 114 + const completion = await tab(cli); 115 + 116 + // Add custom completions for option values 117 + const devCommand = completion.commands.get('dev'); 118 + const portOption = devCommand?.options.get('port'); 119 + if (portOption) { 120 + portOption.handler = (complete) => { 54 121 complete('3000', 'Development port'); 55 122 complete('8080', 'Production port'); 56 - }, 'p'); 123 + }; 124 + } 57 125 58 - // Handle completion requests 59 - if (process.argv[2] === 'complete') { 60 - const shell = process.argv[3]; 61 - if (shell && ['zsh', 'bash', 'fish', 'powershell'].includes(shell)) { 62 - t.setup('my-cli', process.execPath, shell); 63 - } else { 64 - const separatorIndex = process.argv.indexOf('--'); 65 - const completionArgs = separatorIndex !== -1 ? process.argv.slice(separatorIndex + 1) : []; 66 - t.parse(completionArgs); 67 - } 126 + cli.parse(); 127 + ``` 128 + 129 + ### Citty Integration 130 + 131 + ```typescript 132 + import { defineCommand, createMain } from 'citty'; 133 + import tab from '@bomb.sh/tab/citty'; 134 + 135 + const main = defineCommand({ 136 + meta: { name: 'my-cli', description: 'My CLI tool' }, 137 + subCommands: { 138 + dev: defineCommand({ 139 + meta: { name: 'dev', description: 'Start dev server' }, 140 + args: { 141 + port: { type: 'string', description: 'Specify port' }, 142 + host: { type: 'string', description: 'Specify host' }, 143 + }, 144 + }), 145 + }, 146 + }); 147 + 148 + // Initialize tab completions 149 + const completion = await tab(main); 150 + 151 + // Add custom completions 152 + const devCommand = completion.commands.get('dev'); 153 + const portOption = devCommand?.options.get('port'); 154 + if (portOption) { 155 + portOption.handler = (complete) => { 156 + complete('3000', 'Development port'); 157 + complete('8080', 'Production port'); 158 + }; 68 159 } 160 + 161 + const cli = createMain(main); 162 + cli(); 69 163 ``` 70 164 71 - ### For End Users 165 + ### Commander.js Integration 72 166 73 - Get enhanced package manager completions with automatic CLI discovery: 167 + ```typescript 168 + import { Command } from 'commander'; 169 + import tab from '@bomb.sh/tab/commander'; 170 + 171 + const program = new Command('my-cli'); 172 + program.version('1.0.0'); 173 + 174 + // Define commands 175 + program 176 + .command('serve') 177 + .description('Start the server') 178 + .option('-p, --port <number>', 'port to use', '3000') 179 + .option('-H, --host <host>', 'host to use', 'localhost') 180 + .action((options) => { 181 + console.log('Starting server...'); 182 + }); 183 + 184 + // Initialize tab completions 185 + const completion = tab(program); 186 + 187 + // Add custom completions 188 + const serveCommand = completion.commands.get('serve'); 189 + const portOption = serveCommand?.options.get('port'); 190 + if (portOption) { 191 + portOption.handler = (complete) => { 192 + complete('3000', 'Default port'); 193 + complete('8080', 'Alternative port'); 194 + }; 195 + } 196 + 197 + program.parse(); 198 + ``` 199 + 200 + ## How It Works 201 + 202 + tab uses a standardized completion protocol that any CLI can implement: 74 203 75 204 ```bash 76 - # Install tab CLI 77 - npm install -g @bomb.sh/tab 205 + # Generate shell completion script 206 + my-cli complete zsh 78 207 79 - # Generate completions for your preferred package manager 80 - tab pnpm zsh > ~/.zsh_completions/tab-pnpm.zsh 81 - echo 'source ~/.zsh_completions/tab-pnpm.zsh' >> ~/.zshrc 208 + # Parse completion request (called by shell) 209 + my-cli complete -- install --port="" 210 + ``` 82 211 83 - # Now you get enhanced completions for all CLI tools! 84 - pnpm vite dev --port # ← Tab completion works here 212 + **Output Format:** 213 + 214 + ``` 215 + --port=3000 Development port 216 + --port=8080 Production port 217 + :4 85 218 ``` 86 219 87 - ## What's Next? 220 + ## Contributing 88 221 89 - - [Getting Started](/docs/tab/basics/getting-started/) - Learn how to add autocompletions to your CLI 90 - - [Framework Adapters](/docs/tab/guides/adapters/) - Use Tab with CAC, Citty, and Commander.js 91 - - [Package Manager Integration](/docs/tab/guides/package-managers/) - Enhanced completions for npm, pnpm, yarn, and bun 92 - - [Best Practices](/docs/tab/guides/best-practices/) - Learn best practices for implementing autocompletions 93 - - [API Reference](/docs/tab/api/core/) - Detailed API documentation 222 + We welcome contributions! tab's architecture makes it easy to add support for new package managers or CLI frameworks. 223 + 224 + ## Acknowledgments 225 + 226 + tab was inspired by the great [Cobra](https://github.com/spf13/cobra/) project, which set the standard for CLI tooling in the Go ecosystem. 227 + 228 + ## Adoption Support 229 + 230 + We want to make it as easy as possible for the JS ecosystem to enjoy great autocompletions. 231 + We at [Thundraa](https://thundraa.com) would be happy to help any open source CLI utility adopt tab. 232 + If you maintain a CLI and would like autocompletions set up for your users, just [drop the details in our _Adopting tab_ discussion](https://github.com/bombshell-dev/tab/discussions/61). 233 + We'll gladly help and even open a PR to get you started.