zsh-workers
 help / color / mirror / code / Atom feed
From: Nikolai Weibull <now@bitwi.se>
To: Bart Schaefer <schaefer@brasslantern.com>
Cc: zsh-workers@zsh.org
Subject: Re: Slowness issue with git completion
Date: Wed, 27 Apr 2011 14:51:05 +0200	[thread overview]
Message-ID: <BANLkTimmw3+nWyYS27MzDm-z-rFCT2yxaQ@mail.gmail.com> (raw)
In-Reply-To: <110426211951.ZM4200@torch.brasslantern.com>

[-- Attachment #1: Type: text/plain, Size: 1738 bytes --]

On Wed, Apr 27, 2011 at 06:19, Bart Schaefer <schaefer@brasslantern.com> wrote:

> Also as someone noted elsewhere, zsh isn't very efficient at doing
> array appends or slices.  Both complex string manipulations and lots
> of array slicing/appending are done in __git_files_relative which is
> called from _git_files.  Not only that, but it does string ops on the
> path prefix on every pass around the "for file in $rawfiles" loop;
> that at least could be abstracted.
>
> I suspect that if someone undertook to rewrite __git_files_relative
> wholly or partly in something like sed or awk, the whole thing would
> be down to ~2 seconds even for a large number of files.  Heck, even
> redoing the nested loops to do one multi-element array slice each
> instead of many single-element splices might make a huge difference.

Let’s instead remove it.

The attached patch seems to speed up matching a lot, while maintaining
all functionality.  There might be cases that I haven’t considered.
Please review.

Another adjustment is that we could join the calls to git rev-parse
into one call:

gitcdupandprefix=${$(_call_program git-cdup-and-prefix git rev-parse
--show-cdup --show-prefix 2>/dev/null)/$'\n'}

to decrease the fork count as well, which makes a difference on
Cygwin.  This won’t be quite correct, however, as it won’t work for
prefixes with newlines in them.  Git-rev-parse sadly doesn’t take the
-z option.

Also, Bart, supplying -f to _multi_parts here doesn’t seem to have any
effect on match highlighting.  Directories are shown the same as
files.  This was something I asked about a long time ago that we were
going to look at at a later date.  Perhaps that date has come?

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

diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 4664cfa..6f71db3 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -5144,75 +5144,27 @@ __git_notes_refs () {
 
 # File Argument Types
 
-(( $+functions[__git_files_relative] )) ||
-__git_files_relative () {
-  local rawfiles files file f_parts prefix p_parts tmp
-
-  prefix=$(_call_program gitprefix git rev-parse --show-prefix 2>/dev/null)
-  __git_command_successful $pipestatus || return
-
-  # Empty prefix, no modifications
-  if (( $#prefix == 0 )); then
-    print $1
-    return
-  fi
-
-  rawfiles=(${(0)1})
-  files=()
-
-  # Now we assume that we've given "absolute" paths list with "root"
-  # being repository top directory.  $prefix is also "absolute" path.
-  for file in $rawfiles; do
-    # Collapse "/./" and "//", strip "/." and "/" from tail (I know,
-    # this is a bit paranoid).
-    f_parts=(${(s:/:)"${${${${file//\/\///}//\/.\///}%%/.}%%/}"})
-    p_parts=(${(s:/:)"${${${${prefix//\/\///}//\/.\///}%%/.}%%/}"})
-    tmp=()
-
-    # Strip common path prefix.
-    while (( $#f_parts > 0 )) && (( $#p_parts > 0 )) && [[ $f_parts[1] == $p_parts[1] ]]; do
-      f_parts[1]=()
-      p_parts[1]=()
-    done
-
-    # If prefix still not empty, ascend up.
-    while (( $#p_parts > 0 )); do
-      tmp+=..
-      p_parts[1]=()
-    done
-
-    # Add remaining path.
-    tmp+=($f_parts)
-
-    files+=${(j:/:)tmp}
-  done
-
-  print ${(pj:\0:)files}
-}
-
 (( $+functions[__git_files] )) ||
 __git_files () {
-  local compadd_opts opts tag description gitdir gitcdup files expl
+  local compadd_opts opts tag description gitcdup gitprefix files expl
 
   zparseopts -D -E -a compadd_opts V: J: 1 2 n f X: M: P: S: r: R: q F:
   zparseopts -D -E -a opts -- -cached -deleted -modified -others -ignored -unmerged -killed x+: --exclude+:
   tag=$1 description=$2; shift 2
 
-  gitdir=$(_call_program gitdir git rev-parse --git-dir 2>/dev/null)
+  gitcdup=$(_call_program gitcdup git rev-parse --show-cdup 2>/dev/null)
   __git_command_successful $pipestatus || return
 
-  gitcdup=$(_call_program gitcdup git rev-parse --show-cdup 2>/dev/null)
+  gitprefix=$(_call_program gitprefix git rev-parse --show-prefix 2>/dev/null)
   __git_command_successful $pipestatus || return
 
-  opts+='--exclude-per-directory=.gitignore'
-  [[ -f "$gitdir/info/exclude" ]] && opts+="--exclude-from=$gitdir/info/exclude"
+  # TODO: --directory should probably be added to $opts when --others is given.
 
-  files=$(_call_program files git ls-files -z --full-name $opts -- $gitcdup 2>/dev/null)
-  __git_command_successful $pipestatus || return
-  files=(${(0)"$(__git_files_relative $files)"})
+  local pref=$gitcdup$gitprefix$PREFIX
+  files=(${(0)"$(_call_program files git ls-files -z --exclude-standard $opts -- ${pref:+$pref/\*} 2>/dev/null)"})
   __git_command_successful $pipestatus || return
 
-  _wanted $tag expl $description _multi_parts $compadd_opts - / files
+  _wanted $tag expl $description _multi_parts -f $compadd_opts - / files
 }
 
 (( $+functions[__git_cached_files] )) ||

  parent reply	other threads:[~2011-04-27 12:51 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-04-26 18:26 Felipe Contreras
2011-04-26 18:43 ` Frank Terbeck
2011-04-26 19:06   ` Nikolai Weibull
2011-04-26 20:10     ` Frank Terbeck
2011-04-26 20:23   ` Felipe Contreras
2011-04-26 20:34     ` Mikael Magnusson
2011-04-26 20:57       ` Felipe Contreras
2011-04-26 20:59         ` Mikael Magnusson
2011-04-26 21:10           ` Felipe Contreras
2011-04-26 21:13             ` Mikael Magnusson
2011-04-26 21:35               ` Felipe Contreras
2011-04-26 22:03                 ` Nikolai Weibull
2011-04-26 22:25                   ` Felipe Contreras
2011-04-26 23:14                     ` Benjamin R. Haskell
2011-04-27  7:01                       ` Benjamin R. Haskell
2011-04-27  1:52                     ` gi1242+zsh
2011-04-27  6:11                     ` Nikolai Weibull
2011-04-27  8:30                       ` Felipe Contreras
2011-04-27  8:47                         ` Frank Terbeck
2011-04-27  9:06                           ` Felipe Contreras
2011-04-27 10:15                         ` Nikolai Weibull
2011-04-27 10:42                           ` Felipe Contreras
2011-04-27 11:14                             ` Nikolai Weibull
2011-04-27  4:19                 ` Bart Schaefer
2011-04-27  6:13                   ` Nikolai Weibull
2011-04-27 12:51                   ` Nikolai Weibull [this message]
2011-04-27 14:55                     ` Bart Schaefer
2011-04-27 18:36                       ` Nikolai Weibull
2011-04-30 14:37                     ` Simon Ruderich
2011-04-30 15:00                       ` Simon Ruderich
2011-05-02  9:59                       ` Nikolai Weibull
2011-05-03 13:59                         ` Nikolai Weibull
2011-04-26 21:52         ` Benjamin R. Haskell
2011-04-26 22:04           ` Felipe Contreras
2011-04-26 22:35             ` Benjamin R. Haskell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=BANLkTimmw3+nWyYS27MzDm-z-rFCT2yxaQ@mail.gmail.com \
    --to=now@bitwi.se \
    --cc=schaefer@brasslantern.com \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).