1313# *) .git/remotes file names
1414# *) git 'subcommands'
1515# *) tree paths within 'ref:path/to/file' expressions
16+ # *) file paths within current working directory and index
1617# *) common --long-options
1718#
1819# To use these routines:
@@ -233,6 +234,118 @@ __gitcomp_nl ()
233234 COMPREPLY=($( compgen -P " ${2-} " -S " ${4- } " -W " $1 " -- " ${3-$cur } " ) )
234235}
235236
237+ # Generates completion reply with compgen from newline-separated possible
238+ # completion filenames.
239+ # It accepts 1 to 3 arguments:
240+ # 1: List of possible completion filenames, separated by a single newline.
241+ # 2: A directory prefix to be added to each possible completion filename
242+ # (optional).
243+ # 3: Generate possible completion matches for this word (optional).
244+ __gitcomp_file ()
245+ {
246+ local IFS=$' \n '
247+
248+ # XXX does not work when the directory prefix contains a tilde,
249+ # since tilde expansion is not applied.
250+ # This means that COMPREPLY will be empty and Bash default
251+ # completion will be used.
252+ COMPREPLY=($( compgen -P " ${2-} " -W " $1 " -- " ${3-$cur } " ) )
253+
254+ # Tell Bash that compspec generates filenames.
255+ compopt -o filenames 2> /dev/null
256+ }
257+
258+ __git_index_file_list_filter_compat ()
259+ {
260+ local path
261+
262+ while read -r path; do
263+ case " $path " in
264+ ?* /* ) echo " ${path%%/* } /" ;;
265+ * ) echo " $path " ;;
266+ esac
267+ done
268+ }
269+
270+ __git_index_file_list_filter_bash ()
271+ {
272+ local path
273+
274+ while read -r path; do
275+ case " $path " in
276+ ?* /* )
277+ # XXX if we append a slash to directory names when using
278+ # `compopt -o filenames`, Bash will append another slash.
279+ # This is pretty stupid, and this the reason why we have to
280+ # define a compatible version for this function.
281+ echo " ${path%%/* } " ;;
282+ * )
283+ echo " $path " ;;
284+ esac
285+ done
286+ }
287+
288+ # Process path list returned by "ls-files" and "diff-index --name-only"
289+ # commands, in order to list only file names relative to a specified
290+ # directory, and append a slash to directory names.
291+ __git_index_file_list_filter ()
292+ {
293+ # Default to Bash >= 4.x
294+ __git_index_file_list_filter_bash
295+ }
296+
297+ # Execute git ls-files, returning paths relative to the directory
298+ # specified in the first argument, and using the options specified in
299+ # the second argument.
300+ __git_ls_files_helper ()
301+ {
302+ # NOTE: $2 is not quoted in order to support multiple options
303+ cd " $1 " && git ls-files --exclude-standard $2
304+ } 2> /dev/null
305+
306+
307+ # Execute git diff-index, returning paths relative to the directory
308+ # specified in the first argument, and using the tree object id
309+ # specified in the second argument.
310+ __git_diff_index_helper ()
311+ {
312+ cd " $1 " && git diff-index --name-only --relative " $2 "
313+ } 2> /dev/null
314+
315+ # __git_index_files accepts 1 or 2 arguments:
316+ # 1: Options to pass to ls-files (required).
317+ # Supported options are --cached, --modified, --deleted, --others,
318+ # and --directory.
319+ # 2: A directory path (optional).
320+ # If provided, only files within the specified directory are listed.
321+ # Sub directories are never recursed. Path must have a trailing
322+ # slash.
323+ __git_index_files ()
324+ {
325+ local dir=" $( __gitdir) " root=" ${2-.} "
326+
327+ if [ -d " $dir " ]; then
328+ __git_ls_files_helper " $root " " $1 " | __git_index_file_list_filter |
329+ sort | uniq
330+ fi
331+ }
332+
333+ # __git_diff_index_files accepts 1 or 2 arguments:
334+ # 1) The id of a tree object.
335+ # 2) A directory path (optional).
336+ # If provided, only files within the specified directory are listed.
337+ # Sub directories are never recursed. Path must have a trailing
338+ # slash.
339+ __git_diff_index_files ()
340+ {
341+ local dir=" $( __gitdir) " root=" ${2-.} "
342+
343+ if [ -d " $dir " ]; then
344+ __git_diff_index_helper " $root " " $1 " | __git_index_file_list_filter |
345+ sort | uniq
346+ fi
347+ }
348+
236349__git_heads ()
237350{
238351 local dir=" $( __gitdir) "
@@ -430,6 +543,46 @@ __git_complete_revlist_file ()
430543}
431544
432545
546+ # __git_complete_index_file requires 1 argument: the options to pass to
547+ # ls-file
548+ __git_complete_index_file ()
549+ {
550+ local pfx cur_=" $cur "
551+
552+ case " $cur_ " in
553+ ?* /* )
554+ pfx=" ${cur_%/* } "
555+ cur_=" ${cur_##*/ } "
556+ pfx=" ${pfx} /"
557+
558+ __gitcomp_file " $( __git_index_files " $1 " " $pfx " ) " " $pfx " " $cur_ "
559+ ;;
560+ * )
561+ __gitcomp_file " $( __git_index_files " $1 " ) " " " " $cur_ "
562+ ;;
563+ esac
564+ }
565+
566+ # __git_complete_diff_index_file requires 1 argument: the id of a tree
567+ # object
568+ __git_complete_diff_index_file ()
569+ {
570+ local pfx cur_=" $cur "
571+
572+ case " $cur_ " in
573+ ?* /* )
574+ pfx=" ${cur_%/* } "
575+ cur_=" ${cur_##*/ } "
576+ pfx=" ${pfx} /"
577+
578+ __gitcomp_file " $( __git_diff_index_files " $1 " " $pfx " ) " " $pfx " " $cur_ "
579+ ;;
580+ * )
581+ __gitcomp_file " $( __git_diff_index_files " $1 " ) " " " " $cur_ "
582+ ;;
583+ esac
584+ }
585+
433586__git_complete_file ()
434587{
435588 __git_complete_revlist_file
@@ -722,6 +875,43 @@ __git_has_doubledash ()
722875 return 1
723876}
724877
878+ # Try to count non option arguments passed on the command line for the
879+ # specified git command.
880+ # When options are used, it is necessary to use the special -- option to
881+ # tell the implementation were non option arguments begin.
882+ # XXX this can not be improved, since options can appear everywhere, as
883+ # an example:
884+ # git mv x -n y
885+ #
886+ # __git_count_arguments requires 1 argument: the git command executed.
887+ __git_count_arguments ()
888+ {
889+ local word i c=0
890+
891+ # Skip "git" (first argument)
892+ for (( i= 1 ; i < ${# words[@]} ; i++ )) ; do
893+ word=" ${words[i]} "
894+
895+ case " $word " in
896+ --)
897+ # Good; we can assume that the following are only non
898+ # option arguments.
899+ (( c = 0 ))
900+ ;;
901+ " $1 " )
902+ # Skip the specified git command and discard git
903+ # main options
904+ (( c = 0 ))
905+ ;;
906+ ?* )
907+ (( c++ ))
908+ ;;
909+ esac
910+ done
911+
912+ printf " %d" $c
913+ }
914+
725915__git_whitespacelist=" nowarn warn error error-all fix"
726916
727917_git_am ()
@@ -770,8 +960,6 @@ _git_apply ()
770960
771961_git_add ()
772962{
773- __git_has_doubledash && return
774-
775963 case " $cur " in
776964 --* )
777965 __gitcomp "
@@ -780,7 +968,9 @@ _git_add ()
780968 "
781969 return
782970 esac
783- COMPREPLY=()
971+
972+ # XXX should we check for --update and --all options ?
973+ __git_complete_index_file " --others --modified"
784974}
785975
786976_git_archive ()
@@ -930,15 +1120,15 @@ _git_cherry_pick ()
9301120
9311121_git_clean ()
9321122{
933- __git_has_doubledash && return
934-
9351123 case " $cur " in
9361124 --* )
9371125 __gitcomp " --dry-run --quiet"
9381126 return
9391127 ;;
9401128 esac
941- COMPREPLY=()
1129+
1130+ # XXX should we check for -x option ?
1131+ __git_complete_index_file " --others"
9421132}
9431133
9441134_git_clone ()
@@ -969,7 +1159,12 @@ _git_clone ()
9691159
9701160_git_commit ()
9711161{
972- __git_has_doubledash && return
1162+ case " $prev " in
1163+ -c|-C)
1164+ __gitcomp_nl " $( __git_refs) " " " " ${cur} "
1165+ return
1166+ ;;
1167+ esac
9731168
9741169 case " $cur " in
9751170 --cleanup=* )
@@ -998,7 +1193,13 @@ _git_commit ()
9981193 "
9991194 return
10001195 esac
1001- COMPREPLY=()
1196+
1197+ if git rev-parse --verify --quiet HEAD > /dev/null; then
1198+ __git_complete_diff_index_file " HEAD"
1199+ else
1200+ # This is the first commit
1201+ __git_complete_index_file " --cached"
1202+ fi
10021203}
10031204
10041205_git_describe ()
@@ -1216,8 +1417,6 @@ _git_init ()
12161417
12171418_git_ls_files ()
12181419{
1219- __git_has_doubledash && return
1220-
12211420 case " $cur " in
12221421 --* )
12231422 __gitcomp " --cached --deleted --modified --others --ignored
@@ -1230,7 +1429,10 @@ _git_ls_files ()
12301429 return
12311430 ;;
12321431 esac
1233- COMPREPLY=()
1432+
1433+ # XXX ignore options like --modified and always suggest all cached
1434+ # files.
1435+ __git_complete_index_file " --cached"
12341436}
12351437
12361438_git_ls_remote ()
@@ -1362,7 +1564,14 @@ _git_mv ()
13621564 return
13631565 ;;
13641566 esac
1365- COMPREPLY=()
1567+
1568+ if [ $( __git_count_arguments " mv" ) -gt 0 ]; then
1569+ # We need to show both cached and untracked files (including
1570+ # empty directories) since this may not be the last argument.
1571+ __git_complete_index_file " --cached --others --directory"
1572+ else
1573+ __git_complete_index_file " --cached"
1574+ fi
13661575}
13671576
13681577_git_name_rev ()
@@ -2068,15 +2277,14 @@ _git_revert ()
20682277
20692278_git_rm ()
20702279{
2071- __git_has_doubledash && return
2072-
20732280 case " $cur " in
20742281 --* )
20752282 __gitcomp " --cached --dry-run --ignore-unmatch --quiet"
20762283 return
20772284 ;;
20782285 esac
2079- COMPREPLY=()
2286+
2287+ __git_complete_index_file " --cached"
20802288}
20812289
20822290_git_shortlog ()
@@ -2441,6 +2649,15 @@ if [[ -n ${ZSH_VERSION-} ]]; then
24412649 compadd -Q -S " ${4- } " -p " ${2-} " -- ${=1} && _ret=0
24422650 }
24432651
2652+ __gitcomp_file ()
2653+ {
2654+ emulate -L zsh
2655+
2656+ local IFS=$' \n '
2657+ compset -P ' *[=:]'
2658+ compadd -Q -p " ${2-} " -f -- ${=1} && _ret=0
2659+ }
2660+
24442661 __git_zsh_helper ()
24452662 {
24462663 emulate -L ksh
@@ -2462,6 +2679,14 @@ if [[ -n ${ZSH_VERSION-} ]]; then
24622679
24632680 compdef _git git gitk
24642681 return
2682+ elif [[ -n ${BASH_VERSION-} ]]; then
2683+ if (( ${BASH_VERSINFO[0]} < 4 )) ; then
2684+ # compopt is not supported
2685+ __git_index_file_list_filter ()
2686+ {
2687+ __git_index_file_list_filter_compat
2688+ }
2689+ fi
24652690fi
24662691
24672692__git_func_wrap ()
0 commit comments