Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Improved completion for git commit objects (__git_commit_objects)



[ tl;dr: applied patch, attaching further patches for _git and _describe ]

Daniel Hahler wrote on Wed, Mar 04, 2015 at 00:46:42 +0100:
> Hi,
> 
> I am trying to improve completion for Git commit objects.
> 
> __git_commit_objects is defined as follows (in Completion/Unix/Command/_git):
> 
>     __git_commit_objects () {
>       _guard '[[:xdigit:]](#c,40)' 'commit object name'
>     }
> 
> I think it would be great if it actually (optionally?) could provide
> completion for commit objects, maybe only on second invocation / as fallback.

Good morning Daniel,

Hope you don't mind, but I went ahead and tweaked your function a bit:

1. I removed the _guard call which generated a spurious message and
prevented <TAB> from inserting a unique completion to the command line
in my configuration.

2. I used _describe instead of 'compadd -k'.

I've committed the patch with these changes.  Thanks for the patch!

I also made two follow-ups.  The first completes only tags/branches that
refer to one of the most recent N commits, rather than all tags and
branches — see attached.  WDYT?

The second follow-up sorts the hashes offered (as completions)
chronologically, rather than alphabetically, by extending _describe.
I'd appreciate some review of this one, to make sure I didn't miss
anything.

With all these patches applied, I get (in the zsh repo):

% git ci --fixup=4<TAB>
> commit object name
4bc554b  -- 34636: replace broken isprint() on Mac OS X
42e5f59  -- 34640: clarify documentation for _guard function
4edcacb  -- users/19934: document %D{...} for WATCHFMT
49776e8  -- 34588: Complete 'usermod -a'

Thanks again!

Daniel


From c786fb8b28c5ea68cd7a87c3e704f0c137d4e7d8 Mon Sep 17 00:00:00 2001
From: Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx>
Date: Sat, 7 Mar 2015 02:05:44 +0000
Subject: [PATCH 2/3] git completion: only offer recent commits' tags/heads for
 --fixup

---
 Completion/Unix/Command/_git | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 58d6422..aa11247 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -647,8 +647,8 @@ _git-commit () {
   # TODO: --interactive isn't explicitly listed in the documentation.
   _arguments -w -S -s \
     '(-a --all --interactive -o --only -i --include *)'{-a,--all}'[stage all modified and deleted paths]' \
-    '--fixup=[construct a commit message for use with rebase --autosquash]:commit to be amended:__git_commits' \
-    '--squash=[construct a commit message for use with rebase --autosquash]:commit to be amended:__git_commits' \
+    '--fixup=[construct a commit message for use with rebase --autosquash]:commit to be amended:__git_recent_commits' \
+    '--squash=[construct a commit message for use with rebase --autosquash]:commit to be amended:__git_recent_commits' \
     $reset_author_opt \
     '(        --porcelain --dry-run)--short[output dry run in short format]' \
     '(--short             --dry-run)--porcelain[output dry run in porcelain-ready format]' \
@@ -5640,6 +5640,38 @@ __git_commit_objects () {
   _describe -t commits 'commit object name' commits
 }
 
+(( $+functions[__git_recent_commits] )) ||
+__git_recent_commits () {
+  local gitdir expl start
+  declare -a descr tags heads commits
+  local i j k
+
+  # Careful: most %d will expand to the empty string.  Quote properly!
+  : "${(A)commits::=${(@f)"$(_call_program commits git --no-pager log -20 --format='%h%n%d%n%s')"}}"
+  __git_command_successful $pipestatus || return 1
+
+  for i j k in "$commits[@]" ; do
+    descr+=($i:$k)
+    j=${${j# \(}%\)} # strip leading ' (' and trailing ')'
+    for j in ${(s:, :)j}; do
+      if [[ $j == 'tag: '* ]] ; then
+        tags+=( ${j#tag: } )
+      else
+        heads+=( $j )
+      fi
+    done
+  done
+
+  ret=1
+  # Resetting expl to avoid it 'leaking' from one line to the next.
+  expl=()
+  _wanted commit-tags expl 'commit tag' compadd "$@" -a - tags && ret=0
+  expl=()
+  _wanted heads expl 'head' compadd "$@" -a - heads && ret=0
+  expl=()
+  _describe -t commits 'commit object name' descr && ret=0
+}
+
 (( $+functions[__git_blob_objects] )) ||
 __git_blob_objects () {
   _guard '[[:xdigit:]](#c,40)' 'blob object name'
-- 
1.9.1

From 99c9b5507a8725132ee9332bc889b3b3ff03a94d Mon Sep 17 00:00:00 2001
From: Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx>
Date: Sat, 7 Mar 2015 03:05:16 +0000
Subject: [PATCH 3/3] Add -1 -2 -J -V -x to _describe, use them to sort 'git
 --fixup' hash completions

---
 Completion/Base/Utility/_describe | 35 ++++++++++++++++++++---------------
 Completion/Unix/Command/_git      |  2 +-
 Doc/Zsh/compsys.yo                |  5 ++++-
 3 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/Completion/Base/Utility/_describe b/Completion/Base/Utility/_describe
index 1a9f52f..90dcac5 100644
--- a/Completion/Base/Utility/_describe
+++ b/Completion/Base/Utility/_describe
@@ -6,23 +6,28 @@ local _opt _expl _tmpm _tmpd _mlen _noprefix
 local _type=values _descr _ret=1 _showd _nm _hide _args _grp _sep
 local csl="$compstate[list]" csl2
 local _oargv _argv _new _strs _mats _opts _i _try=0
+local OPTIND OPTARG
+local -a _jvx12
 
 # Get the option.
 
-if [[ "$1" = -o ]]; then
-  _type=options
-  shift
-elif [[ "$1" = -O ]]; then
-  _type=options
-  _noprefix=1
-  shift
-elif [[ "$1" = -t ]]; then
-  _type="$2"
-  shift 2
-elif [[ "$1" = -t* ]]; then
-  _type="${1[3,-1]}"
-  shift
-fi
+while getopts "oOt:12JVx" _opt; do
+  case $_opt in
+    (o)
+      _type=options;;
+    (o)
+      _type=options
+      _noprefix=1
+      ;;
+    (t)
+      _type="$OPTARG"
+      ;;
+    (1|2|J|V|x)
+      _jvx12+=(-$_opt)
+  esac
+done
+shift $(( OPTIND - 1 ))
+unset _opt
 
 [[ "$_type$_noprefix" = options && ! -prefix [-+]* ]] && \
     zstyle -T ":completion:${curcontext}:options" prefix-needed &&
@@ -53,7 +58,7 @@ fi
 
 _tags "$_type"
 while _tags; do
-  while _next_label "$_type" _expl "$_descr"; do
+  while _next_label $_jvx12 "$_type" _expl "$_descr"; do
 
     if (( $#_grp )); then
   
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index aa11247..ac5f70b 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -5669,7 +5669,7 @@ __git_recent_commits () {
   expl=()
   _wanted heads expl 'head' compadd "$@" -a - heads && ret=0
   expl=()
-  _describe -t commits 'commit object name' descr && ret=0
+  _describe -2V -t commits 'commit object name' descr && ret=0
 }
 
 (( $+functions[__git_blob_objects] )) ||
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 89cd051..47e96af 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -4140,7 +4140,7 @@ tt(compadd) when generating matches from the style value, or to
 the functions for the fields if they are called.
 )
 findex(_describe)
-item(tt(_describe) [ tt(-oO) | tt(-t) var(tag) ] var(descr) var(name1) [ var(name2) ] var(opts) ... tt(-)tt(-) ...)(
+item(tt(_describe) [-12JVx] [ tt(-oO) | tt(-t) var(tag) ] var(descr) var(name1) [ var(name2) ] var(opts) ... tt(-)tt(-) ...)(
 This function associates completions with descriptions.
 Multiple groups separated by tt(-)tt(-) can be supplied, potentially with
 different completion options var(opts).
@@ -4171,6 +4171,9 @@ tt(prefix-needed) style.
 With the tt(-t) option a var(tag) can be specified.  The default is
 `tt(values)' or, if the tt(-o) option is given, `tt(options)'.
 
+The options tt(-1), tt(-2), tt(-J), tt(-V), tt(-x) are passed to
+tt(_next_labels).
+
 If selected by the tt(list-grouped) style, strings with the same
 description will appear together in the list.
 
-- 
1.9.1



Messages sorted by: Reverse Date, Date, Thread, Author