> -----Original Message----- > From: git-owner@xxxxxxxxxxxxxxx > [mailto:git-owner@xxxxxxxxxxxxxxx] On Behalf Of Manlio Perillo > Sent: Friday, December 21, 2012 11:55 AM > To: git@xxxxxxxxxxxxxxx > Cc: szeder@xxxxxxxxxx; felipe.contreras@xxxxxxxxx; Manlio Perillo > Subject: [PATCH v4] git-completion.bash: add support for path > completion > > The git-completion.bash script did not implemented full, git aware, > support to complete paths, for git commands that operate on > files within > the current working directory or the index. I think this is a great improvement! Very nice. I've been playing with it but I'm not getting the expected behavior when I cd to a sub-directory. Instead I get all files in the repo as proposals. I'm trying it in the git git-repository itself. Here is a sample: > git status # On branch pu nothing to commit, working directory clean > source contrib/completion/git-completion.bash > touch contrib/test1 > touch contrib/test2 > git status # On branch pu # Untracked files: # (use "git add <file>..." to include in what will be committed) # # contrib/test1 # contrib/test2 nothing added to commit but untracked files present (use "git add" to track) > git add <TAB> # this works as expected and I get: contrib/test1 contrib/test2 > cd contrib/ > git add <TAB> Display all 387 possibilities? (y or n) # That is not right. Shouldn't I get # the same two files only? Maybe I mis-understood what should happen? Besides that, without looking at the patch in detail, I put just a couple of minor points below. > As an example: > > git add <TAB> > > will suggest all files in the current working directory, including > ignored files and files that have not been modified. > > Support path completion, for git commands where the > non-option arguments > always refer to paths within the current working directory or > the index, as the follow: s/as the follow/as follows/ > * the path completion for the "git rm" and "git ls-files" > commands will suggest all cached files. > > * the path completion for the "git add" command will suggest all > untracked and modified files. Ignored files are excluded. > > * the path completion for the "git clean" command will suggest all > untracked files. Ignored files are excluded. > > * the path completion for the "git mv" command will suggest all cached > files when expanding the first argument, and all untracked > and cached > files for subsequent arguments. In the latter case, empty > directories > are included and ignored files are excluded. > > * the path completion for the "git commit" command will suggest all > files that have been modified from the HEAD, if HEAD > exists, otherwise > it will suggest all cached files. > > For all affected commands, completion will always stop at directory > boundary. Only standard ignored files are excluded, using the > --exclude-standard option of the ls-files command. > > Signed-off-by: Manlio Perillo <manlio.perillo@xxxxxxxxx> > --- > > Changes from version 3: > > * Fixed quoting issues > * Fixed default parameters handling > * Fixed a typo in the commit message: the affected > command was ls-files, > not ls-tree. > * Fixed incorrect behavior when expanding a path in "git commit" > command, for a newly created repository (when HEAD does not > exists). > * Make sure to always execute git commands with stderr > redirected to > /dev/null. > * Improved path completion for the git mv command. > This required a small refactorization of the __git_index_files > function, in order to support multiple options for ls-files. > > contrib/completion/git-completion.bash | 140 > +++++++++++++++++++++++++++++---- > 1 file changed, 124 insertions(+), 16 deletions(-) > > diff --git a/contrib/completion/git-completion.bash > b/contrib/completion/git-completion.bash > index 0b77eb1..c8c6464 100644 > --- a/contrib/completion/git-completion.bash > +++ b/contrib/completion/git-completion.bash > @@ -13,6 +13,7 @@ > # *) .git/remotes file names > # *) git 'subcommands' > # *) tree paths within 'ref:path/to/file' expressions > +# *) file paths within current working directory and index > # *) common --long-options > # > # To use these routines: > @@ -233,6 +234,62 @@ __gitcomp_nl () > COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- > "${3-$cur}")) > } > > +# Process path list returned by "ls-files" and "diff-index > --name-only" > +# commands, in order to list only file names relative to a specified > +# directory, and append a slash to directory names. > +# It accepts 1 optional argument: a directory path. The > path must have > +# a trailing slash. > +__git_index_file_list_filter () > +{ > + local pfx="${1-}" offset=${#pfx} path > + > + while read -r path; do > + path="${path:$offset}" > + > + case "$path" in > + ?*/*) echo "${path%%/*}/" ;; > + *) echo $path ;; > + esac > + done > +} > + > +# __git_index_files accepts 1 or 2 arguments: > +# 1: Options to pass to ls-files (required). > +# Supported options are --cached, --modified, --deleted, --others, > +# and --directory. > +# 2: A directory path (optional). > +# If provided, only files within the specified directory > are listed. > +# Sub directories are never recursed. Path must have a trailing > +# slash. > +__git_index_files () > +{ > + local dir="$(__gitdir)" > + > + if [ -d "$dir" ]; then > + # NOTE: $1 is not quoted in order to support > multiple options > + git --git-dir="$dir" ls-files > --exclude-standard $1 ${2+"$2"} 2>/dev/null | > + __git_index_file_list_filter ${2+"$2"} | > + uniq Will the output piped to uniq always be sorted? It has to be. If it is not, you must use sort | uniq > + fi > +} > + > +# __git_diff_index_files accepts 1 or 2 arguments: > +# 1) The id of a tree object. > +# 2) A directory path (optional). > +# If provided, only files within the specified directory > are listed. > +# Sub directories are never recursed. Path must have a trailing > +# slash. > +__git_diff_index_files () > +{ > + local dir="$(__gitdir)" > + > + if [ -d "$dir" ]; then > + git --git-dir="$dir" diff-index --name-only > "$1" 2>/dev/null | > + __git_index_file_list_filter ${2+"$2"} | > + uniq Will the output piped to uniq always be sorted? It has to be. If it is not, you must use sort | uniq > + fi > +} > + > __git_heads () > { > local dir="$(__gitdir)" > @@ -430,6 +487,46 @@ __git_complete_revlist_file () > } > > > +# __git_complete_index_file requires 1 argument: the options > to pass to > +# ls-file > +__git_complete_index_file () > +{ > + local pfx cur_="$cur" > + > + case "$cur_" in > + ?*/*) > + pfx="${cur_%/*}" > + cur_="${cur_##*/}" > + pfx="${pfx}/" > + > + __gitcomp_nl "$(__git_index_files "$1" "$pfx")" > "$pfx" "$cur_" "" > + ;; > + *) > + __gitcomp_nl "$(__git_index_files "$1")" "" "$cur_" "" > + ;; > + esac > +} > + > +# __git_complete_diff_index_file requires 1 argument: the id > of a tree > +# object > +__git_complete_diff_index_file () > +{ > + local pfx cur_="$cur" > + > + case "$cur_" in > + ?*/*) > + pfx="${cur_%/*}" > + cur_="${cur_##*/}" > + pfx="${pfx}/" > + > + __gitcomp_nl "$(__git_diff_index_files "$1" > "$pfx")" "$pfx" "$cur_" "" > + ;; > + *) > + __gitcomp_nl "$(__git_diff_index_files "$1")" > "" "$cur_" "" > + ;; > + esac > +} > + > __git_complete_file () > { > __git_complete_revlist_file > @@ -770,8 +867,6 @@ _git_apply () > > _git_add () > { > - __git_has_doubledash && return > - > case "$cur" in > --*) > __gitcomp " > @@ -780,7 +875,9 @@ _git_add () > " > return > esac > - COMPREPLY=() > + > + # XXX should we check for --update and --all options ? > + __git_complete_index_file "--others --modified" > } > > _git_archive () > @@ -930,15 +1027,15 @@ _git_cherry_pick () > > _git_clean () > { > - __git_has_doubledash && return > - > case "$cur" in > --*) > __gitcomp "--dry-run --quiet" > return > ;; > esac > - COMPREPLY=() > + > + # XXX should we check for -x option ? > + __git_complete_index_file "--others" > } > > _git_clone () > @@ -969,8 +1066,6 @@ _git_clone () > > _git_commit () > { > - __git_has_doubledash && return > - > case "$cur" in > --cleanup=*) > __gitcomp "default strip verbatim whitespace > @@ -998,7 +1093,13 @@ _git_commit () > " > return > esac > - COMPREPLY=() > + > + if git rev-parse --verify --quiet HEAD 1>/dev/null; then > + __git_complete_diff_index_file "HEAD" > + else > + # This is the first commit > + __git_complete_index_file "--cached" > + fi > } > > _git_describe () > @@ -1216,8 +1317,6 @@ _git_init () > > _git_ls_files () > { > - __git_has_doubledash && return > - > case "$cur" in > --*) > __gitcomp "--cached --deleted --modified > --others --ignored > @@ -1230,7 +1329,10 @@ _git_ls_files () > return > ;; > esac > - COMPREPLY=() > + > + # XXX ignore options like --modified and always suggest > all cached > + # files. > + __git_complete_index_file "--cached" > } > > _git_ls_remote () > @@ -1362,7 +1464,14 @@ _git_mv () > return > ;; > esac > - COMPREPLY=() > + > + if [ $cword -gt 2 ]; then > + # We need to show both cached and untracked > files (including > + # empty directories) since this may not be the > last argument. > + __git_complete_index_file "--cached --others > --directory" > + else > + __git_complete_index_file "--cached" > + fi > } > > _git_name_rev () > @@ -2068,15 +2177,14 @@ _git_revert () > > _git_rm () > { > - __git_has_doubledash && return > - > case "$cur" in > --*) > __gitcomp "--cached --dry-run --ignore-unmatch --quiet" > return > ;; > esac > - COMPREPLY=() > + > + __git_complete_index_file "--cached" > } > > _git_shortlog () > -- > 1.8.1.rc1.18.g9db0d25 > > -- > To unsubscribe from this list: send the line "unsubscribe git" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html