zsh-workers
 help / color / mirror / code / Atom feed
* [PATCH] vcs_info: add 'find-deepest' zstyle
@ 2020-10-23  8:34 Aleksandr Mezin
  2020-10-23 23:48 ` Daniel Shahaf
  0 siblings, 1 reply; 12+ messages in thread
From: Aleksandr Mezin @ 2020-10-23  8:34 UTC (permalink / raw)
  To: zsh-workers; +Cc: Aleksandr Mezin

Currently, vcs_info iterates over enabled VCS backends and outputs repository
status from the first backend that works (i.e. first backend that can find a
repository).

But I prefer a different behavior: I want to see the status of the repository
closest to the current working directory. For example: if there is a Mercurial
repository inside a Git repository, and I 'cd' into the Mercurial repository,
I want to see the status of Mercurial repo, even if 'git' comes before 'hg' in
the 'enable' list.

Because some people, apparently, want the old behavior of vcs_info, I made it
configurable, and, by default, old behavior is kept. To enable new behavior,
enable 'find-deepest' zstyle:

    zstyle ':vcs_info:*' find-deepest yes

After this change, vcs_info will try all enabled backends, and choose the one
that returns the deepest basedir path. Usually it will be the repository
closest to the current directory - if all basedirs are ancestors of the
current directory. I do not care about cases when a basedir isn't an ancestor
(for example, if GIT_WORK_TREE is pointing to an unrelated directory).

Also, this patch adjusts VCS_INFO_detect_git and VCS_INFO_detect_cvs to make
them set vcs_comm[basedir]. They were the only VCS_INFO_detect_* functions not
setting it.

Signed-off-by: Aleksandr Mezin <mezin.alexander@gmail.com>
---
 Doc/Zsh/contrib.yo                            |  9 +++++++
 .../VCS_Info/Backends/VCS_INFO_detect_cvs     |  2 +-
 .../VCS_Info/Backends/VCS_INFO_detect_git     |  1 +
 .../VCS_Info/Backends/VCS_INFO_get_data_git   |  2 +-
 Functions/VCS_Info/vcs_info                   | 25 ++++++++++++++++---
 5 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 00f693664..88d00c0ac 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -1238,6 +1238,14 @@ of unapplied patches (for example with Mercurial Queue patches).
 
 Used by the tt(quilt), tt(hg), and tt(git) backends.
 )
+kindex(find-deepest)
+item(tt(find-deepest))(
+By default, tt(vcs_info) tries backends in the order of 'enable' list, and
+returns the output of the first backend that can find a repository. When
+tt(find-deepest) is set to tt(true), tt(vcs_info) will try all enabled backends,
+and will choose the one that returns the deepest tt(basedir) path. Usually it
+will be the repository closest to the current directory.
+)
 enditem()
 
 The default values for these styles in all contexts are:
@@ -1272,6 +1280,7 @@ sitem(tt(quiltcommand))(quilt)
 sitem(tt(patch-format))(var(backend dependent))
 sitem(tt(nopatch-format))(var(backend dependent))
 sitem(tt(get-unapplied))(false)
+sitem(tt(find-deepest))(false)
 endsitem()
 
 In normal tt(formats) and tt(actionformats) the following replacements are
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_cvs b/Functions/VCS_Info/Backends/VCS_INFO_detect_cvs
index 7a5ee1eef..491219c16 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_detect_cvs
+++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_cvs
@@ -7,5 +7,5 @@ setopt localoptions NO_shwordsplit
 [[ $1 == '--flavours' ]] && return 1
 
 VCS_INFO_check_com ${vcs_comm[cmd]} || return 1
-[[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
+[[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && vcs_comm[basedir]=.(:P) && return 0
 return 1
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_git b/Functions/VCS_Info/Backends/VCS_INFO_detect_git
index e4191f474..b7955de38 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_detect_git
+++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_git
@@ -7,6 +7,7 @@ setopt localoptions NO_shwordsplit
 [[ $1 == '--flavours' ]] && { print -l git-p4 git-svn; return 0 }
 
 if VCS_INFO_check_com ${vcs_comm[cmd]} && vcs_comm[gitdir]="$(${vcs_comm[cmd]} rev-parse --git-dir 2> /dev/null)" ; then
+    vcs_comm[basedir]="$( ${vcs_comm[cmd]} rev-parse --show-toplevel 2> /dev/null )"
     if   [[ -d ${vcs_comm[gitdir]}/svn ]]             ; then vcs_comm[overwrite_name]='git-svn'
     elif [[ -d ${vcs_comm[gitdir]}/refs/remotes/p4 ]] ; then vcs_comm[overwrite_name]='git-p4' ; fi
     return 0
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
index 79429c8e0..eb04d4b41 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
@@ -138,7 +138,7 @@ VCS_INFO_git_handle_patches () {
 
 gitdir=${vcs_comm[gitdir]}
 VCS_INFO_git_getbranch ${gitdir}
-gitbase=$( ${vcs_comm[cmd]} rev-parse --show-toplevel 2> /dev/null )
+gitbase=${vcs_comm[basedir]}
 if [[ -z ${gitbase} ]]; then
     # Bare repository
     gitbase=${gitdir:P}
diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info
index 786b61918..53e0f9416 100644
--- a/Functions/VCS_Info/vcs_info
+++ b/Functions/VCS_Info/vcs_info
@@ -54,7 +54,7 @@ vcs_info () {
     [[ -r . ]] || return 0
 
     local pat
-    local -i found retval
+    local -i retval
     local -a enabled disabled dps
     local usercontext vcs rrn quiltmode
     local -x LC_MESSAGES
@@ -114,7 +114,9 @@ vcs_info () {
 
     VCS_INFO_maxexports
 
-    (( found = 0 ))
+    local -A deepest_vcs_comm deepest_backend_misc
+    local deepest_vcs find_first
+
     for vcs in ${enabled} ; do
         [[ -n ${(M)disabled:#${vcs}} ]] && continue
         if (( ${+functions[VCS_INFO_detect_${vcs}]} == 0 )) ; then
@@ -124,10 +126,25 @@ vcs_info () {
         fi
         vcs_comm=()
         VCS_INFO_get_cmd
-        VCS_INFO_detect_${vcs} && (( found = 1 )) && break
+        if VCS_INFO_detect_${vcs}; then
+            zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" find-deepest
+            find_first=$?
+
+            if (( find_first )) || (( ${#vcs_comm[basedir]//[!\/]} > ${#deepest_vcs_comm[basedir]//[!\/]} )) ; then
+                deepest_vcs="${vcs}"
+                deepest_vcs_comm=("${(kv)vcs_comm[@]}")
+                deepest_backend_misc=("${(kv)backend_misc[@]}")
+
+                (( find_first )) && break
+            fi
+        fi
     done
 
-    (( found == 0 )) && {
+    vcs="${deepest_vcs}"
+    vcs_comm=("${(kv)deepest_vcs_comm[@]}")
+    backend_misc=("${(kv)deepest_backend_misc[@]}")
+
+    [ -z "${vcs}" ] && {
         vcs='-quilt-'; quiltmode='standalone'
         VCS_INFO_quilt standalone || VCS_INFO_set --nvcs
         return 0
-- 
2.29.0



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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-23  8:34 [PATCH] vcs_info: add 'find-deepest' zstyle Aleksandr Mezin
@ 2020-10-23 23:48 ` Daniel Shahaf
  2020-10-24  0:13   ` Frank Terbeck
  2020-10-28  1:33   ` Aleksandr Mezin
  0 siblings, 2 replies; 12+ messages in thread
From: Daniel Shahaf @ 2020-10-23 23:48 UTC (permalink / raw)
  To: Aleksandr Mezin; +Cc: zsh-workers

Aleksandr Mezin wrote on Fri, 23 Oct 2020 14:34 +0600:
> Currently, vcs_info iterates over enabled VCS backends and outputs repository
> status from the first backend that works (i.e. first backend that can find a
> repository).
> 
> But I prefer a different behavior: I want to see the status of the repository
> closest to the current working directory. For example: if there is a Mercurial
> repository inside a Git repository, and I 'cd' into the Mercurial repository,
> I want to see the status of Mercurial repo, even if 'git' comes before 'hg' in
> the 'enable' list.

I suppose that's the Right thing to do in most cases: e.g., it's
context-sensitive whereas the 'enable' style's value doesn't usually
depend on the current directory.

(Separately, in your example it might be nice to indicate that there's
an "outside" Git repository, but that'd be a separate feature request.)

> Because some people, apparently, want the old behavior of vcs_info,

What's those people's argument?  The default behaviour should be decided
on on this list, not simply announced to this list as a _fait accompli_.

> I made it configurable, and, by default, old behavior is kept. To
> enable new behavior, enable 'find-deepest' zstyle:
> 
>     zstyle ':vcs_info:*' find-deepest yes
> 

I'd probably set this in my dotfiles: in the rare cases that I nest
repositories, I don't add files in the deeper repository to the
shallower repository.

> After this change, vcs_info will try all enabled backends, and choose the one
> that returns the deepest basedir path. Usually it will be the repository
> closest to the current directory - if all basedirs are ancestors of the
> current directory. I do not care about cases when a basedir isn't an ancestor
> (for example, if GIT_WORK_TREE is pointing to an unrelated directory).

Would you clarify the last sentence (not the parenthetical but the part
before it)?

> Also, this patch adjusts VCS_INFO_detect_git and VCS_INFO_detect_cvs to make
> them set vcs_comm[basedir]. They were the only VCS_INFO_detect_* functions not
> setting it.

Thanks.  I don't recall if there's "How to write a backend"
documentation, but so long as all existing backends get it right, we're
probably covered well enough in practice.  Going forward, we could
heavily comment one of the backends and declare it documentation, as
with Test/B01cd.ztst.

> Signed-off-by: Aleksandr Mezin <mezin.alexander@gmail.com>
> ---
>  Doc/Zsh/contrib.yo                            |  9 +++++++
>  .../VCS_Info/Backends/VCS_INFO_detect_cvs     |  2 +-
>  .../VCS_Info/Backends/VCS_INFO_detect_git     |  1 +
>  .../VCS_Info/Backends/VCS_INFO_get_data_git   |  2 +-
>  Functions/VCS_Info/vcs_info                   | 25 ++++++++++++++++---

Please update _zstyle.

>  5 files changed, 33 insertions(+), 6 deletions(-)
> 
> diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
> index 00f693664..88d00c0ac 100644
> --- a/Doc/Zsh/contrib.yo
> +++ b/Doc/Zsh/contrib.yo
> @@ -1238,6 +1238,14 @@ of unapplied patches (for example with Mercurial Queue patches).
>  
>  Used by the tt(quilt), tt(hg), and tt(git) backends.
>  )
> +kindex(find-deepest)
> +item(tt(find-deepest))(
> +By default, tt(vcs_info) tries backends in the order of 'enable' list, and
> +returns the output of the first backend that can find a repository. When
> +tt(find-deepest) is set to tt(true), tt(vcs_info) will try all enabled backends,
> +and will choose the one that

Multiple tweaks here.  How about:

    By default, tt(vcs_info) tries backends in the order given by the tt(enable) style, and
    operates on the repository detected by the first backend to successfully detect a repository.
    
    When this style (tt(find-deepest)) is set to tt(true), tt(vcs_info) will try all enabled backends,
    and will operate on [...]

Wordier, yes, but "the output of a backend" didn't parse for me.

> +returns the deepest tt(basedir) path.

"basedir" is an implementation term; readers won't know what it means.
Keeping it would be like having zshparam(1) document $? as "The value
of tt(lastval)".

If /foo/.${vcs} and /foo/bar/.${vcs} both exist (same value of ${vcs} in
both) the style is set, the latter should be used.  However, you don't
seem to be handling this case in any way.  I guess that if this patch is
to be accepted, we'll have to go through all backends and verify that
they prefer /foo/bar/.${vcs} to /foo/.${vcs} when both exist and the
style is set appropriately.  It's probably best if you go through
backends you can install via your distro and ask -workers@ volunteers to
go through any others.  (Some backends will probably be left over, but
we can cross that bridge when we come to it.)

When /foo/.${vcs} and /foo/bar/.${vcs} both exist and «find-deepest» is
set to _«false»_, might someone expect /foo/.${vcs} to be used?  (After
all, one might reasonably presume flipping the style's value would
_somehow_ affect vcs_info's behaviour.)  Perhaps we can name the style
more unambiguously?  How about changing it from boolean to enum, as in:
.
    zstyle ':vcs_info:*' detection-algorithm enablement-order
    zstyle ':vcs_info:*' detection-algorithm deepest-.vcs-dir
.
That'd also be more extensible.

Separately, as implemented the style doesn't quite go by the _deepest_
basedir path.  Rather, it goes by the one that _has more path
components_.¹  That's not the same thing, at least if you take "X is
deeper than Y" to imply "X is a (possibly nested) subdirectory of Y",
which, I think, would be the appropriate semantics here.  For instance,
given the pair of repository root paths {/foo/bar/baz, /lorem/ipsum},
the patch will prefer /foo/bar/baz, even though it's not "deeper than"
/lorem/ipsum.  I don't think setting find-deepest should affect the
relative precedence of /foo/bar/baz and /lorem/ipsum…

… unless either of the two directories happens to be an ancestor of cwd,
in which case there's an argument to be made that that directory should
be preferred.  (I hope we don't have to worry about symlinks here.)

Moreover, the above description wasn't entirely accurate.  The patch
doesn't count path components; it counts slashes.  That's not
equivalent, because of things like «/foo/bar», «/foo/bar/»,
«/foo/./bar», «/foo//bar», and «bar» (the last one depends on cwd, of
course).  For instance, «/foo///bar» will be considered deeper than
«/foo/bar/baz».

I think a reasonable next step would be to nail down what repository
should be chosen, given $PWD and a set of existing .${vcs} dirs
(possibly more than one of those per value of ${vcs}).  For instance:

    1. The .${vcs} dir whose parent is an ancestor of ${PWD}; if there's
    more than one of these, the closest ancestor; if there's more than
    one of _these_, the first enabled.

    2. If there's no such .${vcs} dir, then a .${vcs} dir from the first
    backend in enablement order.  If there's more than one of these,
    then XXX.  (TODO: What if the first backend in enablement order
    identifies two repository directories, and one of them is an
    ancestor of the other?  Which one will be used?)

> +Usually it will be the repository closest to the current directory.

Documentation shouldn't say "usually" without also explaining what
happens in the _unusual_ case.

> +++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_cvs
> @@ -7,5 +7,5 @@ setopt localoptions NO_shwordsplit
> -[[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
> +[[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && vcs_comm[basedir]=.(:P) && return 0

«.(:P)» won't be expanded here.

Cheers,

Daniel


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-23 23:48 ` Daniel Shahaf
@ 2020-10-24  0:13   ` Frank Terbeck
  2020-10-24  0:56     ` Bart Schaefer
  2020-10-24  2:31     ` Oliver Kiddle
  2020-10-28  1:33   ` Aleksandr Mezin
  1 sibling, 2 replies; 12+ messages in thread
From: Frank Terbeck @ 2020-10-24  0:13 UTC (permalink / raw)
  To: zsh-workers

Daniel Shahaf wrote:
> Aleksandr Mezin wrote on Fri, 23 Oct 2020 14:34 +0600:
>> Currently, vcs_info iterates over enabled VCS backends and outputs repository
>> status from the first backend that works (i.e. first backend that can find a
>> repository).
>> 
>> But I prefer a different behavior: I want to see the status of the repository
>> closest to the current working directory. For example: if there is a Mercurial
>> repository inside a Git repository, and I 'cd' into the Mercurial repository,
>> I want to see the status of Mercurial repo, even if 'git' comes before 'hg' in
>> the 'enable' list.
>
> I suppose that's the Right thing to do in most cases: e.g., it's
> context-sensitive whereas the 'enable' style's value doesn't usually
> depend on the current directory.
>
> (Separately, in your example it might be nice to indicate that there's
> an "outside" Git repository, but that'd be a separate feature request.)
>
>> Because some people, apparently, want the old behavior of vcs_info,
>
> What's those people's argument?  The default behaviour should be decided
> on on this list, not simply announced to this list as a _fait accompli_.

I, for one,  vastly prefer the current behaviour. I  don't think nesting
repositories is  all that common. Even  when I was using  many different
systems, never did I have a need for that.

The most common reason  I heard in the past, when this  came up is, wan-
ting to keep all of $HOME in git, which I consider borderline insane.

What the  current behaviour permits  is to set  the enable style  in the
order  of probability.  That way  the most  common system  you use  gets
checked first, cutting down on detection time. Since some systems take a
fair bit of time  to do detection, I deemed this  reasonable at the time
this was written. And like I said,  I think this is still the preferable
default choice.

I skimmed over the  patch and I like the limited  amount of changes that
are required  to get  the other  behaviour. So  I think  something along
those lines should go in. But I'd prefer the default as it is.


Regards, Frank


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-24  0:13   ` Frank Terbeck
@ 2020-10-24  0:56     ` Bart Schaefer
  2020-10-25 20:04       ` Daniel Shahaf
  2020-10-24  2:31     ` Oliver Kiddle
  1 sibling, 1 reply; 12+ messages in thread
From: Bart Schaefer @ 2020-10-24  0:56 UTC (permalink / raw)
  To: Frank Terbeck; +Cc: zsh-workers

On Fri, Oct 23, 2020 at 5:13 PM Frank Terbeck <ft@zsh.org> wrote:
>
> I, for one,  vastly prefer the current behaviour. I  don't think nesting
> repositories is  all that common. Even  when I was using  many different
> systems, never did I have a need for that.

At my $WORK we have two related but distinct code bases, an older
version of the platform that is maintained for several longtime
customers and the modern version used by all new customers.  The old
code base is in CVS, the new code base (which incorporates a large
subset of the old) has been moved to git.  Occasionally there are
bugfixes that need to be ported from one to the other within that
shared subset.  Maintaining nested repositories has been useful for
this situation, but it's difficult to get vcs_info to select the
correct one.

That said, I'm not sure "deepest" reflects the right behavior either.
I'd pretty much need to select the repository that differs from the
current working file, whichever one that is at the time.


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-24  0:13   ` Frank Terbeck
  2020-10-24  0:56     ` Bart Schaefer
@ 2020-10-24  2:31     ` Oliver Kiddle
  2020-10-25 19:54       ` Daniel Shahaf
  1 sibling, 1 reply; 12+ messages in thread
From: Oliver Kiddle @ 2020-10-24  2:31 UTC (permalink / raw)
  To: Frank Terbeck; +Cc: zsh-workers

Frank Terbeck wrote:
> What the  current behaviour permits  is to set  the enable style  in the
> order  of probability.  That way  the most  common system  you use  gets
> checked first, cutting down on detection time. Since some systems take a
> fair bit of time  to do detection, I deemed this  reasonable at the time
> this was written. And like I said,  I think this is still the preferable
> default choice.

Long detection times can still very much be a problem. At both home
and work, I use automount and NFS home directories so the NFS server
regularly gets queried for non-existent homes named .git etc. It isn't
just vcs_info that does this. At work, people using /net had to be
redirected where vscode in particular was generating excessive DNS
requests - with dots in some names making that especially bad.

I suspect some of this could be avoided by doing something similar to
the find -xdev option to stop searching when a different filesystem is
reached. It might also be more efficient to search for all of .git,
.svn, CVS etc in tandem, especially where the behaviour of stopping at
the first (deepest) one is used. Can we do better by doing the scan in
C? A dedicated module for this would seem quite reasonable.

Or maybe globs could suffice. I've pondered in the past about some sort
of glob shortcut for (../)# and perhaps a way to prevent it crossing
filesystems.

I don't have much use for nested repositories but vcs_info tends to be
more use with git than subversion.

Oliver


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-24  2:31     ` Oliver Kiddle
@ 2020-10-25 19:54       ` Daniel Shahaf
  2020-10-25 23:13         ` Frank Terbeck
  0 siblings, 1 reply; 12+ messages in thread
From: Daniel Shahaf @ 2020-10-25 19:54 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: Frank Terbeck, zsh-workers

Oliver Kiddle wrote on Sat, 24 Oct 2020 04:31 +0200:
> Long detection times can still very much be a problem. At both home
> and work, I use automount and NFS home directories so the NFS server
> regularly gets queried for non-existent homes named .git etc. [...]
> 
> I suspect some of this could be avoided by doing something similar to
> the find -xdev option to stop searching when a different filesystem is
> reached.

So you'd like to assume that a single worktree will not cross into
nested mount points.

I'm not actually sure this is true every time.  For instance, if
a project's tree is huge and someone works only on part of it but has
multiple worktrees for that project, they might use bind mounts for the
parts of the tree they never touch; and conversely, people doing in-tree
builds might mount ramdisks inside their worktrees to generate the
object files and executables in, and then cd into those and expect to
still see the info for the enclosing worktree.

Whether any of these use-cases is a deal breaker is another question.

How about, if cwd is writable (in the access(W_OK) sense), stopping the
upwards crawl when reaching a directory that isn't writable?  This would
typically stop on «~/../».

> I don't have much use for nested repositories but vcs_info tends to be
> more use with git than subversion.

+1, primarily because git is much more stateful (e.g., interrupted
rebases).

Cheers,

Daniel


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-24  0:56     ` Bart Schaefer
@ 2020-10-25 20:04       ` Daniel Shahaf
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Shahaf @ 2020-10-25 20:04 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote on Fri, 23 Oct 2020 17:56 -0700:
> On Fri, Oct 23, 2020 at 5:13 PM Frank Terbeck <ft@zsh.org> wrote:
> >
> > I, for one,  vastly prefer the current behaviour. I  don't think nesting
> > repositories is  all that common. Even  when I was using  many different
> > systems, never did I have a need for that.  
> 
> At my $WORK we have two related but distinct code bases, an older
> version of the platform that is maintained for several longtime
> customers and the modern version used by all new customers.  The old
> code base is in CVS, the new code base (which incorporates a large
> subset of the old) has been moved to git.  Occasionally there are
> bugfixes that need to be ported from one to the other within that
> shared subset.  Maintaining nested repositories has been useful for
> this situation, but it's difficult to get vcs_info to select the
> correct one.
> 
> That said, I'm not sure "deepest" reflects the right behavior either.
> I'd pretty much need to select the repository that differs from the
> current working file, whichever one that is at the time.

At the risk of veering off-topic, how about running vcs_info twice
(with different argv[1] values for zstyle purposes) and have it print
_both_ the CVS info and git info every prompt.  Something like:

precmd() {
  vcs_info
  print -rPC1 -- $vcs_info_msg_0_
  local tmp=$vcs_info_msg_0_
  vcs_info foo
  if [[ -n $vcs_info_msg_0_ && $vcs_info_msg_0_ != $tmp ]]; then print -rPC1 -- $vcs_info_msg_0_; fi
}
zstyle ':vcs_info:*:foo:*' enable …

Cheers,

Daniel


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-25 19:54       ` Daniel Shahaf
@ 2020-10-25 23:13         ` Frank Terbeck
  2020-10-26 20:58           ` Daniel Shahaf
  0 siblings, 1 reply; 12+ messages in thread
From: Frank Terbeck @ 2020-10-25 23:13 UTC (permalink / raw)
  To: zsh-workers

Heya,

Daniel Shahaf wrote:
> Oliver Kiddle wrote on Sat, 24 Oct 2020 04:31 +0200:
[…]
>> I don't have much use for nested repositories but vcs_info tends to be
>> more use with git than subversion.
>
> +1, primarily because git is much more stateful (e.g., interrupted
> rebases).

I think it's mostly because git is a decentralised system, where more
information is available without having to touch a networked system,
like the central server in centralised systems. The latter will kill
latency dependant use cases, such as prompts.


Regards, Frank


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-25 23:13         ` Frank Terbeck
@ 2020-10-26 20:58           ` Daniel Shahaf
  2020-10-27  1:01             ` Frank Terbeck
  0 siblings, 1 reply; 12+ messages in thread
From: Daniel Shahaf @ 2020-10-26 20:58 UTC (permalink / raw)
  To: Frank Terbeck, zsh-workers

Frank Terbeck wrote on Sun, 25 Oct 2020 23:13 +00:00:
> Heya,
> 
> Daniel Shahaf wrote:
> > Oliver Kiddle wrote on Sat, 24 Oct 2020 04:31 +0200:
> […]
> >> I don't have much use for nested repositories but vcs_info tends to be
> >> more use with git than subversion.
> >
> > +1, primarily because git is much more stateful (e.g., interrupted
> > rebases).
> 
> I think it's mostly because git is a decentralised system, where more
> information is available without having to touch a networked system,
> like the central server in centralised systems. The latter will kill
> latency dependant use cases, such as prompts.

I don't see how vcs_info's admittedly increased usefulness under Git
follows from Git's being decentralized and from more information being
available locally.

Decentralization is reflected in, for instance, the data model (a DAG of
commits) and in the existence of the «git push $remote» syntax.  Neither
of those is directly reflected in information typically extracted into
prompts: for instance, when the checked out branch tracks a remote
branch, vcs_info doesn't have a built-in facility for displaying the
name of the remote.

Same goes for having the history available locally.  vcs_info git
prompts do not typically show information from commits other than the
current one.  The only exceptions I can think of are the detached HEAD %b
expando fallback code that uses `git describe`/`git name-rev` and the
statistics expandos in the patch-format style.

If showing previous commits' data were a common requirement, one would
have expected the use-server style to be used by at least some of the
centralized backends.  However, that style is used only by the p4
backend for detection (as opposed to interrogation) and by the
'checkout' variant of the bzr backend.

On the other hand, consider «git rebase -i» which I cited as an example.
There is no conceptual problem with implementing the equivalent of that
feature in Subversion — and if that were done, showing state in the
prompt would become much more useful under that backend.

Furthermore, under Subversion I use hooks to display some additional
information I find useful: a list of changelist names and the
modified/switched/partial-depth indications from `svnversion` output.
None of these states is inherent to Subversion's centralized
nature: there's nothing stopping git and hg from implementing the
equivalents of «svn changelist», «svn switch» and «svn update
--set-depth=exclude».  (To be clear, I'm not saying they should.  I'm
just saying those features are orthogonal to centralization/decentralization.)

And the reason all this is so?  vcs_info shows the _current_ state,
which is a moving target.  It doesn't show the history, and doesn't need
to, because the history is in the user's mental cache anyway.  That's
also why the git-rev-list(1) uses in Misc/vcs_info-examples print the
statistics of the local HEAD relative to the upstream HEAD, but not the
statistics of the upstream HEAD relative to an empty repository.

Cheers,

Daniel

P.S.  Speaking of my hooks, I've got some other ones that might be of
independent interest: I have my svn prompts show the `svnversion`
output's revision range, e.g., "42:100", rather than just whatever `svn
info --show-item=revision ./` happens to be; I print the topmost patch
in quilt addon mode, and the commit being rebased in interrupted
rebases; and I indicate presence of GIT_* envvars and per-repository
addons (e.g., git-annex(1), vcsh(1)).


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-26 20:58           ` Daniel Shahaf
@ 2020-10-27  1:01             ` Frank Terbeck
  2020-11-04  8:42               ` Daniel Shahaf
  0 siblings, 1 reply; 12+ messages in thread
From: Frank Terbeck @ 2020-10-27  1:01 UTC (permalink / raw)
  To: zsh-workers

Hey,

Daniel Shahaf wrote:
> Frank Terbeck wrote on Sun, 25 Oct 2020 23:13 +00:00:
>> Daniel Shahaf wrote:
[…]
>> > +1, primarily because git is much more stateful (e.g., interrupted
>> > rebases).
>> 
>> I think it's mostly because git is a decentralised system, where more
>> information is available without having to touch a networked system,
>> like the central server in centralised systems. The latter will kill
>> latency dependant use cases, such as prompts.
>
> I don't see how vcs_info's admittedly increased usefulness under Git
> follows from Git's being decentralized and from more information being
> available locally.

The fact that  the system *can* do things *locally*  enables things like
notifying the user about differences in  tracked files — like staged and
unstaged changes.


> On the other hand, consider «git rebase -i» which I cited as an example.
> There is no conceptual problem with implementing the equivalent of that
> feature in Subversion — and if that were done, showing state in the
> prompt would become much more useful under that backend.

Certainly — I don't doubt features being present in the git-backend that
are not applicable with other systems.

I was  merely stating my  impression. I  don't think it's  a coincidence
that the two most feature-rich backends  are the ones for git and mercu-
rial. I think the low-latency nature of local information enables this.

That is not  to say that other  factors cannot play a role,  but this is
the one that I always considered  the “obvious” reason. Clearly only for
some values of “obvious”. :)


> Furthermore, under Subversion I use hooks to display some additional
> information I find useful: a list of changelist names and the
> modified/switched/partial-depth indications from `svnversion` output.
> None of these states is inherent to Subversion's centralized
> nature: there's nothing stopping git and hg from implementing the
> equivalents of «svn changelist», «svn switch» and «svn update
> --set-depth=exclude».  (To be clear, I'm not saying they should.  I'm
> just saying those features are orthogonal to centralization/decentralization.)

Sure. I wonder however, how long  this takes. My experience with subver-
sion was always that any time I had  to hit the network, and you need to
for basically  everything, latency  was unbearable  for use  in prompts.
Even with servers in the same building. Not having to access the network
enables using this sort of information because you get to it quicker.


> And the reason all this is so?  vcs_info shows the _current_ state,
> which is a moving target.  It doesn't show the history[…]

It could of course, but like you I don't think it would be all that
useful.


[…]
> P.S.  Speaking of my hooks, I've got some other ones that might be of
> independent interest: I have my svn prompts show the `svnversion`
> output's revision range, e.g., "42:100", rather than just whatever `svn
> info --show-item=revision ./` happens to be;

Sounds useful. But I always thought  svnversion also had to hit the net-
work, to  figure out if the  working copy has local  modifications. Does
this run in finite time, or would  this be mostly useful with local ser-
vers?


> I print the topmost patch
> in quilt addon mode, and the commit being rebased in interrupted
> rebases; and I indicate presence of GIT_* envvars and per-repository
> addons (e.g., git-annex(1), vcsh(1)).

This sounds interesting. Care to share? :)


Regards, Frank
-- 
In protocol design, perfection has been reached not when there is
nothing left to add, but when there is nothing left to take away.
                                                  -- RFC 1925


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-23 23:48 ` Daniel Shahaf
  2020-10-24  0:13   ` Frank Terbeck
@ 2020-10-28  1:33   ` Aleksandr Mezin
  1 sibling, 0 replies; 12+ messages in thread
From: Aleksandr Mezin @ 2020-10-28  1:33 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: zsh-workers

On Sat, Oct 24, 2020 at 5:49 AM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> Aleksandr Mezin wrote on Fri, 23 Oct 2020 14:34 +0600:
> > Currently, vcs_info iterates over enabled VCS backends and outputs repository
> > status from the first backend that works (i.e. first backend that can find a
> > repository).
> >
> > But I prefer a different behavior: I want to see the status of the repository
> > closest to the current working directory. For example: if there is a Mercurial
> > repository inside a Git repository, and I 'cd' into the Mercurial repository,
> > I want to see the status of Mercurial repo, even if 'git' comes before 'hg' in
> > the 'enable' list.
>
> I suppose that's the Right thing to do in most cases: e.g., it's
> context-sensitive whereas the 'enable' style's value doesn't usually
> depend on the current directory.
>
> (Separately, in your example it might be nice to indicate that there's
> an "outside" Git repository, but that'd be a separate feature request.)
>
> > Because some people, apparently, want the old behavior of vcs_info,
>
> What's those people's argument?  The default behaviour should be decided
> on on this list, not simply announced to this list as a _fait accompli_.

I can change the default to 'yes', no problem.

I think I should have mentioned that this is a "v2" of this patch.
Here are some important quotes from comments for the v1:

Bart Schaefer wrote on Mon, Nov 25, 2019 at 01:13:21 -0800:
> I have several directories that are BOTH git and CVS repositories, used for
> keeping two different origins in sync.
>
> This is admittedly an unusual situation -- we have a legacy process that
> expects to fetch sources from CVS, and developers collaborating through git
> -- but I would be annoyed if vcs didn't find the git data because of the
> CVS subdir.

Previously, you proposed the following solution:
> How about showing the information from the worktree whose root is deeper
> (= closer to cwd)?  Users can show the information for the other worktree
> by setting the 'enable' style in a :vcs_info:foo:* context and calling
> «vcs_info foo».
...
> In my proposal, if {foo,foo/bar,foo/bar/baz}/CVS
> and foo/bar/.git all exist, and cwd is foo/bar/baz/, git info would be shown
> because the git root, foo/bar/, is closer (deeper) than the CVS root, foo/ —
> notwithstanding that foo/bar/baz/CVS exists.

I thought this patch implements what you suggested, except for CVS.
After re-reading the comments I think I made a mistake with
VCS_INFO_detect_cvs, and should revert it to what it was in v1:

> -[[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
> -return 1
> +[[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] || return 1
> +
> +local cvsbase="."
> +while [[ -d "${cvsbase}/../CVS" ]]; do
> +    cvsbase="${cvsbase}/.."
> +done
> +vcs_comm[basedir]=${cvsbase:P}
> +
> +return 0

(and maybe fix that potentially infinite loop, yes)

It will work for Bart's use case this way, and it's what
VCS_INFO_get_data_cvs currently does.

>
> > I made it configurable, and, by default, old behavior is kept. To
> > enable new behavior, enable 'find-deepest' zstyle:
> >
> >     zstyle ':vcs_info:*' find-deepest yes
> >
>
> I'd probably set this in my dotfiles: in the rare cases that I nest
> repositories, I don't add files in the deeper repository to the
> shallower repository.
>
> > After this change, vcs_info will try all enabled backends, and choose the one
> > that returns the deepest basedir path. Usually it will be the repository
> > closest to the current directory - if all basedirs are ancestors of the
> > current directory. I do not care about cases when a basedir isn't an ancestor
> > (for example, if GIT_WORK_TREE is pointing to an unrelated directory).
>
> Would you clarify the last sentence (not the parenthetical but the part
> before it)?

I do not have a strong opinion on how vcs_info should behave when some
basedir isn't an ancestor of pwd.

When some basedir is a subdirectory in pwd, vcs_info should likely
choose that backend (because it should mean that the user specified
that basedir explicitly - for example GIT_WORK_TREE).

But when a basedir is neither ancestor nor subdir of pwd, simply
choosing the backend based on path depth doesn't look quite correct to
me. But I don't know what the correct way is, so I ignore the fact
that vcs_info could behave weirdly (from the user's POV) in this case.
Maybe vcs_info should actually prefer the basedir that's not an
ancestor of pwd (i. e. choose it immediately when encountered, before
all depth comparisons)? Because "basedir isn't an ancestor of pwd" is
"the user somehow specified this directory explicitly". As far as I
understand.

>
> > Also, this patch adjusts VCS_INFO_detect_git and VCS_INFO_detect_cvs to make
> > them set vcs_comm[basedir]. They were the only VCS_INFO_detect_* functions not
> > setting it.
>
> Thanks.  I don't recall if there's "How to write a backend"
> documentation

I haven't found anything like that.

> but so long as all existing backends get it right, we're
> probably covered well enough in practice.  Going forward, we could
> heavily comment one of the backends and declare it documentation, as
> with Test/B01cd.ztst.
>
> > Signed-off-by: Aleksandr Mezin <mezin.alexander@gmail.com>
> > ---
> >  Doc/Zsh/contrib.yo                            |  9 +++++++
> >  .../VCS_Info/Backends/VCS_INFO_detect_cvs     |  2 +-
> >  .../VCS_Info/Backends/VCS_INFO_detect_git     |  1 +
> >  .../VCS_Info/Backends/VCS_INFO_get_data_git   |  2 +-
> >  Functions/VCS_Info/vcs_info                   | 25 ++++++++++++++++---
>
> Please update _zstyle.
>
> >  5 files changed, 33 insertions(+), 6 deletions(-)
> >
> > diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
> > index 00f693664..88d00c0ac 100644
> > --- a/Doc/Zsh/contrib.yo
> > +++ b/Doc/Zsh/contrib.yo
> > @@ -1238,6 +1238,14 @@ of unapplied patches (for example with Mercurial Queue patches).
> >
> >  Used by the tt(quilt), tt(hg), and tt(git) backends.
> >  )
> > +kindex(find-deepest)
> > +item(tt(find-deepest))(
> > +By default, tt(vcs_info) tries backends in the order of 'enable' list, and
> > +returns the output of the first backend that can find a repository. When
> > +tt(find-deepest) is set to tt(true), tt(vcs_info) will try all enabled backends,
> > +and will choose the one that
>
> Multiple tweaks here.  How about:
>
>     By default, tt(vcs_info) tries backends in the order given by the tt(enable) style, and
>     operates on the repository detected by the first backend to successfully detect a repository.
>
>     When this style (tt(find-deepest)) is set to tt(true), tt(vcs_info) will try all enabled backends,
>     and will operate on [...]
>
> Wordier, yes, but "the output of a backend" didn't parse for me.

If I add the documentation written by you to my patch, I guess I
should mention you in the commit message somehow?

>
> > +returns the deepest tt(basedir) path.
>
> "basedir" is an implementation term; readers won't know what it means.
> Keeping it would be like having zshparam(1) document $? as "The value
> of tt(lastval)".
>
> If /foo/.${vcs} and /foo/bar/.${vcs} both exist (same value of ${vcs} in
> both) the style is set, the latter should be used.  However, you don't
> seem to be handling this case in any way.  I guess that if this patch is
> to be accepted, we'll have to go through all backends and verify that
> they prefer /foo/bar/.${vcs} to /foo/.${vcs} when both exist and the
> style is set appropriately.  It's probably best if you go through
> backends you can install via your distro and ask -workers@ volunteers to
> go through any others.  (Some backends will probably be left over, but
> we can cross that bridge when we come to it.)

If the current directory is /foo/bar in your example, then, I think,
all backends, except CVS, will choose /foo/bar/.${vcs}
Most of them simply use VCS_INFO_bydir_detect, git will definitely
choose /foo/bar too.
CVS is special just because it has its subdirectory in every directory
of the working copy. VCS_INFO_get_data_cvs thinks that the last
successive parent directory that still has CVS subdirectory is the
root of the working copy. And I think it's correct.

>
> When /foo/.${vcs} and /foo/bar/.${vcs} both exist and «find-deepest» is
> set to _«false»_, might someone expect /foo/.${vcs} to be used?  (After
> all, one might reasonably presume flipping the style's value would
> _somehow_ affect vcs_info's behaviour.)  Perhaps we can name the style
> more unambiguously?  How about changing it from boolean to enum, as in:
> .
>     zstyle ':vcs_info:*' detection-algorithm enablement-order
>     zstyle ':vcs_info:*' detection-algorithm deepest-.vcs-dir
> .
> That'd also be more extensible.

Yep, I agree

>
> Separately, as implemented the style doesn't quite go by the _deepest_
> basedir path.  Rather, it goes by the one that _has more path
> components_.¹  That's not the same thing, at least if you take "X is
> deeper than Y" to imply "X is a (possibly nested) subdirectory of Y",
> which, I think, would be the appropriate semantics here.  For instance,
> given the pair of repository root paths {/foo/bar/baz, /lorem/ipsum},
> the patch will prefer /foo/bar/baz, even though it's not "deeper than"
> /lorem/ipsum.  I don't think setting find-deepest should affect the
> relative precedence of /foo/bar/baz and /lorem/ipsum…

I used the word 'deep/deepest' because I was thinking that "depth" in
a tree is the length of the path from the root. Which is a number, and
can be compared for any nodes. Is this incorrect?

Maybe I should iterate over basedirs, and just check if "current"
basedir is a subdir (maybe nested) of the current best match? I'm ok
with this behavior too. Though I don't find it any better in "weird"
cases - when some basedirs aren't ancestors of pwd

>
> … unless either of the two directories happens to be an ancestor of cwd,
> in which case there's an argument to be made that that directory should
> be preferred.  (I hope we don't have to worry about symlinks here.)
>
> Moreover, the above description wasn't entirely accurate.  The patch
> doesn't count path components; it counts slashes.  That's not
> equivalent, because of things like «/foo/bar», «/foo/bar/»,
> «/foo/./bar», «/foo//bar», and «bar» (the last one depends on cwd, of
> course).  For instance, «/foo///bar» will be considered deeper than
> «/foo/bar/baz».

I think vcs_comm[basedir] can never contain duplicate slashes - either
the value assigned to it is expanded with ':P' modifier, or the vcs
itself returns it in that form (for example, git rev-parse
--show-toplevel removes duplicate slashes from GIT_WORK_TREE). If
necessary, I can add an extra expansion with ':P' in vcs_info itself.

>
> I think a reasonable next step would be to nail down what repository
> should be chosen, given $PWD and a set of existing .${vcs} dirs
> (possibly more than one of those per value of ${vcs}).  For instance:
>
>     1. The .${vcs} dir whose parent is an ancestor of ${PWD}; if there's
>     more than one of these, the closest ancestor; if there's more than
>     one of _these_, the first enabled.
>
>     2. If there's no such .${vcs} dir, then a .${vcs} dir from the first
>     backend in enablement order.  If there's more than one of these,
>     then XXX.  (TODO: What if the first backend in enablement order
>     identifies two repository directories, and one of them is an
>     ancestor of the other?  Which one will be used?)
>
> > +Usually it will be the repository closest to the current directory.
>
> Documentation shouldn't say "usually" without also explaining what
> happens in the _unusual_ case.
>
> > +++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_cvs
> > @@ -7,5 +7,5 @@ setopt localoptions NO_shwordsplit
> > -[[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
> > +[[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && vcs_comm[basedir]=.(:P) && return 0
>
> «.(:P)» won't be expanded here.

Oops.

Also, again, it seems that I should revert to the previous version of
my patch here - find the root CVS directory, like
VCS_INFO_get_data_cvs does.

>
> Cheers,
>
> Daniel


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

* Re: [PATCH] vcs_info: add 'find-deepest' zstyle
  2020-10-27  1:01             ` Frank Terbeck
@ 2020-11-04  8:42               ` Daniel Shahaf
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Shahaf @ 2020-11-04  8:42 UTC (permalink / raw)
  To: Frank Terbeck; +Cc: zsh-workers

(Sorry again for the late/out-of-order replies.)

Frank Terbeck wrote on Tue, 27 Oct 2020 02:01 +0100:
> Daniel Shahaf wrote:
> > Frank Terbeck wrote on Sun, 25 Oct 2020 23:13 +00:00:  
> >> Daniel Shahaf wrote:  
> […]
> >> > +1, primarily because git is much more stateful (e.g., interrupted
> >> > rebases).  
> >> 
> >> I think it's mostly because git is a decentralised system, where more
> >> information is available without having to touch a networked system,
> >> like the central server in centralised systems. The latter will kill
> >> latency dependant use cases, such as prompts.  
> >
> > I don't see how vcs_info's admittedly increased usefulness under Git
> > follows from Git's being decentralized and from more information being
> > available locally.  
> 
> The fact that  the system *can* do things *locally*  enables things like
> notifying the user about differences in  tracked files — like staged and
> unstaged changes.

(The language "do things" is rather imprecise.)

The ability to show staged/unstaged mods has nothing to do with the
entire history being available locally and everything to do with the
data model sporting three trees: the latest commit, the change the user
is about to commit, and the user's worktree.

Git calls these HEAD, index, and worktree.  Subversion calls these BASE,
WORKING, and ACTUAL (the last term is not part of the public API).

The three Git trees work just fine in a «git clone --depth=1» worktree.
That's part of the reason vcs_info is as useful in such worktrees as
in other Git worktrees, despite the shallowness.

Across the pond, in Subversion it's possible to have differences between
BASE and WORKING (e.g., through any use of the add/rm/mkdir/cp/mv/prop*
subcommands), and I think it would be reasonable for the svn backend to
have stagedstr shown in those cases (namely, if «svn status | grep -E
'^[AD]|^.M'» is non-empty).

> > On the other hand, consider «git rebase -i» which I cited as an example.
> > There is no conceptual problem with implementing the equivalent of that
> > feature in Subversion — and if that were done, showing state in the
> > prompt would become much more useful under that backend.  
> 
> Certainly — I don't doubt features being present in the git-backend that
> are not applicable with other systems.
> 
> I was  merely stating my  impression. I  don't think it's  a coincidence
> that the two most feature-rich backends  are the ones for git and mercu-
> rial. I think the low-latency nature of local information enables this.
> 

That would depend on what you mean by "local information".

Git, for instance, is stateful (e.g., «git merge --no-commit»,
interrupted rebases, etc).  The state is local (and hence is low
latency).  So is the entire history.  However:

- vcs_info queries only the state, not the history, so the history's
  latency is a red herring.

- State information would be local (and hence low latency) in Subversion
  too.

I do agree that the low-latency nature of the information that vcs_info
_does_ query is important.  However, vcs_info wouldn't actually care
that much if .git/objects/**/*(md+7) were mounted on a slow network
disk, would it?

> That is not  to say that other  factors cannot play a role,  but this is
> the one that I always considered  the “obvious” reason. Clearly only for
> some values of “obvious”. :)

:)

> > Furthermore, under Subversion I use hooks to display some additional
> > information I find useful: a list of changelist names and the
> > modified/switched/partial-depth indications from `svnversion` output.
> > None of these states is inherent to Subversion's centralized
> > nature: there's nothing stopping git and hg from implementing the
> > equivalents of «svn changelist», «svn switch» and «svn update
> > --set-depth=exclude».  (To be clear, I'm not saying they should.  I'm
> > just saying those features are orthogonal to centralization/decentralization.)  
> 
> Sure. I wonder however, how long  this takes.
[...]
> Not having to access the network enables using this sort of
> information because you get to it quicker.

The changelist names and switched/partial-depth indications are local
SQLite queries.  The 'modified' information (unavoidably) requires
a local disk crawl, so it's conditional on the check-for-changes style.
None of these require network access.

> My experience with subversion was always that any time I had  to hit
> the network, and you need to for basically  everything, latency  was
> unbearable  for use  in prompts.  Even with servers in the same
> building.

What information did you want to show in the prompt that required
a network round-trip?

As to the latency, the report is not very concrete, but feel free to hit
users@svn (or me offlist) with more details, if needed.

> > P.S.  Speaking of my hooks, I've got some other ones that might be of
> > independent interest: I have my svn prompts show the `svnversion`
> > output's revision range, e.g., "42:100", rather than just whatever `svn
> > info --show-item=revision ./` happens to be;  
> 
> Sounds useful. But I always thought  svnversion also had to hit the net-
> work,

svnversion doesn't hit the network, ever:

% ldd =svnversion | grep libsvn_ra
% 

> to  figure out if the  working copy has local  modifications.

No.  Subversion can determine local modifications without accessing the
server.  Were you perhaps thinking of CVS?

> Does this run in finite time […]?

I'm sure it does, and when my test run finishes, I'll let you know how
long it took. :-)

Seriously, though, as I mentioned, just does a SQLite database query
(plus a disk crawl if that's been opted in to).  More precisely, it
makes a dummy propmod, calls svnversion(1), and reverts the propmod.
(The write operations are conditional on another opt-in knob.)  That's
in order to ensure svnversion(1) doesn't fall back to a disk crawl when
check-for-changes is unset.

The dummy propmod design does mean I don't get an indication of local
mods when there are legitimate tree/property changes in the tree.

It'd be easy to add a --never-do-a-disk-crawl flag to svnversion(1)
itself to remove the need for the dummy propmod.  (It'd just be a matter
of revving svn_wc_revision_status2() with an additional boolean
parameter.)

> > I print the topmost patch
> > in quilt addon mode, and the commit being rebased in interrupted
> > rebases; and I indicate presence of GIT_* envvars and per-repository
> > addons (e.g., git-annex(1), vcsh(1)).  
> 
> This sounds interesting. Care to share? :)

Sure, enclosed.

I wonder whether the $pc/.snap check should be upgraded to a patch.  It seems
to work fine so far, at least.

Cheers,

Daniel


_git_config_setting_exists() {
  git config --get-all --null -- "$1" >/dev/null
}

zstyle ':vcs_info:*+gen-applied-string:*' hooks gen-applied-string

+vi-gen-applied-string() {
  # Arguments: $1 is the topmost patch;
  # the value of each parameter is as though by [in git terms] --pretty="%H %s"
  local H s
  H=${1%% *}
  s=${1#* }

  s=${s/#$'\x5bPATCH '/$'\x5b'} # s#[PATCH 3/8]#[3/8]#

  # Truncate the hash, if the VCS uses hashes for revision numbers.
  # Under quilt, $H is the patch filename.
  #
  # cf the 'enable' style.
  if [[ $vcs == (git|hg|bzr) ]] && ! (( $+funcstack[(r)VCS_INFO_quilt] )); then
    H=$H[1,12]
  fi

  if [[ $vcs == git && $H == <0-> ]]; then
    # git-am(1)
    #
    # ${patchdir} is set by VCS_INFO_get_data_git
    # That's an implementation detail twice over, but $ZSHRC_COMMIT_BEING_REBASED is shown interactively before it's used, so *shrug*
    local new_value
    printf -v new_value "%s/%04d" "${patchdir}" "$H" 
    H=${new_value##*/}
    typeset -g ZSHRC_COMMIT_BEING_REBASED=${new_value}
  else
    typeset -g ZSHRC_COMMIT_BEING_REBASED=$H
  fi
  print -Pr -- >&2 "zshrc: setting ZSHRC_COMMIT_BEING_REBASED=%B${(qq)new_value//'%'/%%}%b"
  # (Actually, I name the global variable just «$y» for convenience, but I changed that for posting.)

  ## Change ASCII ellipsis (added by VCS_INFO-set-patch-format) to Unicode ellipsis, to save columns
  if [[ $s =~ [.][.][.]$ ]]; then
    s[-3,-1]=…
  fi

  ## Try harder to get meaningful information
  if [[ $s == '?' ]] && (( $+funcstack[(r)VCS_INFO_quilt] )); then
    # By now, VCS_INFO_quilt will have run quilt commands, so we needn't worry about ${QUILT_PATCHES}
    if quilt top >/dev/null; then
      # Silence stderr because of "Warning: more recent patches modify files in patch $H"
      # Silence stderr because of "Patch debian/patches/foo.diff is not applied"
      local -a files_touched; files_touched=( ${(f)"$(quilt diff -P "$H" -p0 2>/dev/null | lsdiff)"} )
      if (( $#files_touched == 1 )); then
        s="(${files_touched[1]})"
      else
        s="(${#files_touched}:`quilt diff -P "$H" -p0 2>/dev/null | wc -l` files:ΔLoC)"
      fi
    fi
  fi

  # Under quilt, add an indicator of whether a `quilt snapshot` exists
  local stagedstr=
  if (( $+funcstack[(r)VCS_INFO_quilt] )) && [[ -d $pc/.snap ]]; then
    zstyle -s "${context}" stagedstr stagedstr
  fi

  ## Set [applied-string] to the original value of $1, plus $stagedstr, plus coloring.
  hook_com[applied-string]="%F{yellow}${H//'%'/'%%'}%f${stagedstr} ${terminfo[dim]}${s//'%'/%%}${terminfo[sgr0]}"

  ## Tell vcs_info to use our value.
  ret=1
}

zstyle -e ':vcs_info:git+set-message:*' hooks 'reply=( ${${(k)functions[(I)[+]vi-git-set-message*]}#+vi-} )'

+vi-git-set-message_git-annex() {
  (( $1 == 0 )) || return 0
  # If this is a git-annex repository, then display "/annex" when working on the master
  # branch, and a Big Red Warning when the special "git-annex" (sic) branch is checked out.
  if _git_config_setting_exists 'annex.uuid'; then
    if [[ ${hook_com[branch_orig]} == *git-annex* ]]; then
      hook_com[branch]='%F{red}%B'${hook_com[branch]//'%'/%%}'%f%b'
    else
      hook_com[branch]+="%f/annex" # %f ends coloring
    fi
  fi
  return 0
}

+vi-git-set-message_vcsh_and_git_dir() {
  (( $1 == 0 )) || return 0
  # If this is a vcsh repository, then display "/vcsh:foo" where 'foo' is
  # the repository basename (from $GIT_DIR, $VCSH_DIRECTORY, $VCSH_REPO_NAME).
  #
  # Else, if $GIT_DIR is set, then warn about it.
  if _git_config_setting_exists 'vcsh.vcsh'; then
    hook_com[branch]+="%f/vcsh${GIT_DIR:+":${${GIT_DIR:t}%.git}"}" # %f ends coloring
  elif [[ ${(t)GIT_DIR} == *'export'* ]]; then
    # TODO: simplify?
    if [[ $GIT_DIR == $PWD(/.git|) ]]; then
      # nothing
    elif
      # silence errors when not inside a git dir
      [[ $GIT_DIR != `unset GIT_DIR; git rev-parse --git-dir 2>/dev/null` ]]
    then
      hook_com[branch]+="%f%B%F{yellow}@${(q-)${${GIT_DIR%.git}%/}:t}%f%b"
    fi
  fi
  return 0
}

# Show in the prompt names and values of ${GIT_*} variables.
# TODO: only show exported ones
+vi-git-set-message_git_others() {
  local GIT_DIR
  unset GIT_DIR # handled by +vi-git-set-message_vcsh_and_git_dir
  local -a gits=( "${(k@)parameters[(I)GIT*]}" )
  for 1 in $gits; do
    hook_com[branch]+=";%U${(q-)1}%u%F{white}=${(Pq-)1//'%'/%%}%f"
  done
  return 0
}


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

end of thread, other threads:[~2020-11-04  8:42 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-23  8:34 [PATCH] vcs_info: add 'find-deepest' zstyle Aleksandr Mezin
2020-10-23 23:48 ` Daniel Shahaf
2020-10-24  0:13   ` Frank Terbeck
2020-10-24  0:56     ` Bart Schaefer
2020-10-25 20:04       ` Daniel Shahaf
2020-10-24  2:31     ` Oliver Kiddle
2020-10-25 19:54       ` Daniel Shahaf
2020-10-25 23:13         ` Frank Terbeck
2020-10-26 20:58           ` Daniel Shahaf
2020-10-27  1:01             ` Frank Terbeck
2020-11-04  8:42               ` Daniel Shahaf
2020-10-28  1:33   ` Aleksandr Mezin

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).