diff --git a/cmd/generate_changelog/incoming/1689.txt b/cmd/generate_changelog/incoming/1689.txt new file mode 100644 index 00000000..70f258d1 --- /dev/null +++ b/cmd/generate_changelog/incoming/1689.txt @@ -0,0 +1,7 @@ +### PR [#1689](https://github.com/danielmiessler/Fabric/pull/1689) by [ksylvan](https://github.com/ksylvan): Enhanced Shell Completions for Fabric CLI Binaries + +- Add 'fabric-ai' alias support across all shell completions +- Use invoked command name for dynamic completion list queries +- Refactor fish completions into reusable registrar for multiple commands +- Update Bash completion to reference executable via COMP_WORDS[0] +- Install completions automatically with new cross-shell setup script diff --git a/completions/_fabric b/completions/_fabric index 34d199ed..be6f0ba1 100644 --- a/completions/_fabric +++ b/completions/_fabric @@ -1,47 +1,54 @@ -#compdef fabric +#compdef fabric fabric-ai # Zsh completion for fabric CLI # Place this file in a directory in your $fpath (e.g. /usr/local/share/zsh/site-functions) _fabric_patterns() { local -a patterns - patterns=(${(f)"$(fabric --listpatterns --shell-complete-list 2>/dev/null)"}) + local cmd=${words[1]} + patterns=(${(f)"$($cmd --listpatterns --shell-complete-list 2>/dev/null)"}) compadd -X "Patterns:" ${patterns} } _fabric_models() { local -a models - models=(${(f)"$(fabric --listmodels --shell-complete-list 2>/dev/null)"}) + local cmd=${words[1]} + models=(${(f)"$($cmd --listmodels --shell-complete-list 2>/dev/null)"}) compadd -X "Models:" ${models} } _fabric_contexts() { local -a contexts - contexts=(${(f)"$(fabric --listcontexts --shell-complete-list 2>/dev/null)"}) + local cmd=${words[1]} + contexts=(${(f)"$($cmd --listcontexts --shell-complete-list 2>/dev/null)"}) compadd -X "Contexts:" ${contexts} } _fabric_sessions() { local -a sessions - sessions=(${(f)"$(fabric --listsessions --shell-complete-list 2>/dev/null)"}) + local cmd=${words[1]} + sessions=(${(f)"$($cmd --listsessions --shell-complete-list 2>/dev/null)"}) compadd -X "Sessions:" ${sessions} } _fabric_strategies() { local -a strategies - strategies=(${(f)"$(fabric --liststrategies --shell-complete-list 2>/dev/null)"}) + local cmd=${words[1]} + strategies=(${(f)"$($cmd --liststrategies --shell-complete-list 2>/dev/null)"}) compadd -X "Strategies:" ${strategies} } _fabric_extensions() { local -a extensions - extensions=(${(f)"$(fabric --listextensions --shell-complete-list 2>/dev/null)"}) + local cmd=${words[1]} + extensions=(${(f)"$($cmd --listextensions --shell-complete-list 2>/dev/null)"}) compadd -X "Extensions:" ${extensions} } _fabric_gemini_voices() { local -a voices - voices=(${(f)"$(fabric --list-gemini-voices --shell-complete-list 2>/dev/null)"}) + local cmd=${words[1]} + voices=(${(f)"$($cmd --list-gemini-voices --shell-complete-list 2>/dev/null)"}) compadd -X "Gemini TTS Voices:" ${voices} } diff --git a/completions/fabric.bash b/completions/fabric.bash index e5d345f5..376f7a06 100644 --- a/completions/fabric.bash +++ b/completions/fabric.bash @@ -17,7 +17,7 @@ _fabric() { # Helper function for dynamic completions _fabric_get_list() { - fabric "$1" --shell-complete-list 2>/dev/null + "${COMP_WORDS[0]}" "$1" --shell-complete-list 2>/dev/null } # Handle completions based on the previous word @@ -104,4 +104,4 @@ _fabric() { } -complete -F _fabric fabric +complete -F _fabric fabric fabric-ai diff --git a/completions/fabric.fish b/completions/fabric.fish index d5b29976..50dc265f 100755 --- a/completions/fabric.fish +++ b/completions/fabric.fish @@ -8,107 +8,120 @@ # Helper functions for dynamic completions function __fabric_get_patterns - fabric --listpatterns --shell-complete-list 2>/dev/null + set cmd (commandline -opc)[1] + $cmd --listpatterns --shell-complete-list 2>/dev/null end function __fabric_get_models - fabric --listmodels --shell-complete-list 2>/dev/null + set cmd (commandline -opc)[1] + $cmd --listmodels --shell-complete-list 2>/dev/null end function __fabric_get_contexts - fabric --listcontexts --shell-complete-list 2>/dev/null + set cmd (commandline -opc)[1] + $cmd --listcontexts --shell-complete-list 2>/dev/null end function __fabric_get_sessions - fabric --listsessions --shell-complete-list 2>/dev/null + set cmd (commandline -opc)[1] + $cmd --listsessions --shell-complete-list 2>/dev/null end function __fabric_get_strategies - fabric --liststrategies --shell-complete-list 2>/dev/null + set cmd (commandline -opc)[1] + $cmd --liststrategies --shell-complete-list 2>/dev/null end function __fabric_get_extensions - fabric --listextensions --shell-complete-list 2>/dev/null + set cmd (commandline -opc)[1] + $cmd --listextensions --shell-complete-list 2>/dev/null end function __fabric_get_gemini_voices - fabric --list-gemini-voices --shell-complete-list 2>/dev/null + set cmd (commandline -opc)[1] + $cmd --list-gemini-voices --shell-complete-list 2>/dev/null end # Main completion function -complete -c fabric -f +function __fabric_register_completions + set cmd $argv[1] + complete -c $cmd -f -# Flag completions with arguments -complete -c fabric -s p -l pattern -d "Choose a pattern from the available patterns" -a "(__fabric_get_patterns)" -complete -c fabric -s v -l variable -d "Values for pattern variables, e.g. -v=#role:expert -v=#points:30" -complete -c fabric -s C -l context -d "Choose a context from the available contexts" -a "(__fabric_get_contexts)" -complete -c fabric -l session -d "Choose a session from the available sessions" -a "(__fabric_get_sessions)" -complete -c fabric -s a -l attachment -d "Attachment path or URL (e.g. for OpenAI image recognition messages)" -r -complete -c fabric -s t -l temperature -d "Set temperature (default: 0.7)" -complete -c fabric -s T -l topp -d "Set top P (default: 0.9)" -complete -c fabric -s P -l presencepenalty -d "Set presence penalty (default: 0.0)" -complete -c fabric -s F -l frequencypenalty -d "Set frequency penalty (default: 0.0)" -complete -c fabric -s m -l model -d "Choose model" -a "(__fabric_get_models)" -complete -c fabric -l modelContextLength -d "Model context length (only affects ollama)" -complete -c fabric -s o -l output -d "Output to file" -r -complete -c fabric -s n -l latest -d "Number of latest patterns to list (default: 0)" -complete -c fabric -s y -l youtube -d "YouTube video or play list URL to grab transcript, comments from it" -complete -c fabric -s g -l language -d "Specify the Language Code for the chat, e.g. -g=en -g=zh" -complete -c fabric -s u -l scrape_url -d "Scrape website URL to markdown using Jina AI" -complete -c fabric -s q -l scrape_question -d "Search question using Jina AI" -complete -c fabric -s e -l seed -d "Seed to be used for LMM generation" -complete -c fabric -s w -l wipecontext -d "Wipe context" -a "(__fabric_get_contexts)" -complete -c fabric -s W -l wipesession -d "Wipe session" -a "(__fabric_get_sessions)" -complete -c fabric -l printcontext -d "Print context" -a "(__fabric_get_contexts)" -complete -c fabric -l printsession -d "Print session" -a "(__fabric_get_sessions)" -complete -c fabric -l address -d "The address to bind the REST API (default: :8080)" -complete -c fabric -l api-key -d "API key used to secure server routes" -complete -c fabric -l config -d "Path to YAML config file" -r -a "*.yaml *.yml" -complete -c fabric -l search-location -d "Set location for web search results (e.g., 'America/Los_Angeles')" -complete -c fabric -l image-file -d "Save generated image to specified file path (e.g., 'output.png')" -r -a "*.png *.webp *.jpeg *.jpg" -complete -c fabric -l image-size -d "Image dimensions: 1024x1024, 1536x1024, 1024x1536, auto (default: auto)" -a "1024x1024 1536x1024 1024x1536 auto" -complete -c fabric -l image-quality -d "Image quality: low, medium, high, auto (default: auto)" -a "low medium high auto" -complete -c fabric -l image-compression -d "Compression level 0-100 for JPEG/WebP formats (default: not set)" -r -complete -c fabric -l image-background -d "Background type: opaque, transparent (default: opaque, only for PNG/WebP)" -a "opaque transparent" -complete -c fabric -l addextension -d "Register a new extension from config file path" -r -a "*.yaml *.yml" -complete -c fabric -l rmextension -d "Remove a registered extension by name" -a "(__fabric_get_extensions)" -complete -c fabric -l strategy -d "Choose a strategy from the available strategies" -a "(__fabric_get_strategies)" -complete -c fabric -l think-start-tag -d "Start tag for thinking sections (default: )" -complete -c fabric -l think-end-tag -d "End tag for thinking sections (default: )" -complete -c fabric -l voice -d "TTS voice name for supported models (e.g., Kore, Charon, Puck)" -a "(__fabric_get_gemini_voices)" -complete -c fabric -l notification-command -d "Custom command to run for notifications (overrides built-in notifications)" + # Flag completions with arguments + complete -c $cmd -s p -l pattern -d "Choose a pattern from the available patterns" -a "(__fabric_get_patterns)" + complete -c $cmd -s v -l variable -d "Values for pattern variables, e.g. -v=#role:expert -v=#points:30" + complete -c $cmd -s C -l context -d "Choose a context from the available contexts" -a "(__fabric_get_contexts)" + complete -c $cmd -l session -d "Choose a session from the available sessions" -a "(__fabric_get_sessions)" + complete -c $cmd -s a -l attachment -d "Attachment path or URL (e.g. for OpenAI image recognition messages)" -r + complete -c $cmd -s t -l temperature -d "Set temperature (default: 0.7)" + complete -c $cmd -s T -l topp -d "Set top P (default: 0.9)" + complete -c $cmd -s P -l presencepenalty -d "Set presence penalty (default: 0.0)" + complete -c $cmd -s F -l frequencypenalty -d "Set frequency penalty (default: 0.0)" + complete -c $cmd -s m -l model -d "Choose model" -a "(__fabric_get_models)" + complete -c $cmd -l modelContextLength -d "Model context length (only affects ollama)" + complete -c $cmd -s o -l output -d "Output to file" -r + complete -c $cmd -s n -l latest -d "Number of latest patterns to list (default: 0)" + complete -c $cmd -s y -l youtube -d "YouTube video or play list URL to grab transcript, comments from it" + complete -c $cmd -s g -l language -d "Specify the Language Code for the chat, e.g. -g=en -g=zh" + complete -c $cmd -s u -l scrape_url -d "Scrape website URL to markdown using Jina AI" + complete -c $cmd -s q -l scrape_question -d "Search question using Jina AI" + complete -c $cmd -s e -l seed -d "Seed to be used for LMM generation" + complete -c $cmd -s w -l wipecontext -d "Wipe context" -a "(__fabric_get_contexts)" + complete -c $cmd -s W -l wipesession -d "Wipe session" -a "(__fabric_get_sessions)" + complete -c $cmd -l printcontext -d "Print context" -a "(__fabric_get_contexts)" + complete -c $cmd -l printsession -d "Print session" -a "(__fabric_get_sessions)" + complete -c $cmd -l address -d "The address to bind the REST API (default: :8080)" + complete -c $cmd -l api-key -d "API key used to secure server routes" + complete -c $cmd -l config -d "Path to YAML config file" -r -a "*.yaml *.yml" + complete -c $cmd -l search-location -d "Set location for web search results (e.g., 'America/Los_Angeles')" + complete -c $cmd -l image-file -d "Save generated image to specified file path (e.g., 'output.png')" -r -a "*.png *.webp *.jpeg *.jpg" + complete -c $cmd -l image-size -d "Image dimensions: 1024x1024, 1536x1024, 1024x1536, auto (default: auto)" -a "1024x1024 1536x1024 1024x1536 auto" + complete -c $cmd -l image-quality -d "Image quality: low, medium, high, auto (default: auto)" -a "low medium high auto" + complete -c $cmd -l image-compression -d "Compression level 0-100 for JPEG/WebP formats (default: not set)" -r + complete -c $cmd -l image-background -d "Background type: opaque, transparent (default: opaque, only for PNG/WebP)" -a "opaque transparent" + complete -c $cmd -l addextension -d "Register a new extension from config file path" -r -a "*.yaml *.yml" + complete -c $cmd -l rmextension -d "Remove a registered extension by name" -a "(__fabric_get_extensions)" + complete -c $cmd -l strategy -d "Choose a strategy from the available strategies" -a "(__fabric_get_strategies)" + complete -c $cmd -l think-start-tag -d "Start tag for thinking sections (default: )" + complete -c $cmd -l think-end-tag -d "End tag for thinking sections (default: )" + complete -c $cmd -l voice -d "TTS voice name for supported models (e.g., Kore, Charon, Puck)" -a "(__fabric_get_gemini_voices)" + complete -c $cmd -l notification-command -d "Custom command to run for notifications (overrides built-in notifications)" -# Boolean flags (no arguments) -complete -c fabric -s S -l setup -d "Run setup for all reconfigurable parts of fabric" -complete -c fabric -s s -l stream -d "Stream" -complete -c fabric -s r -l raw -d "Use the defaults of the model without sending chat options" -complete -c fabric -s l -l listpatterns -d "List all patterns" -complete -c fabric -s L -l listmodels -d "List all available models" -complete -c fabric -s x -l listcontexts -d "List all contexts" -complete -c fabric -s X -l listsessions -d "List all sessions" -complete -c fabric -s U -l updatepatterns -d "Update patterns" -complete -c fabric -s c -l copy -d "Copy to clipboard" -complete -c fabric -l output-session -d "Output the entire session to the output file" -complete -c fabric -s d -l changeDefaultModel -d "Change default model" -complete -c fabric -l playlist -d "Prefer playlist over video if both ids are present in the URL" -complete -c fabric -l transcript -d "Grab transcript from YouTube video and send to chat" -complete -c fabric -l transcript-with-timestamps -d "Grab transcript from YouTube video with timestamps" -complete -c fabric -l comments -d "Grab comments from YouTube video and send to chat" -complete -c fabric -l metadata -d "Output video metadata" -complete -c fabric -l yt-dlp-args -d "Additional arguments to pass to yt-dlp (e.g. '--cookies-from-browser brave')" -complete -c fabric -l readability -d "Convert HTML input into a clean, readable view" -complete -c fabric -l input-has-vars -d "Apply variables to user input" -complete -c fabric -l dry-run -d "Show what would be sent to the model without actually sending it" -complete -c fabric -l search -d "Enable web search tool for supported models (Anthropic, OpenAI, Gemini)" -complete -c fabric -l serve -d "Serve the Fabric Rest API" -complete -c fabric -l serveOllama -d "Serve the Fabric Rest API with ollama endpoints" -complete -c fabric -l version -d "Print current version" -complete -c fabric -l listextensions -d "List all registered extensions" -complete -c fabric -l liststrategies -d "List all strategies" -complete -c fabric -l listvendors -d "List all vendors" -complete -c fabric -l list-gemini-voices -d "List all available Gemini TTS voices" -complete -c fabric -l shell-complete-list -d "Output raw list without headers/formatting (for shell completion)" -complete -c fabric -l suppress-think -d "Suppress text enclosed in thinking tags" -complete -c fabric -l disable-responses-api -d "Disable OpenAI Responses API (default: false)" -complete -c fabric -l notification -d "Send desktop notification when command completes" -complete -c fabric -s h -l help -d "Show this help message" + # Boolean flags (no arguments) + complete -c $cmd -s S -l setup -d "Run setup for all reconfigurable parts of fabric" + complete -c $cmd -s s -l stream -d "Stream" + complete -c $cmd -s r -l raw -d "Use the defaults of the model without sending chat options" + complete -c $cmd -s l -l listpatterns -d "List all patterns" + complete -c $cmd -s L -l listmodels -d "List all available models" + complete -c $cmd -s x -l listcontexts -d "List all contexts" + complete -c $cmd -s X -l listsessions -d "List all sessions" + complete -c $cmd -s U -l updatepatterns -d "Update patterns" + complete -c $cmd -s c -l copy -d "Copy to clipboard" + complete -c $cmd -l output-session -d "Output the entire session to the output file" + complete -c $cmd -s d -l changeDefaultModel -d "Change default model" + complete -c $cmd -l playlist -d "Prefer playlist over video if both ids are present in the URL" + complete -c $cmd -l transcript -d "Grab transcript from YouTube video and send to chat" + complete -c $cmd -l transcript-with-timestamps -d "Grab transcript from YouTube video with timestamps" + complete -c $cmd -l comments -d "Grab comments from YouTube video and send to chat" + complete -c $cmd -l metadata -d "Output video metadata" + complete -c $cmd -l yt-dlp-args -d "Additional arguments to pass to yt-dlp (e.g. '--cookies-from-browser brave')" + complete -c $cmd -l readability -d "Convert HTML input into a clean, readable view" + complete -c $cmd -l input-has-vars -d "Apply variables to user input" + complete -c $cmd -l dry-run -d "Show what would be sent to the model without actually sending it" + complete -c $cmd -l search -d "Enable web search tool for supported models (Anthropic, OpenAI, Gemini)" + complete -c $cmd -l serve -d "Serve the Fabric Rest API" + complete -c $cmd -l serveOllama -d "Serve the Fabric Rest API with ollama endpoints" + complete -c $cmd -l version -d "Print current version" + complete -c $cmd -l listextensions -d "List all registered extensions" + complete -c $cmd -l liststrategies -d "List all strategies" + complete -c $cmd -l listvendors -d "List all vendors" + complete -c $cmd -l list-gemini-voices -d "List all available Gemini TTS voices" + complete -c $cmd -l shell-complete-list -d "Output raw list without headers/formatting (for shell completion)" + complete -c $cmd -l suppress-think -d "Suppress text enclosed in thinking tags" + complete -c $cmd -l disable-responses-api -d "Disable OpenAI Responses API (default: false)" + complete -c $cmd -l notification -d "Send desktop notification when command completes" + complete -c $cmd -s h -l help -d "Show this help message" +end + +__fabric_register_completions fabric +__fabric_register_completions fabric-ai diff --git a/completions/setup-completions.sh b/completions/setup-completions.sh new file mode 100755 index 00000000..22f0259c --- /dev/null +++ b/completions/setup-completions.sh @@ -0,0 +1,387 @@ +#!/bin/sh + +# Fabric Shell Completions Setup Script +# This script automatically installs shell completions for the fabric CLI +# based on your current shell and the installed fabric command name. + +set -e + +# Global variables +DRY_RUN=false + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Function to print colored output +print_info() { + printf "${BLUE}[INFO]${NC} %s\n" "$1" +} + +print_success() { + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" +} + +print_warning() { + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" +} + +print_error() { + printf "${RED}[ERROR]${NC} %s\n" "$1" +} + +print_dry_run() { + printf "${CYAN}[DRY-RUN]${NC} %s\n" "$1" +} + +# Function to execute commands with dry-run support +execute_command() { + cmd="$1" + + if [ "$DRY_RUN" = true ]; then + print_dry_run "Would run: $cmd" + return 0 + else + eval "$cmd" 2>/dev/null + fi +} + +# Ensure directory exists, try sudo on permission failure +ensure_dir() { + dir="$1" + # Expand ~ if present + case "$dir" in + ~/*) + dir="$HOME${dir#~}" + ;; + esac + + if [ -d "$dir" ]; then + return 0 + fi + + if [ "$DRY_RUN" = true ]; then + print_dry_run "Would run: mkdir -p \"$dir\"" + print_dry_run "If permission denied, would run: sudo mkdir -p \"$dir\"" + return 0 + fi + + if mkdir -p "$dir" 2>/dev/null; then + return 0 + fi + if command -v sudo >/dev/null 2>&1 && sudo mkdir -p "$dir" 2>/dev/null; then + return 0 + fi + print_error "Failed to create directory: $dir" + return 1 +} + +# Copy file with sudo fallback on permission failure +install_file() { + src="$1" + dest="$2" + + if [ "$DRY_RUN" = true ]; then + print_dry_run "Would run: cp \"$src\" \"$dest\"" + print_dry_run "If permission denied, would run: sudo cp \"$src\" \"$dest\"" + return 0 + fi + + if cp "$src" "$dest" 2>/dev/null; then + return 0 + fi + if command -v sudo >/dev/null 2>&1 && sudo cp "$src" "$dest" 2>/dev/null; then + return 0 + fi + print_error "Failed to install file to: $dest" + return 1 +} + +# Function to detect fabric command name +detect_fabric_command() { + if command -v fabric >/dev/null 2>&1; then + echo "fabric" + elif command -v fabric-ai >/dev/null 2>&1; then + echo "fabric-ai" + else + print_error "Neither 'fabric' nor 'fabric-ai' command found in PATH" + exit 1 + fi +} + +# Function to detect shell +detect_shell() { + if [ -n "$SHELL" ]; then + basename "$SHELL" + else + print_warning "SHELL environment variable not set, defaulting to sh" + echo "sh" + fi +} + +# Function to get script directory +get_script_dir() { + # Get the directory where this script is located + script_path="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")" + dirname "$script_path" +} + +# Function to setup Zsh completions +setup_zsh_completions() { + fabric_cmd="$1" + script_dir="$2" + completion_file="_${fabric_cmd}" + + print_info "Setting up Zsh completions for '$fabric_cmd'..." + + # Try to use existing $fpath first, then fall back to default directories + zsh_dirs="" + + # Check if user's shell is zsh and try to get fpath from it + if [ "$(basename "$SHELL")" = "zsh" ] && command -v zsh >/dev/null 2>&1; then + # Get fpath from zsh by sourcing user's .zshrc first + fpath_output=$(zsh -c "source \$HOME/.zshrc 2>/dev/null && print -l \$fpath" 2>/dev/null | head -5 | tr '\n' ' ') + if [ -n "$fpath_output" ] && [ "$fpath_output" != "" ]; then + print_info "Using directories from zsh \$fpath" + zsh_dirs="$fpath_output" + fi + fi + + # If we couldn't get fpath or it's empty, use default directories + if [ -z "$zsh_dirs" ] || [ "$zsh_dirs" = "" ]; then + print_info "Using default zsh completion directories" + zsh_dirs="/usr/local/share/zsh/site-functions /opt/homebrew/share/zsh/site-functions /usr/share/zsh/site-functions ~/.local/share/zsh/site-functions" + fi + + installed=false + + for dir in $zsh_dirs; do + # Create directory (with sudo fallback if needed) + if ensure_dir "$dir"; then + if install_file "$script_dir/_fabric" "$dir/$completion_file"; then + if [ "$DRY_RUN" = true ]; then + print_success "Would install Zsh completion to: $dir/$completion_file" + else + print_success "Installed Zsh completion to: $dir/$completion_file" + fi + installed=true + break + fi + fi + done + + if [ "$installed" = false ]; then + if [ "$DRY_RUN" = true ]; then + print_warning "Would attempt to install Zsh completions but no writable directory found." + else + print_error "Failed to install Zsh completions. Try running with sudo or check permissions." + return 1 + fi + fi + + if [ "$DRY_RUN" = true ]; then + print_info "Would suggest: Restart your shell or run 'autoload -U compinit && compinit' to enable completions." + else + print_info "Restart your shell or run 'autoload -U compinit && compinit' to enable completions." + fi +} + +# Function to setup Bash completions +setup_bash_completions() { + fabric_cmd="$1" + script_dir="$2" + completion_file="${fabric_cmd}.bash" + + print_info "Setting up Bash completions for '$fabric_cmd'..." + + # Try different completion directories + bash_dirs="/etc/bash_completion.d /usr/local/etc/bash_completion.d /opt/homebrew/etc/bash_completion.d ~/.local/share/bash-completion/completions" + installed=false + + for dir in $bash_dirs; do + if ensure_dir "$dir"; then + if install_file "$script_dir/fabric.bash" "$dir/$completion_file"; then + if [ "$DRY_RUN" = true ]; then + print_success "Would install Bash completion to: $dir/$completion_file" + else + print_success "Installed Bash completion to: $dir/$completion_file" + fi + installed=true + break + fi + fi + done + + if [ "$installed" = false ]; then + if [ "$DRY_RUN" = true ]; then + print_warning "Would attempt to install Bash completions but no writable directory found." + else + print_error "Failed to install Bash completions. Try running with sudo or check permissions." + return 1 + fi + fi + + if [ "$DRY_RUN" = true ]; then + print_info "Would suggest: Restart your shell or run 'source ~/.bashrc' to enable completions." + else + print_info "Restart your shell or run 'source ~/.bashrc' to enable completions." + fi +} + +# Function to setup Fish completions +setup_fish_completions() { + fabric_cmd="$1" + script_dir="$2" + completion_file="${fabric_cmd}.fish" + + print_info "Setting up Fish completions for '$fabric_cmd'..." + + # Fish completion directory + fish_dir="$HOME/.config/fish/completions" + + if [ "$DRY_RUN" = true ]; then + print_dry_run "Would run: mkdir -p \"$fish_dir\"" + print_dry_run "Would run: cp \"$script_dir/fabric.fish\" \"$fish_dir/$completion_file\"" + print_success "Would install Fish completion to: $fish_dir/$completion_file" + print_info "Fish will automatically load the completions (no restart needed)." + elif mkdir -p "$fish_dir" 2>/dev/null; then + if cp "$script_dir/fabric.fish" "$fish_dir/$completion_file"; then + print_success "Installed Fish completion to: $fish_dir/$completion_file" + print_info "Fish will automatically load the completions (no restart needed)." + else + print_error "Failed to copy Fish completion file." + return 1 + fi + else + print_error "Failed to create Fish completions directory: $fish_dir" + return 1 + fi +} + +# Function to setup completions for other shells +setup_other_shell_completions() { + fabric_cmd="$1" + shell_name="$2" + + print_warning "Shell '$shell_name' is not directly supported." + print_info "You can manually source the completion files:" + print_info " Bash-compatible: source $script_dir/fabric.bash" + print_info " Zsh-compatible: source $script_dir/_fabric" +} + +# Function to show help +show_help() { + cat << EOF +Fabric Shell Completions Setup Script + +USAGE: + setup-completions.sh [OPTIONS] + +OPTIONS: + --dry-run Show what commands would be run without executing them + --help Show this help message + +DESCRIPTION: + This script automatically installs shell completions for the fabric CLI + based on your current shell and the installed fabric command name. + + The script looks for completion files in the same directory as the script, + so it can be run from anywhere. + + Supports: zsh, bash, fish + + The script will: + 1. Detect whether 'fabric' or 'fabric-ai' is installed + 2. Detect your current shell from the SHELL environment variable + 3. Install the appropriate completion file with the correct name + 4. Try multiple standard completion directories + +EXAMPLES: + ./setup-completions.sh # Install completions + ./setup-completions.sh --dry-run # Show what would be done + ./setup-completions.sh --help # Show this help + +EOF +} + +# Main function +main() { + # Parse command line arguments + while [ $# -gt 0 ]; do + case "$1" in + --dry-run) + DRY_RUN=true + shift + ;; + --help|-h) + show_help + exit 0 + ;; + *) + print_error "Unknown option: $1" + print_info "Use --help for usage information." + exit 1 + ;; + esac + done + + print_info "Fabric Shell Completions Setup" + print_info "===============================" + + if [ "$DRY_RUN" = true ]; then + print_info "DRY RUN MODE - Commands will be shown but not executed" + print_info "" + fi + + # Get script directory + script_dir="$(get_script_dir)" + + # Check if completion files exist + if [ ! -f "$script_dir/_fabric" ] || [ ! -f "$script_dir/fabric.bash" ] || [ ! -f "$script_dir/fabric.fish" ]; then + print_error "Completion files not found. Make sure you're running this script from the fabric completions directory." + print_error "Expected files:" + print_error " $script_dir/_fabric" + print_error " $script_dir/fabric.bash" + print_error " $script_dir/fabric.fish" + exit 1 + fi + + # Detect fabric command + fabric_cmd="$(detect_fabric_command)" + print_info "Detected fabric command: $fabric_cmd" + + # Detect shell + shell_name="$(detect_shell)" + print_info "Detected shell: $shell_name" + + # Setup completions based on shell + case "$shell_name" in + zsh) + setup_zsh_completions "$fabric_cmd" "$script_dir" + ;; + bash) + setup_bash_completions "$fabric_cmd" "$script_dir" + ;; + fish) + setup_fish_completions "$fabric_cmd" "$script_dir" + ;; + *) + setup_other_shell_completions "$fabric_cmd" "$shell_name" + ;; + esac + + if [ "$DRY_RUN" = true ]; then + print_success "Dry-run completed! The above commands would set up shell completions." + print_info "Run without --dry-run to actually install the completions." + else + print_success "Shell completion setup completed!" + print_info "You can now use tab completion with the '$fabric_cmd' command." + fi +} + +# Run main function +main "$@" diff --git a/docs/Shell-Completions.md b/docs/Shell-Completions.md new file mode 100644 index 00000000..7bfaee89 --- /dev/null +++ b/docs/Shell-Completions.md @@ -0,0 +1,124 @@ +# Shell Completions for Fabric + +Fabric comes with shell completion support for Zsh, Bash, and Fish shells. These completions provide intelligent tab-completion for commands, flags, patterns, models, contexts, and more. + +## Quick Setup (Automated) + +For a quick automated installation, use the setup script: + +```bash +# Run the automated setup script +./completions/setup-completions.sh + +# Or see what it would do first +./completions/setup-completions.sh --dry-run +``` + +The script will: + +- Detect whether you have `fabric` or `fabric-ai` installed +- Detect your current shell (zsh, bash, or fish) +- Use your existing `$fpath` directories (for zsh) or standard completion directories +- Install the completion file with the correct name +- Provide instructions for enabling the completions + +For manual installation or troubleshooting, see the detailed instructions below. + +## Manual Installation + +### Zsh + +1. Copy the completion file to a directory in your `$fpath`: + + ```bash + sudo cp completions/_fabric /usr/local/share/zsh/site-functions/ + ``` + +2. **Important**: If you installed fabric as `fabric-ai`, create a symlink so completions work: + + ```bash + sudo ln -s /usr/local/share/zsh/site-functions/_fabric /usr/local/share/zsh/site-functions/_fabric-ai + ``` + +3. Restart your shell or reload completions: + + ```bash + autoload -U compinit && compinit + ``` + +### Bash + +1. Copy the completion file to a standard completion directory: + + ```bash + # System-wide installation + sudo cp completions/fabric.bash /etc/bash_completion.d/ + + # Or user-specific installation + mkdir -p ~/.local/share/bash-completion/completions/ + cp completions/fabric.bash ~/.local/share/bash-completion/completions/fabric + ``` + +2. **Important**: If you installed fabric as `fabric-ai`, create a symlink: + + ```bash + # For system-wide installation + sudo ln -s /etc/bash_completion.d/fabric.bash /etc/bash_completion.d/fabric-ai.bash + + # Or for user-specific installation + ln -s ~/.local/share/bash-completion/completions/fabric ~/.local/share/bash-completion/completions/fabric-ai + ``` + +3. Restart your shell or source the completion: + + ```bash + source ~/.bashrc + ``` + +### Fish + +1. Copy the completion file to Fish's completion directory: + + ```bash + mkdir -p ~/.config/fish/completions + cp completions/fabric.fish ~/.config/fish/completions/ + ``` + +2. **Important**: If you installed fabric as `fabric-ai`, create a symlink: + + ```bash + ln -s ~/.config/fish/completions/fabric.fish ~/.config/fish/completions/fabric-ai.fish + ``` + +3. Fish will automatically load the completions (no restart needed). + +## Features + +The completions provide intelligent suggestions for: + +- **Patterns**: Tab-complete available patterns with `-p` or `--pattern` +- **Models**: Tab-complete available models with `-m` or `--model` +- **Contexts**: Tab-complete contexts for context-related flags +- **Sessions**: Tab-complete sessions for session-related flags +- **Strategies**: Tab-complete available strategies +- **Extensions**: Tab-complete registered extensions +- **Gemini Voices**: Tab-complete TTS voices for `--voice` +- **File paths**: Smart file completion for attachment, output, and config options +- **Flag completion**: All available command-line flags and options + +## Alternative Installation Method + +You can also source the completion files directly in your shell's configuration file: + +- **Zsh**: Add to `~/.zshrc`: `source /path/to/fabric/completions/_fabric` +- **Bash**: Add to `~/.bashrc`: `source /path/to/fabric/completions/fabric.bash` +- **Fish**: The file-based installation method above is preferred for Fish + +## Troubleshooting + +- If completions don't work, ensure the completion files have proper permissions +- For Zsh, verify that the completion directory is in your `$fpath` +- If you renamed the fabric binary, make sure to create the appropriate symlinks as described above +- Restart your shell after installation to ensure completions are loaded + +The completion system dynamically queries the fabric command for current patterns, models, and other resources, so your completions will always be up-to-date with your fabric installation.