zsh-workers
 help / color / mirror / code / Atom feed
* git checkout @... completion
@ 2015-03-31 11:10 Robbie Gates
  2015-04-01  9:41 ` Daniel Shahaf
  0 siblings, 1 reply; 2+ messages in thread
From: Robbie Gates @ 2015-03-31 11:10 UTC (permalink / raw)
  To: zsh-workers


[-- Attachment #1.1: Type: text/plain, Size: 1454 bytes --]

Hi All,

  i've modified the git completions in _git to complete git checkout's
@{-n} syntax for recent branches. I'm pretty sure the way i've done it is
somewhat ugly, because my understanding of the completion system is
primitive. I've attached a patch (against a local copy) - please let me
know if it's better to submit changes as a PR and i'll do that.

  More importantly, any review comments before the patch is usable are most
welcome. In particular, it just offers the first for each unique amongst
the most recent 9 branches. This is done by parsing the output of git log
--walk-reflogs using the same logic as git uses to interpret the @...
syntax according to my reading of sha1_name.c
<https://github.com/git/git/blob/e80e85a52adfda053cafc3b23058a86aff35404f/sha1_name.c#L930>
in
the git source using a bit of awkery. Although simplistic, i think this is
useful in practice.

  In particular, it could be rewritten to loop over git check-ref-format
--branch "@{-$i}" for increasing i until a given (by completion style
maybe, or environment variable) number of unique previous branches was
found. This felt a bit more rounadabout (and effort) than the quick version
here, but if it's more likely to be acceptable that this patch please let
me know and i'll rework it. Any pointers to completions with a configurable
depth / length that i could use to glean the right way to do this kind of
thing welcome.

  Thanks for your time,

 - Robbie

[-- Attachment #1.2: Type: text/html, Size: 1661 bytes --]

[-- Attachment #2: _git.patch --]
[-- Type: application/octet-stream, Size: 2379 bytes --]

diff --git a/functions/_git b/functions/_git
index c4e386b..884756c 100644
--- a/functions/_git
+++ b/functions/_git
@@ -463,27 +463,37 @@ _git-checkout () {
         local branch_arg='branches::__git_revisions' \
               remote_branch_noprefix_arg='remote branches::__git_remote_branch_names_noprefix' \
               tree_ish_arg='tree-ishs::__git_tree_ishs' \
-              file_arg='modified-files::__git_modified_files'
+              file_arg='modified-files::__git_modified_files' \
+              previous_arg='previous-branches::__git_previous_branches'
 
         if [[ -n ${opt_args[(I)-b|-B|--orphan|--detach]} ]]; then
           remote_branch_noprefix_arg=
           tree_ish_arg=
           file_arg=
+          previous_arg=
         elif [[ -n $opt_args[(I)--track] ]]; then
           branch_arg='remote-branches::__git_remote_branch_names'
           remote_branch_noprefix_arg=
           tree_ish_arg=
           file_arg=
+          previous_arg=
         elif [[ -n ${opt_args[(I)--ours|--theirs|-m|--conflict|--patch]} ]]; then
           branch_arg=
           remote_branch_noprefix_arg=
+          previous_arg=
+        elif [[ $line[CURRENT] = @* ]]; then
+          branch_arg=
+          remote_branch_noprefix_arg=
+          tree_ish_arg=
+          file_arg=
         fi
 
         _alternative \
           $branch_arg \
           $remote_branch_noprefix_arg \
           $tree_ish_arg \
-          $file_arg && ret=0
+          $file_arg \
+          $previous_arg && ret=0
       elif [[ -n ${opt_args[(I)-b|-B|-t|--track|--orphan|--detach]} ]]; then
         _nothing
       elif [[ -n $line[1] ]] && __git_is_treeish $line[1]; then
@@ -5769,6 +5779,14 @@ __git_notes_refs () {
   _wanted notes-refs expl 'notes ref' compadd $* - $notes_refs
 }
 
+(( $+functions[__git_previous_branches] )) ||
+__git_previous_branches () {
+  declare -a previous_branches
+  # We don't need to escape : in branch names, because they can't be there (see git help check-ref-format)
+  previous_branches=(${(f)"$(_call_program previous-branches "git log --max-count=9 --walk-reflogs --grep-reflog '^checkout: moving from .* to' --format='%gs' 2>/dev/null" | awk '{if (!seen[$4]) { seen[$4]=1 ; print "@{-" NR "}:" $4 } }')"})
+  _describe "previous branch" previous_branches
+}
+
 # File Argument Types
 
 (( $+functions[__git_files_relative] )) ||

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: git checkout @... completion
  2015-03-31 11:10 git checkout @... completion Robbie Gates
@ 2015-04-01  9:41 ` Daniel Shahaf
  0 siblings, 0 replies; 2+ messages in thread
From: Daniel Shahaf @ 2015-04-01  9:41 UTC (permalink / raw)
  To: Robbie Gates; +Cc: zsh-workers

Robbie Gates wrote on Tue, Mar 31, 2015 at 22:10:42 +1100:
> I've attached a patch (against a local copy) - please let me
> know if it's better to submit changes as a PR and i'll do that.

Patches are preferred.

>   In particular, it could be rewritten to loop over git check-ref-format
> --branch "@{-$i}" for increasing i until a given (by completion style
> maybe, or environment variable) number of unique previous branches was

The number of external command invocations should be minimized,
therefore, this doesn't sound like a good approach.

> Any pointers to completions with a configurable depth / length that
> i could use to glean the right way to do this kind of thing welcome.

I don't have a concrete example in mind, but grepping for uses of
'zstyle -s' might turn one up.

I'm unsure this should be made configurable.  Hardcoding a small
constant might be better.  I suspect 9 is too small, but not having used
this patch "in the field" that's just a guess.

On the other hand, __git_recent_commits had exactly the same problem:
what argument to pass to 'git log --limit=N'.  So perhaps a "limit"
style, or some such, would be justified, which both of these (and other
places) could use.

> diff --git a/functions/_git b/functions/_git

Please ensure attachments have the text/plain MIME type.  Usually naming
them with a "*.txt" extension does that.  Thanks.

> index c4e386b..884756c 100644
> --- a/functions/_git
> +++ b/functions/_git

What is the patch relative to?  There is no "functions/_git" in zsh's
repository [git://git.code.sf.net/p/zsh/code].

> @@ -5769,6 +5779,14 @@ __git_notes_refs () {
>    _wanted notes-refs expl 'notes ref' compadd $* - $notes_refs
>  }
>  
> +(( $+functions[__git_previous_branches] )) ||
> +__git_previous_branches () {
> +  declare -a previous_branches
> +  # We don't need to escape : in branch names, because they can't be there (see git help check-ref-format)
> +  previous_branches=(${(f)"$(_call_program previous-branches "git log --max-count=9 --walk-reflogs --grep-reflog '^checkout: moving from .* to' --format='%gs' 2>/dev/null" | awk '{if (!seen[$4]) { seen[$4]=1 ; print "@{-" NR "}:" $4 } }')"})

I see some other completions use awk, but I think it would be better to
avoid it, if possible; and here it's easily possible.  Perhaps something
like this:

    previous_branches=( ${${(f)"$(git reflog -9 --grep-reflog checkout: )"}##* } )

and then arrange the uniquification and @{-N} prefixes in zsh code,
through a unique array ('local -Ua') or an associative array.

> +  _describe "previous branch" previous_branches

Note that if the limit would be greater than 9, _describe would by
default sort the matches alphabetically, not numerically.  See
__git_recent_commits for an example of using _describe while retaining
the array sort order (in this case, the numerical order).  The problem
discussed in workers/34768 won't be a concern here because you already
uniquify the descriptions.

When reflog contains a detached head, the patch prints the full 40-digit
hash.  Is there a cheap way to shorten it into an unambiguous prefix?

I imagine in the future this could be extended to print not just
"checkout:" reflog entries, but also other entries.  Use-case: going to
the point before a rebase (which may be a commit, rather than
a checkout).

Thanks for the patch.  Looking forward to the revised version.

Daniel
(I'm going to be on-and-off AFK for the next couple of weeks, so I might
be late to reply.)


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-04-01  9:41 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-31 11:10 git checkout @... completion Robbie Gates
2015-04-01  9:41 ` Daniel Shahaf

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).