-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit-sync-completion.bash
More file actions
245 lines (226 loc) · 6.02 KB
/
git-sync-completion.bash
File metadata and controls
245 lines (226 loc) · 6.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#!/usr/bin/env bash
# Bash completion for git-sync.sh
# Copyright (C) 2026 Julien Cochuyt (https://github.com/JulienCochuyt)
# SPDX-License-Identifier: GPL-2.0-only
#
# Source this file to enable completion:
# source /path/to/git-sync-completion.bash
#
# To persist, add the above line to ~/.bashrc (Linux/macOS) or
# ~/.bash_profile (Git for Windows).
# If bash-completion is installed, you may also copy this file to its
# completions directory (e.g. /etc/bash_completion.d/ on Linux,
# $(brew --prefix)/etc/bash_completion.d/ on macOS with Homebrew).
_git_sync_remotes() {
if declare -f __git_remotes >/dev/null 2>&1; then
__git_remotes
else
git remote 2>/dev/null
fi
}
_git_sync_refs() {
local mode="$1"
if [[ "$mode" == "tags" ]]; then
if declare -f __git_tags >/dev/null 2>&1; then
__git_tags
else
git tag -l 2>/dev/null
fi
else
if declare -f __git_heads >/dev/null 2>&1; then
__git_heads
else
git for-each-ref --format='%(refname:short)' refs/heads/ 2>/dev/null
fi
fi
}
_git_sync_complete_subset() {
local cur_value="$1" subcommand="$2"
local categories="new missing different same behind ahead diverged unrelated unknown"
[[ "$subcommand" == "align" ]] && categories="new missing different behind ahead diverged unrelated unknown"
# Strip prefix already typed (everything up to and including the last comma)
local prefix="" stem="$cur_value"
if [[ "$cur_value" == *,* ]]; then
prefix="${cur_value%,*},"
stem="${cur_value##*,}"
fi
# Strip +/- prefix from stem
local sign=""
if [[ "$stem" == +* || "$stem" == -* ]]; then
sign="${stem:0:1}"
stem="${stem:1}"
fi
# Generate candidates with the sign prefix
local -a candidates=()
local cat
for cat in $categories; do
candidates+=("${sign}${cat}")
done
# Match candidates against the typed stem
if [[ -z "${sign}${stem}" ]]; then
# Empty input: return all candidates
COMPREPLY=("${candidates[@]}")
else
COMPREPLY=($(compgen -W "${candidates[*]}" -- "${sign}${stem}"))
fi
# Prepend the comma-separated prefix to each match
if [[ -n "$prefix" ]]; then
COMPREPLY=("${COMPREPLY[@]/#/$prefix}")
fi
}
_git_sync() {
local cur prev
local -a words
local cword
# Use _init_completion if available (bash-completion package),
# otherwise fall back to raw COMP_ variables.
if declare -f _init_completion >/dev/null 2>&1; then
_init_completion || return
else
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
words=("${COMP_WORDS[@]}")
cword=$COMP_CWORD
fi
# Handle '=' from COMP_WORDBREAKS splitting.
# Case 1: cursor is on "=" itself (prev is the option, cur is "=")
# Case 2: cursor is after "=" (prev is "=", cur is the typed value)
if [[ "$cur" == "=" ]]; then
prev="${prev}" # prev is already the option name
cur=""
elif [[ "$prev" == "=" ]]; then
prev="${words[cword-2]}"
fi
local subcommand=""
local has_tags=0
local positional_count=0
local i
# Find subcommand, check for --tags/-t, and count positional args
for ((i = 1; i < cword; i++)); do
case "${words[i]}" in
status|align)
if [[ -z "$subcommand" ]]; then
subcommand="${words[i]}"
else
((positional_count++))
fi
;;
-t|--tags)
has_tags=1
;;
-s|--subset|-i|--include|-x|--exclude|-I|--include-from|-X|--exclude-from|--on-failure)
# Skip the next word (option argument)
((i++))
;;
=)
# Skip '=' inserted by COMP_WORDBREAKS splitting
;;
-*)
# Check combined short opts for -t
if [[ "${words[i]}" =~ ^-[a-zA-Z]*t[a-zA-Z]*$ ]]; then
has_tags=1
fi
;;
*)
# Non-option, non-subcommand word = positional arg
if [[ -n "$subcommand" ]]; then
((positional_count++))
fi
;;
esac
done
# Determine ref mode for pattern completion
local ref_mode="branches"
((has_tags)) && ref_mode="tags"
# Handle option arguments
case "$prev" in
-s|--subset)
compopt -o nospace 2>/dev/null
_git_sync_complete_subset "$cur" "$subcommand"
return
;;
--on-failure)
compopt +o nospace 2>/dev/null
COMPREPLY=($(compgen -W "continue fail-fast interactive" -- "$cur"))
return
;;
-i|--include|-x|--exclude)
compopt +o nospace 2>/dev/null
COMPREPLY=($(compgen -W "$(_git_sync_refs "$ref_mode")" -- "$cur"))
return
;;
-I|--include-from|-X|--exclude-from)
compopt +o nospace 2>/dev/null
if declare -f _filedir >/dev/null 2>&1; then
_filedir
else
COMPREPLY=($(compgen -f -- "$cur"))
fi
return
;;
esac
# Complete options
if [[ "$cur" == -* ]]; then
compopt -o nospace 2>/dev/null
local -a opts=()
case "$subcommand" in
status)
opts=(
-h --help
-p --porcelain --name-only
-t --tags -a --annotated -A --lightweight
-s --subset=
-i --include= -I --include-from=
-x --exclude= -X --exclude-from=
)
;;
align)
opts=(
-h --help
-n --dry-run -v --verbose -y --yes
-t --tags -a --annotated -A --lightweight
-f --force -F --force-with-lease
-s --subset= --on-failure=
-i --include= -I --include-from=
-x --exclude= -X --exclude-from=
)
;;
*)
opts=(-h --help --version)
;;
esac
COMPREPLY=($(compgen -W "${opts[*]}" -- "$cur"))
# Append trailing space to completions that don't end with =
local j
for j in "${!COMPREPLY[@]}"; do
if [[ "${COMPREPLY[j]}" != *= ]]; then
COMPREPLY[j]="${COMPREPLY[j]} "
fi
done
return
fi
# Complete positional arguments
compopt +o nospace 2>/dev/null
if [[ -z "$subcommand" ]]; then
COMPREPLY=($(compgen -W "status align" -- "$cur"))
return
fi
# Limit positional args: status accepts 0-2, align requires exactly 2
local max_positional=2
if ((positional_count >= max_positional)); then
return
fi
# Positional args are remotes (with optional @ prefix)
local remotes
remotes=$(_git_sync_remotes)
if [[ "$cur" == @* ]]; then
# Prefix each remote with @
local at_remotes
at_remotes=$(printf "@%s\n" $remotes)
COMPREPLY=($(compgen -W "$at_remotes" -- "$cur"))
else
COMPREPLY=($(compgen -W "$remotes" -- "$cur"))
fi
}
complete -F _git_sync git-sync.sh
complete -F _git_sync git-sync