From 0501efc54af2d194f952c2968a7aeeb5bac8fdf4 Mon Sep 17 00:00:00 2001 From: Frank Terbeck Date: Mon, 10 May 2010 10:46:48 +0000 Subject: 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. --- Misc/.distfiles | 1 + Misc/vcs_info-examples | 496 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 497 insertions(+) create mode 100644 Misc/vcs_info-examples (limited to 'Misc') diff --git a/Misc/.distfiles b/Misc/.distfiles index 4e6a00aac..d40656c0d 100644 --- a/Misc/.distfiles +++ b/Misc/.distfiles @@ -3,4 +3,5 @@ DISTFILES_SRC=' bash2zshprompt c2z compctl-examples globtests globtests.ksh job-control-tests lete2ctl make-zsh-urls + vcs_info-examples ' diff --git a/Misc/vcs_info-examples b/Misc/vcs_info-examples new file mode 100644 index 000000000..6060f2306 --- /dev/null +++ b/Misc/vcs_info-examples @@ -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 : + +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 +# . 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:.quilt-:*:* +# "" is the version-control-system string and "" 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/'. 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. -- cgit 1.4.1