refactor: extract _forgit_print_dim helper and improve worktree ops

- Extract dim formatting into _forgit_print_dim() to replace hardcoded
  ANSI sequences in _forgit_branch_list()
- Add empty state check and alt-l lock toggle reload for worktree delete
- Fix worktree path completion to handle paths with spaces using -z flag
- Add worktree command completion for bash and zsh
This commit is contained in:
Wenxuan Zhang 2026-03-09 10:41:11 +08:00 committed by Wenxuan
parent fc081846c0
commit 3b9ebce8bc
4 changed files with 36 additions and 6 deletions

View file

@ -31,6 +31,7 @@ $FORGIT_FZF_DEFAULT_OPTS
_forgit_warn() { printf "%b[Warn]%b %s\n" '\e[0;33m' '\e[0m' "$@" >&2; }
_forgit_info() { printf "%b[Info]%b %s\n" '\e[0;32m' '\e[0m' "$@" >&2; }
_forgit_print_dim() { printf "\e[90m%s\e[0m\n" "$*"; }
_forgit_inside_work_tree() { git rev-parse --is-inside-work-tree >/dev/null 2>&1; }
_forgit_inside_git_dir() { git rev-parse --is-inside-git-dir >/dev/null 2>&1; }
_forgit_inside_git_repo() { _forgit_inside_work_tree || _forgit_inside_git_dir; }
@ -166,9 +167,9 @@ _forgit_branch_list() {
local current
current=$(git branch --show-current)
if [[ -n "$current" ]]; then
printf '\e[90m%s\e[0m\n' "* $current"
_forgit_print_dim "* $current"
else
printf '\e[90m%s\e[0m\n' "* (HEAD detached at $(git rev-parse --short HEAD))"
_forgit_print_dim "* (HEAD detached at $(git rev-parse --short HEAD))"
fi
git branch --color=always "$@" | grep -v '^\*' | grep -v ' -> '
}
@ -1381,18 +1382,26 @@ _forgit_worktree_delete() {
local opts worktrees
[[ $# -ne 0 ]] && { _forgit_git_worktree_delete "$@"; return $?; }
local candidates
candidates=$(_forgit_worktree_list_deletable)
if [[ -z "$candidates" ]]; then
echo "Nothing to delete."
return 1
fi
opts="
$FORGIT_FZF_DEFAULT_OPTS
+s --multi --tiebreak=index
--preview=\"$FORGIT worktree_preview {}\"
--bind=\"ctrl-y:execute-silent($FORGIT worktree_yank_path {})\"
--bind=\"alt-l:execute-silent($FORGIT worktree_toggle_lock {})+reload($FORGIT worktree_list_deletable)\"
$FORGIT_WORKTREE_DELETE_FZF_OPTS
"
worktrees=()
while IFS='' read -r line; do
[[ -n "$line" ]] && worktrees+=("$(echo "$line" | _forgit_extract_worktree_path)")
done < <(_forgit_worktree_list_deletable | FZF_DEFAULT_OPTS="$opts" fzf)
done < <(echo "$candidates" | FZF_DEFAULT_OPTS="$opts" fzf)
[[ ${#worktrees[@]} -eq 0 ]] && return 1
@ -1511,6 +1520,7 @@ PRIVATE_COMMANDS=(
"worktree_yank_path"
"worktree_toggle_lock"
"worktree_list"
"worktree_list_deletable"
)
# Check if the script is being sourced. This is necessary for unit tests where

View file

@ -19,7 +19,12 @@ _git-stash-show() {
}
_git-worktrees() {
_alternative "worktrees:worktree:($(git worktree list --porcelain 2>/dev/null | grep '^worktree ' | cut -d' ' -f2-))"
local -a wt_list
local field
while IFS= read -r -d '' field; do
[[ "$field" == worktree\ * ]] && wt_list+=("${field#worktree }")
done < <(git worktree list --porcelain -z 2>/dev/null)
_alternative "worktrees:worktree:(${(@q)wt_list})"
}
# The completions for git already define a _git-diff completion function, but
@ -108,7 +113,7 @@ _git-forgit() {
squash) _git-log ;;
stash_show) _git-stash-show ;;
show) _git-show ;;
worktree) ;;
worktree) _git-worktree ;;
worktree_delete) _git-worktrees ;;
esac
}
@ -139,6 +144,7 @@ compdef _git-log forgit::reword
compdef _git-log forgit::squash
compdef _git-stash-show forgit::stash::show
compdef _git-show forgit::show
compdef _git-worktree forgit::worktree
compdef _git-worktrees forgit::worktree::delete
# this is the case of calling the command and pressing tab

View file

@ -37,7 +37,11 @@ _git_stash_show()
_git_worktrees()
{
__gitcomp_nl "$(__git worktree list --porcelain 2>/dev/null | grep '^worktree ' | cut -d' ' -f2-)"
local wt_list="" field
while IFS= read -r -d '' field; do
[[ "$field" == worktree\ * ]] && wt_list+="${field#worktree }"$'\n'
done < <(__git worktree list --porcelain -z 2>/dev/null)
__gitcomp_nl "$wt_list"
}
# Completion for git-forgit
@ -115,6 +119,7 @@ _git_forgit()
show) _git_show ;;
squash) _git_log ;;
stash_show) _git_stash_show ;;
worktree) _git_worktree ;;
worktree_delete) _git_worktrees ;;
esac
;;
@ -154,6 +159,7 @@ then
__git_complete forgit::show _git_show
__git_complete forgit::squash _git_log
__git_complete forgit::stash::show _git_stash_show
__git_complete forgit::worktree _git_worktree
__git_complete forgit::worktree::delete _git_worktrees
# Completion for forgit plugin shell aliases
@ -178,6 +184,7 @@ then
__git_complete "${forgit_show}" _git_show
__git_complete "${forgit_squash}" _git_log
__git_complete "${forgit_stash_show}" _git_stash_show
__git_complete "${forgit_worktree}" _git_worktree
__git_complete "${forgit_worktree_delete}" _git_worktrees
fi
fi

View file

@ -31,3 +31,10 @@ function test_checkout_tag_shows_message_when_no_tags() {
assert_same "Nothing to checkout: there are no tags." "$output"
}
function test_worktree_delete_shows_message_when_no_deletable_worktrees() {
output=$(_forgit_worktree_delete 2>&1)
assert_general_error
assert_same "Nothing to delete." "$output"
}