Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [PATCH v5] vcs_info: choose backend by basedir
Ping
On Fri, Jun 4, 2021 at 12:14 PM Aleksandr Mezin
<mezin.alexander@xxxxxxxxx> wrote:
>
> Previously, vcs_info iterated over enabled VCS backends and output 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.
>
> This patch adds a new algorithm for vcs_info to choose the backend:
>
> 1. Among backends whose basedir isn't an ancestor of the current directory,
> old algorithm is used: whichever comes first in 'enable' list.
>
> 2. If all backends return basedirs that are ancestors of the current directory,
> the one with basedir closest to the current directory is chosen.
>
> As far as I know, unless the user has set basedir manually (GIT_WORK_TREE),
> all backend return basedirs that are ancestors of the current directory.
> Backends that return non-ancestor basedirs have higher priority to show the
> status of that manually-configured repository.
>
> The algorithm used by vcs_info can be configured using 'choose-closest-backend'
> zstyle:
>
> zstyle ':vcs_info:*' choose-closest-backend yes
>
> By default, old algorithm is used.
>
> It can also be configured per-backend:
>
> zstyle ':vcs_info:hg:*' choose-closest-backend no
>
> This effectively moves the backend into group (1), as if its basedir is never
> an ancestor of the current directory. Not sure how useful this is though.
>
> Signed-off-by: Aleksandr Mezin <mezin.alexander@xxxxxxxxx>
> ---
> v4: back to boolean zstyle, keep old behavior by default, documentation
> v5: described expected vcs_info[basedir] use in a comment, addressed Daniel's
> questions in comments.
>
> Completion/Zsh/Command/_zstyle | 1 +
> Doc/Zsh/contrib.yo | 41 ++++++++++++++++++++++
> Functions/VCS_Info/vcs_info | 62 +++++++++++++++++++++++++++++++---
> 3 files changed, 100 insertions(+), 4 deletions(-)
>
> diff --git a/Completion/Zsh/Command/_zstyle b/Completion/Zsh/Command/_zstyle
> index 9d06076e4..b7a73c5a2 100644
> --- a/Completion/Zsh/Command/_zstyle
> +++ b/Completion/Zsh/Command/_zstyle
> @@ -193,6 +193,7 @@ styles=(
> quilt-standalone v:bool
> quilt-patch-dir v:_directories
> quiltcommand v:_command_names
> + choose-closest-backend v:bool
>
> chpwd z:bool
> progress z:progress
> diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
> index a972f08d6..67823716a 100644
> --- a/Doc/Zsh/contrib.yo
> +++ b/Doc/Zsh/contrib.yo
> @@ -1238,6 +1238,46 @@ of unapplied patches (for example with Mercurial Queue patches).
>
> Used by the tt(quilt), tt(hg), and tt(git) backends.
> )
> +kindex(choose-closest-backend)
> +item(tt(choose-closest-backend))(
> +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.
> +
> +If this style (tt(choose-closest-backend)) is set to tt(true) for some (or all)
> +backends, all backends will be divided into two groups:
> +
> +1) Backends, for which this style is set to tt(true), that detect a
> +repository/working copy that is an ancestor of the current directory (including
> +the current directory itself).
> +
> +2) All other backends: backends with tt(choose-closest-backend) unset/set to
> +tt(false); and backends that detected a repository/working copy that's not an
> +ancestor of the current directory, even if tt(choose-closest-backend) is set to
> +tt(true) for them.
> +
> +First, tt(vcs_info) will try backends from the 2nd group in the order given by
> +the tt(enable) style, and operate on the repository detected by the first
> +backend to successfully detect a repository (the default behavior of
> +tt(vcs_info), only limited to backends from the 2nd group).
> +
> +If no backends from the 2nd group detected a repository (or if there are no
> +backends in that group), tt(vcs_info) will try backends from the 1st group.
> +tt(vcs_info) will then operate on the repository closest to the current working
> +directory.
> +
> +Usually, all VCS backends search for repositories only in ancestors of the
> +current directory, and choose the repository closest to the current directory.
> +So if tt(choose-closest-backend) is set to tt(true) globally for all backends,
> +tt(vcs_info) will effectively search for the repository closest to the current
> +directory.
> +
> +However, there is at least one backend that can detect a repository in an
> +arbitrary location - Git backend. tt(GIT_WORK_TREE) can be set to a path that
> +doesn't point to an ancestor of the current directory. In this case, even if
> +tt(choose-closest-backend) is set to tt(true) globally for all backends,
> +the repository/working copy pointed by tt(GIT_WORK_TREE) will be preferred.
> +)
> enditem()
>
> The default values for these styles in all contexts are:
> @@ -1272,6 +1312,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(choose-closest-backend))(false)
> endsitem()
>
> In normal tt(formats) and tt(actionformats) the following replacements are
> diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info
> index 786b61918..85f7ca0ab 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
> @@ -64,6 +64,9 @@ vcs_info () {
> # vcs_comm is used internally for passing values among VCS_INFO_* functions.
> # It is not part of the public API.
> #
> + # VCS_INFO_detect_* functions should set vcs_comm[basedir] to the path to
> + # the root of the working copy.
> + #
> # hook_com, backend_misc, and user_data are public API; see zshcontrib(1)
> # and Misc/vcs_info-examples.
> local -A vcs_comm hook_com backend_misc user_data
> @@ -114,7 +117,9 @@ vcs_info () {
>
> VCS_INFO_maxexports
>
> - (( found = 0 ))
> + local -A chosen_vcs_comm chosen_backend_misc
> + local chosen_vcs basedir_realpath chosen_basedir_realpath choose_first_available
> +
> for vcs in ${enabled} ; do
> [[ -n ${(M)disabled:#${vcs}} ]] && continue
> if (( ${+functions[VCS_INFO_detect_${vcs}]} == 0 )) ; then
> @@ -124,10 +129,59 @@ vcs_info () {
> fi
> vcs_comm=()
> VCS_INFO_get_cmd
> - VCS_INFO_detect_${vcs} && (( found = 1 )) && break
> + if VCS_INFO_detect_${vcs}; then
> + # Most backends already set vcs_comm[basedir] to an absolute path
> + # with symlinks resolved:
> + #
> + # * Backends using VCS_INFO_bydir_detect:
> + # bzr, cdv, darcs, fossil, hg, mtn, p4, svn
> + #
> + # * cvs - custom logic, but uses :P too
> + #
> + # * git - $(git rev-parse --show-toplevel) resolves symlinks and
> + # returns an absolute path
> + #
> + # * for tla (GNU Arch) I can't find any online documentation or
> + # packages (seems to be dead)
> + #
> + # * svk doesn't use :P modifier and returns the path as is from
> + # the config file (as far as I understand)
> + #
> + # So I'm not sure whether to modify the backends or just resolve
> + # the path here to be sure. VCS_INFO_get_data_* usually reads
> + # vcs_comm[basedir] too. In particular, I'm not sure if it's safe to
> + # resolve symlinks in vcs_comm[basedir] for svk.
> + #
> + # Because most backends already do :P substitution, I expect all
> + # the info needed to resolve the path to be cached in memory by the
> + # OS (so it shouldn't cause performance issues).
> + basedir_realpath="${vcs_comm[basedir]:P}"
> +
> + zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" choose-closest-backend
> + choose_first_available=$?
> +
> + [[ "${PWD:P}/" == "${basedir_realpath}"/* ]] || [[ "${basedir_realpath}" == "/" ]] || choose_first_available=1
> +
> + # If choose_first_available is 0 at this point, all basedir_realpaths
> + # (and thus chosen_basedir_realpath) are parents (and thus prefixes)
> + # of PWD:P. So comparing their lengths is enough to figure out which
> + # one is closer to PWD.
> + if (( choose_first_available )) || (( ${#basedir_realpath} > ${#chosen_basedir_realpath} )) ; then
> + chosen_vcs="${vcs}"
> + chosen_vcs_comm=("${(kv)vcs_comm[@]}")
> + chosen_backend_misc=("${(kv)backend_misc[@]}")
> + chosen_basedir_realpath="${basedir_realpath}"
> +
> + (( choose_first_available )) && break
> + fi
> + fi
> done
>
> - (( found == 0 )) && {
> + vcs="${chosen_vcs}"
> + vcs_comm=("${(kv)chosen_vcs_comm[@]}")
> + backend_misc=("${(kv)chosen_backend_misc[@]}")
> +
> + [ -z "${vcs}" ] && {
> vcs='-quilt-'; quiltmode='standalone'
> VCS_INFO_quilt standalone || VCS_INFO_set --nvcs
> return 0
> --
> 2.31.1
>
Messages sorted by:
Reverse Date,
Date,
Thread,
Author