diff --git a/COMPLETION.md b/COMPLETION.md new file mode 100644 index 0000000000..6092c4b1cf --- /dev/null +++ b/COMPLETION.md @@ -0,0 +1,116 @@ +# Shell Autocomplete for OpenAI CLI + +This implementation adds shell autocomplete support for the `openai` CLI tool, making it faster and easier to use. + +## Supported Shells + +- **Bash** (Linux, macOS, WSL) +- **Zsh** (macOS default, Linux) +- **Fish** (cross-platform) +- **PowerShell** (Windows, cross-platform) + +## Usage + +### Generate Completion Script + +```bash +# For bash +openai completion bash + +# For zsh +openai completion zsh + +# For fish +openai completion fish + +# For PowerShell +openai completion powershell +``` + +### Show Installation Instructions + +```bash +openai completion bash --instructions +``` + +## Installation + +### Bash + +```bash +# Quick setup (add to ~/.bashrc) +eval "$(openai completion bash)" + +# Or save permanently +openai completion bash > ~/.openai-completion.bash +echo 'source ~/.openai-completion.bash' >> ~/.bashrc +``` + +### Zsh + +```bash +# Quick setup (add to ~/.zshrc) +eval "$(openai completion zsh)" + +# Or install to fpath +mkdir -p ~/.zsh/completions +openai completion zsh > ~/.zsh/completions/_openai +# Add to ~/.zshrc: fpath=(~/.zsh/completions $fpath) +``` + +### Fish + +```bash +openai completion fish > ~/.config/fish/completions/openai.fish +``` + +### PowerShell + +```powershell +# Add to PowerShell profile +openai completion powershell | Out-String | Invoke-Expression + +# Or save and source +openai completion powershell > ~\Documents\PowerShell\openai-completion.ps1 +# Add to profile: . ~\Documents\PowerShell\openai-completion.ps1 +``` + +## What Gets Autocompleted + +- **Commands**: `api`, `chat`, `audio`, `models`, `files`, `fine-tuning`, etc. +- **Flags**: `--api-key`, `--organization`, `--api-base`, `--help`, etc. +- **Subcommands**: Context-aware completions for nested commands + +## Examples + +```bash +# Type "openai " and press TAB to see all commands +$ openai +api chat audio models files fine-tuning embeddings images completions + +# Type "openai --" and press TAB for flags +$ openai -- +--api-key --organization --api-base --help --version + +# Context-aware completions +$ openai completion +bash zsh fish powershell +``` + +## Implementation Details + +- Built using native shell completion frameworks +- No external dependencies +- Lightweight and fast +- Works with existing CLI structure +- Easy to extend for new commands + +## Testing + +```bash +# Test completion generation +python3 -m openai.cli completion bash | head -20 + +# Verify syntax +python3 -m py_compile src/openai/cli/_completion.py +``` diff --git a/src/openai/cli/_cli.py b/src/openai/cli/_cli.py index d31196da50..f3b2fc23cf 100644 --- a/src/openai/cli/_cli.py +++ b/src/openai/cli/_cli.py @@ -12,6 +12,7 @@ import openai from . import _tools +from ._completion import generate_completion, print_installation_instructions from .. import _ApiType, __version__ from ._api import register_commands from ._utils import can_use_http2 @@ -119,6 +120,27 @@ def help() -> None: sub_tools = subparsers.add_parser("tools", help="Client side tools for convenience") _tools.register_commands(sub_tools, subparsers) + + # Add completion command + sub_completion = subparsers.add_parser("completion", help="Generate shell completion scripts") + sub_completion.add_argument( + "shell", + choices=["bash", "zsh", "fish", "powershell"], + help="Shell type (bash, zsh, fish, or powershell)" + ) + sub_completion.add_argument( + "--instructions", + action="store_true", + help="Show installation instructions" + ) + + def completion_handler(args: Any) -> None: + if args.instructions: + print_installation_instructions(args.shell) + else: + generate_completion(args.shell) + + sub_completion.set_defaults(func=completion_handler) return parser diff --git a/src/openai/cli/_completion.py b/src/openai/cli/_completion.py new file mode 100644 index 0000000000..a1f7dabc0d --- /dev/null +++ b/src/openai/cli/_completion.py @@ -0,0 +1,229 @@ +""" +Shell autocomplete generation for openai CLI. + +Generates completion scripts for bash, zsh, fish, and PowerShell. +""" + +from __future__ import annotations + +import sys +from typing import TextIO + + +BASH_COMPLETION = """ +# openai completion script for bash + +_openai_completion() { + local cur prev opts base + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + # Top-level commands + opts="api chat audio models files fine-tuning embeddings images completions completion --help --version" + + # API-related subcommands + api_cmds="chat.completions.create audio.speech.create audio.transcriptions.create audio.translations.create" + + # Common flags + flags="--api-key --organization --api-base --api-version --timeout --max-retries" + + case "${prev}" in + openai) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + api) + COMPREPLY=( $(compgen -W "${api_cmds}" -- ${cur}) ) + return 0 + ;; + --api-key|--organization|--api-base|--api-version|--timeout|--max-retries) + # No completion for values + return 0 + ;; + *) + ;; + esac + + COMPREPLY=( $(compgen -W "${opts} ${flags}" -- ${cur}) ) + return 0 +} + +complete -F _openai_completion openai +""" + +ZSH_COMPLETION = """ +#compdef openai + +# openai completion script for zsh + +_openai() { + local -a commands + commands=( + 'api:Direct API access' + 'chat:Chat completions' + 'audio:Audio generation and transcription' + 'models:List and retrieve models' + 'files:File operations' + 'fine-tuning:Fine-tuning operations' + 'embeddings:Create embeddings' + 'images:Image generation and manipulation' + 'completions:Text completions' + 'completion:Generate shell completion scripts' + ) + + local -a options + options=( + '--help:Show help message' + '--version:Show version' + '--api-key:OpenAI API key' + '--organization:Organization ID' + '--api-base:API base URL' + '--api-version:API version' + '--timeout:Request timeout' + '--max-retries:Maximum retry attempts' + ) + + _arguments -C \\ + '1: :->command' \\ + '*::arg:->args' + + case $state in + command) + _describe 'openai commands' commands + _describe 'options' options + ;; + args) + case ${words[1]} in + api) + _values 'api operations' \\ + 'chat.completions.create' \\ + 'audio.speech.create' \\ + 'audio.transcriptions.create' \\ + 'audio.translations.create' \\ + 'models.list' \\ + 'files.create' \\ + 'files.list' + ;; + completion) + _values 'shells' 'bash' 'zsh' 'fish' 'powershell' + ;; + esac + ;; + esac +} + +_openai "$@" +""" + +FISH_COMPLETION = """ +# openai completion script for fish + +# Top-level commands +complete -c openai -n "__fish_use_subcommand" -a "api" -d "Direct API access" +complete -c openai -n "__fish_use_subcommand" -a "chat" -d "Chat completions" +complete -c openai -n "__fish_use_subcommand" -a "audio" -d "Audio operations" +complete -c openai -n "__fish_use_subcommand" -a "models" -d "Model operations" +complete -c openai -n "__fish_use_subcommand" -a "files" -d "File operations" +complete -c openai -n "__fish_use_subcommand" -a "fine-tuning" -d "Fine-tuning" +complete -c openai -n "__fish_use_subcommand" -a "embeddings" -d "Embeddings" +complete -c openai -n "__fish_use_subcommand" -a "images" -d "Image generation" +complete -c openai -n "__fish_use_subcommand" -a "completions" -d "Text completions" +complete -c openai -n "__fish_use_subcommand" -a "completion" -d "Generate completion script" + +# Global options +complete -c openai -l help -d "Show help message" +complete -c openai -l version -d "Show version" +complete -c openai -l api-key -d "OpenAI API key" +complete -c openai -l organization -d "Organization ID" +complete -c openai -l api-base -d "API base URL" +complete -c openai -l api-version -d "API version" +complete -c openai -l timeout -d "Request timeout" +complete -c openai -l max-retries -d "Maximum retry attempts" + +# Completion subcommand +complete -c openai -n "__fish_seen_subcommand_from completion" -a "bash zsh fish powershell" -d "Shell type" +""" + +POWERSHELL_COMPLETION = """ +# openai completion script for PowerShell + +Register-ArgumentCompleter -Native -CommandName openai -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + + $commands = @( + [CompletionResult]::new('api', 'api', [CompletionResultType]::ParameterValue, 'Direct API access') + [CompletionResult]::new('chat', 'chat', [CompletionResultType]::ParameterValue, 'Chat completions') + [CompletionResult]::new('audio', 'audio', [CompletionResultType]::ParameterValue, 'Audio operations') + [CompletionResult]::new('models', 'models', [CompletionResultType]::ParameterValue, 'Model operations') + [CompletionResult]::new('files', 'files', [CompletionResultType]::ParameterValue, 'File operations') + [CompletionResult]::new('fine-tuning', 'fine-tuning', [CompletionResultType]::ParameterValue, 'Fine-tuning') + [CompletionResult]::new('embeddings', 'embeddings', [CompletionResultType]::ParameterValue, 'Embeddings') + [CompletionResult]::new('images', 'images', [CompletionResultType]::ParameterValue, 'Image generation') + [CompletionResult]::new('completions', 'completions', [CompletionResultType]::ParameterValue, 'Text completions') + [CompletionResult]::new('completion', 'completion', [CompletionResultType]::ParameterValue, 'Generate completion script') + [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Show help') + [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Show version') + [CompletionResult]::new('--api-key', '--api-key', [CompletionResultType]::ParameterName, 'API key') + [CompletionResult]::new('--organization', '--organization', [CompletionResultType]::ParameterName, 'Organization') + ) + + $commands | Where-Object { $_.CompletionText -like "$wordToComplete*" } +} +""" + + +def generate_completion(shell: str, output: TextIO = sys.stdout) -> None: + """Generate completion script for the specified shell.""" + shell = shell.lower() + + if shell == "bash": + output.write(BASH_COMPLETION) + elif shell == "zsh": + output.write(ZSH_COMPLETION) + elif shell == "fish": + output.write(FISH_COMPLETION) + elif shell == "powershell": + output.write(POWERSHELL_COMPLETION) + else: + raise ValueError(f"Unsupported shell: {shell}. Supported: bash, zsh, fish, powershell") + + +def print_installation_instructions(shell: str) -> None: + """Print installation instructions for the completion script.""" + shell = shell.lower() + + instructions = { + "bash": """ +To enable bash completion, add this to your ~/.bashrc: + eval "$(openai completion bash)" + +Or save the completion script: + openai completion bash > ~/.openai-completion.bash + echo 'source ~/.openai-completion.bash' >> ~/.bashrc +""", + "zsh": """ +To enable zsh completion, add this to your ~/.zshrc: + eval "$(openai completion zsh)" + +Or save the completion script to your fpath: + openai completion zsh > ~/.zsh/completions/_openai + # Add to ~/.zshrc: fpath=(~/.zsh/completions $fpath) +""", + "fish": """ +To enable fish completion: + openai completion fish > ~/.config/fish/completions/openai.fish + +The completion will be loaded automatically in new fish sessions. +""", + "powershell": """ +To enable PowerShell completion, add this to your profile: + openai completion powershell | Out-String | Invoke-Expression + +Or save and source it: + openai completion powershell > ~\\Documents\\PowerShell\\openai-completion.ps1 + # Add to profile: . ~\\Documents\\PowerShell\\openai-completion.ps1 +""" + } + + sys.stderr.write(instructions.get(shell, ""))