@@ -3084,19 +3084,127 @@ __gitcomp_directories ()
3084
3084
COMPREPLY+=(" $c /" )
3085
3085
_found=1
3086
3086
fi
3087
- done < <( git ls-tree -z -d --name-only HEAD $_tmp_dir )
3087
+ done < <( __git ls-tree -z -d --name-only HEAD $_tmp_dir )
3088
3088
3089
3089
if [[ $_found == 0 ]] && [[ " $cur " =~ /$ ]]; then
3090
3090
# No possible further completions any deeper, so assume we're at
3091
3091
# a leaf directory and just consider it complete
3092
3092
__gitcomp_direct_append " $cur "
3093
+ elif [[ $_found == 0 ]]; then
3094
+ # No possible completions found. Avoid falling back to
3095
+ # bash's default file and directory completion, because all
3096
+ # valid completions have already been searched and the
3097
+ # fallbacks can do nothing but mislead. In fact, they can
3098
+ # mislead in three different ways:
3099
+ # 1) Fallback file completion makes no sense when asking
3100
+ # for directory completions, as this function does.
3101
+ # 2) Fallback directory completion is bad because
3102
+ # e.g. "/pro" is invalid and should NOT complete to
3103
+ # "/proc".
3104
+ # 3) Fallback file/directory completion only completes
3105
+ # on paths that exist in the current working tree,
3106
+ # i.e. which are *already* part of their
3107
+ # sparse-checkout. Thus, normal file and directory
3108
+ # completion is always useless for "git
3109
+ # sparse-checkout add" and is also probelmatic for
3110
+ # "git sparse-checkout set" unless using it to
3111
+ # strictly narrow the checkout.
3112
+ COMPREPLY=( " " )
3113
+ fi
3114
+ }
3115
+
3116
+ # In non-cone mode, the arguments to {set,add} are supposed to be
3117
+ # patterns, relative to the toplevel directory. These can be any kind
3118
+ # of general pattern, like 'subdir/*.c' and we can't complete on all
3119
+ # of those. However, if the user presses Tab to get tab completion, we
3120
+ # presume that they are trying to provide a pattern that names a specific
3121
+ # path.
3122
+ __gitcomp_slash_leading_paths ()
3123
+ {
3124
+ local dequoted_word pfx=" " cur_ toplevel
3125
+
3126
+ # Since we are dealing with a sparse-checkout, subdirectories may not
3127
+ # exist in the local working copy. Therefore, we want to run all
3128
+ # ls-files commands relative to the repository toplevel.
3129
+ toplevel=" $( git rev-parse --show-toplevel) /"
3130
+
3131
+ __git_dequote " $cur "
3132
+
3133
+ # If the paths provided by the user already start with '/', then
3134
+ # they are considered relative to the toplevel of the repository
3135
+ # already. If they do not start with /, then we need to adjust
3136
+ # them to start with the appropriate prefix.
3137
+ case " $cur " in
3138
+ /* )
3139
+ cur=" ${cur: 1} "
3140
+ ;;
3141
+ * )
3142
+ pfx=" $( __git rev-parse --show-prefix) "
3143
+ esac
3144
+
3145
+ # Since sparse-index is limited to cone-mode, in non-cone-mode the
3146
+ # list of valid paths is precisely the cached files in the index.
3147
+ #
3148
+ # NEEDSWORK:
3149
+ # 1) We probably need to take care of cases where ls-files
3150
+ # responds with special quoting.
3151
+ # 2) We probably need to take care of cases where ${cur} has
3152
+ # some kind of special quoting.
3153
+ # 3) On top of any quoting from 1 & 2, we have to provide an extra
3154
+ # level of quoting for any paths that contain a '*', '?', '\',
3155
+ # '[', ']', or leading '#' or '!' since those will be
3156
+ # interpreted by sparse-checkout as something other than a
3157
+ # literal path character.
3158
+ # Since there are two types of quoting here, this might get really
3159
+ # complex. For now, just punt on all of this...
3160
+ completions=" $( __git -C " ${toplevel} " -c core.quotePath=false \
3161
+ ls-files --cached -- " ${pfx}${cur} *" \
3162
+ | sed -e s%^%/% -e ' s%$% %' ) "
3163
+ # Note, above, though that we needed all of the completions to be
3164
+ # prefixed with a '/', and we want to add a space so that bash
3165
+ # completion will actually complete an entry and let us move on to
3166
+ # the next one.
3167
+
3168
+ # Return what we've found.
3169
+ if test -n " $completions " ; then
3170
+ # We found some completions; return them
3171
+ local IFS=$' \n '
3172
+ COMPREPLY=($completions )
3173
+ else
3174
+ # Do NOT fall back to bash-style all-local-files-and-dirs
3175
+ # when we find no match. Such options are worse than
3176
+ # useless:
3177
+ # 1. "git sparse-checkout add" needs paths that are NOT
3178
+ # currently in the working copy. "git
3179
+ # sparse-checkout set" does as well, except in the
3180
+ # special cases when users are only trying to narrow
3181
+ # their sparse checkout to a subset of what they
3182
+ # already have.
3183
+ #
3184
+ # 2. A path like '.config' is ambiguous as to whether
3185
+ # the user wants all '.config' files throughout the
3186
+ # tree, or just the one under the current directory.
3187
+ # It would result in a warning from the
3188
+ # sparse-checkout command due to this. As such, all
3189
+ # completions of paths should be prefixed with a
3190
+ # '/'.
3191
+ #
3192
+ # 3. We don't want paths prefixed with a '/' to
3193
+ # complete files in the system root directory, we
3194
+ # want it to complete on files relative to the
3195
+ # repository root.
3196
+ #
3197
+ # As such, make sure that NO completions are offered rather
3198
+ # than falling back to bash's default completions.
3199
+ COMPREPLY=( " " )
3093
3200
fi
3094
3201
}
3095
3202
3096
3203
_git_sparse_checkout ()
3097
3204
{
3098
3205
local subcommands=" list init set disable add reapply"
3099
3206
local subcommand=" $( __git_find_on_cmdline " $subcommands " ) "
3207
+ local using_cone=true
3100
3208
if [ -z " $subcommand " ]; then
3101
3209
__gitcomp " $subcommands "
3102
3210
return
@@ -3107,9 +3215,18 @@ _git_sparse_checkout ()
3107
3215
__gitcomp_builtin sparse-checkout_$subcommand " " " --"
3108
3216
;;
3109
3217
set,* |add,* )
3110
- if [ " $( __git config core.sparseCheckoutCone) " == " true" ] ||
3111
- [ -n " $( __git_find_on_cmdline --cone) " ]; then
3218
+ if [[ " $( __git config core.sparseCheckout) " == " true" &&
3219
+ " $( __git config core.sparseCheckoutCone) " == " false" &&
3220
+ -z " $( __git_find_on_cmdline --cone) " ]]; then
3221
+ using_cone=false
3222
+ fi
3223
+ if [[ -n " $( __git_find_on_cmdline --no-cone) " ]]; then
3224
+ using_cone=false
3225
+ fi
3226
+ if [[ " $using_cone " == " true" ]]; then
3112
3227
__gitcomp_directories
3228
+ else
3229
+ __gitcomp_slash_leading_paths
3113
3230
fi
3114
3231
esac
3115
3232
}
0 commit comments