13
13
# *) .git/remotes file names
14
14
# *) git 'subcommands'
15
15
# *) tree paths within 'ref:path/to/file' expressions
16
+ # *) file paths within current working directory and index
16
17
# *) common --long-options
17
18
#
18
19
# To use these routines:
@@ -233,6 +234,118 @@ __gitcomp_nl ()
233
234
COMPREPLY=($( compgen -P " ${2-} " -S " ${4- } " -W " $1 " -- " ${3-$cur } " ) )
234
235
}
235
236
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
+
236
349
__git_heads ()
237
350
{
238
351
local dir=" $( __gitdir) "
@@ -430,6 +543,46 @@ __git_complete_revlist_file ()
430
543
}
431
544
432
545
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
+
433
586
__git_complete_file ()
434
587
{
435
588
__git_complete_revlist_file
@@ -722,6 +875,43 @@ __git_has_doubledash ()
722
875
return 1
723
876
}
724
877
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
+
725
915
__git_whitespacelist=" nowarn warn error error-all fix"
726
916
727
917
_git_am ()
@@ -770,8 +960,6 @@ _git_apply ()
770
960
771
961
_git_add ()
772
962
{
773
- __git_has_doubledash && return
774
-
775
963
case " $cur " in
776
964
--* )
777
965
__gitcomp "
@@ -780,7 +968,9 @@ _git_add ()
780
968
"
781
969
return
782
970
esac
783
- COMPREPLY=()
971
+
972
+ # XXX should we check for --update and --all options ?
973
+ __git_complete_index_file " --others --modified"
784
974
}
785
975
786
976
_git_archive ()
@@ -930,15 +1120,15 @@ _git_cherry_pick ()
930
1120
931
1121
_git_clean ()
932
1122
{
933
- __git_has_doubledash && return
934
-
935
1123
case " $cur " in
936
1124
--* )
937
1125
__gitcomp " --dry-run --quiet"
938
1126
return
939
1127
;;
940
1128
esac
941
- COMPREPLY=()
1129
+
1130
+ # XXX should we check for -x option ?
1131
+ __git_complete_index_file " --others"
942
1132
}
943
1133
944
1134
_git_clone ()
@@ -969,7 +1159,12 @@ _git_clone ()
969
1159
970
1160
_git_commit ()
971
1161
{
972
- __git_has_doubledash && return
1162
+ case " $prev " in
1163
+ -c|-C)
1164
+ __gitcomp_nl " $( __git_refs) " " " " ${cur} "
1165
+ return
1166
+ ;;
1167
+ esac
973
1168
974
1169
case " $cur " in
975
1170
--cleanup=* )
@@ -998,7 +1193,13 @@ _git_commit ()
998
1193
"
999
1194
return
1000
1195
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
1002
1203
}
1003
1204
1004
1205
_git_describe ()
@@ -1216,8 +1417,6 @@ _git_init ()
1216
1417
1217
1418
_git_ls_files ()
1218
1419
{
1219
- __git_has_doubledash && return
1220
-
1221
1420
case " $cur " in
1222
1421
--* )
1223
1422
__gitcomp " --cached --deleted --modified --others --ignored
@@ -1230,7 +1429,10 @@ _git_ls_files ()
1230
1429
return
1231
1430
;;
1232
1431
esac
1233
- COMPREPLY=()
1432
+
1433
+ # XXX ignore options like --modified and always suggest all cached
1434
+ # files.
1435
+ __git_complete_index_file " --cached"
1234
1436
}
1235
1437
1236
1438
_git_ls_remote ()
@@ -1362,7 +1564,14 @@ _git_mv ()
1362
1564
return
1363
1565
;;
1364
1566
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
1366
1575
}
1367
1576
1368
1577
_git_name_rev ()
@@ -2068,15 +2277,14 @@ _git_revert ()
2068
2277
2069
2278
_git_rm ()
2070
2279
{
2071
- __git_has_doubledash && return
2072
-
2073
2280
case " $cur " in
2074
2281
--* )
2075
2282
__gitcomp " --cached --dry-run --ignore-unmatch --quiet"
2076
2283
return
2077
2284
;;
2078
2285
esac
2079
- COMPREPLY=()
2286
+
2287
+ __git_complete_index_file " --cached"
2080
2288
}
2081
2289
2082
2290
_git_shortlog ()
@@ -2441,6 +2649,15 @@ if [[ -n ${ZSH_VERSION-} ]]; then
2441
2649
compadd -Q -S " ${4- } " -p " ${2-} " -- ${=1} && _ret=0
2442
2650
}
2443
2651
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
+
2444
2661
__git_zsh_helper ()
2445
2662
{
2446
2663
emulate -L ksh
@@ -2462,6 +2679,14 @@ if [[ -n ${ZSH_VERSION-} ]]; then
2462
2679
2463
2680
compdef _git git gitk
2464
2681
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
2465
2690
fi
2466
2691
2467
2692
__git_func_wrap ()
0 commit comments