Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
65 changes: 58 additions & 7 deletions lib/commands/completion.sh
Original file line number Diff line number Diff line change
@@ -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_error "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
Expand All @@ -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 <<EOF
Expand All @@ -25,7 +71,7 @@ cmd_completion() {
zstyle ':completion:*:*:git:*' user-commands gtr:'Git worktree management'

# Add completions to fpath and initialize
fpath=($GTR_DIR/completions \$fpath)
fpath=($zsh_dir_quoted \$fpath)

# Note: If you already have compinit in your .zshrc, you may want to
# source this file before your existing compinit call and remove the
Expand All @@ -34,7 +80,9 @@ autoload -Uz compinit && compinit -C
EOF
;;
fish)
cat "$GTR_DIR/completions/git-gtr.fish"
local fish_path
fish_path="$(_completion_fish_path)" || return 1
cat "$fish_path"
;;
""|--help|-h)
echo "Generate shell completions for git gtr"
Expand All @@ -46,14 +94,17 @@ EOF
echo " zsh Generate Zsh completions"
echo " fish Generate Fish completions"
echo ""
echo "Homebrew installs native shell completions automatically."
echo ""
echo "Examples:"
echo " # Bash: add to ~/.bashrc"
echo " # Bash: manual setup (~/.bashrc)"
echo " source <(git gtr completion bash)"
echo ""
echo " # Zsh: add to ~/.zshrc (BEFORE any existing compinit call)"
echo " # Zsh: manual setup (~/.zshrc, BEFORE any existing compinit call)"
echo " eval \"\$(git gtr completion zsh)\""
echo ""
echo " # Fish: save to completions directory"
echo " # Fish: manual setup"
echo " mkdir -p ~/.config/fish/completions"
echo " git gtr completion fish > ~/.config/fish/completions/git-gtr.fish"
return 0
;;
Expand All @@ -64,4 +115,4 @@ EOF
return 1
;;
esac
}
}
13 changes: 8 additions & 5 deletions lib/commands/help.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
110 changes: 110 additions & 0 deletions tests/completion.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/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_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_ROOT"
}

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."* ]]
}
Loading