1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-05-21 23:46:03 +02:00

Seth House, Simon Ruderich and myself: 27948: various vcs_info changes

Here's a diff-stat:

 Doc/Zsh/contrib.yo                                |  506 ++++++++++++++-------
 Functions/VCS_Info/.distfiles                     |    1 +
 Functions/VCS_Info/Backends/VCS_INFO_detect_hg    |   14 +-
 Functions/VCS_Info/Backends/VCS_INFO_get_data_git |   35 +-
 Functions/VCS_Info/Backends/VCS_INFO_get_data_hg  |  295 +++++++++----
 Functions/VCS_Info/VCS_INFO_formats               |   26 +-
 Functions/VCS_Info/VCS_INFO_hook                  |   10 +-
 Functions/VCS_Info/VCS_INFO_quilt                 |  190 ++++++++
 Functions/VCS_Info/vcs_info                       |   30 +-
 Misc/.distfiles                                   |    1 +
 Misc/vcs_info-examples                            |  496 ++++++++++++++++++++
 11 files changed, 1303 insertions(+), 301 deletions(-)

The major changes are vast improvements for the mercurial (hg) backend
(which was done almost entirely by Seth); improved documentation (mostly
done by Simon and again Seth); quilt support (as an addon and stand
alone, see the manual for details); a number of new hooks and a fair
share of bugfixes.
This commit is contained in:
Frank Terbeck 2010-05-10 10:46:48 +00:00
parent 144a06bf95
commit 0501efc54a
12 changed files with 1326 additions and 312 deletions

View File

@ -1,3 +1,15 @@
2010-05-10 Frank Terbeck <ft@bewatermyfriend.org>
* Seth House, Simon Ruderich and myself: 27948:
Doc/Zsh/contrib.yo, Functions/VCS_Info/.distfiles, Misc/.distfiles,
Misc/vcs_info-examples, Functions/VCS_Info/Backends/VCS_INFO_detect_hg,
Functions/VCS_Info/Backends/VCS_INFO_get_data_git,
Functions/VCS_Info/Backends/VCS_INFO_get_data_hg,
Functions/VCS_Info/VCS_INFO_formats, Functions/VCS_Info/VCS_INFO_hook,
Functions/VCS_Info/VCS_INFO_quilt, Functions/VCS_Info/vcs_info: various
vcs_info changes: mercurial backend improvements, new hooks, quilt
support, documentation improvements and bugfixes
2010-05-05 Peter Stephenson <pws@csr.com>
* users/15031: Completion/Unix/Type/_path_files: fix (still
@ -13105,5 +13117,5 @@
*****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL
* $Revision: 1.4973 $
* $Revision: 1.4974 $
*****************************************************

View File

@ -334,16 +334,20 @@ startsitem()
sitem(Bazaar (tt(bzr)))(http://bazaar-vcs.org/)
sitem(Codeville (tt(cdv)))(http://codeville.org/)
sitem(Concurrent Versioning System (tt(cvs)))(http://www.nongnu.org/cvs/)
sitem(tt(darcs))(http://darcs.net/)
sitem(tt(git))(http://git.or.cz/)
sitem(Darcs (tt(darcs)))(http://darcs.net/)
sitem(Git (tt(git)))(http://git-scm.com/)
sitem(GNU arch (tt(tla)))(http://www.gnu.org/software/gnu-arch/)
sitem(Mercurial (tt(hg)))(http://selenic.com/mercurial/)
sitem(Mercurial (tt(hg)))(http://mercurial.selenic.com/)
sitem(Monotone (tt(mtn)))(http://monotone.ca/)
sitem(Perforce (tt(p4)))(http://www.perforce.com/)
sitem(Subversion (tt(svn)))(http://subversion.tigris.org/)
sitem(SVK (tt(svk)))(http://svk.bestpractical.com/)
endsitem()
There is also support for the patch management system tt(quilt)
(http://savannah.nongnu.org/projects/quilt). See tt(Quilt Support)
below for details.
To load var(vcs_info):
example(autoload -Uz vcs_info)
@ -364,7 +368,7 @@ zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat '%b%F{1}:%F{3}%r'
precmd () { vcs_info }
PS1='%F{5}[%F{2}%n%F{5}] %F{3}%3~ ${vcs_info_msg_0_}%f%# ')
Obviously, the last two lines are there for demonstration: You need to
Obviously, the last two lines are there for demonstration. You need to
call var(vcs_info) from your var(precmd) function. Once that is done you need
a tt(single quoted) var('${vcs_info_msg_0_}') in your prompt.
@ -391,7 +395,10 @@ tla
## are enabled and disabled with their master [git-svn -> git])
## they *can* be used in contexts: ':vcs_info:git-svn:*'.
git-p4
git-svn)
git-svn
hg-git
hg-hgsubversion
hg-hgsvn)
You may not want all of these because there is no point in running the
code to detect systems you do not use. So there is a way to disable
@ -409,6 +416,7 @@ var(enable) style - if you used that) marked as disabled by a hash sign.
That means the detection of these systems is skipped tt(completely). No
wasted time there.
subsect(Configuration)
The var(vcs_info) feature can be configured via var(zstyle).
@ -418,9 +426,9 @@ example(:vcs_info:<vcs-string>:<user-context>:<repo-root-name>)
startitem()
item(tt(<vcs-string>))(
is one of: git, git-svn, git-p4, hg, darcs, bzr,
cdv, mtn, svn, cvs, svk, tla or p4. When hooks are active the hooks name
is added after a `+'. (See tt(Hooks in vcs_info) below.)
is one of: git, git-svn, git-p4, hg, hg-git, hg-hgsubversion, hg-hgsvn,
darcs, bzr, cdv, mtn, svn, cvs, svk, tla or p4. When hooks are active the
hooks name is added after a `+'. (See tt(Hooks in vcs_info) below.)
)
item(tt(<user-context>))(
is a freely configurable string, assignable by
@ -430,13 +438,13 @@ below).
item(tt(<repo-root-name>))(
is the name of a repository in which you want a
style to match. So, if you want a setting specific to var(/usr/src/zsh),
with that being a cvs checkout, you can set tt(<repo-root-name>) to
with that being a CVS checkout, you can set tt(<repo-root-name>) to
var(zsh) to make it so.
)
enditem()
There are three special values for tt(<vcs-string>): The first is named
var(-init-), that is in effect as long as there was no decision what vcs
var(-init-), that is in effect as long as there was no decision what VCS
backend to use. The second is var(-preinit-); it is used tt(before)
var(vcs_info) is run, when initializing the data exporting variables. The
third special value is var(formats) and is used by the tt(vcs_info_lastmsg)
@ -469,36 +477,28 @@ A list of formats, used when actionformats is not used
kindex(actionformats)
item(tt(actionformats))(
A list of formats, used if a there is a special
action going on in your current repository; (like an interactive rebase or
a merge conflict).
action going on in your current repository; like an interactive rebase or
a merge conflict.
)
kindex(branchformat)
item(tt(branchformat))(
Some backends replace var(%b) in the formats and
actionformats styles above, not only by a branch name but also by a
revision number. This style lets you modify how that string should look
like.
revision number. This style lets you modify how that string should look.
)
kindex(nvcsformats)
item(tt(nvcsformats))(
These "formats" are exported, when we didn't detect
a version control system for the current directory. This is useful, if you
These "formats" are exported when we didn't detect
a version control system for the current directory. This is useful if you
want var(vcs_info) to completely take over the generation of your prompt.
You would do something like tt(PS1='${vcs_info_msg_0_}') to accomplish
that.
)
kindex(stgitformat)
item(tt(stgitformat))(
The tt(git) backend replaces var(%m) in the formats and
actionformats styles with tt(stgit)-specific information for
tt(stgit)-initialized branches. This style lets you modify how that string
should look like.
)
kindex(hgrevformat)
item(tt(hgrevformat))(
tt(hg) uses both a hash and a revision number to reference a specific
changeset in a repository. With this style you can format the revision
string (see var(branchformat)) to include either of both. It's only
string (see var(branchformat)) to include either or both. It's only
useful when var(get-revision) is true.
)
kindex(max-exports)
@ -508,16 +508,15 @@ var(vcs_info_msg_*_) variables var(vcs_info) will export.
)
kindex(enable)
item(tt(enable))(
A list of backends you want to use. Checked in the
var(-init-) context. If this list contains an item called tt(NONE) no
backend is used at all and var(vcs_info) will do nothing. If this list
contains tt(ALL) var(vcs_info) will use all backends known to it. Only with
tt(ALL) in tt(enable), the tt(disable) style has any effect. tt(ALL) and
tt(NONE) are actually tested case insensitively.
A list of backends you want to use. Checked in the var(-init-) context. If
this list contains an item called tt(NONE) no backend is used at all and
var(vcs_info) will do nothing. If this list contains tt(ALL) var(vcs_info)
will use all known backends. Only with tt(ALL) in tt(enable) will the
tt(disable) style have any effect. tt(ALL) and tt(NONE) are case insensitive.
)
kindex(disable)
item(tt(disable))(
A list of VCSs, you don't want var(vcs_info) to test for
A list of VCSs you don't want var(vcs_info) to test for
repositories (checked in the var(-init-) context, too). Only used if
tt(enable) contains tt(ALL).
)
@ -531,19 +530,37 @@ Say, tt(~/.zsh) is a directory under version control, in which you do
not want var(vcs_info) to be active, do:
example(zstyle ':vcs_info:*' disable-patterns "$HOME/.zsh+LPAR()|/*+RPAR()")
)
kindex(use-quilt)
item(tt(use-quilt))(
If enabled, the tt(quilt) support code is active in `addon' mode.
See tt(Quilt Support) for details.
)
kindex(quilt-standalone)
item(tt(quilt-standalone))(
If enabled, `standalone' mode detection is attempted if no VCS is active
in a given directory. See tt(Quilt Support) for details.
)
kindex(quilt-patch-dir)
item(tt(quilt-patch-dir))(
Overwrite the value of the var($QUILT_PATCHES) environment variable. See
tt(Quilt Support) for details.
)
kindex(quiltcommand)
item(tt(quiltcommand))(
When tt(quilt) itself is called in quilt support the value of this style
is used as the command name.
)
kindex(check-for-changes)
item(tt(check-for-changes))(
If enabled, this style causes the tt(%c) and tt(%u) format escapes to be filled
with information. The strings filled into these escapes can be controlled via
the var(stagedstr) and var(unstagedstr) styles. The only backends that
currently support this option are tt(git) and tt(hg) (tt(hg) only supports
unstaged).
If enabled, this style causes the tt(%c) and tt(%u) format escapes to show
when the working directory has uncommitted changes. The strings displayed by
these escapes can be controlled via the var(stagedstr) and var(unstagedstr)
styles. The only backends that currently support this option are tt(git) and
tt(hg) (tt(hg) only supports unstaged).
Note, that the actions taken if this style is enabled are potentially expensive
(read: they take time, depending on how big the current repository is).
Therefore, it is disabled by default. In order to use this style with
the tt(hg) backend you must also use the var(get-revision) style to avoid
having to start the interpreter more than once.
Note, the actions taken if this style is enabled are potentially expensive
(read: they may be slow, depending on how big the current repository is).
Therefore, it is disabled by default.
)
kindex(stagedstr)
item(tt(stagedstr))(
@ -552,25 +569,25 @@ the repository.
)
kindex(unstagedstr)
item(tt(unstagedstr))(
This string will be used in the tt(%u) escape if there are unstaged changes in
the repository.
This string will be used in the tt(%u) escape if there are unstaged changes
in the repository.
)
kindex(command)
item(tt(command))(
This style causes var(vcs_info) to use the supplied string as the command
to use as the vcs's binary. Note, that setting this in ':vcs_info:*' is
to use as the VCS's binary. Note, that setting this in ':vcs_info:*' is
not a good idea.
If the value of this style is empty (which is the default), the used binary
name is the name of the backend in use (e.g. var(svn) is used in a var(svn)
name is the name of the backend in use (e.g. var(svn) is used in an var(svn)
repository).
The var(repo-root-name) part in the context is always the default tt(-all-)
when this style is looked up.
For example, this style can be used to use binaries from non-default
installation directories. Assume, var(git) is installed in /usr/bin, but
your sysadmin installed a newer version in /usr/bin/local. Now, instead of
installation directories. Assume, var(git) is installed in /usr/bin but
your sysadmin installed a newer version in /usr/bin/local. Instead of
changing the order of your tt($PATH) parameter, you can do this:
example(zstyle ':vcs_info:git:*:-all-' command /usr/local/bin/git)
)
@ -581,8 +598,8 @@ contact the Perforce server to find out if a directory is managed
by Perforce. This is the only reliable way of doing this, but runs
the risk of a delay if the server name cannot be found. If the
server (more specifically, the var(host)tt(:)var(port) pair describing the
server) cannot be contacted its name is put into the associative array
tt(vcs_info_p4_dead_servers) and not contacted again during the session
server) cannot be contacted, its name is put into the associative array
tt(vcs_info_p4_dead_servers) and is not contacted again during the session
until it is removed by hand. If you do not set this style, the tt(p4)
backend is only usable if you have set the environment variable
tt(P4CONFIG) to a file name and have corresponding files in the root
@ -594,8 +611,10 @@ item(tt(use-simple))(
If there are two different ways of gathering
information, you can select the simpler one by setting this style to true;
the default is to use the not-that-simple code, which is potentially a lot
slower but might be more accurate in all possible cases. This style is only
used by the tt(bzr) backend.
slower but might be more accurate in all possible cases. This style is
used by the tt(bzr) and tt(hg) backends. In the case of tt(hg) it will invoke
the external hexdump program to parse the binary dirstate cache file; this
method will not return the local revision number.
)
kindex(get-revision)
item(tt(get-revision))(
@ -604,15 +623,17 @@ a repository's work tree (currently for the tt(git) and tt(hg) backends,
where this kind of information is not always vital). For tt(git), the
hash value of the currently checked out commit is available via the tt(%i)
expansion. With tt(hg), the local revision number and the corresponding
global hash are available via tt(%i); in addition, the topmost
applied tt(mq) patch and bookmarks are available via tt(%m).
If this style is set in the tt(hg) context, the backend supports the
var(branchformat) style.
global hash are available via tt(%i).
)
kindex(get-mq)
item(tt(get-mq))(
If set to true, the tt(hg) backend will look for a Mercurial Queue (tt(mq))
patch directory. Information will be available via the `tt(%m)' replacement.
)
kindex(get-bookmarks)
item(tt(get-bookmarks))(
If set to true, the tt(hg) backend will try to get a list of current
bookmarks. They will be available in via the `tt(%m)' replacement.
bookmarks. They will be available via the `tt(%m)' replacement.
)
kindex(use-prompt-escapes)
item(tt(use-prompt-escapes))(
@ -622,12 +643,12 @@ tt(vcs_info_lastmsg).)
)
kindex(debug)
item(tt(debug))(
Enable debugging output, to track possible problems. Currently this style
is only used by tt(vcs_info)'s hooks system.
Enable debugging output to track possible problems. Currently this style
is only used by var(vcs_info)'s hooks system.
)
kindex(hooks)
item(tt(hooks))(
A list style, that defines hook-function names. See tt(Hooks in vcs_info)
A list style that defines hook-function names. See tt(Hooks in vcs_info)
below for details.
)
enditem()
@ -639,7 +660,6 @@ sitem(tt(formats))(" (%s)-[%b]-")
sitem(tt(actionformats))(" (%s)-[%b|%a]-")
sitem(tt(branchformat))("%b:%r" (for bzr, svn, svk and hg))
sitem(tt(nvcsformats))("")
sitem(tt(stgitformat))(" %p (%c)")
sitem(tt(hgrevformat))("%r:%h")
sitem(tt(max-exports))(2)
sitem(tt(enable))(ALL)
@ -652,62 +672,70 @@ sitem(tt(command))((empty string))
sitem(tt(use-server))(false)
sitem(tt(use-simple))(false)
sitem(tt(get-revision))(false)
sitem(tt(get-mq))(true)
sitem(tt(get-bookmarks))(false)
sitem(tt(use-prompt-escapes))(true)
sitem(tt(debug))(false)
sitem(tt(hooks))((empty list))
sitem(tt(use-quilt))(false)
sitem(tt(quilt-standalone))(false)
sitem(tt(quilt-patch-dir))(empty - use var($QUILT_PATCHES))
sitem(tt(quiltcommand))(quilt)
endsitem()
In normal tt(formats) and tt(actionformats), the following replacements are
In normal tt(formats) and tt(actionformats) the following replacements are
done:
startsitem()
sitem(tt(%s))(The vcs in use (git, hg, svn etc.))
sitem(tt(%s))(The VCS in use (git, hg, svn, etc.).)
sitem(tt(%b))(Information about the current branch.)
sitem(tt(%a))(An identifier, that describes the action. Only makes sense in
actionformats.)
sitem(tt(%a))(An identifier that describes the action. Only makes sense in
var(actionformats).)
sitem(tt(%i))(The current revision number or identifier. For tt(hg)
the var(hgrevformat) style may be used to customize the output.)
sitem(tt(%c))(The string from the var(stagedstr) style if there are staged
changes in the repository.)
sitem(tt(%u))(The string from the var(unstagedstr) style if there are unstaged
changes in the repository.)
sitem(tt(%R))(base directory of the repository.)
sitem(tt(%r))(repository name. If tt(%R) is var(/foo/bar/repoXY), tt(%r) is
var(repoXY).)
sitem(tt(%S))(subdirectory within a repository. If tt($PWD) is
sitem(tt(%u))(The string from the var(unstagedstr) style if there are
unstaged changes in the repository.)
sitem(tt(%R))(The base directory of the repository.)
sitem(tt(%r))(The repository name. If tt(%R) is var(/foo/bar/repoXY), tt(%r)
is var(repoXY).)
sitem(tt(%S))(A subdirectory within a repository. If tt($PWD) is
var(/foo/bar/repoXY/beer/tasty), tt(%S) is var(beer/tasty).)
sitem(tt(%m))(A "misc" replacement. It is at the discretion of the backend
to decide what this replacement expands to. It is currently used by
the tt(hg) and tt(git) backends. The tt(hg) backend replaces tt(%m) with the
topmost tt(mq) patch applied (qtop) and a list of any current bookmarks. The
tt(git) backend replaces it with the string from the var(stgitformat)
style.)
sitem(tt(%m))(A "misc" replacement. It is at the discretion of the backend to
decide what this replacement expands to. It is currently used by the tt(hg)
and tt(git) backends to display patch information from the tt(mq) and
tt(stgit) extensions.)
endsitem()
In tt(branchformat) these replacements are done:
startsitem()
sitem(tt(%b))(the branch name)
sitem(tt(%r))(the current revision number or the var(hgrevformat) style for tt(hg))
endsitem()
In tt(stgitformat) these replacements are done:
startsitem()
sitem(tt(%p))(the name of the patch currently on top of the stack)
sitem(tt(%c))(the number of unapplied patches)
sitem(tt(%b))(The branch name.)
sitem(tt(%r))(The current revision number or the var(hgrevformat) style for
tt(hg).)
endsitem()
In tt(hgrevformat) these replacements are done:
startsitem()
sitem(tt(%r))(the current revision number)
sitem(tt(%h))(the hash identifier for the current resivion in short form)
sitem(tt(%r))(The current local revision number.)
sitem(tt(%h))(The current 40-character changeset ID hash identifier.)
endsitem()
Not all vcs backends have to support all replacements. For tt(nvcsformats)
no replacements are performed at all. It is just a string.
In tt(patch-format) and tt(nopatch-format) these replacements are done:
startsitem()
sitem(tt(%p))(The name of the top-most applied patch.)
sitem(tt(%u))(The number of unapplied patches.)
sitem(tt(%n))(The number of applied patches.)
sitem(tt(%c))(The number of unapplied patches.)
sitem(tt(%g))(The names of active tt(mq) guards (tt(hg) backend).)
sitem(tt(%G))(The number of active tt(mq) guards (tt(hg) backend).)
endsitem()
Not all VCS backends have to support all replacements. For tt(nvcsformats)
no replacements are performed at all, it is just a string.
subsect(Oddities)
@ -720,21 +748,110 @@ cannot be easily avoided. Luckily we do not clash with a lot of prompt
expansions and this only needs to be done for those.
subsect(Function descriptions (public API))
subsect(Quilt Support)
tt(Quilt) is not a version control system, therefore this is not implemented
as a backend. It can help keeping track of a series of patches. People use it
to keep a set of changes they want to use on top of software packages (which
is tightly integrated into the package build process - the Debian project
does this for a large number of packages). Quilt can also help individual
developers keep track of their own patches on top of real version control
systems.
The var(vcs_info) integration tries to support both ways of using quilt by
having two slightly different modes of operation: `addon' mode and
`standalone' mode).
For `addon' mode to become active var(vcs_info) must have already detected a
real version control system controlling the directory. If that is the case,
a directory that holds quilt's patches needs to be found. That directory is
configurable via the var(`QUILT_PATCHES') environment variable. If that
variable exists its value is used, otherwise the value tt(`patches') is
assumed. The value from var($QUILT_PATCHES) can be overwritten using the
tt(`quilt-patches') style. (Note: you can use var(vcs_info) to keep the value
of var($QUILT_PATCHES) correct all the time via the tt(post-quilt) hook).
When the directory in question is found, quilt is assumed to be active. To
gather more information, var(vcs_info) looks for a directory called `.pc';
Quilt uses that directory to track its current state. If this directory does
not exist we know that quilt has not done anything to the working directory
(read: no patches have been applied yet).
If patches are applied, var(vcs_info) will try to find out which. If you want
to know which patches of a series are not yet applied, you need to activate
the tt(get-unapplied) style in the appropriate context.
var(vcs_info) allows for very detailed control over how the gathered
information is presented (see the below sections, tt(Styles) and tt(Hooks in
vcs_info)), all of which are documented below. Note there are a number of
other patch tracking systems that work on top of a certain version control
system (like tt(stgit) for tt(git), or tt(mq) for tt(hg)); the configuration
for systems like that are generally configured the same way as the tt(quilt)
support.
If the tt(quilt) support is working in `addon' mode, the produced string is
available as a simple format replacement (var(%Q) to be precise), which can
be used in tt(formats) and tt(actionformats); see below for details).
If, on the other hand, the support code is working in `standalone' mode,
var(vcs_info) will pretend as if tt(quilt) were an actual version control
system. That means that the version control system identifier (which
otherwise would be something like `svn' or `cvs') will be set to
`tt(-quilt-)'. This has implications on the used style context where this
identifier is the second element. var(vcs_info) will have filled in a proper
value for the "repository's" root directory and the string containing the
information about quilt's state will be available as the `misc' replacement
(and var(%Q) for compatibility with `addon' mode.
What is left to discuss is how `standalone' mode is detected. The detection
itself is a series of searches for directories. You can have this detection
enabled all the time in every directory that is not otherwise under version
control. If you know there is only a limited set of trees where you would
like var(vcs_info) to try and look for Quilt in `standalone' mode to minimise
the amount of searching on every call to var(vcs_info), there are a number of
ways to do that:
Essentially, `standalone' mode detection is controlled by a style called
`tt(quilt-standalone)'. It is a string style and its value can have different
effects. The simplest values are: `tt(always)' to run detection every time
var(vcs_info) is run, and `tt(never)' to turn the detection off entirely.
If the value of tt(quilt-standalone) is something else, it is interpreted
differently. If the value is the name of a scalar variable the value of that
variable is checked and that value is used in the same `always'/`never' way
as described above.
If the value of tt(quilt-standalone) is an array, the elements of that array
are used as directory names under which you want the detection to be active.
If tt(quilt-standalone) is an associative array, the keys are taken as
directory names under which you want the detection to be active, but only if
the corresponding value is the string `tt(true)'.
Last, but not least, if the value of tt(quilt-standalone) is the name of a
function, the function is called without arguments and the return value
decides whether detection should be active. A `0' return value is true; a
non-zero return value is interpreted as false.
Note, if there is both a function and a variable by the name of
tt(quilt-standalone), the function will take precedence.
subsect(Function Descriptions (Public API))
startitem()
findex(vcs_info)
item(tt(vcs_info) [var(user-context)])(
The main function, that runs all
backends and assembles all data into var(${vcs_info_msg_*_}). This is the
function you want to call from tt(precmd) if you want to include up-to-date
information in your prompt (see Variable description below). If an argument
is given, that string will be used instead of tt(default) in the
user-context field of the style context.
The main function, that runs all backends and assembles all data into
var(${vcs_info_msg_*_}). This is the function you want to call from
tt(precmd) if you want to include up-to-date information in your prompt (see
tt(Variable description) below). If an argument is given, that string will be
used instead of tt(default) in the tt(user-context) field of the style
context.
)
item(tt(vcs_info_lastmsg))(
Outputs the last var(${vcs_info_msg_*_}) value.
Takes into account the value of the use-prompt-escapes style in
Takes into account the value of the tt(use-prompt-escapes) style in
var(':vcs_info:formats:command:-all-'). It also only prints tt(max-exports)
values.
)
@ -753,14 +870,14 @@ enditem()
All functions named VCS_INFO_* are for internal use only.
subsect(Variable description)
subsect(Variable Description)
startitem()
item(tt(${vcs_info_msg_N_}) (Note the trailing underscore))
(
Where var(N) is an integer, eg: var(vcs_info_msg_0_) These variables
Where var(N) is an integer, e.g., var(vcs_info_msg_0_). These variables
are the storage for the informational message the last var(vcs_info) call
has assembled. These are strongly connected to the formats,
has assembled. These are strongly connected to the tt(formats),
tt(actionformats) and tt(nvcsformats) styles described above. Those styles
are lists. The first member of that list gets expanded into
var(${vcs_info_msg_0_}), the second into var(${vcs_info_msg_1_})
@ -773,7 +890,7 @@ All variables named VCS_INFO_* are for internal use only.
subsect(Hooks in vcs_info)
Hooks are places in tt(vcs_info) where you can run your own code. That
Hooks are places in var(vcs_info) where you can run your own code. That
code can communicate with the code that called it and through that,
change the system's behaviour.
@ -799,114 +916,152 @@ When you register more than one function to a hook, all functions are
executed one after another until one function returns non-zero or until
all functions have been called.
There are a number of variables, that are special in hook contexts:
You may pass data between functions via an associative array, tt(user_data).
For example:
example(
+vi-git-myfirsthook+LPAR()RPAR(){
user_data[myval]=$myval
}
+vi-git-mysecondhook+LPAR()RPAR(){
# do something with ${user_data[myval]}
})
There are a number of variables that are special in hook contexts:
startitem()
item(tt(ret))(
The return value, that the hooks system will return to the caller. The
The return value that the hooks system will return to the caller. The
default is an integer `zero'. If and how a changed tt(ret) value changes
the execution of the caller depends on the specific hook. See the hook's
the execution of the caller depends on the specific hook. See the hook
documentation below for details.
)
item(tt(hook_com))(
An associated array, which is used for bidirectional communication from
An associated array which is used for bidirectional communication from
the caller to hook functions. The used keys depend on the specific hook.
)
item(tt(context))(
The active context of the hook. Functions that wish to change this
variable should make it local scope first.
)
item(tt(vcs))(
The current VCS after it was detected. The same values as in the
enable/disable style are used. Available in all hooks except tt(start-up).
)
enditem()
Finally, the full list of currently available hooks:
startitem()
item(tt(start-up))(
Called after starting var(vcs_info) but before the VCS in this directory is
determined. It can be used to deactivate var(vcs_info) temporarily if
necessary. When tt(ret) is set to var(1), var(vcs_info) aborts and does
nothing; when set to var(2), var(vcs_info) sets up everything as if no
version control were active and exits.
)
item(tt(pre-get-data))(
Same as tt(start-up) but after the VCS was detected.
)
item(tt(gen-hg-bookmark-string))(
Called in the Mercurial backend (the tt(get-revision) and tt(get-bookmarks)
styles must be active) when a bookmark string is generated.
Called in the Mercurial backend when a bookmark string is generated; the
tt(get-revision) and tt(get-bookmarks) styles must be true.
This hook gets the names of the Mercurial bookmarks, that
tt(vcs_info) collected from `hg'.
This hook gets the names of the Mercurial bookmarks that
var(vcs_info) collected from `hg'.
When setting tt(ret) to non-zero, the string in
tt(${hook_com[hg-bookmark-string]}) will be used as the
`tt(misc1)' replacement in the variables set by tt(vcs_info).
tt(${hook_com[hg-bookmark-string]}) will be used in the var(%m) escape in
tt(formats) and tt(actionformats) and will be availabe in the global
var(backend_misc) array as tt(${backend_misc[bookmarks]}).
)
item(tt(gen-mq-patch-string))(
Called in the Mercurial backend when a mq-patch string is generated. That
only happens if a tt(.hg/patches) directory exists in the repository.
item(tt(gen-applied-string))(
Called in the tt(git) (with tt(stgit)), and tt(hg) (with tt(mq)) backends
and in tt(quilt) support when the var(applied-string) is generated; the
tt(use-quilt) zstyle must be true for tt(quilt) (the tt(mq) and tt(stgit)
backends are active by default).
This hook gets the names of all applied mq patches which tt(vcs_info)
collected so far in the opposite order, which mean that the first argument
is the top-most patch and so forth.
This hook gets the names of all applied patches which var(vcs_info) collected
so far in the opposite order, which means that the first argument is the
top-most patch and so forth.
When setting tt(ret) to non-zero, the string in
tt(${hook_com[hg-mqpatch-string]}) will be used as the
`tt(misc0)' replacement in the variables set by tt(vcs_info).
tt(${hook_com[applied-string]}) will be used in the var(%m) escape in
tt(formats) and tt(actionformats); it will be available in the global
var(backend_misc) array as tt($backend_misc[patches]}); and it will be
available as var(%p) in the tt(patch-format) and tt(nopatch-format) styles.
)
item(tt(gen-stgit-patch-string))(
Called in the git backend when a stgit-patch string is generated. That
only happens if stgit is in use in the repository.
item(tt(gen-unapplied-string))(
Called in the tt(git) (with tt(stgit)), and tt(hg) (with tt(mq)) backend
and in tt(quilt) support when the var(unapplied-string) is generated; the
tt(get-unapplied) style must be true.
This hook gets the names of all applied stgit patches which tt(vcs_info)
collected so far in the opposite order, which mean that the first argument
is the top-most patch and so forth.
This hook gets the names of all unapplied patches which var(vcs_info)
collected so far in the opposite order, which mean that the first argument is
the patch next-in-line to be applied and so forth.
When setting tt(ret) to non-zero, the string in
tt(${hook_com[stgit-patch-string]}) will be used as the
`tt(misc0)' replacement in the variables set by tt(vcs_info).
tt(${hook_com[unapplied-string]}) will be available as var(%u) in the
tt(patch-format) and tt(nopatch-format) styles.
)
item(tt(gen-stgit-unapplied-string))(
Called in the git backend when a stgit-unapplied string is generated. That
only happens if stgit is in use in the repository.
item(tt(gen-mqguards-string))(
Called in the tt(hg) backend when tt(guards-string) is generated; the
tt(get-mq) style must be true (default).
This hook gets the names of all unapplied stgit patches which tt(vcs_info)
collected so far.
This hook gets the names of any active tt(mq) guards.
When setting tt(ret) to non-zero, the string in
tt(${hook_com[stgit-unapplied-string]}) will be used as the
`tt(misc0)' replacement in the variables set by tt(vcs_info).
tt(${hook_com[guards-string]}) will be used in the var(%g) escape in the
tt(patch-format) and tt(nopatch-format) styles.
)
item(tt(post-quilt))(
Called after the tt(quilt) support is done. The following information
is passed as arguments to the hook: 1. the quilt-support mode (`addon' or
`standalone'); 2. the directory that contains the patch series; 3. the
directory that holds quilt's status information (the `.pc' directory) or
the string tt("-nopc-") if that directory wasn't found.
The `hook_com' parameter is not used.
)
item(tt(set-branch-format))(
Called before a `tt(branchformat)' is set. The only argument to the
Called before `tt(branchformat)' is set. The only argument to the
hook is the format that is configured at this point.
The `tt(hook_com)' keys considered are `tt(branch)' and `tt(revision)'.
They are set to the values figured out so far by tt(vcs_info) and any
They are set to the values figured out so far by var(vcs_info) and any
change will be used directly when the actual replacement is done.
If tt(ret) is set to to non-zero, the string in
tt(${hook_com[branch-replace]}) will be used unchanged as the
`tt(%b)' replacement in the variables set by tt(vcs_info).
`tt(%b)' replacement in the variables set by var(vcs_info).
)
item(tt(set-hgrev-format))(
Called before a `tt(hgrevformat)' is set. The only argument to the
hook is the format that is configured at this point.
The `tt(hook_com)' keys considered are `tt(hash)' and `tt(localref)'.
They are set to the values figured out so far by tt(vcs_info) and any
The `tt(hook_com)' keys considered are `tt(hash)' and `tt(localrev)'.
They are set to the values figured out so far by var(vcs_info) and any
change will be used directly when the actual replacement is done.
If tt(ret) is set to to non-zero, the string in
tt(${hook_com[rev-replace]}) will be used unchanged as the
`tt(%i)' replacement in the variables set by tt(vcs_info).
`tt(%i)' replacement in the variables set by var(vcs_info).
)
item(tt(set-message))(
Called each time before a `tt(vcs_info_msg_N_)' message is set.
It takes two arguments; the first being the `N' in the message
variable name, the second is the currently configured format or
actionformat.
variable name, the second is the currently configured tt(formats) or
tt(actionformats).
There are a number of `tt(hook_com)' keys, that are used here:
`tt(action)', `tt(branch)', `tt(base)', `tt(base-name)', `tt(subdir)',
`tt(staged)', `tt(unstaged)', `tt(revision)', `tt(misc)', `tt(vcs)'
and one `tt(miscN)' entry for each backend-specific data field (tt(N)
starting at zero). They are set to the values figured out so far by
tt(vcs_info) and any change will be used directly when the actual
var(vcs_info) and any change will be used directly when the actual
replacement is done.
Since this hook is triggered multiple times (once for each configured
format or actionformat), each of the `tt(hook_com)' keys mentioned
tt(formats) or tt(actionformats)), each of the `tt(hook_com)' keys mentioned
above (except for the tt(miscN) entries) has an `tt(_orig)' counterpart,
so even if you changed a value to your liking you can still get the
original value in the next run. Changing the `tt(_orig)' values is
@ -914,28 +1069,16 @@ probably not a good idea.
If tt(ret) is set to to non-zero, the string in
tt(${hook_com[message]}) will be used unchanged as the message by
tt(vcs_info).
var(vcs_info).
)
item(tt(set-stgit-format))(
Called before a `tt(stgitformat)' is set. The only argument to the
hook is the format that is configured at this point.
The `tt(hook_com)' keys considered are `tt(patch)' and `tt(unapplied)'.
They are set to the values figured out so far by tt(vcs_info) and any
change will be used directly when the actual replacement is done.
If tt(ret) is set to to non-zero, the string in
tt(${hook_com[stgit-replace]}) will be used unchanged as the
`tt(misc0)' replacement in the variables set by tt(vcs_info).
)
enditem()
If all of this sounds rather confusing, take a look at the tt(Examples)
section below. It contains some explanatory code.
section below and also in the Misc/vcs_info-examples file in the Zsh source.
They contain some explanatory code.
subsect(Examples)
Don't use tt(vcs_info) at all (even though it's in your prompt):
Don't use var(vcs_info) at all (even though it's in your prompt):
example(zstyle ':vcs_info:*' enable NONE)
Disable the backends for tt(bzr) and tt(svk):
@ -948,6 +1091,17 @@ Provide a special formats for tt(git):
example(zstyle ':vcs_info:git:*' formats ' GIT, BABY! [%b]'
zstyle ':vcs_info:git:*' actionformats ' GIT ACTION! [%b|%a]')
All tt(%x) expansion in all sorts of formats ("formats", "actionformats",
branchformat, you name it) are done using the `tt(zformat)' builtin from
the `tt(zsh/zutil)' module. That means you can do everything with these
tt(%x) items what zformat supports. In particular, if you want something
that is really long to have a fixed width, like a hash in a mercurial
branchformat, you can do this: tt(%12.12i). That'll shrink the 40 character
hash to its 12 leading characters. The form is actually
`tt(%)var(min)tt(.)var(max)tt(x)'. More is possible.
See ifzman(the section `The zsh/zutil Module' in zmanref(zshmodules))\
ifnzman(noderef(The zsh/zutil Module)) for details.
Use the quicker tt(bzr) backend
example(zstyle ':vcs_info:bzr:*' use-simple true)
@ -956,10 +1110,10 @@ If you do use tt(use-simple), please report if it does `the-right-thing[tm]'.
Display the revision number in yellow for tt(bzr) and tt(svn):
example(zstyle ':vcs_info:(svn|bzr):*' branchformat '%b%{'${fg[yellow]}'%}:%r')
If you want colors, make sure you enclose the color codes in tt(%{...%}),
if you want to use the string provided by tt(vcs_info) in prompts.
If you want colors, make sure you enclose the color codes in tt(%{...%})
if you want to use the string provided by var(vcs_info) in prompts.
Here is how to print the vcs information as a command (not in a prompt):
Here is how to print the VCS information as a command (not in a prompt):
example(alias vcsi='vcs_info command; vcs_info_lastmsg')
This way, you can even define different formats for output via
@ -967,15 +1121,15 @@ tt(vcs_info_lastmsg) in the ':vcs_info:*:command:*' namespace.
Now as promised, some code that uses hooks:
say, you'd like to replace the string `svn' by `subversion' in
tt(vcs_info)'s tt(%s) format-replacement.
var(vcs_info)'s tt(%s) tt(formats) replacement.
First, we will tell tt(vcs_info) to call a function when populating
First, we will tell var(vcs_info) to call a function when populating
the message variables with the gathered information:
example(zstyle ':vcs_info:*+set-message:*' hooks svn2subversion)
Nothing happens. Which is reasonable, since there we didn't define
the actual function yet. To see what the hooks subsystem is trying to
do, enable the `tt(debug)' style:
Nothing happens. Which is reasonable, since we didn't define the actual
function yet. To see what the hooks subsystem is trying to do, enable the
`tt(debug)' style:
example(zstyle ':vcs_info:*+*:*' debug true)
That should give you an idea what is going on. Specifically, the function
@ -1010,7 +1164,7 @@ And then we define the `tt(+vi-hgbookmarks) function:
example(
function +vi-hgbookmarks+LPAR()RPAR() {
# The default is to connect all bookmark names by
# semicolons. This mixes things up a little.
# commas. This mixes things up a little.
# Imagine, there's one type of bookmarks that is
# special to you. Say, because it's *your* work.
# Those bookmarks look always like this: "sh/*"
@ -1018,8 +1172,7 @@ function +vi-hgbookmarks+LPAR()RPAR() {
# This makes the bookmarks string use only those
# bookmarks. If there's more than one, it
# concatenates them using commas.
local s i)
example(
local s i
# The bookmarks returned by `hg' are available in
# the functions positional parameters.
(( $# == 0 )) && return 0
@ -1028,22 +1181,25 @@ example(
[[ -n $s ]] && s=$s,
s=${s}$i
fi
done)
example(
done
# Now, the communication with the code that calls
# the hook functions is done via the hook_com[]
# hash. The key, at which the `gen-hg-bookmark-string'
# hook looks at is `hg-bookmark-string'. So:
hook_com[hg-bookmark-string]=$s)
example(
hook_com[hg-bookmark-string]=$s
# And to signal, that we want to use the sting we
# just generated, set the special variable `ret' to
# something other than the default zero:
ret=1
return 0
})
}
)
This concludes our guided tour through zsh's tt(vcs_info).
Some longer examples and code snippets which might be useful are available in
the examples file located at Misc/vcs_info-examples in the Zsh source
directory.
This concludes our guided tour through zsh's var(vcs_info).
texinode(Prompt Themes)(ZLE Functions)(Version Control Information)(User Contributions)

View File

@ -11,6 +11,7 @@ vcs_info_lastmsg
VCS_INFO_maxexports
VCS_INFO_nvcsformats
vcs_info_printsys
VCS_INFO_quilt
VCS_INFO_realpath
VCS_INFO_reposub
VCS_INFO_set

View File

@ -4,9 +4,17 @@
setopt localoptions NO_shwordsplit
[[ $1 == '--flavours' ]] && return 1
[[ $1 == '--flavours' ]] && { print -l hg-git hg-hgsubversion hg-hgsvn; return 0 }
VCS_INFO_check_com ${vcs_comm[cmd]} || return 1
vcs_comm[detect_need_file]=store
VCS_INFO_bydir_detect '.hg'
return $?
VCS_INFO_bydir_detect '.hg' || return 1
if [[ -d ${vcs_comm[basedir]}/.hg/svn ]] ; then
vcs_comm[overwrite_name]='hg-hgsubversion'
elif [[ -d ${vcs_comm[basedir]}/.hgsvn ]] ; then
vcs_comm[overwrite_name]='hg-hgsvn'
elif [[ -e ${vcs_comm[basedir]}/.hg/git-mapfile ]] ; then
vcs_comm[overwrite_name]='hg-git'
fi
return 0

View File

@ -3,7 +3,7 @@
## Distributed under the same BSD-ish license as zsh itself.
setopt localoptions extendedglob NO_shwordsplit
local gitdir gitbase gitbranch gitaction gitunstaged gitstaged gitsha1 gitmisc
local gitdir gitbase gitbranch gitaction gitunstaged gitstaged gitsha1
local stgitpatch stgitunapplied
local -xA hook_com
@ -139,33 +139,40 @@ if [[ -d $patchdir ]] ; then
stgit_unapplied=(${(f)"$(< "${patchdir}/unapplied")"})
stgit_unapplied=( ${(oa)stgit_applied} )
if VCS_INFO_hook 'gen-stgit-patch-string' "${stgit_applied[@]}"; then
if VCS_INFO_hook 'gen-applied-string' "${stgit_applied[@]}"; then
if (( ${#stgit_applied} )); then
stgitpatch=${stgit_applied[1]}
else
stgitpatch="no patch applied"
stgitpatch=""
fi
else
stgitpatch=${hook_com[stgit-patch-string]}
stgitpatch=${hook_com[patch-string]}
fi
if VCS_INFO_hook 'gen-stgit-unapplied-string' "${stgit_unapplied[@]}"; then
hook_com=()
if VCS_INFO_hook 'gen-unapplied-string' "${stgit_unapplied[@]}"; then
stgitunapplied=${#stgit_unapplied}
else
stgitunapplied=${hook_com[stgit-unapplied-string]}
stgitunapplied=${hook_com[unapplied-string]}
fi
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" stgitformat stgitmsg || stgitmsg=" %p (%c)"
hook_com=( patch "${stgitpatch}" unapplied "${stgitunapplied}" )
if VCS_INFO_hook 'set-stgit-format' "${stgitformat}"; then
zformat -f stgitmsg "${stgitmsg}" "p:${hook_com[patch]}" "c:${hook_com[unapplied]}"
gitmisc=${stgitmsg}
if (( ${#stgit_applied} )); then
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" patch-format stgitmsg || stgitmsg="%p (%n applied)"
else
gitmisc=${hook_com[stgit-replace]}
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" nopatch-format stgitmsg || stgitmsg="no patch applied"
fi
hook_com=( applied "${stgitpatch}" unapplied "${stgitunapplied}"
applied-n ${#stgit_applied} unapplied-n ${#stgit_unapplied} )
if VCS_INFO_hook 'set-patch-format' "${stgitmsg}"; then
zformat -f stgitmsg "${stgitmsg}" "p:${hook_com[applied]}" "u:${hook_com[unapplied]}" \
"n:${#stgit_applied}" "c:${#stgit_unapplied}"
else
stgitmsg=${hook_com[patch-replace]}
fi
hook_com=()
else
gitmisc=''
stgitmsg=''
fi
VCS_INFO_formats "${gitaction}" "${gitbranch}" "${gitbase}" "${gitstaged}" "${gitunstaged}" "${gitsha1}" "${gitmisc}"
backend_misc[patches]="${stgitmsg}"
VCS_INFO_formats "${gitaction}" "${gitbranch}" "${gitbase}" "${gitstaged}" "${gitunstaged}" "${gitsha1}" "${stgitmsg}"
return 0

View File

@ -1,128 +1,239 @@
## vim:ft=zsh
## mercurial support by: Frank Terbeck <ft@bewatermyfriend.org>
## with large contributions by Seth House <seth@eseth.com>
## Distributed under the same BSD-ish license as zsh itself.
setopt localoptions NO_shwordsplit
local file hgbranch hgbranch_name hgbase hghash hglrev hgmqstring \
r_branch hgchanges revformat bookmarks r_bmhash r_bmname hgbmstring
local -i getbookmarks
local -a hgbm mqpatches hgmisc_args
setopt localoptions extendedglob NO_shwordsplit
local hgbase bmfile branchfile rebasefile dirstatefile mqseriesfile \
mqstatusfile mqguardsfile patchdir mergedir \
r_csetid r_lrev r_branch i_bmhash i_bmname \
revformat branchformat hgactionstring hgchanges \
hgbmstring hgmqstring applied_string unapplied_string guards_string
local -a hgid_args defrevformat defbranchformat \
hgbmarks mqpatches mqseries mqguards mqunapplied hgmisc \
i_patchguards i_negguards i_posguards
local -xA hook_com
hgbase=${vcs_comm[basedir]}
rrn=${hgbase:t}
r_csetid='' # changeset id (long hash)
r_lrev='' # local revision
patchdir="${hgbase}/.hg/patches"
mergedir="${hgbase}/.hg/merge/"
bmfile="${hgbase}/.hg/bookmarks"
branchfile="${hgbase}/.hg/branch"
rebasefile="${hgbase}/.hg/rebasestate"
dirstatefile="${hgbase}/.hg/dirstate"
mqstatusfile="${patchdir}/status" # currently applied patches
mqseriesfile="${patchdir}/series" # all patches
mqguardsfile="${patchdir}/guards"
file="${hgbase}/.hg/branch"
if [[ -r ${file} ]] ; then
hgbranch_name=$(< ${file})
else
hgbranch_name="default"
fi
# Look for any --flavours
VCS_INFO_adjust
hghash=''
hglrev=''
hgbm=()
bookmarks="${hgbase}/.hg/bookmarks"
# Calling the 'hg' program is quite a bit too slow for prompts.
# Disabled by default anyway, so no harm done.
if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision ; then
# Calling the 'hg' program is quite a bit too slow for prompts.
# If there's a way around that, I'd be interested.
# Disabled by default anyway, so no harm done.
local HGRCPATH
if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" \
"check-for-changes" ; then
HGRCPATH="/dev/null" ${vcs_comm[cmd]} id --debug -i -n -b \
| read -r hghash hglrev r_branch
# Are there uncommitted-changes?
if [[ $hglrev[-1] == + ]] ; then
hgchanges=1
fi
# Remove uncommitted-changes marker, if any
hglrev=${hglrev/+/}
hghash=${hghash/+/}
# Calling hexdump is (much) faster than hg but doesn't get the local rev
if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" use-simple \
&& ( VCS_INFO_check_com hexdump ) && [[ -r ${dirstatefile} ]] ; then
r_csetid=$(hexdump -n 20 -e '1/1 "%02x"' ${dirstatefile})
else
HGRCPATH="/dev/null" ${vcs_comm[cmd]} \
parents --template="{node} {rev} {branches}\n" \
| read -r hghash hglrev r_branch
fi
hgid_args=( --debug id -i -n -b )
if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" "get-bookmarks" \
&& getbookmarks=1 || getbookmarks=0
# Looking for changes is a tad bit slower since the dirstate cache must
# first be refreshed before being read
zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" \
"check-for-changes" || hgid_args+=( -r. )
if (( getbookmarks )) && [[ -r "${bookmarks}" ]] ; then
while read -r r_bmhash r_bmname ; do
if [[ $hghash == $r_bmhash ]] ; then
hgbm=( "$r_bmname" ${hgbm} )
fi
done < ${bookmarks}
local HGRCPATH
HGRCPATH="/dev/null" ${vcs_comm[cmd]} ${(z)hgid_args} \
| read -r r_csetid r_lrev r_branch
fi
if [[ -n ${hglrev} ]] ; then
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" hgrevformat revformat || revformat="%r:%h"
hook_com=( localrev "${hglrev}" "hash" "${hghash}" )
if VCS_INFO_hook 'set-hgrev-format' "${revformat}"; then
zformat -f hglrev "${revformat}" "r:${hook_com[localrev]}" "h:${hook_com[hash]}"
else
hglrev=${hook_com[rev-replace]}
fi
hook_com=()
if (( getbookmarks )) ; then
if VCS_INFO_hook 'gen-hg-bookmark-string' "${hgbm[@]}"; then
hgbmstring=${(j.;.)hgbm}
else
hgbmstring=${hook_com[hg-bookmark-string]}
fi
hook_com=()
fi
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" branchformat hgbranch || hgbranch="%b:%r"
hook_com=( branch "${hgbranch_name}" revision "${hglrev}" )
if VCS_INFO_hook 'set-branch-format' "${hgbranch}"; then
zformat -f hgbranch "${hgbranch}" "b:${hook_com[branch]}" "r:${hook_com[revision]}"
else
hgbranch=${hook_com[branch-replace]}
fi
hook_com=()
fi
else
hgbranch="${hgbranch_name}"
fi
local patchdir=${hgbase}/.hg/patches/
# If the user doesn't opt to invoke hg we can still get the current branch
if [[ -z ${r_branch} && -r ${branchfile} ]] ; then
r_branch=$(< ${branchfile})
else
r_branch="default"
fi
if [[ -d $patchdir ]] ; then
local -a mqpatches
if [[ -e "${patchdir}/status" ]]; then
# The working dir has uncommitted-changes if the revision ends with a +
if [[ $r_lrev[-1] == + ]] ; then
hgchanges=1
r_lrev=${r_lrev%+}
r_csetid=${r_csetid%+}
fi
# This directory only exists during a merge
[[ -d $mergedir ]] && hgactionstring="merging"
# This file only exists during a rebase
[[ -e $rebasefile ]] && hgactionstring="rebasing"
### Build the current revision display
[[ -n ${r_csetid} ]] && defrevformat+=( "%h" )
[[ -n ${r_lrev} ]] && defrevformat+=( "%r" )
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" \
"hgrevformat" revformat || revformat=${(j/:/)defrevformat}
hook_com=( localrev "${r_lrev}" "hash" "${r_csetid}" )
if VCS_INFO_hook 'set-hgrev-format' "${revformat}"; then
zformat -f r_lrev "${revformat}" \
"r:${hook_com[localrev]}" "h:${hook_com[hash]}"
else
r_lrev=${hook_com[rev-replace]}
fi
hook_com=()
### Build the branch display
[[ -n ${r_branch} ]] && defbranchformat+=( "%b" )
[[ -n ${r_lrev} ]] && defbranchformat+=( "%r" )
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" \
branchformat branchformat || branchformat=${(j/:/)defbranchformat}
hook_com=( branch "${r_branch}" revision "${r_lrev}" )
if VCS_INFO_hook 'set-branch-format' "${branchformat}"; then
zformat -f branchformat "${branchformat}" \
"b:${hook_com[branch]}" "r:${hook_com[revision]}"
else
branchformat=${hook_com[branch-replace]}
fi
hook_com=()
### Look for current Bookmarks (this requires knowing the changeset id)
if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-bookmarks \
&& [[ -r "${bmfile}" ]] && [[ -n "$r_csetid" ]] ; then
while read -r i_bmhash i_bmname ; do
# Compare hash in bookmarks file with changeset id
[[ $r_csetid == $i_bmhash ]] && hgbmarks+=( $i_bmname )
done < ${bmfile}
if VCS_INFO_hook 'gen-hg-bookmark-string' "${hgbmarks[@]}"; then
hgbmstring=${(j:, :)hgbmarks}
else
hgbmstring=${hook_com[hg-bookmark-string]}
fi
hook_com=()
fi
### Look for any applied Mercurial Queue patches
if zstyle -T ":vcs_info:${vcs}:${usercontext}:${rrn}" get-mq \
&& [[ -d $patchdir ]] ; then
if [[ -e $mqstatusfile ]]; then
mqpatches=( ${${(f)"$(< "${patchdir}/status")"}/(#s)[a-f0-9]##:/} )
mqpatches=( ${(Oa)mqpatches} )
else
mqpatches=( )
fi
if VCS_INFO_hook 'gen-mq-patch-string' "${mqpatches[@]}"; then
if (( ${#mqpatches} )); then
hgmqstring=${mqpatches[1]}
else
hgmqstring="no patch applied"
if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-unapplied \
&& [[ -r ${mqseriesfile} ]]; then
# Okay, here's a little something that assembles a list of unapplied
# patches that takes into account if mq-guards are active or not.
# Collect active guards
if [[ -r ${mqguardsfile} ]]; then
mqguards=( ${(f)"$(< "${mqguardsfile}")"} )
mqguards=( ${(oa)mqguards} )
fi
else
hgbmstring=${hook_com[hg-mqpatch-string]}
while read -r i_patch i_patchguards ; do
# Skip commented lines
[[ ${i_patch} == [[:space:]]#"#"* ]] && continue
# Keep list of all patches
mqseries+=( $i_patch )
# Separate negative and positive guards to more easily find the
# intersection of active guards with patch guards
i_patchguards=( ${(s: :)i_patchguards} )
i_negguards=( ${${(M)i_patchguards:#*"#-"*}/(#s)\#-/} )
i_posguards=( ${${(M)i_patchguards:#*"#+"*}/(#s)\#+/} )
# Patch with any negative guards is never pushed if guard is active
if [[ ${#i_negguards} -gt 0
&& ${#${(@M)mqguards:#${(~j,|,)i_negguards}}} -gt 0 ]] ; then
continue
fi
# Patch with positive guards is only pushed if guard is active
if [[ ${#i_posguards} -gt 0 ]] ; then
if [[ ${#${(@M)mqguards:#${(~j,|,)i_posguards}}} -gt 0 ]] ; then
mqunapplied+=( $i_patch )
fi
continue
fi
# If we made it this far the patch isn't guarded and should be pushed
mqunapplied+=( $i_patch )
done < ${mqseriesfile}
fi
if VCS_INFO_hook 'gen-applied-string' "${mqpatches[@]}"; then
(( ${#mqpatches} )) && applied_string=${mqpatches[1]}
else
applied_string=${hook_com[applied-string]}
fi
hook_com=()
if VCS_INFO_hook 'gen-unapplied-string' "${mqunapplied[@]}"; then
unapplied_string=${#mqunapplied}
else
unapplied_string=${hook_com[unapplied-string]}
fi
hook_com=()
if VCS_INFO_hook 'gen-mqguards-string' "${mqguards[@]}"; then
guards_string=${(j:,:)mqguards}
else
guards_string=${hook_com[guards-string]}
fi
if (( ${#mqpatches} )); then
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" patch-format \
hgmqstring || hgmqstring="%p (%n applied)"
else
zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" nopatch-format \
hgmqstring || hgmqstring="no patch applied"
fi
hook_com=( applied "${applied_string}" unapplied "${unapplied_string}"
applied-n ${#mqpatches} unapplied-n ${#mqunapplied}
guards "${guards_string}" guards-n ${#mqguards} )
if VCS_INFO_hook 'set-patch-format' ${qstring}; then
zformat -f hgmqstring "${hgmqstring}" \
"p:${hook_com[applied]}" "u:${hook_com[unapplied]}" \
"n:${#mqpatches}" "c:${#mqunapplied}" \
"g:${hook_com[guards]}" "G:${#mqguards}"
else
hgmqstring=${hook_com[patch-replace]}
fi
hook_com=()
else
hgmqstring=''
fi
if [[ -z "${hgmqstring}" ]] && [[ -z "${hgbmstring}" ]]; then
hgmisc_args=( '' ) # make sure there's at least *one* misc argument
elif [[ -z "${hgmqstring}" ]]; then
hgmisc_args=( "${hgmqstring}" )
elif [[ -z "${hgbmstring}" ]]; then
hgmisc_args=( "${hgbmstring}" )
else
hgmisc_args=( "${hgmqstring}" "${hgbmstring}" )
fi
VCS_INFO_formats '' "${hgbranch}" "${hgbase}" '' "${hgchanges}" "${hglrev}" "${hgmisc_args[@]}"
### Build the misc string
hgmisc+=( ${hgmqstring} )
hgmisc+=( ${hgbmstring} )
backend_misc[patches]="${hgmqstring}"
backend_misc[bookmarks]="${hgbmstring}"
VCS_INFO_formats "${hgactionstring}" "${branchformat}" "${hgbase}" '' "${hgchanges}" "${r_lrev}" "${(j:;:)hgmisc}"
return 0

View File

@ -22,21 +22,18 @@ hook_com=(
unstaged_orig "$5"
revision "$6"
revision_orig "$6"
misc "$7"
misc_orig "$7"
vcs "${vcs}"
vcs_orig "${vcs}"
)
shift 6
i=0
for tmp in "$@"; do
hook_com[misc$((i++))]="${tmp}"
done
hook_com[misc]=${(j:,:)argv}
hook_com[misc_orig]=${hook_com[misc]}
hook_com[base-name]="${${hook_com[base]}:t}"
hook_com[base-name_orig]="${hook_com[base_name]}"
hook_com[subdir]="$(VCS_INFO_reposub ${hook_com[base]})"
hook_com[subdir_orig]="${hook_com[subdir]}"
VCS_INFO_hook 'post-backend'
## description:
# action: a string that signals a certain non-default condition in the
# repository (like 'rebase-i' in git). If this in non-empty,
@ -46,8 +43,7 @@ hook_com[subdir_orig]="${hook_com[subdir]}"
# staged: non-empty if the repository contains staged changes.
# unstaged: non-empty if the repository contains unstaged changes.
# revision: an identifier of the currently checked out revision.
# misc0..N: a set of strings that may contain anything the author likes.
# the backends should document what they put in it and when.
# misc: a string that may contain anything the backend author likes.
#
# If an argument has no valid value for a given backend, an empty value
# should be provided. eg:
@ -71,6 +67,15 @@ if [[ -n ${hook_com[unstaged]} ]] ; then
[[ -z ${tmp} ]] && hook_com[unstaged]='U' || hook_com[unstaged]=${tmp}
fi
if [[ ${quiltmode} != 'standalone' ]] && VCS_INFO_hook "pre-addon-quilt"; then
local -x REPLY
VCS_INFO_quilt addon
hook_com[quilt]="${REPLY}"
unset REPLY
elif [[ ${quiltmode} == 'standalone' ]]; then
hook_com[quilt]=${hook_com[misc]}
fi
(( ${#msgs} > maxexports )) && msgs[$(( maxexports + 1 )),-1]=()
for i in {1..${#msgs}} ; do
if VCS_INFO_hook "set-message" $(( $i - 1 )) "${msgs[$i]}"; then
@ -83,6 +88,7 @@ for i in {1..${#msgs}} ; do
r:${hook_com[base-name]} \
s:${hook_com[vcs]} \
u:${hook_com[unstaged]} \
Q:${hook_com[quilt]} \
R:${hook_com[base]} \
S:${hook_com[subdir]}
msgs[$i]=${msg}
@ -90,4 +96,6 @@ for i in {1..${#msgs}} ; do
msgs[$i]=${hook_com[message]}
fi
done
hook_com=()
backend_misc=()
return 0

View File

@ -20,8 +20,11 @@ if (( debug )); then
fi
zstyle -a "${context}" hooks hooks || return 0
# protect some internal variables in hooks
typeset -r vcs rrn usercontext maxexports msgs vcs_comm
# Protect some internal variables in hooks. The `-g' parameter to
# typeset does *not* make the parameters global here (they are already
# "*-local-export). It prevents typeset from creating *new* *local*
# parameters in this function's scope.
typeset -g -r vcs rrn usercontext maxexports msgs vcs_comm
for hook in ${hooks} ; do
func="+vi-${hook}"
if (( ${+functions[$func]} == 0 )); then
@ -29,6 +32,7 @@ for hook in ${hooks} ; do
continue
fi
(( debug )) && printf ' + Running function: "%s"\n' "${func}"
true
${func} "$@"
case $? in
(0)
@ -38,5 +42,5 @@ for hook in ${hooks} ; do
;;
esac
done
typeset +r vcs rrn usercontext maxexports msgs vcs_comm
typeset -g +r vcs rrn usercontext maxexports msgs vcs_comm
return $ret

View File

@ -0,0 +1,190 @@
## vim:ft=zsh:foldmethod=marker
function VCS_INFO_quilt-match() {
emulate -L zsh
setopt extendedglob
local d mode="$1" param="$2"
local -a list
case ${mode} in
(assoc) list=( ${(kOP)param} );;
(array) : "${foo[@]}" ${(t)foo}; list=( ${(OP)param} );;
(*) return 1;;
esac
for d in "${list[@]}"; do
if [[ ${PWD} == ${d%/##}(|/*) ]]; then
print "$d"
return 0
fi
done
return 1
}
function VCS_INFO_quilt-standalone-detect() {
emulate -L zsh
setopt extendedglob
local param
local -i ret
zstyle -s "${context}" quilt-standalone param || return 1
[[ "${param}" == 'never' ]] && return 1
[[ "${param}" == 'always' ]] && return 0
if (( ${+functions[$param]} )); then
${param}
return $?
fi
case ${(Pt)param} in
*association*)
local m
local -A A
m="$(VCS_INFO_quilt-match assoc ${param})"
A=(${(kvP)param})
(( $? == 0 )) && [[ ${A[$m]} == "true" ]] && return 0
return 1
;;
*array*)
typeset -gU ${param}
VCS_INFO_quilt-match array ${param} > /dev/null
return $?
;;
*scalar*)
[[ "${(P)param}" == 'always' ]] && return 0
[[ "${(P)param}" == 'never' ]] && return 1
;;
esac
# If nothing hit yet, it just wasn't meant to be.
return 1
}
function VCS_INFO_quilt-dirfind() {
# This is a wrapper around VCS_INFO_bydir_detect(). It makes sure
# that $vcs_comm[] is unchanged. Currently, changing anything in it
# should not be an issue, but this makes sure the code can safely
# be called elsewhere, too - if needed.
emulate -L zsh
setopt extendedglob
local dir="$1" file="$2"; shift $#
local ret oldfile olddir
olddir=${vcs_comm[basedir]}
vcs_comm[basedir]=''
if [[ -n "${file}" ]]; then
oldfile=${vcs_comm[detect_need_file]}
vcs_comm[detect_need_file]=${file}
fi
VCS_INFO_bydir_detect ${dir}
ret=$?
[[ -n "${file}" ]] && vcs_comm[detect_need_file]=${oldfile}
printf '%s' ${vcs_comm[basedir]}
vcs_comm[basedir]="${olddir}"
return ${ret}
}
function VCS_INFO_quilt() {
emulate -L zsh
setopt extendedglob
local mode="$1"
local patches pc tmp qstring root
local -i ret
local -x context
local -a applied unapplied applied_string unapplied_string quiltcommand
local -Ax hook_com
context=":vcs_info:${vcs}.quilt-${mode}:${usercontext}:${rrn}"
zstyle -t "${context}" use-quilt || return 1
case ${mode} in
(standalone)
VCS_INFO_quilt-standalone-detect || return 1
;;
(addon)
;;
(*)
printf 'Invalid mode: `%s'\''\n' "$1"
return 2
;;
esac
zstyle -s "${context}" quilt-patch-dir patches || patches="${QUILT_PATCHES}"
if [[ "${patches}" != /* ]]; then
tmp=${patches:-patches}
patches="$(VCS_INFO_quilt-dirfind "${tmp}")"
ret=$?
(( ret )) && return ${ret}
patches=${patches}/${tmp}
else
[[ -d ${patches} ]] || return 1
fi
pc="$(VCS_INFO_quilt-dirfind .pc .version)"
ret=$?
if (( ret == 0 )); then
[[ ${quiltmode} == 'standalone' ]] && root=${pc}
pc=${pc}/.pc
if [[ -e ${pc}/applied-patches ]]; then
applied=( ${(f)"$(<$pc/applied-patches)"} )
# throw away empty entries
applied=( ${applied:#} )
applied=( ${(Oa)applied} )
else
applied=()
fi
fi
if zstyle -t "${context}" get-unapplied; then
# This zstyle call needs to be moved further up if `quilt' needs
# to be run in more places than this one.
zstyle -s "${context}" quiltcommand quiltcommand || quiltcommand='quilt'
unapplied=( ${(f)"$(QUILT_PATCHES=$patches $quiltcommand --quiltrc /dev/null unapplied 2> /dev/null)"} )
unapplied=( ${unapplied:#} )
else
unapplied=()
fi
if VCS_INFO_hook 'gen-applied-string' "${applied[@]}"; then
if (( ${#applied} )); then
applied_string=${applied[1]}
else
applied_string=""
fi
else
applied_string=${hook_com[applied-string]}
fi
hook_com=()
if VCS_INFO_hook 'gen-unapplied-string' "${unapplied[@]}"; then
unapplied_string="${#unapplied}"
else
unapplied_string=${hook_com[unapplied-string]}
fi
if (( ${#applied} )); then
zstyle -s "${context}" patch-format qstring || qstring="%p (%n applied)"
else
zstyle -s "${context}" nopatch-format qstring || qstring="no patch applied"
fi
hook_com=( applied "${applied_string}" unapplied "${unapplied_string}"
applied-n ${#applied} unapplied-n ${#unapplied} )
if VCS_INFO_hook 'set-patch-format' ${qstring}; then
zformat -f qstring "${qstring}" "p:${hook_com[applied]}" "u:${hook_com[unapplied]}" \
"n:${#applied}" "c:${#unapplied}"
else
qstring=${hook_com[patch-replace]}
fi
hook_com=()
case ${mode} in
(standalone)
VCS_INFO_formats '' '' "${root}" '' '' '' "${qstring}"
VCS_INFO_set
;;
(addon)
# When VCS_INFO_quilt() is called with "addon" a "local -x REPLY" variable
# should be in place. That variable can be unset after it's being used.
REPLY="${qstring}"
;;
esac
VCS_INFO_hook 'post-quilt' ${mode} ${patches} ${pc:-\\-nopc-}
}
VCS_INFO_quilt "$@"

View File

@ -21,6 +21,7 @@ static_functions=(
VCS_INFO_hook
VCS_INFO_maxexports
VCS_INFO_nvcsformats
VCS_INFO_quilt
VCS_INFO_realpath
VCS_INFO_reposub
VCS_INFO_set
@ -45,12 +46,12 @@ vcs_info () {
[[ -r . ]] || return 0
local pat
local -i found
local -i found retval
local -a enabled disabled dps
local -x usercontext vcs rrn LC_MESSAGES
local -x usercontext vcs rrn quiltmode LC_MESSAGES
local -ix maxexports
local -ax msgs
local -Ax vcs_comm
local -Ax vcs_comm hook_com backend_misc user_data
LC_MESSAGES=C
if [[ -n ${LC_ALL} ]]; then
@ -58,9 +59,18 @@ vcs_info () {
LANG=${LC_ALL}
local -x LC_ALL
fi
vcs='-init-'; rrn='-all-'
vcs='-init-'; rrn='-all-'; quiltmode='addon'
usercontext=${1:-default}
VCS_INFO_hook "start-up"
retval=$?
if (( retval == 1 )); then
return 0
elif (( retval == 2 )); then
VCS_INFO_set --nvcs
return 0
fi
zstyle -a ":vcs_info:${vcs}:${usercontext}:${rrn}" "enable" enabled
(( ${#enabled} == 0 )) && enabled=( all )
@ -99,10 +109,20 @@ vcs_info () {
done
(( found == 0 )) && {
VCS_INFO_set --nvcs
vcs='-quilt-'; quiltmode='standalone'
VCS_INFO_quilt standalone || VCS_INFO_set --nvcs
return 0
}
VCS_INFO_hook "pre-get-data"
retval=$?
if (( retval == 1 )); then
return 0
elif (( retval == 2 )); then
VCS_INFO_set --nvcs
return 0
fi
VCS_INFO_get_data_${vcs} || {
VCS_INFO_set --nvcs
return 1

View File

@ -3,4 +3,5 @@ DISTFILES_SRC='
bash2zshprompt
c2z compctl-examples globtests globtests.ksh
job-control-tests lete2ctl make-zsh-urls
vcs_info-examples
'

496
Misc/vcs_info-examples Normal file
View File

@ -0,0 +1,496 @@
# A collection of vcs_info usage examples
### Running vcs_info #########################################################
# As always, there's more than one way to skin a cat. Running vcs_info is
# exception. Here is a rundown of three common ways to get it into action.
#
# All three ways need vcs_info to be marked for autoloading first, so you'd
# do this somewhere in your setup:
autoload -Uz vcs_info
# Episode I: "The prompt_subst way"
# Also known as the Quick-Start-Way. Probably the simplest way to add
# vcs_info functionality to existing setups. You just drop a vcs_info call
# to your `precmd' (or into a `precmd_functions[]' entry) and include a
# single-quoted ${vcs_info_msg_0_} in your PS1 definition:
precmd() { vcs_info }
# This needs prompt_subst set, hence the name. So:
setopt prompt_subst
PS1='%!-%3~ ${vcs_info_msg_0_}%# '
# Episode II: "The way of the psvar"
# With $psvar you got a simple way to get user defined things into your
# prompt without having to set `prompt_subst', which requires extra
# attention to quoting if you like characters like ` in your prompt...
# As described in <http://xana.scru.org/xana2/quanks/vcsinfoprompt/>:
precmd() {
psvar=()
vcs_info
[[ -n $vcs_info_msg_0_ ]] && psvar[1]="$vcs_info_msg_0_"
}
# You can now use `%1v' to drop the $vcs_info_msg_0_ contents in your prompt;
# like this:
PS1="%m%(1v.%F{red}%1v%f.)%# "
# Episode III: "The justsetitinprecmd way"
# This is the way I prefer. When you see it, you may think "Setting that
# variable in precmd() each time? What a waste..."; but let me assure you,
# you're running vcs_info already, setting one variable is not an issue.
#
# You're getting the benefit of being able to programmatically setting your
# prompt, which is nice especially when you're going to do weird things in
# there anyway. Here goes:
precmd() {
# As always first run the system so everything is setup correctly.
vcs_info
# And then just set PS1, RPS1 and whatever you want to. This $PS1
# is (as with the other examples above too) just an example of a very
# basic single-line prompt. See "man zshmisc" for details on how to
# make this less readable. :-)
if [[ -n ${vcs_info_msg_0_} ]]; then
# Oh hey, nothing from vcs_info, so we got more space.
# Let's print a longer part of $PWD...
PS1="%5~%# "
else
# vcs_info found something, that needs space. So a shorter $PWD
# makes sense.
PS1="%3~${vcs_info_msg_0_}%# "
fi
}
### Hooks ####################################################################
# A number of examples in this file revolve around the concept of `hooks'
# in vcs_info. Hooks are places in vcs_info where you may put in your
# own code to achieve something "totally awesome"[tm].
#
# Hooks can be confusing. It's hard to keep track of what's going on.
# In order to help you with that vcs_info can output some debugging
# information when it processes hooks. This will tell you which hooks
# are being run and which functions are attempted to run (and if the
# functions in question were found or not).
#
# If you feel like you need to see what's attempted and where, I suggest
# you use the following line and see for yourself.
zstyle ':vcs_info:*+*:*' debug true
# You can just comment it out (or disable it) again when you've seen enough.
# Debugging is off by default - of course.
zstyle ':vcs_info:*+*:*' debug false
# Further down, every example that uses a function named `+vi-*' uses a hook.
### check-for-changes just in some places ####################################
# Some backends (git and mercurial at the time of writing) can tell you
# whether there are local changes in the current repository. While that's
# nice, the actions needed to obtain the information can be potentially
# expensive. So if you're working on something the size of the linux kernel
# or some corporate code monstrosity you may want to think twice about
# enabling the `check-for-changes' style unconditionally.
#
# Zsh's zstyle configuration system let's you do some magic to enable styles
# only depending on some code you're running.
#
# So, what I'm doing is this: I'm keeping my own projects in `~/src/code'.
# There are the projects I want the information for most. They are also
# a lot smaller than the linux kernel so the information can be retrieved
# instantaneously - even on my old laptop at 600MHz. And the following code
# enables `check-for-changes' only in that subtree:
zstyle -e ':vcs_info:git:*' \
check-for-changes 'estyle-cfc && reply=( true ) || reply=( false )'
function estyle-cfc() {
local d
local -a cfc_dirs
cfc_dirs=(
${HOME}/src/code/*(/)
)
for d in ${cfc_dirs}; do
d=${d%/##}
[[ $PWD == $d(|/*) ]] && return 0
done
return 1
}
### Mercurial Tips #########################################################
### Truncate Long Hashes ####################################################
### Truncate a long hash to 12 characters (which is usually unique enough)
# NOTE: On Mercurial this will hide the second parent hash during a merge
# (see an example in the Mercurial section below on how to retain both parents)
# Use zformat syntax (remember %i is the hash): %12.12i
# First, remove the hash from the default 'branchformat':
zstyle ':vcs_info:hg:*' branchformat '%b'
# Then add the hash to 'formats' as %i and truncate it to 12 chars:
zstyle ':vcs_info:hg:*' formats ' (%s)-[%12.12i %b]-'
### Truncate long hash to 12-chars but also allow for multiple parents
# Hashes are joined with a + to mirror the output of `hg id`.
zstyle ':vcs_info:hg+set-hgrev-format:*' hooks hg-shorthash
function +vi-hg-shorthash() {
local -a parents
parents=( ${(s:+:)hook_com[hash]} )
parents=( ${(@r:12:)parents} )
hook_com[rev-replace]=${(j:+:)parents}
ret=1
}
### Show marker when the working directory is not on a branch head
# This may indicate that running `hg up` will do something
# NOTE: the branchheads.cache file is not updated with every Mercurial
# operation, so it will sometimes give false positives. Think of this more as a
# hint that you might not be on a branch head instead of the final word.
zstyle ':vcs_info:hg+set-hgrev-format:*' hooks hg-storerev
zstyle ':vcs_info:hg+set-message:*' hooks hg-branchhead
# The hash is availabe in the hgrev-format hook, store a copy of it in the
# user_data array so we can access it in the second function
function +vi-hg-storerev() {
user_data[hash]=${hook_com[hash]}
}
function +vi-hg-branchhead() {
local branchheadsfile i_tiphash i_branchname
local -a branchheads
local branchheadsfile=${hook_com[base]}/.hg/branchheads.cache
# Bail out if any mq patches are applied
[[ -s ${hook_com[base]}/.hg/patches/status ]] && return 0
if [[ -r ${branchheadsfile} ]] ; then
while read -r i_tiphash i_branchname ; do
branchheads+=( $i_tiphash )
done < ${branchheadsfile}
if [[ ! ${branchheads[(i)${user_data[hash]}]} -le ${#branchheads} ]] ; then
hook_com[revision]="^ ${hook_com[revision]}"
fi
fi
}
### Run vcs_info selectively to increase speed in large repos #################
# The following example shows a possible setup for vcs_info which displays
# staged and unstaged changes in the vcs_info prompt and prevents running
# it too often for speed reasons.
# Allow substitutions and expansions in the prompt, necessary for
# using a single-quoted $vcs_info_msg_0_ in PS1, RPOMPT (as used here) and
# similar. Other ways of using the information are described above.
setopt promptsubst
# Load vcs_info to display information about version control repositories.
autoload -Uz vcs_info
# Check the repository for changes so they can be used in %u/%c (see
# below). This comes with a speed penalty for bigger repositories.
zstyle ':vcs_info:*' check-for-changes true
zstyle ':vcs_info:*' get-revision true
# Improve default formats/actionformats to display staged (%c) and
# unstaged (%u) changes. You can change the displayed string with the
# 'unstagedstr' and 'stagedstr' settings.
zstyle ':vcs_info:*' formats " (%s)-[%b]%u%c-"
zstyle ':vcs_info:*' actionformats " (%s)-[%b|%a]%u%c-"
# Default to running vcs_info. If possible we prevent running it later for
# speed reasons. If set to a non empty value vcs_info is run.
FORCE_RUN_VCS_INFO=1
# Only run vcs_info when necessary to speed up the prompt and make using
# check-for-changes bearable in bigger repositories. This setup was
# inspired by Bart Trojanowski
# (http://jukie.net/~bart/blog/pimping-out-zsh-prompt).
#
# This setup is by no means perfect. It can only detect changes done
# through the VCS's commands run by the current shell. If you use your
# editor to commit changes to the VCS or if you run them in another shell
# this setup won't detect them. To fix this just run "cd ." which causes
# vcs_info to run and update the information. If you use aliases to run
# the VCS commands update the case check below.
zstyle ':vcs_info:*+pre-get-data:*' hooks pre-get-data
+vi-pre-get-data() {
# Only Git and Mercurial support and need caching. Abort if any other
# VCS is used.
[[ "$vcs" != git && "$vcs" != hg ]] && return
# If the shell just started up or we changed directories (or for other
# custom reasons) we must run vcs_info.
if [[ -n $FORCE_RUN_VCS_INFO ]]; then
FORCE_RUN_VCS_INFO=
return
fi
# If we got to this point, running vcs_info was not forced, so now we
# default to not running it and selectively choose when we want to run
# it (ret=1 means run it, ret=0 means don't).
ret=1
# If a git/hg command was run then run vcs_info as the status might
# need to be updated.
case "$(fc -ln $(($HISTCMD-1)))" in
git*)
ret=0
;;
hg*)
ret=0
;;
esac
}
# Call vcs_info as precmd before every prompt.
prompt_precmd() {
vcs_info
}
add-zsh-hook precmd prompt_precmd
# Must run vcs_info when changing directories.
prompt_chpwd() {
FORCE_RUN_VCS_INFO=1
}
add-zsh-hook chpwd prompt_chpwd
# Display the VCS information in the right prompt. The {..:- } is a
# workaround for Zsh below 4.3.9.
RPROMPT='${vcs_info_msg_0_:- }'
### Quilt support ############################################################
# Vcs_info does its best to support the patch management system quilt
# <http://savannah.nongnu.org/projects/quilt>. The information gathered by
# the quilt support always (and I'm saying always, because there are two
# ways quilt support can be active - see "man zshcontrib" for details)
# ends up in the `%Q' replacement in formats.
#
# Quilt support is also disabled by default. To turn its `addon' mode
# on for all backends, do:
zstyle ':vcs_info:*' use-quilt true
# Then use `%Q' somewhere in the `formats' and `actionformats' styles:
zstyle ':vcs_info:*' formats " (%s)-[%b%Q]-"
zstyle ':vcs_info:*' actionformats " (%s)-[%b%Q|%a]-"
# In the quilt support code, the zstyle context changes a little, it's now:
# :vcs_info:<vcs>.quilt-<quiltmode>:*:*
# "<vcs>" is the version-control-system string and "<quiltmode>" is either
# `addon' or `standalone'. So, if you'd use quilt on top of CVS, the
# context becomes ":vcs_info:cvs.quilt-addon:*:*".
# That's almost all you need to know. Almost.
#
# Quilt support has a standalone mode. Even though quilt is not really
# a version control system, it keeps track of patches. It can work on top
# of a real VCS (like subversion or CVS - which is covered by addon mode)
# or apply patches to a normal directory tree that's not under version
# control. The debian project does this for a large number of packages,
# during their automatic build process.
# The `use-quilt' style only enables# addon-mode, because for standalone
# mode we'd have to try to detect whether quilt is "active" in a directory.
# You can fine-tune that "detection" using the `quilt-standalone' style.
# If the value of that style is a function name, that function is executed
# without arguments to determine whether quilt-detection should be attempted.
# It's the most powerful way of doing this and we'll give a simple
# example later.
# First let's assume you want standalone mode to be active only in
# /usr/src/debian, ~/src/debian and their subdirectories. That's simple:
typeset -a foobar
foobar=(
/usr/src/debian
~/src/debian
)
zstyle ':vcs_info:*' quilt-standalone foobar
# As mentioned earlier, using a function in this style is more powerful:
function foobar() {
# You can do any sort of wicked wizardry here. This example just
# checks if we're in "/usr/src/debian" or a subdirectory and if so
# enables standalone detection.
[[ $PWD == /usr/src/debian(|/*) ]] && return 0
# Returning non-zero means false, which means don't enable the
# "detection".
return 1
}
# In standalone-mode, vcs_info pretends as if quilt actually was a VCS.
# Well, kind of. The vcs string is set to '-quilt-'. So let's define a
# format just for that mode:
zstyle ':vcs_info:-quilt-:*' formats " [%s%Q]-"
# As with other format insertions, you got total control over what is being
# inserted. The `%Q' insertion is controlled by the `quiltformat' and
# `quilt-nopatch-format' styles.
# quiltformat (default: "%p (%n applied)")
# The `%p' replacement tells you which patches are applied. `%n' tells you
# How many patches are applied. `%u' and `%N' do the same for unapplied patches.
#
# Now you might say, that's way too much. That'll eat up my entire screen if I
# all my 1002 patches applied. Well, true.
# By default, `%p' contains the top-most applied patch. `%u' says contains the
# number of unapplied patches and is therefore the same as `%c'.
# There are two hooks you can use to setup what these contain. Those would be
# `gen-applied-string' and `gen-unapplied-string'. We'll go with the default
# here... ...no need to go into every insane detail.
zstyle ':vcs_info:*' quiltformat '#%p [%n|%c]'
# quilt-nopatch-format (default: "no patch applied")
zstyle ':vcs_info:*' quilt-nopatch-format '#cleeaaaaan!1!!'
# To retrieve inforamation about unapplied patches, vcs_info invokes `quilt'
# itself. Even though that's pretty quick, it's not needed for the default
# behaviour. If we want to have `%c' and `%u' to contain meaningful data,
# we have to enable retrieval of unapplied data:
zstyle ':vcs_info:*' quilt-get-unapplied true
# With quilt, the location of its patches are configurable. It's either
# $QUILT_PATCHES or `patches' if that's unset. Let's assume we're a debian
# developer and want $QUILT_PATCHES to always be `debian/patches' in stand-
# alone mode:
zstyle ':vcs_info:-quilt-.quilt-standalone:*:*' quilt-patch-dir debian/patches
# Since we're a debian developer, we also have some packages of our own,
# and so we want addon mode to also use a $QUILT_PATCHES value of
# `debian/patches' in some directories. In the other directories we never
# want the default `patches' though but a dedicated place for them.
# Say `~/patches/<repository-name>'. Now we'll use some evaluated-style
# magic to achieve all that:
zstyle -e ':vcs_info:*.quilt-addon:*:*' quilt-patch-dir 'my-patches-func'
# That runs something called `my-patches-func', and the value of $reply is
# used as the value for the `quilt-patch-dir' style. We'll define the thing
# as a function - as the name suggests:
function my-patches-func() {
local p
# As the tidy debian developer we are, we're keeping our packages
# in VCSs and they are located in one place `~/src/mypkgs/'
if [[ $PWD == ${HOME}/src/mypkgs(|/*) ]]; then
reply=( debian/patches )
return 0
fi
# Now the part about the dedicated directory is a little trickier.
# It requires some knowledge of vcs_info's internals. Not much though.
# Everything about this is described in the manual because this
# variable (plus a few others) may be of interest in hooks, where
# they are available, too.
#
# The variable in question here is `$rrn' which is an abbreviation
# of repository-root-name. if you're in
# /usr/src/zsh/Functions
# and the repository being
# /usr/src/zsh
# then the value of `$rrn' is `zsh'. Now in case the variable is
# empty (it shouldn't at this point, but you never know), let's
# drop back to quilt's default "patches".
if [[ -z ${rrn} ]]; then
reply=( patches )
return 0
fi
# If we're here, there's something in $rrn, so:
p="${HOME}/patches/${rrn}"
if [[ ! -d $p ]]; then
# ...and while we're at it, make sure it exists...
mkdir -p "$p"
fi
reply=( $p )
}
# And finally, let's use the `post-quilt' hook to let vcs_info help us
# with setting the $QUILT_PATCHES variable. Since vcs_info already knows
# which $QUILT_PATCHES value is correct, it should just export that variable
# for us. No need to configure something twice when it can work
# automatically. :-)
# Register the hook:
zstyle ':vcs_info:*+post-quilt:*:*' hooks set-quilt-patches
# Define the corresponding function:
function +vi-set-quilt-patches() {
# The `post-quilt' hook functions are called with three arguments:
# $1 the mode (`addon' vs. `standalone').
# $2 the path-name of the detected patches directory.
# $3 the path-name of the `.pc' directory (or "-nopc-" if it
# could not be found).
# So, what we're after is in $2 already, which makes this function
# rather trivial:
export QUILT_PATCHES="$2"
return 0
}
# This would take care of all the dedicated-patches-directory-in-${HOME}
# from earlier examples, too.
### Using vcs_info from CVS ##################################################
# You've decided you desperately need a newer feature of vcs_info than
# there is in your installed version of zsh. That's possible, but be aware
# that you are choosing not only the newest features but potentially also
# the newest bugs of vcs_info. Also note, that vcs_info from CVS *may* rely
# on features of zsh that are only available in a newer version than you
# got installed on your system.
#
# So, now that the warnings are out of the way - let's cut to the chase:
# First you'll need to decide where to put the files from CVS. Many people
# keep a directory for personal function files such as `~/.zfuncs' or
# similar. That's what we'll use here.
#
# Step one: "get the thing from CVS"
# % mkdir -p ~/.zfuncs
# % cd ~/.zfuncs
# % cvs -z3 -d:pserver:anonymous@zsh.cvs.sourceforge.net:/cvsroot/zsh \
# co -d VCS_Info -PA zsh/Functions/VCS_Info
#
# There, now you got a `~/.zfuncs/VCS_Info' directory that has all the files
# you need. Whenever you feel like updating the checkout, you can do:
# % cd ~/.zfuncs/VCS_Info; cvs up; cd -
#
# Step two: "Tell zsh to use the checkout"
# Zsh looks for function files in the directories listed in $fpath. If
# you're already using `~/.zfuncs' you probably have something like this
# in your setup:
fpath=( ~/.zfuncs $fpath )
# Note, that the private directory is added in *front* of the default
# value, so that files from that directory supersede the ones from system
# directories. To add the VCS_Info subtree (excluding the CVS directories)
# in front, change that line to this:
fpath=( ~/.zfuncs ~/.zfuncs/VCS_Info/**/*~*/(CVS)#(/) $fpath )
# The weirdly looking pattern requires the `extended_glob' option to be
# active, so make sure it is.
#
# Step three: "Restart Z shell"
# A simple
# % exec zsh
# gets you there. You should be all set now. Have fun.