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

Re: [PATCH] _git: offer changed files relative to current directory



On Sat, Dec 05, 2009 at 06:12:03PM +0300, Alexey I. Froloff wrote:
> On Sat, Dec 05, 2009 at 03:42:58PM +0300, Alexey I. Froloff wrote:
> > Just need pure-zsh "relative" implementation.
> Here's my quick'n'dirty code:
> 
I'm not sure about the exact purpose of this function, but it doesn't
seem correct to me:
> relate()
> {
>     local -a what to res
> 
>     what=( ${(ps:/:)"${${${${1//\/\///}//\/.\///}%%/.}%%/}"} )
>     to=( ${(ps:/:)"${${${${2//\/\///}//\/.\///}%%/.}%%/}"} )
> 
>     while (( $#what > 0 )) && (( $#to > 0 )) && [[ $what[1] == $to[1] ]]; do
> 	what[1]=()
> 	to[1]=()
>     done
It is not unlikely to have more same-named directories in different
parts of directory tree. IIUC, the code above won't always work
correctly in such situation (i.e. it will remove the directory from the
path, wrongly assuming it is the same directory for both paths).

I believe the only correct way to solve the path relativization problem
for arbitrary input is to use the *absolute* paths.

In any case, it would be more useful/comprehensible (to me at least) if
you included the solution with the former patch to solve the actual
problem.


Anyway, here is what I've been succesfully using for some time; don't
laugh your teeth off:

------- 8< -------
From: ÅtÄpÃn NÄmec <stepnem@xxxxxxxxx>
Date: Sat, 5 Dec 2009 17:42:56 +0100
Subject: [PATCH] _git: Fix commit path completion.

Paths returned by git-diff-index are relative to repository root; make
them relative to the current directory (i.e. how git-commit requires
them), using a `munge_paths' monsterfunction.

Signed-off-by: ÅtÄpÃn NÄmec <stepnem@xxxxxxxxx>
---
 _git |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 54 insertions(+), 1 deletions(-)

diff --git a/_git b/_git
index e483133..b426612 100644
--- a/_git
+++ b/_git
@@ -2824,12 +2824,65 @@ __git_unmerged_files () {
 #this is for git-commit which can take files both git-added and not
 (( $+functions[__git_changed_files] )) ||
 __git_changed_files () {
+  # this function is needed to transform paths relative to the repo base dir
+  # (as returned by diff-index) into the form relative to the current directory
+  # :|
+  munge_paths () {
+    # SN FIXME is this needed? How come I don't see emulate -R anywhere in this file?
+    emulate -LR zsh
+    local cwd scnt scnta scntc
+    local -a abs paths
+    cwd=${"$(pwd)":a}
+    base=${${"$(git rev-parse --git-dir)":a}%.git}
+    abs=($base${^files})
+    scntc=${#${cwd//[^\/]}}
+    for ((i=1; i <= $#abs; i++)); do
+      scnta=${#${abs[$i]//[^\/]}}
+      scnt=$(($scntc - $scnta))
+      if ((scnt >= 0)); then
+      paths[$i]="$abs[$i]:t"
+        for ((j=0; j <= $scnt; j++)); do
+          paths[$i]="../$paths[$i]"
+        done
+      else
+        if [[ $abs[$i] == $cwd* ]]; then
+          paths[$i]="${${abs[$i]}#$cwd/}"
+        else
+          # longest common prefix
+          lcp () {
+            local lcp
+            for ((i=1; i<=$#1; i++)); do
+              if [[ ${1[i]} == ${2[i]} ]]; then
+                lcp+=${1[i]}
+              else
+                break
+              fi
+            done
+            echo "$lcp"
+          }
+          local common="$(lcp $cwd $abs[$i])"
+          local prefix=""
+          paths[$i]="${${abs[$i]}#$common}"
+          local cwdr="${${cwd}#$common}"
+          scntcr=${#${cwdr//[^\/]}}
+          for ((j=0; j <= $scntcr; j++)); do
+            prefix="../$prefix"
+          done
+          paths[$i]="$prefix$paths[$i]"
+        fi
+      fi
+    done
+    print ${(pj:\0:)paths}
+  }
+
   local -a files

   files=(${(ps:\0:)"$(_call_program files git diff-index -z --name-only --no-color HEAD 2>/dev/null)"})
   __git_command_successful || return
+  files=(${(ps:\0:)"$(munge_paths)"})

-  _wanted files expl 'index file' _multi_parts $@ - / files
+  _description files expl 'Changed files'
+  compadd "$expl[@]" - "$files[@]"
 }

 (( $+functions[__git_tree_files] )) ||
--



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