summaryrefslogtreecommitdiff
path: root/contrib/completion/git-completion.zsh
AgeCommit message (Collapse)AuthorFilesLines
2018-04-17completion: fill COMPREPLY directly when completing pathsLibravatar SZEDER Gábor1-0/+9
During git-aware path completion, when a lot of path components have to be listed, a significant amount of time is spent in __gitcomp_file(), or more accurately in the shell loop of __gitcompappend(), iterating over all the path components filtering path components matching the current word to be completed, adding prefix path components, and placing the resulting matching paths into the COMPREPLY array. Now, a previous patch in this series made 'git ls-files' and 'git diff-index' list only paths matching the current word to be completed, so an additional filtering in __gitcomp_file() is not necessary anymore. Adding the prefix path components could be done much more efficiently in __git_index_files()'s 'awk' script while stripping trailing path components and removing duplicates and quoting. And then the resulting paths won't require any more filtering or processing before being handed over to Bash, so we could fill the COMPREPLY array directly. Unfortunately, we can't simply use the __gitcomp_direct() helper function to do that, because __gitcomp_file() does one additional thing: it tells Bash that we are doing filename completion, so the shell will kindly do four important things for us: 1. Append a trailing space to all filenames. 2. Append a trailing '/' to all directory names. 3. Escape any meta, globbing, separator, etc. characters. 4. List only the current path component when listing possible completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2', etc. instead of the whole 'dir/subdir/file1', 'dir/subdir/file2'). While we could let __git_index_files()'s 'awk' script take care of the first two points, the third one gets tricky, and we absolutely need the shell's support for the fourth. Add the helper function __gitcomp_file_direct(), which, just like __gitcomp_direct(), fills the COMPREPLY array with prefiltered and preprocessed paths without any additional processing, without a shell loop, with just one single compound assignment, and, similar to __gitcomp_file(), tells Bash and ZSH that we are doing filename completion. Extend __git_index_files()'s 'awk' script a bit to prepend any prefix path components to all listed paths. Finally, modify __git_complete_index_file() to feed __git_index_files()'s output to ___gitcomp_file_direct() instead of __gitcomp_file(). After this patch there is no shell loop left in the path completion code path. This speeds up path completion when there are a lot of paths matching the current word to be completed. In a pathological repository with 100k files in a single directory, listing all those files: Before this patch, best of five, using GNU awk on Linux: $ time cur=dir/ __git_complete_index_file real 0m0.983s user 0m1.004s sys 0m0.033s After: real 0m0.313s user 0m0.341s sys 0m0.029s Difference: -68.2% Speedup: 3.1x To see the benefits of the whole patch series, the same command with v2.17.0: real 0m2.736s user 0m2.472s sys 0m0.610s Difference: -88.6% Speedup: 8.7x Note that this patch changes the output of the __git_index_files() helper function by unconditionally prepending the prefix path components to every listed path. This would break users' completion scriptlets that directly run: __gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_" because that would add the prefix path components once more. However, __git_index_files() is kind of a "helper function of a helper function", and users' completion scriptlets should have been using __git_complete_index_file() for git-aware path completion in the first place, so this is likely doesn't worth worrying about. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23completion: fill COMPREPLY directly when completing refsLibravatar SZEDER Gábor1-0/+9
__gitcomp_nl() iterates over all the possible completion words it gets as argument - filtering matching words, - appending a trailing space to each matching word (in all but two cases), - prepending a prefix to each matching word (when completing words after e.g. '--option=<TAB>' or 'master..<TAB>'), and - adding each matching word to the COMPREPLY array. This takes a while when a lot of refs are passed to __gitcomp_nl(). The previous changes in this series ensure that __git_refs() lists only refs matching the current word to be completed, making a second filtering in __gitcomp_nl() redundant. Adding the necessary prefix and suffix could be done in __git_refs() as well: - When refs come from 'git for-each-ref', then that prefix and suffix could be added much more efficiently using a 'git for-each-ref' format containing said prefix and suffix. Care should be taken, though, because that prefix might contain 'for-each-ref' format specifiers as part of the left hand side of a '..' range or '...' symmetric difference notation or fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'. Doubling every '%' in the prefix will prevent 'git for-each-ref' from interpolating any of those contained specifiers. - When refs come from 'git ls-remote', then that prefix and suffix can be added in the shell loop that has to process 'git ls-remote's output anyway. - Finally, the prefix and suffix can be added to that handful of potentially matching symbolic and pseudo refs right away in the shell loop listing them. And then all what is still left to do is to assign a bunch of newline-separated words to a shell array, which can be done without a shell loop iterating over each word, basically making all of __gitcomp_nl() unnecessary for refs completion. Add the helper function __gitcomp_direct() to fill the COMPREPLY array with prefiltered and preprocessed words without any additional processing, without a shell loop, with just one single compound assignment. Modify __git_refs() to accept prefix and suffix parameters and add them to each and every listed ref as described above. Modify __git_complete_refs() to pass the prefix and suffix parameters to __git_refs() and to feed __git_refs()'s output to __gitcomp_direct() instead of __gitcomp_nl(). This speeds up refs completion when there are a lot of refs matching the current word to be completed. Listing all branches for completion in a repo with 100k local branches, all packed, best of five: On Linux, near the beginning of this series, for reference: $ time __git_complete_refs real 0m2.028s user 0m1.692s sys 0m0.344s Before this patch: real 0m1.135s user 0m1.112s sys 0m0.024s After: real 0m0.367s user 0m0.352s sys 0m0.020s On Windows, near the beginning: real 0m13.078s user 0m1.609s sys 0m0.060s Before this patch: real 0m2.093s user 0m1.641s sys 0m0.060s After: real 0m0.683s user 0m0.203s sys 0m0.076s Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-07Merge branch 'pd/completion-filenames-fix'Libravatar Junio C Hamano1-1/+1
The top-of-the-file instruction for completion scripts (in contrib/) did not name the files correctly. * pd/completion-filenames-fix: Update documentation occurrences of filename .sh
2014-12-15Update documentation occurrences of filename .shLibravatar Peter van der Does1-1/+1
Documentation in the completion scripts for Bash and Zsh state the wrong filenames. Signed-off-by: Peter van der Does <peter@avirtualhome.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-04-09completion: fix completing args of aliased "push", "fetch", etc.Libravatar Felipe Contreras1-0/+1
Some commands need the first word to determine the actual action that is being executed, however, the command is wrong when we use an alias, for example 'alias.p=push', if we try to complete 'git p origin ', the result would be wrong because __git_complete_remote_or_refspec() doesn't know where it came from. So let's override words[1], so the alias 'p' is override by the actual command, 'push'. Reported-by: Aymeric Beaumet <aymeric.beaumet@gmail.com> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-06completion: introduce __gitcomp_nl_append ()Libravatar Ramkumar Ramachandra1-0/+8
There are situations where multiple classes of completions possible. For example branch.<TAB> should try to complete branch.master. branch.autosetupmerge branch.autosetuprebase The first candidate has the suffix ".", and the second/ third candidates have the suffix " ". To facilitate completions of this kind, create a variation of __gitcomp_nl () that appends to the existing list of completion candidates, COMPREPLY. Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-06zsh completion: find matching custom bash completionLibravatar Ramkumar Ramachandra1-1/+1
If zsh completion is being read from a location that is different from system-wide default, it is likely that the user is trying to use a custom version, perhaps closer to the bleeding edge, installed in her own directory. We will more likely to find the matching bash completion script in the same directory than in those system default places. Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-05-29completion: zsh: improve bash script loadingLibravatar Felipe Contreras1-8/+19
It's better to check in multiple locations, so the user doesn't have to. And update the documentation. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-05-03completion: zsh: don't override suffix on _detaultLibravatar Felipe Contreras1-1/+1
zsh is smart enough to add the right suffix while completing, there's no point in trying to do the same as bash. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-29complete: zsh: use zsh completion for the main cmdLibravatar Felipe Contreras1-1/+119
So that we can have a nice zsh completion output: % git <tab> add -- add file contents to the index bisect -- find by binary search the change that introduced a bug branch -- list, create, or delete branches checkout -- checkout a branch or paths to the working tree clone -- clone a repository into a new directory commit -- record changes to the repository diff -- show changes between commits, commit and working tree, etc fetch -- download objects and refs from another repository grep -- print lines matching a pattern init -- create an empty Git repository or reinitialize an existing one log -- show commit logs merge -- join two or more development histories together mv -- move or rename a file, a directory, or a symlink pull -- fetch from and merge with another repository or a local branch push -- update remote refs along with associated objects rebase -- forward-port local commits to the updated upstream head reset -- reset current HEAD to the specified state rm -- remove files from the working tree and from the index show -- show various types of objects status -- show the working tree status tag -- create, list, delete or verify a tag object signed with GPG And other niceties, like 'git --git-dir=<tab>' showing only directories. For the rest, the bash completion stuff is still used. Also, add my copyright, since this more than a thin wrapper. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-29complete: zsh: trivial simplificationLibravatar Felipe Contreras1-8/+8
There should be no functional changes. The only reason I wrapped this code around a sub-function is because zsh did the same in it's bashcompinit script in order to declare the special variable 'words' as hidden, but only in this context. There's no need for that any more since we access __git_main directly, so 'words' is not modified, so there's no need for the sub-function. In zsh mode the array indexes are different though. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-05git-completion.zsh: define __gitcomp_file compatibility functionLibravatar Matthieu Moy1-0/+9
Commit fea16b47b60 (Fri Jan 11 19:48:43 2013, Manlio Perillo, git-completion.bash: add support for path completion), introduced a new __gitcomp_file function that uses the bash builtin "compgen". The function was redefined for ZSH in the deprecated section of git-completion.bash, but not in the new git-completion.zsh script. As a result, users of git-completion.zsh trying to complete "git add fo<tab>" get an error: git add fo__gitcomp_file:8: command not found: compgen This patch adds the redefinition and removes the error. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-11-19completion: add new zsh completionLibravatar Felipe Contreras1-0/+78
It seems there's always issues with zsh's bash completion emulation. I've tried to fix as many as I could[1], and most of the fixes are already in the latest version of zsh, but still, there are issues. There is no point going through all that pain; the emulation is easy to achieve, and this patch works better than zsh's bash completion emulation. [1] http://zsh.git.sourceforge.net/git/gitweb.cgi?p=zsh/zsh;a=commitdiff;h=23907bb840c80eef99eabba17e086e44c9b2d3fc Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>