diff options
-rw-r--r-- | Doc/Zsh/contrib.yo | 290 | ||||
-rw-r--r-- | Functions/VCS_Info/Backends/VCS_INFO_get_data_bzr | 9 | ||||
-rw-r--r-- | Functions/VCS_Info/Backends/VCS_INFO_get_data_git | 65 | ||||
-rw-r--r-- | Functions/VCS_Info/Backends/VCS_INFO_get_data_hg | 117 | ||||
-rw-r--r-- | Functions/VCS_Info/Backends/VCS_INFO_get_data_p4 | 15 | ||||
-rw-r--r-- | Functions/VCS_Info/Backends/VCS_INFO_get_data_svk | 9 | ||||
-rw-r--r-- | Functions/VCS_Info/Backends/VCS_INFO_get_data_svn | 9 | ||||
-rw-r--r-- | Functions/VCS_Info/VCS_INFO_formats | 83 | ||||
-rw-r--r-- | Functions/VCS_Info/vcs_info | 1 |
9 files changed, 488 insertions, 110 deletions
diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index b815e0112..e77fc13cc 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -324,7 +324,7 @@ cindex(version control utility) In a lot of cases, it is nice to automatically retrieve information from version control systems (VCSs), such as subversion, CVS or git, to be able to provide it to the user; possibly in the user's prompt. So that you can -instantly tell on which branch you are currently on, for example. +instantly tell which branch you are currently on, for example. In order to do that, you may use the tt(vcs_info) function. @@ -419,7 +419,8 @@ 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. +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 @@ -532,14 +533,17 @@ example(zstyle ':vcs_info:*' disable-patterns "$HOME/.zsh+LPAR()|/*+RPAR()") ) kindex(check-for-changes) item(tt(check-for-changes))( -If enabled, this style (currently only used by the tt(git) backend) 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. +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). 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. +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. ) kindex(stagedstr) item(tt(stagedstr))( @@ -599,10 +603,16 @@ If set to true, vcs_info goes the extra mile to figure out the revision of 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 is available via tt(%i) -and the corresponding global hash is available via tt(%m). +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 -branchformat style. +var(branchformat) style. +) +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. ) kindex(use-prompt-escapes) item(tt(use-prompt-escapes))( @@ -610,6 +620,16 @@ Determines if we assume that the assembled string from var(vcs_info) includes prompt escapes. (Used by 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. +) +kindex(hooks) +item(tt(hooks))( +A list style, that defines hook-function names. See tt(Hooks in vcs_info) +below for details. +) enditem() The default values for these styles in all contexts are: @@ -632,7 +652,10 @@ sitem(tt(command))((empty string)) sitem(tt(use-server))(false) sitem(tt(use-simple))(false) sitem(tt(get-revision))(false) +sitem(tt(get-bookmarks))(false) sitem(tt(use-prompt-escapes))(true) +sitem(tt(debug))(false) +sitem(tt(hooks))((empty list)) endsitem() In normal tt(formats) and tt(actionformats), the following replacements are @@ -657,8 +680,9 @@ var(/foo/bar/reposXY/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 Mq patch applied (qtop) and the tt(git) backend replaces it -with the string from the var(stgitformat) style.) +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.) endsitem() In tt(branchformat) these replacements are done: @@ -747,6 +771,168 @@ enditem() 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 +code can communicate with the code that called it and through that, +change the system's behaviour. + +For configuration, hooks change the style context: +example(:vcs_info:<vcs-string>+<hook-name>:<user-context>:<repo-root-name>) + +To register functions to a hook, you need to list them in the tt(hooks) +style in the appropriate context. + +Example: +example(zstyle ':vcs_info:*+foo:*' hooks bar baz) + +This registers functions to the hook `foo' for all backends. In order to +avoid namespace problems, all registered function names are prepended by +a `+vi-', so the actual functions called for the `foo' hook are +`tt(+vi-bar)' and `tt(+vi-baz)'. + +If something seems weird, you can enable the `debug' boolean style in +the proper context and the hook-calling code will print what it tried +to execute and whether the function in question existed. + +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: + +startitem() +item(tt(ret))( +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 +documentation below for details. +) +item(tt(hook_com))( +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. +) +enditem() + +Finally, the full list of currently available hooks: + +startitem() +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. + +This hook gets the names of the Mercurial bookmarks, that +tt(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). +) +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. + +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. + +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). +) +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. + +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. + +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). +) +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. + +This hook gets the names of all unapplied stgit patches which tt(vcs_info) +collected so far. + +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). +) +item(tt(set-branch-format))( +Called before a `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 +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). +) +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 +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). +) +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. + +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 +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 +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 +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). +) +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. + subsect(Examples) Don't use tt(vcs_info) at all (even though it's in your prompt): @@ -779,6 +965,86 @@ example(alias vcsi='vcs_info command; vcs_info_lastmsg') This way, you can even define different formats for output via 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. + +First, we will tell tt(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: +example(zstyle ':vcs_info:*+*:*' debug true) + +That should give you an idea what is going on. Specifically, the function +that we are looking for is `tt(+vi-svn2subversion)'. Note, the `tt(+vi-)' +prefix. So, everything is in order, just as documented. When you are done +checking out the debugging output, disable it again: +example(zstyle ':vcs_info:*+*:*' debug false) + +Now, let's define the function: +example( +function +vi-svn2subversion+LPAR()RPAR() { + [[ ${hook_com[vcs_orig]} == svn ]] && hook_com[vcs]=subversion +}) + +Simple enough. And it could have even been simpler, if only we had +registered our function in a less generic context. If we do it only in +the `tt(svn)' backend's context, we don't need to test which the active +backend is: +example(zstyle ':vcs_info:svn+set-message:*' hooks svn2subversion) +example( +function +vi-svn2subversion+LPAR()RPAR() { + hook_com[vcs]=subversion +}) + +And finally a little more elaborate example, that uses a hook to create +a customised bookmark string for the tt(hg) backend. + +Again, we start off by registering a function: +example(zstyle ':vcs_info:hg+gen-hg-bookmark-string:*' hooks hgbookmarks) + +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. + # 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/*" + # (because your initials are sh, for example). + # This makes the bookmarks string use only those + # bookmarks. If there's more than one, it + # concatenates them using commas. + local s i) +example( + # The bookmarks returned by `hg' are available in + # the functions positional parameters. + (( $# == 0 )) && return 0 + for i in "$@"; do + if [[ $i == sh/* ]]; then + [[ -n $s ]] && s=$s, + s=${s}$i + fi + done) +example( + # 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( + # 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). + texinode(Prompt Themes)(ZLE Functions)(Version Control Information)(User Contributions) sect(Prompt Themes) diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_bzr b/Functions/VCS_Info/Backends/VCS_INFO_get_data_bzr index e85de311e..5d4deaac9 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_bzr +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_bzr @@ -5,6 +5,7 @@ setopt localoptions noksharrays extendedglob NO_shwordsplit local bzrbase bzrbr local -a bzrinfo +local -xA hook_com if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" "use-simple" ; then bzrbase=${vcs_comm[basedir]} @@ -21,6 +22,12 @@ fi rrn=${bzrbase:t} zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" branchformat bzrbr || bzrbr="%b:%r" -zformat -f bzrbr "${bzrbr}" "b:${bzrinfo[2]}" "r:${bzrinfo[1]}" +hook_com=( branch "${bzrinfo[2]}" revision "${bzrinfo[1]}" ) +if VCS_INFO_hook 'set-branch-format' "${bzrbr}"; then + zformat -f bzrbr "${bzrbr}" "b:${hook_com[branch]}" "r:${hook_com[revision]}" +else + bzrbr=${hook_com[branch-replace]} +fi +hook_com=() VCS_INFO_formats '' "${bzrbr}" "${bzrbase}" '' '' "${bzrinfo[1]}" '' return 0 diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git index bf7c47927..4018b5d92 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git @@ -4,6 +4,8 @@ setopt localoptions extendedglob NO_shwordsplit local gitdir gitbase gitbranch gitaction gitunstaged gitstaged gitsha1 gitmisc +local stgitpatch stgitunapplied +local -xA hook_com VCS_INFO_git_getaction () { local gitaction='' gitdir=$1 @@ -97,36 +99,6 @@ VCS_INFO_git_getbranch () { return 0 } -VCS_INFO_git_get_stgit_top_patch () { - local patchdir=$1 - - if [[ -d "$patchdir" ]]; then - local -a patches - patches=(${(f)"$(< "${patchdir}/applied")"}) - printf '%s' $patches[-1] - return 0 - fi - - return 1 -} - -VCS_INFO_git_get_stgit_unapplied() { - local patchdir=$1 - - if [[ -d "$patchdir" ]]; then - local -a patches - patches=(${(f)"$(< "${patchdir}/unapplied")"}) - if [[ -z $patches[@] ]]; then - printf 0 - else - printf '%d' $#patches - fi - return 0 - fi - - return 1 -} - gitdir=${vcs_comm[gitdir]} gitbranch="$(VCS_INFO_git_getbranch ${gitdir})" if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision && \ @@ -160,14 +132,37 @@ rrn=${gitbase:t} local patchdir=${gitdir}/patches/${gitbranch} if [[ -d $patchdir ]] ; then - stgitpatch=$(VCS_INFO_git_get_stgit_top_patch "${patchdir}") - stgitunapplied=$(VCS_INFO_git_get_stgit_unapplied "${patchdir}") + local -a stgit_applied stgit_unapplied - stgitpatch=${stgitpatch:-"no patch applied"} + stgit_applied=(${(f)"$(< "${patchdir}/applied")"}) + stgit_applied=( ${(Oa)stgit_applied} ) + stgit_unapplied=(${(f)"$(< "${patchdir}/unapplied")"}) + stgit_unapplied=( ${(oa)stgit_applied} ) + + if VCS_INFO_hook 'gen-stgit-patch-string' "${stgit_applied[@]}"; then + if (( ${#stgit_applied} )); then + stgitpatch=${stgit_applied[1]} + else + stgitpatch="no patch applied" + fi + else + stgitpatch=${hook_com[stgit-patch-string]} + fi + if VCS_INFO_hook 'gen-stgit-unapplied-string' "${stgit_unapplied[@]}"; then + stgitunapplied=${#stgit_unapplied} + else + stgitunapplied=${hook_com[stgit-unapplied-string]} + fi zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" stgitformat stgitmsg || stgitmsg=" %p (%c)" - zformat -f stgitmsg "${stgitmsg}" "p:${stgitpatch}" "c:${stgitunapplied}" - gitmisc=${stgitmsg} + 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} + else + gitmisc=${hook_com[stgit-replace]} + fi + hook_com=() else gitmisc='' fi diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg index 0b66463fa..1c103a541 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg @@ -3,21 +3,11 @@ ## Distributed under the same BSD-ish license as zsh itself. setopt localoptions NO_shwordsplit -local file hgbranch hgbranch_name hgbase hghash hglrev hgmisc r_branch r_info revformat - -VCS_INFO_hg_get_mq_top_patch () { - local patchdir=$1 - - if [[ -e "${patchdir}/status" ]]; then - local -a patches - patches=(${(f)"$(< "${patchdir}/status")"}) - printf "%s" "${patches[-1]/[^:]*:/}" - return 0 - fi - - return 1 -} - +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 +local -xA hook_com hgbase=${vcs_comm[basedir]} rrn=${hgbase:t} @@ -31,27 +21,70 @@ fi hghash='' hglrev='' +hgbm=() +bookmarks="${hgbase}/.hg/bookmarks" 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 - HGRCPATH="/dev/null" ${vcs_comm[cmd]} branches \ - | while read -r r_branch r_info ; do - if [[ ${r_branch} == ${hgbranch_name} ]] ; then - match=() - : ${r_info/(#b)([^:]##):(*)} - hglrev=${match[1]} - hghash=${match[2]} - break + 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 - done + + # Remove uncommitted-changes marker, if any + hglrev=${hglrev/+/} + hghash=${hghash/+/} + else + HGRCPATH="/dev/null" ${vcs_comm[cmd]} \ + parents --template="{node} {rev} {branches}\n" \ + | read -r hghash hglrev r_branch + fi + + if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" "get-bookmarks" \ + && getbookmarks=1 || getbookmarks=0 + + 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} + fi if [[ -n ${hglrev} ]] ; then zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" hgrevformat revformat || revformat="%r:%h" - zformat -f hglrev "${revformat}" "r:${hglrev}" "h:${hghash}" + 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" - zformat -f hgbranch "${hgbranch}" "b:${hgbranch_name}" "r:${hglrev}" + 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}" @@ -60,12 +93,36 @@ fi local patchdir=${hgbase}/.hg/patches/ if [[ -d $patchdir ]] ; then - hgmisc=$(VCS_INFO_hg_get_mq_top_patch "${patchdir}") + local -a mqpatches + if [[ -e "${patchdir}/status" ]]; then + mqpatches=( ${${(f)"$(< "${patchdir}/status")"}/(#s)[a-f0-9]##:/} ) + mqpatches=( ${(Oa)mqpatches} ) + else + mqpatches=( ) + fi - hgmisc=${hgmisc:-"no patch applied"} + if VCS_INFO_hook 'gen-mq-patch-string' "${mqpatches[@]}"; then + if (( ${#mqpatches} )); then + hgmqstring=${mqpatches[1]} + else + hgmqstring="no patch applied" + fi + else + hgbmstring=${hook_com[hg-mqpatch-string]} + fi + hook_com=() else - hgmisc='' + hgmqstring='' fi -VCS_INFO_formats '' "${hgbranch}" "${hgbase}" '' '' "${hglrev}" "${hgmisc}" +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[@]}" return 0 diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_p4 b/Functions/VCS_Info/Backends/VCS_INFO_get_data_p4 index e4bbb06c4..430cfa6f0 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_p4 +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_p4 @@ -6,6 +6,7 @@ setopt localoptions extendedglob local p4base a b local -A p4info +local -xA hook_com ${vcs_comm[cmd]} info | while IFS=: read a b; do p4info[${a// /_}]="${b## #}"; done p4base=${vcs_comm[basedir]} @@ -16,9 +17,13 @@ local p4branch change # here down is synced as the revision. # I suppose the following might be slow on a tortuous client view. change="${${$(${vcs_comm[cmd]} changes -m 1 ...\#have)##Change }%% *}" -zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" branchformat p4branch || -p4branch="%b:%r" -zformat -f p4branch "${p4branch}" "b:${p4info[Client_name]}" \ -"r:$change" - +zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" branchformat p4branch || p4branch="%b:%r" +hook_com=( branch "${p4info[Client_name]}" revision "${change}" ) +if VCS_INFO_hook 'set-branch-format' "${p4branch}"; then + zformat -f p4branch "${p4branch}" "b:${hook_com[branch]}" "r:${hook_com[revision]}" +else + p4branch=${hook_com[branch-replace]} +fi +hook_com=() VCS_INFO_formats '' "${p4branch}" "${p4base}" '' '' "$change" '' +return 0 diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_svk b/Functions/VCS_Info/Backends/VCS_INFO_get_data_svk index 3df9a7366..6107a14f3 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_svk +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_svk @@ -4,10 +4,17 @@ setopt localoptions NO_shwordsplit local svkbranch svkbase +local -xA hook_com svkbase=${vcs_comm[basedir]} rrn=${svkbase:t} zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" branchformat svkbranch || svkbranch="%b:%r" -zformat -f svkbranch "${svkbranch}" "b:${vcs_comm[branch]}" "r:${vcs_comm[revision]}" +hook_com=( branch "${vcs_comm[branch]}" revision "${vcs_comm[revision]}" ) +if VCS_INFO_hook 'set-branch-format' "${svkbranch}"; then + zformat -f svkbranch "${svkbranch}" "b:${hook_com[branch]}" "r:${hook_com[revision]}" +else + svkbranch=${hook_com[branch-replace]} +fi +hook_com=() VCS_INFO_formats '' "${svkbranch}" "${svkbase}" '' '' "${vcs_comm[revision]}" '' return 0 diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_svn b/Functions/VCS_Info/Backends/VCS_INFO_get_data_svn index 75da22bda..b1cb7302b 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_svn +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_svn @@ -7,6 +7,7 @@ setopt localoptions noksharrays extendedglob NO_shwordsplit local svnbase svnbranch a b rrn local -A svninfo parentinfo +local -xA hook_com svnbase="."; svninfo=() @@ -23,6 +24,12 @@ svnbase="$(VCS_INFO_realpath ${svnbase})" rrn=${svnbase:t} zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" branchformat svnbranch || svnbranch="%b:%r" -zformat -f svnbranch "${svnbranch}" "b:${svninfo[URL]##*/}" "r:${svninfo[Revision]}" +hook_com=( branch "${svninfo[URL]##*/}" revision "${svninfo[Revision]}" ) +if VCS_INFO_hook 'set-branch-format' "${svnbranch}"; then + zformat -f svnbranch "${svnbranch}" "b:${hook_com[branch]}" "r:${hook_com[revision]}" +else + svnbranch=${hook_com[branch-replace]} +fi +hook_com=() VCS_INFO_formats '' "${svnbranch}" "${svnbase}" '' '' "${svninfo[Revision]}" '' return 0 diff --git a/Functions/VCS_Info/VCS_INFO_formats b/Functions/VCS_Info/VCS_INFO_formats index 35b3b963d..db7a8dd48 100644 --- a/Functions/VCS_Info/VCS_INFO_formats +++ b/Functions/VCS_Info/VCS_INFO_formats @@ -3,7 +3,39 @@ ## Distributed under the same BSD-ish license as zsh itself. setopt localoptions noksharrays NO_shwordsplit -local action=$1 branch=$2 base=$3 staged=$4 unstaged=$5 rev=$6 misc=$7 +local msg tmp +local -i i +local -xA hook_com +# The _origs are needed because hooks can change values and there would +# be no way to get the originals back for later hooks (a hook is run for +# each message, that's being created). +hook_com=( + action "$1" + action_orig "$1" + branch "$2" + branch_orig "$2" + base "$3" + base_orig "$3" + staged "$4" + staged_orig "$4" + unstaged "$5" + unstaged_orig "$5" + revision "$6" + revision_orig "$6" + 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]}" ## description: # action: a string that signals a certain non-default condition in the @@ -13,18 +45,15 @@ local action=$1 branch=$2 base=$3 staged=$4 unstaged=$5 rev=$6 misc=$7 # base: the full name of the repository's root directory. # staged: non-empty if the repository contains staged changes. # unstaged: non-empty if the repository contains unstaged changes. -# rev: an identifier of the currently checked out revision. -# misc: a string that may contain anything the author likes. +# 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. # # If an argument has no valid value for a given backend, an empty value # should be provided. eg: # VCS_INFO_formats '' "${foobranch}" "${foobase}" '' '' '' "${foomisc}" -local msg -local -i i j - -if [[ -n ${action} ]] ; then +if [[ -n ${hook_com[action]} ]] ; then zstyle -a ":vcs_info:${vcs}:${usercontext}:${rrn}" actionformats msgs (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b|%a]-' else @@ -32,29 +61,33 @@ else (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b]-' fi -if [[ -n ${staged} ]] ; then - zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" stagedstr staged - [[ -z ${staged} ]] && staged='S' +if [[ -n ${hook_com[staged]} ]] ; then + zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" stagedstr tmp + [[ -z ${tmp} ]] && hook_com[staged]='S' || hook_com[staged]=${tmp} fi -if [[ -n ${unstaged} ]] ; then - zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" unstagedstr unstaged - [[ -z ${unstaged} ]] && unstaged='U' +if [[ -n ${hook_com[unstaged]} ]] ; then + zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" unstagedstr tmp + [[ -z ${tmp} ]] && hook_com[unstaged]='U' || hook_com[unstaged]=${tmp} fi (( ${#msgs} > maxexports )) && msgs[$(( maxexports + 1 )),-1]=() for i in {1..${#msgs}} ; do - zformat -f msg ${msgs[$i]} \ - a:${action} \ - b:${branch} \ - c:${staged} \ - i:${rev} \ - m:${misc} \ - r:${base:t} \ - s:${vcs} \ - u:${unstaged} \ - R:${base} \ - S:"$(VCS_INFO_reposub ${base})" - msgs[$i]=${msg} + if VCS_INFO_hook "set-message" $(( $i - 1 )) "${msgs[$i]}"; then + zformat -f msg ${msgs[$i]} \ + a:${hook_com[action]} \ + b:${hook_com[branch]} \ + c:${hook_com[staged]} \ + i:${hook_com[revision]} \ + m:${hook_com[misc]} \ + r:${hook_com[base-name]} \ + s:${hook_com[vcs]} \ + u:${hook_com[unstaged]} \ + R:${hook_com[base]} \ + S:${hook_com[subdir]} + msgs[$i]=${msg} + else + msgs[$i]=${hook_com[message]} + fi done return 0 diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info index 4344d0b6e..906d984ef 100644 --- a/Functions/VCS_Info/vcs_info +++ b/Functions/VCS_Info/vcs_info @@ -18,6 +18,7 @@ static_functions=( VCS_INFO_check_com VCS_INFO_formats VCS_INFO_get_cmd + VCS_INFO_hook VCS_INFO_maxexports VCS_INFO_nvcsformats VCS_INFO_realpath |