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

Re: [PATCH] vcs_info: add 'find-deepest' zstyle



(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
}




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