From 933df024b6357a504bddd5f375dc9b059801e164 Mon Sep 17 00:00:00 2001 From: Tom Elizaga Date: Tue, 10 Mar 2026 18:57:19 -0700 Subject: [PATCH 1/2] fix(completion): support Homebrew-installed assets --- README.md | 4 ++ docs/configuration.md | 2 + lib/commands/completion.sh | 65 +++++++++++++++++++--- lib/commands/help.sh | 13 +++-- tests/completion.bats | 108 +++++++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 tests/completion.bats diff --git a/README.md b/README.md index 2d8b57e..ee0e5e0 100644 --- a/README.md +++ b/README.md @@ -397,6 +397,10 @@ git gtr config set gtr.ui.color never ## Shell Completions (Optional) +Homebrew installs native Bash, Zsh, and Fish completion files automatically. +Use the commands below for manual setup when installing from source or when you +want to load completions explicitly. + ```bash # Bash (~/.bashrc) source <(git gtr completion bash) diff --git a/docs/configuration.md b/docs/configuration.md index feb59d6..fba6ea5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -364,6 +364,8 @@ The `NO_COLOR` environment variable ([no-color.org](https://no-color.org)) alway ## Shell Completions Enable tab completion using the built-in `completion` command. +Homebrew installs native Bash, Zsh, and Fish completion files automatically, so +manual setup is mainly for source installs or explicit shell configuration. ### Bash diff --git a/lib/commands/completion.sh b/lib/commands/completion.sh index 0ca04c9..ad1c42c 100644 --- a/lib/commands/completion.sh +++ b/lib/commands/completion.sh @@ -1,5 +1,45 @@ #!/usr/bin/env bash +# Resolve a completion asset from supported install layouts. +_completion_asset_path() { + local shell="$1" + shift + + local candidate + for candidate in "$@"; do + if [ -f "$candidate" ]; then + printf '%s\n' "$candidate" + return 0 + fi + done + + log_error "Could not find $shell completion asset under: $GTR_DIR" + log_info "Expected either a source checkout (completions/) or a Homebrew install layout." + return 1 +} + +_completion_bash_path() { + _completion_asset_path "bash" \ + "$GTR_DIR/completions/gtr.bash" \ + "$GTR_DIR/etc/bash_completion.d/git-gtr" +} + +_completion_zsh_path() { + _completion_asset_path "zsh" \ + "$GTR_DIR/completions/_git-gtr" \ + "$GTR_DIR/share/zsh/site-functions/_git-gtr" +} + +_completion_fish_path() { + _completion_asset_path "fish" \ + "$GTR_DIR/completions/git-gtr.fish" \ + "$GTR_DIR/share/fish/vendor_completions.d/git-gtr.fish" +} + +_completion_single_quote() { + printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")" +} + # Completion command (generate shell completions) cmd_completion() { if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then @@ -10,9 +50,15 @@ cmd_completion() { case "$shell" in bash) - cat "$GTR_DIR/completions/gtr.bash" + local bash_path + bash_path="$(_completion_bash_path)" || return 1 + cat "$bash_path" ;; zsh) + local zsh_path zsh_dir zsh_dir_quoted + zsh_path="$(_completion_zsh_path)" || return 1 + zsh_dir="$(dirname "$zsh_path")" + zsh_dir_quoted="$(_completion_single_quote "$zsh_dir")" # Output zstyle registration + completion loading # The zstyle MUST run before compinit to register gtr as a git subcommand cat < ~/.config/fish/completions/git-gtr.fish" return 0 ;; @@ -64,4 +115,4 @@ EOF return 1 ;; esac -} \ No newline at end of file +} diff --git a/lib/commands/help.sh b/lib/commands/help.sh index 75e881a..bbb3e60 100644 --- a/lib/commands/help.sh +++ b/lib/commands/help.sh @@ -326,14 +326,17 @@ shell configuration for tab completion of git gtr commands and options. Supported shells: bash, zsh, fish Setup: - # Bash (add to ~/.bashrc) - eval "$(git gtr completion bash)" + Homebrew installs native shell completions automatically. + + # Bash (manual setup, add to ~/.bashrc) + source <(git gtr completion bash) - # Zsh (add to ~/.zshrc BEFORE compinit) + # Zsh (manual setup, add to ~/.zshrc BEFORE compinit) eval "$(git gtr completion zsh)" - # Fish (symlink to completions dir) - ln -s /path/to/completions/git-gtr.fish ~/.config/fish/completions/ + # Fish (manual setup) + mkdir -p ~/.config/fish/completions + git gtr completion fish > ~/.config/fish/completions/git-gtr.fish EOF } diff --git a/tests/completion.bats b/tests/completion.bats new file mode 100644 index 0000000..fab9a0b --- /dev/null +++ b/tests/completion.bats @@ -0,0 +1,108 @@ +#!/usr/bin/env bats +# Tests for completion path resolution in lib/commands/completion.sh + +load test_helper + +log_error() { printf '%s\n' "$*" >&2; } +log_info() { printf '%s\n' "$*" >&2; } + +setup() { + TEST_GTR_DIR="$(mktemp -d)" + export GTR_DIR="$TEST_GTR_DIR" + # shellcheck disable=SC1091 + . "$PROJECT_ROOT/lib/commands/completion.sh" +} + +teardown() { + rm -rf "$TEST_GTR_DIR" +} + +write_test_file() { + local path="$1" content="$2" + mkdir -p "$(dirname "$path")" + printf '%s\n' "$content" > "$path" +} + +setup_source_layout() { + write_test_file "$TEST_GTR_DIR/completions/gtr.bash" "# source bash completion" + write_test_file "$TEST_GTR_DIR/completions/_git-gtr" "#compdef git-gtr" + write_test_file "$TEST_GTR_DIR/completions/git-gtr.fish" "# fish source completion" +} + +setup_homebrew_layout() { + write_test_file "$TEST_GTR_DIR/etc/bash_completion.d/git-gtr" "# brew bash completion" + write_test_file "$TEST_GTR_DIR/share/zsh/site-functions/_git-gtr" "#compdef git-gtr" + write_test_file "$TEST_GTR_DIR/share/fish/vendor_completions.d/git-gtr.fish" "# fish brew completion" +} + +@test "cmd_completion bash uses source checkout asset when present" { + setup_source_layout + + run cmd_completion bash + + [ "$status" -eq 0 ] + [ "$output" = "# source bash completion" ] +} + +@test "cmd_completion zsh uses source checkout completions directory when present" { + setup_source_layout + + run cmd_completion zsh + + [ "$status" -eq 0 ] + [[ "$output" == *"fpath=('$TEST_GTR_DIR/completions' \$fpath)"* ]] +} + +@test "cmd_completion fish uses source checkout asset when present" { + setup_source_layout + + run cmd_completion fish + + [ "$status" -eq 0 ] + [ "$output" = "# fish source completion" ] +} + +@test "cmd_completion bash falls back to Homebrew asset layout" { + setup_homebrew_layout + + run cmd_completion bash + + [ "$status" -eq 0 ] + [ "$output" = "# brew bash completion" ] +} + +@test "cmd_completion zsh falls back to Homebrew site-functions directory" { + setup_homebrew_layout + + run cmd_completion zsh + + [ "$status" -eq 0 ] + [[ "$output" == *"fpath=('$TEST_GTR_DIR/share/zsh/site-functions' \$fpath)"* ]] +} + +@test "cmd_completion fish falls back to Homebrew vendor completions" { + setup_homebrew_layout + + run cmd_completion fish + + [ "$status" -eq 0 ] + [ "$output" = "# fish brew completion" ] +} + +@test "cmd_completion prefers source checkout assets over Homebrew assets" { + setup_source_layout + setup_homebrew_layout + + run cmd_completion bash + + [ "$status" -eq 0 ] + [ "$output" = "# source bash completion" ] +} + +@test "cmd_completion returns a clear error when completion assets are missing" { + run cmd_completion bash + + [ "$status" -eq 1 ] + [[ "$output" == *"Could not find bash completion asset under:"* ]] + [[ "$output" == *"Expected either a source checkout (completions/) or a Homebrew install layout."* ]] +} From d81dee7fd154c3cf7ef84e8c8c784bab84e8981c Mon Sep 17 00:00:00 2001 From: Tom Elizaga Date: Tue, 10 Mar 2026 19:25:56 -0700 Subject: [PATCH 2/2] Address CodeRabbit review: fix error logging and test paths - Change log_info to log_error in completion failure path to avoid misleading success marker - Use paths with spaces in test fixtures to exercise zsh fpath quoting --- lib/commands/completion.sh | 2 +- tests/completion.bats | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/commands/completion.sh b/lib/commands/completion.sh index ad1c42c..3f32665 100644 --- a/lib/commands/completion.sh +++ b/lib/commands/completion.sh @@ -14,7 +14,7 @@ _completion_asset_path() { done log_error "Could not find $shell completion asset under: $GTR_DIR" - log_info "Expected either a source checkout (completions/) or a Homebrew install layout." + log_error "Expected either a source checkout (completions/) or a Homebrew install layout." return 1 } diff --git a/tests/completion.bats b/tests/completion.bats index fab9a0b..10ba672 100644 --- a/tests/completion.bats +++ b/tests/completion.bats @@ -7,14 +7,16 @@ log_error() { printf '%s\n' "$*" >&2; } log_info() { printf '%s\n' "$*" >&2; } setup() { - TEST_GTR_DIR="$(mktemp -d)" + TEST_ROOT="$(mktemp -d)" + TEST_GTR_DIR="$TEST_ROOT/prefix with spaces" + mkdir -p "$TEST_GTR_DIR" export GTR_DIR="$TEST_GTR_DIR" # shellcheck disable=SC1091 . "$PROJECT_ROOT/lib/commands/completion.sh" } teardown() { - rm -rf "$TEST_GTR_DIR" + rm -rf "$TEST_ROOT" } write_test_file() {