changeset 2591:61f2008cd6bf

Addition of CVScommand vim script as a base for HGcommand
author "Mathieu Clabaut <mathieu.clabaut@gmail.com>"
date Mon, 10 Jul 2006 23:39:08 +0200
parents 6a961a54f953
children 457846f400e8
files contrib/vim/HGAnnotate.vim contrib/vim/hgcommand.txt contrib/vim/hgcommand.vim
diffstat 3 files changed, 2031 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vim/HGAnnotate.vim	Mon Jul 10 23:39:08 2006 +0200
@@ -0,0 +1,27 @@
+" $Id: CVSAnnotate.vim,v 1.5 2002/10/01 21:34:02 rhiestan Exp $
+" Vim syntax file
+" Language:	CVS annotate output
+" Maintainer:	Bob Hiestand <bob@hiestandfamily.org>
+" Last Change:	$Date: 2002/10/01 21:34:02 $
+" Remark:	Used by the cvscommand plugin.  Originally written by Mathieu
+" Clabaut
+if version < 600
+  syntax clear
+elseif exists("b:current_syntax")
+  finish
+endif
+
+syn match cvsDate 	/\S\S\S \S\+ \d\+ \d\+:\d\+:\d\+ \d\+ [+-]\?\d\+/ contained
+syn match cvsName  	/^\s*\S\+ / 		contained nextgroup=cvsVer
+syn match cvsVer 	/\d\+ / 		contained nextgroup=cvsDate
+syn region cvsHead 	start="^" end=":" 	contains=cvsVer,cvsName,cvsDate
+
+if !exists("did_cvsannotate_syntax_inits")
+let did_cvsannotate_syntax_inits = 1
+hi link cvsText 	String
+hi link cvsDate 	Comment
+hi link cvsName	Type
+hi link cvsVer	Statement
+endif
+
+let b:current_syntax="CVSAnnotate"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vim/hgcommand.txt	Mon Jul 10 23:39:08 2006 +0200
@@ -0,0 +1,617 @@
+*cvscommand.txt*	CVSCommand
+
+For instructions on installing this file, type
+	:help add-local-help
+inside Vim.
+
+Author:  Bob Hiestand <bob.hiestand@gmail.com>
+Credits:  Benji Fisher's excellent MatchIt documentation
+
+==============================================================================
+1. Contents						*cvscommand-contents*
+
+	Installation		: |cvscommand-install|
+	CVSCommand Intro	: |cvscommand|
+	CVSCommand Manual	: |cvscommand-manual|
+	Customization		: |cvscommand-customize|
+	SSH "integration"	: |cvscommand-ssh|
+	Bugs			: |cvscommand-bugs|
+
+==============================================================================
+
+2. CVSCommand Installation				*cvscommand-install*
+
+The CVSCommand plugin comprises two files, cvscommand.vim and cvscommand.txt
+(this file).  In order to install the plugin, place the cvscommand.vim file
+into a plugin' directory in your runtime path (please see |add-global-plugin|
+and |'runtimepath'|.
+
+CVSCommand may be customized by setting variables, creating maps, and
+specifying event handlers.  Please see |cvscommand-customize| for more
+details.
+
+This help file can be included in the VIM help system by copying it into a
+'doc' directory in your runtime path and then executing the |:helptags|
+command, specifying the full path of the 'doc' directory.  Please see
+|add-local-help| for more details.
+
+==============================================================================
+
+3. CVSCommand Intro					*cvscommand*
+							*cvscommand-intro*
+
+The CVSCommand plugin provides global ex commands for manipulating
+CVS-controlled source files.  In general, each command operates on the current
+buffer and accomplishes a separate cvs function, such as update, commit, log,
+and others (please see |cvscommand-commands| for a list of all available
+commands).  The results of each operation are displayed in a scratch buffer.
+Several buffer variables are defined for those scratch buffers (please see
+|cvscommand-buffer-variables|).
+
+The notion of "current file" means either the current buffer, or, in the case
+of a directory buffer, the file on the current line within the buffer.
+
+For convenience, any CVSCommand invoked on a CVSCommand scratch buffer acts as
+though it was invoked on the original file and splits the screen so that the
+output appears in a new window.
+
+Many of the commands accept revisions as arguments.  By default, most operate
+on the most recent revision on the current branch if no revision is specified
+(though see |CVSCommandInteractive| to prompt instead).
+
+Each CVSCommand is mapped to a key sequence starting with the <Leader>
+keystroke.  The default mappings may be overridden by supplying different
+mappings before the plugin is loaded, such as in the vimrc, in the standard
+fashion for plugin mappings.  For examples, please see
+|cvscommand-mappings-override|.
+
+The CVSCommand plugin may be configured in several ways.  For more details,
+please see |cvscommand-customize|.
+
+==============================================================================
+
+4. CVSCommand Manual					*cvscommand-manual*
+
+4.1 CVSCommand commands					*cvscommand-commands*
+
+CVSCommand defines the following commands:
+
+|:CVSAdd|
+|:CVSAnnotate|
+|:CVSCommit|
+|:CVSDiff|
+|:CVSEdit|
+|:CVSEditors|
+|:CVSGotoOriginal|
+|:CVSLog|
+|:CVSRevert|
+|:CVSReview|
+|:CVSStatus|
+|:CVSUnedit|
+|:CVSUpdate|
+|:CVSVimDiff|
+|:CVSWatch|
+|:CVSWatchAdd|
+|:CVSWatchOn|
+|:CVSWatchOff|
+|:CVSWatchRemove|
+|:CVSWatchers|
+
+:CVSAdd							*:CVSAdd*
+
+This command performs "cvs add" on the current file.  Please note, this does
+not commit the newly-added file.
+
+:CVSAnnotate						*:CVSAnnotate*
+
+This command performs "cvs annotate" on the current file.  If an argument is
+given, the argument is used as a revision number to display.  If not given an
+argument, it uses the most recent version of the file on the current branch.
+Additionally, if the current buffer is a CVSAnnotate buffer already, the
+version number on the current line is used.
+
+If the |CVSCommandAnnotateParent| variable is set to a non-zero value, the
+version previous to the one on the current line is used instead.  This allows
+one to navigate back to examine the previous version of a line.
+
+The filetype of the CVSCommand scratch buffer is set to 'CVSAnnotate', to take
+advantage of the bundled syntax file.
+
+
+:CVSCommit[!]						*:CVSCommit*
+
+If called with arguments, this performs "cvs commit" using the arguments as
+the log message.
+
+If '!' is used with no arguments, an empty log message is committed.
+
+If called with no arguments, this is a two-step command.  The first step opens
+a buffer to accept a log message.  When that buffer is written, it is
+automatically closed and the file is committed using the information from that
+log message.  The commit can be abandoned if the log message buffer is deleted
+or wiped before being written.
+
+Alternatively, the mapping that is used to invoke :CVSCommit (by default
+<Leader>cc) can be used in the log message buffer to immediately commit.  This
+is useful if the |CVSCommandCommitOnWrite| variable is set to 0 to disable the
+normal commit-on-write behavior.
+
+:CVSDiff						*:CVSDiff*
+
+With no arguments, this performs "cvs diff" on the current file against the
+current repository version.
+
+With one argument, "cvs diff" is performed on the current file against the
+specified revision.
+
+With two arguments, cvs diff is performed between the specified
+revisions of the current file.
+
+This command uses the 'CVSCommandDiffOpt' variable to specify diff options.
+If that variable does not exist, then 'wbBc' is assumed.  If you wish to have
+no options, then set it to the empty string.
+
+:CVSEdit						*:CVSEdit*
+
+This command performs "cvs edit" on the current file.  Yes, the output buffer
+in this case is almost completely useless.
+
+:CVSEditors						*:CVSEditors*
+
+This command performs "cvs edit" on the current file.
+
+:CVSGotoOriginal					*:CVSGotoOriginal*
+
+This command returns the current window to the source buffer, if the current
+buffer is a CVS command output buffer.
+
+:CVSGotoOriginal!
+
+Like ":CVSGotoOriginal" but also executes :bufwipeout on all CVS command
+output buffers for the source buffer.
+
+:CVSLog							*:CVSLog*
+
+Performs "cvs log" on the current file.
+
+If an argument is given, it is passed as an argument to the "-r" option of
+"cvs log".
+
+:CVSRevert						*:CVSRevert*
+
+Replaces the current file with the most recent version from the repository in
+order to wipe out any undesired changes.
+
+:CVSReview						*:CVSReview*
+
+Retrieves a particular version of the current file.  If no argument is given,
+the most recent version of the file on the current branch is retrieved.
+Otherwise, the specified version is retrieved.
+
+:CVSStatus						*:CVSStatus*
+
+Performs "cvs status" on the current file.
+
+:CVSUnedit						*:CVSUnedit*
+
+Performs "cvs unedit" on the current file.  Again, yes, the output buffer here
+is basically useless.
+
+:CVSUpdate						*:CVSUpdate*
+
+Performs "cvs update" on the current file.  This intentionally does not
+automatically reload the current buffer, though vim should prompt the user to
+do so if the underlying file is altered by this command.
+
+:CVSVimDiff						*:CVSVimDiff*
+
+With no arguments, this prompts the user for a revision and then uses vimdiff
+to display the differences between the current file and the specified
+revision.  If no revision is specified, the most recent version of the file on
+the current branch is used.
+
+With one argument, that argument is used as the revision as above.  With two
+arguments, the differences between the two revisions is displayed using
+vimdiff.
+
+With either zero or one argument, the original buffer is used to perform the
+vimdiff.  When the other buffer is closed, the original buffer will be
+returned to normal mode.
+
+Once vimdiff mode is started using the above methods, additional vimdiff
+buffers may be added by passing a single version argument to the command.
+There may be up to 4 vimdiff buffers total.
+
+Using the 2-argument form of the command resets the vimdiff to only those 2
+versions.  Additionally, invoking the command on a different file will close
+the previous vimdiff buffers.
+
+:CVSWatch						*:CVSWatch*
+
+This command takes an argument which must be one of [on|off|add|remove].  The
+command performs "cvs watch" with the given argument on the current file.
+
+:CVSWatchAdd						*:CVSWatchAdd*
+
+This command is an alias for ":CVSWatch add"
+
+:CVSWatchOn						*:CVSWatchOn*
+
+This command is an alias for ":CVSWatch on"
+
+:CVSWatchOff						*:CVSWatchOff*
+
+This command is an alias for ":CVSWatch off"
+
+:CVSWatchRemove						*:CVSWatchRemove*
+
+This command is an alias for ":CVSWatch remove"
+
+:CVSWatchers						*:CVSWatchers*
+
+This command performs "cvs watchers" on the current file.
+
+4.2 Mappings						*cvscommand-mappings*
+
+By default, a mapping is defined for each command.  These mappings execute the
+default (no-argument) form of each command.
+
+<Leader>ca CVSAdd
+<Leader>cn CVSAnnotate
+<Leader>cc CVSCommit
+<Leader>cd CVSDiff
+<Leader>ce CVSEdit
+<Leader>ci CVSEditors
+<Leader>cg CVSGotoOriginal
+<Leader>cG CVSGotoOriginal!
+<Leader>cl CVSLog
+<Leader>cr CVSReview
+<Leader>cs CVSStatus
+<Leader>ct CVSUnedit
+<Leader>cu CVSUpdate
+<Leader>cv CVSVimDiff
+<Leader>cwv CVSWatchers
+<Leader>cwa CVSWatchAdd
+<Leader>cwn CVSWatchOn
+<Leader>cwf CVSWatchOff
+<Leader>cwf CVSWatchRemove
+
+						*cvscommand-mappings-override*
+
+The default mappings can be overriden by user-provided instead by mapping to
+<Plug>CommandName.  This is especially useful when these mappings collide with
+other existing mappings (vim will warn of this during plugin initialization,
+but will not clobber the existing mappings).
+
+For instance, to override the default mapping for :CVSAdd to set it to '\add',
+add the following to the vimrc:
+
+nmap \add <Plug>CVSAdd
+
+4.3 Automatic buffer variables			*cvscommand-buffer-variables*
+
+Several buffer variables are defined in each CVSCommand result buffer.	These
+may be useful for additional customization in callbacks defined in the event
+handlers (please see |cvscommand-events|).
+
+The following variables are automatically defined:
+
+b:cvsOrigBuffNR						*b:cvsOrigBuffNR*
+
+This variable is set to the buffer number of the source file.
+
+b:cvscmd						*b:cvscmd*
+
+This variable is set to the name of the cvs command that created the result
+buffer.
+==============================================================================
+
+5. Configuration and customization			*cvscommand-customize*
+							*cvscommand-config*
+
+The CVSCommand plugin can be configured in two ways:  by setting configuration
+variables (see |cvscommand-options|) or by defining CVSCommand event handlers
+(see |cvscommand-events|).  Additionally, the CVSCommand plugin provides
+several option for naming the CVS result buffers (see |cvscommand-naming|) and
+supported a customized status line (see |cvscommand-statusline| and
+|cvscommand-buffer-management|).
+
+5.1 CVSCommand configuration variables			*cvscommand-options*
+
+Several variables affect the plugin's behavior.  These variables are checked
+at time of execution, and may be defined at the window, buffer, or global
+level and are checked in that order of precedence.
+
+
+The following variables are available:
+
+|CVSCommandAnnotateParent|
+|CVSCommandCommitOnWrite|
+|CVSCommandCVSExec|
+|CVSCommandDeleteOnHide|
+|CVSCommandDiffOpt|
+|CVSCommandDiffSplit|
+|CVSCommandEdit|
+|CVSCommandEnableBufferSetup|
+|CVSCommandInteractive|
+|CVSCommandNameMarker|
+|CVSCommandNameResultBuffers|
+|CVSCommandSplit|
+
+CVSCommandAnnotateParent			*CVSCommandAnnotateParent*
+
+This variable, if set to a non-zero value, causes the zero-argument form of
+CVSAnnotate when invoked on a CVSAnnotate buffer to go to the version previous
+to that displayed on the current line.  If not set, it defaults to 0.
+
+CVSCommandCommitOnWrite				*CVSCommandCommitOnWrite*
+
+This variable, if set to a non-zero value, causes the pending cvs commit
+to take place immediately as soon as the log message buffer is written.
+If set to zero, only the CVSCommit mapping will cause the pending commit to
+occur.	If not set, it defaults to 1.
+
+CVSCommandCVSExec				*CVSCommandCVSExec*
+
+This variable controls the executable used for all CVS commands  If not set,
+it defaults to "cvs".
+
+CVSCommandDeleteOnHide				*CVSCommandDeleteOnHide*
+
+This variable, if set to a non-zero value, causes the temporary CVS result
+buffers to automatically delete themselves when hidden.
+
+CVSCommandDiffOpt				*CVSCommandDiffOpt*
+
+This variable, if set, determines the options passed to the diff command of
+CVS.  If not set, it defaults to 'wbBc'.
+
+CVSCommandDiffSplit				*CVSCommandDiffSplit*
+
+This variable overrides the |CVSCommandSplit| variable, but only for buffers
+created with |:CVSVimDiff|.
+
+CVSCommandEdit					*CVSCommandEdit*
+
+This variable controls whether the original buffer is replaced ('edit') or
+split ('split').  If not set, it defaults to 'edit'.
+
+CVSCommandEnableBufferSetup			*CVSCommandEnableBufferSetup*
+
+This variable, if set to a non-zero value, activates CVS buffer management
+mode see (|cvscommand-buffer-management|).  This mode means that two buffer
+variables, 'CVSRevision' and 'CVSBranch', are set if the file is
+CVS-controlled.  This is useful for displaying version information in the
+status bar.
+
+CVSCommandInteractive				*CVSCommandInteractive*
+
+This variable, if set to a non-zero value, causes appropriate commands (for
+the moment, only |:CVSReview|) to query the user for a revision to use instead
+of the current revision if none is specified.
+
+CVSCommandNameMarker				*CVSCommandNameMarker*
+
+This variable, if set, configures the special attention-getting characters
+that appear on either side of the cvs buffer type in the buffer name.  This
+has no effect unless |CVSCommandNameResultBuffers| is set to a true value.  If
+not set, it defaults to '_'.  
+
+CVSCommandNameResultBuffers			*CVSCommandNameResultBuffers*
+
+This variable, if set to a true value, causes the cvs result buffers to be
+named in the old way ('<source file name> _<cvs command>_').  If not set
+or set to a false value, the result buffer is nameless.
+
+CVSCommandSplit					*CVSCommandSplit*
+
+This variable controls the orientation of the various window splits that
+may occur (such as with CVSVimDiff, when using a CVS command on a CVS
+command buffer, or when the |CVSCommandEdit| variable is set to 'split'.
+If set to 'horizontal', the resulting windows will be on stacked on top of
+one another.  If set to 'vertical', the resulting windows will be
+side-by-side.  If not set, it defaults to 'horizontal' for all but
+CVSVimDiff windows.
+
+5.2 CVSCommand events				*cvscommand-events*
+
+For additional customization, CVSCommand can trigger user-defined events.
+Event handlers are provided by defining User event autocommands (see
+|autocommand|, |User|) in the CVSCommand group with patterns matching the
+event name.
+
+For instance, the following could be added to the vimrc to provide a 'q'
+mapping to quit a CVSCommand scratch buffer:
+
+augroup CVSCommand
+  au CVSCommand User CVSBufferCreated silent! nmap <unique> <buffer> q: bwipeout<cr>
+augroup END
+
+The following hooks are available:
+
+CVSBufferCreated		This event is fired just after a cvs command
+				result buffer is created and filled with the
+				result of a cvs command.  It is executed within
+				the context of the CVS command buffer.  The
+				CVSCommand buffer variables may be useful for
+				handlers of this event (please see
+				|cvscommand-buffer-variables|).
+
+CVSBufferSetup			This event is fired just after CVS buffer setup
+				occurs, if enabled.
+
+CVSPluginInit			This event is fired when the CVSCommand plugin
+				first loads.
+
+CVSPluginFinish			This event is fired just after the CVSCommand
+				plugin loads.
+
+CVSVimDiffFinish		This event is fired just after the CVSVimDiff
+				command executes to allow customization of,
+				for instance, window placement and focus.
+
+5.3 CVSCommand buffer naming				*cvscommand-naming*
+
+By default, the buffers containing the result of CVS commands are nameless
+scratch buffers.  It is intended that buffer variables of those buffers be
+used to customize the statusline option so that the user may fully control the
+display of result buffers.
+
+If the old-style naming is desired, please enable the
+|CVSCommandNameResultBuffers| variable.  Then, each result buffer will receive
+a unique name that includes the source file name, the CVS command, and any
+extra data (such as revision numbers) that were part of the command.
+
+5.4 CVSCommand status line support			*cvscommand-statusline*
+
+It is intended that the user will customize the |'statusline'| option to
+include CVS result buffer attributes.  A sample function that may be used in
+the |'statusline'| option is provided by the plugin, CVSGetStatusLine().  In
+order to use that function in the status line, do something like the
+following:
+
+set statusline=%<%f\ %{CVSGetStatusLine()}\ %h%m%r%=%l,%c%V\ %P
+
+of which %{CVSGetStatusLine()} is the relevant portion.
+
+The sample CVSGetStatusLine() function handles both CVS result buffers and
+CVS-managed files if CVSCommand buffer management is enabled (please see
+|cvscommand-buffer-management|).
+
+5.5 CVSCommand buffer management		*cvscommand-buffer-management*
+
+The CVSCommand plugin can operate in buffer management mode, which means that
+it attempts to set two buffer variables ('CVSRevision' and 'CVSBranch') upon
+entry into a buffer.  This is rather slow because it means that 'cvs status'
+will be invoked at each entry into a buffer (during the |BufEnter|
+autocommand).
+
+This mode is disabled by default.  In order to enable it, set the
+|CVSCommandEnableBufferSetup| variable to a true (non-zero) value.  Enabling
+this mode simply provides the buffer variables mentioned above.  The user must
+explicitly include those in the |'statusline'| option if they are to appear in
+the status line (but see |cvscommand-statusline| for a simple way to do that).
+
+==============================================================================
+
+6. SSH "integration"					*cvscommand-ssh*
+
+The following instructions are intended for use in integrating the
+cvscommand.vim plugin with an SSH-based CVS environment.
+
+Familiarity with SSH and CVS are assumed.
+
+These instructions assume that the intent is to have a message box pop up in
+order to allow the user to enter a passphrase.  If, instead, the user is
+comfortable using certificate-based authentication, then only instructions
+6.1.1 and 6.1.2 (and optionally 6.1.4) need to be followed; ssh should then
+work transparently.
+
+6.1 Environment settings				*cvscommand-ssh-env*
+
+6.1.1 CVSROOT should be set to something like:
+
+	:ext:user@host:/path_to_repository
+
+6.1.2 CVS_RSH should be set to:
+
+	ssh
+
+	Together, those settings tell CVS to use ssh as the transport when
+	performing CVS calls.
+
+6.1.3 SSH_ASKPASS should be set to the password-dialog program.  In my case,
+	running gnome, it's set to:
+
+	/usr/libexec/openssh/gnome-ssh-askpass
+
+	This tells SSH how to get passwords if no input is available.
+
+6.1.4 OPTIONAL.  You may need to set SSH_SERVER to the location of the cvs
+	executable on the remote (server) machine.
+
+6.2 CVS wrapper program				*cvscommand-ssh-wrapper*
+
+Now you need to convince SSH to use the password-dialog program.  This means
+you need to execute SSH (and therefore CVS) without standard input.  The
+following script is a simple perl wrapper that dissasociates the CVS command
+from the current terminal.  Specific steps to do this may vary from system to
+system; the following example works for me on linux.
+
+#!/usr/bin/perl -w
+use strict;
+use POSIX qw(setsid);
+open STDIN, '/dev/null';
+fork and do {wait; exit;};
+setsid;
+exec('cvs', @ARGV);
+
+6.3 Configuring cvscommand.vim			*cvscommand-ssh-config*
+
+At this point, you should be able to use your wrapper script to invoke CVS with
+various commands, and get the password dialog.  All that's left is to make CVS
+use your newly-created wrapper script.
+
+6.3.1 Tell cvscommand.vim what CVS executable to use.  The easiest way to do this
+	is globally, by putting the following in your .vimrc:
+
+	let CVSCommandCVSExec=/path/to/cvs/wrapper/script
+
+6.4 Where to go from here			*cvscommand-ssh-other*
+
+The script given above works even when non-SSH CVS connections are used,
+except possibly when interactively entering the message for CVS commit log
+(depending on the editor you use... VIM works fine).  Since the cvscommand.vim
+plugin handles that message without a terminal, the wrapper script can be used
+all the time.
+
+This allows mixed-mode operation, where some work is done with SSH-based CVS
+repositories, and others with pserver or local access.
+
+It is possible, though beyond the scope of the plugin, to dynamically set the
+CVS executable based on the CVSROOT for the file being edited.  The user
+events provided (such as CVSBufferCreated and CVSBufferSetup) can be used to
+set a buffer-local value (b:CVSCommandCVSExec) to override the CVS executable
+on a file-by-file basis.  Alternatively, much the same can be done (less
+automatically) by the various project-oriented plugins out there.
+
+It is highly recommended for ease-of-use that certificates with no passphrase
+or ssh-agent are employed so that the user is not given the password prompt
+too often.
+
+==============================================================================
+9. Tips							*cvscommand-tips*
+
+9.1 Split window annotation, by Michael Anderson
+
+:nmap <Leader>cN :vs<CR><C-w>h<Leader>cn:vertical res 40<CR>
+                 \ggdddd:set scb<CR>:set nowrap<CR><C-w>lgg:set scb<CR>
+                 \:set nowrap<CR>
+
+This splits the buffer vertically, puts an annotation on the left (minus the
+header) with the width set to 40. An editable/normal copy is placed on the
+right.  The two versions are scroll locked so they  move as one. and wrapping
+is turned off so that the lines line up correctly. The advantages are...
+
+1) You get a versioning on the right.
+2) You can still edit your own code.
+3) Your own code still has syntax highlighting.
+
+==============================================================================
+
+8. Known bugs						*cvscommand-bugs*
+
+Please let me know if you run across any.
+
+CVSUnedit may, if a file is changed from the repository, provide prompt text
+to determine whether the changes should be thrown away.  Currently, that text
+shows up in the CVS result buffer as information; there is no way for the user
+to actually respond to the prompt and the CVS unedit command does nothing.  If
+this really bothers anyone, please let me know.
+
+CVSVimDiff, when using the original (real) source buffer as one of the diff
+buffers, uses some hacks to try to restore the state of the original buffer
+when the scratch buffer containing the other version is destroyed.  There may
+still be bugs in here, depending on many configuration details.
+
+vim:tw=78:ts=8:ft=help
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/vim/hgcommand.vim	Mon Jul 10 23:39:08 2006 +0200
@@ -0,0 +1,1387 @@
+" vim600: set foldmethod=marker:
+"
+" Vim plugin to assist in working with CVS-controlled files.
+"
+" Last Change:   2006/02/22
+" Version:       1.76
+" Maintainer:    Bob Hiestand <bob.hiestand@gmail.com>
+" License:       This file is placed in the public domain.
+" Credits: {{{1
+"                Mathieu Clabaut for many suggestions and improvements.
+"
+"                Suresh Govindachar and Jeeva Chelladhurai for finding waaaay
+"                too many bugs.
+"
+"                Suresh Govindachar (again!) for finding the
+"                fully-folded-last-line-delete bug.
+"
+"                Albrecht Gass for the Delete-on-Hide behavior suggestion.
+"
+"                Joe MacDonald for finding the CVS log message header bug and
+"                pointing out that buffer refreshes are needed after CVS
+"                \%(un\)\?edit.
+"
+"                Srinath Avadhanula for the suggestion and original patch for
+"                the CVSCommitOnWrite option and mapping hot key.
+"
+"                John Sivak for helping to debug Windows issues and suggesting
+"                the CVSEditors and CVSWatchers commands.
+"
+"                Igor Levko for the patch to recognize numerical sticky tags.
+"
+"                Domink Strasser for the patch to correct the status line for
+"                CVSAdd'd files.
+"
+"                Weerapong Sirikanya for finding a bug with CVSCommit and
+"                autochdir.
+"
+"                David Gotz for finding a bug with CVSVimDiff buffer splitting
+"                and original buffer restoration.
+"
+"                CJ van den Berg for the patch to not change working directory
+"                when editing a non-CVS file.
+"
+"                Luca Gerli for noticing bad behavior for keywords in files
+"                after commit if split windows are used.
+
+" Section: Documentation {{{1
+"
+" Provides functions to invoke various CVS commands on the current file
+" (either the current buffer, or, in the case of an directory buffer, the file
+" on the current line).  The output of the commands is captured in a new
+" scratch window.  For convenience, if the functions are invoked on a CVS
+" output window, the original file is used for the cvs operation instead after
+" the window is split.  This is primarily useful when running CVSCommit and
+" you need to see the changes made, so that CVSDiff is usable and shows up in
+" another window.
+"
+" Command documentation {{{2
+"
+" CVSAdd           Performs "cvs add" on the current file.
+"
+" CVSAnnotate      Performs "cvs annotate" on the current file.  If an
+"                  argument is given, the argument is used as a revision
+"                  number to display.  If not given an argument, it uses the
+"                  most recent version of the file on the current branch.
+"                  Additionally, if the current buffer is a CVSAnnotate buffer
+"                  already, the version number on the current line is used.
+"
+"                  If the 'CVSCommandAnnotateParent' variable is set to a
+"                  non-zero value, the version previous to the one on the
+"                  current line is used instead.  This allows one to navigate
+"                  back to examine the previous version of a line.
+"
+" CVSCommit[!]     If called with arguments, this performs "cvs commit" using
+"                  the arguments as the log message.
+"
+"                  If '!' is used, an empty log message is committed.
+"
+"                  If called with no arguments, this is a two-step command.
+"                  The first step opens a buffer to accept a log message.
+"                  When that buffer is written, it is automatically closed and
+"                  the file is committed using the information from that log
+"                  message.  The commit can be abandoned if the log message
+"                  buffer is deleted or wiped before being written.
+"
+" CVSDiff          With no arguments, this performs "cvs diff" on the current
+"                  file.  With one argument, "cvs diff" is performed on the
+"                  current file against the specified revision.  With two
+"                  arguments, cvs diff is performed between the specified
+"                  revisions of the current file.  This command uses the
+"                  'CVSCommandDiffOpt' variable to specify diff options.  If
+"                  that variable does not exist, then 'wbBc' is assumed.  If
+"                  you wish to have no options, then set it to the empty
+"                  string.
+"
+" CVSEdit          Performs "cvs edit" on the current file.
+"
+" CVSEditors       Performs "cvs editors" on the current file.
+"
+" CVSGotoOriginal  Returns the current window to the source buffer if the
+"                  current buffer is a CVS output buffer.
+"
+" CVSLog           Performs "cvs log" on the current file.
+"
+" CVSRevert        Replaces the modified version of the current file with the
+"                  most recent version from the repository.
+"
+" CVSReview        Retrieves a particular version of the current file.  If no
+"                  argument is given, the most recent version of the file on
+"                  the current branch is retrieved.  The specified revision is
+"                  retrieved into a new buffer.
+"
+" CVSStatus        Performs "cvs status" on the current file.
+"
+" CVSUnedit        Performs "cvs unedit" on the current file.
+"
+" CVSUpdate        Performs "cvs update" on the current file.
+"
+" CVSVimDiff       With no arguments, this prompts the user for a revision and
+"                  then uses vimdiff to display the differences between the
+"                  current file and the specified revision.  If no revision is
+"                  specified, the most recent version of the file on the
+"                  current branch is used.  With one argument, that argument
+"                  is used as the revision as above.  With two arguments, the
+"                  differences between the two revisions is displayed using
+"                  vimdiff.
+"
+"                  With either zero or one argument, the original buffer is used
+"                  to perform the vimdiff.  When the other buffer is closed, the
+"                  original buffer will be returned to normal mode.
+"
+"                  Once vimdiff mode is started using the above methods,
+"                  additional vimdiff buffers may be added by passing a single
+"                  version argument to the command.  There may be up to 4
+"                  vimdiff buffers total.
+"
+"                  Using the 2-argument form of the command resets the vimdiff
+"                  to only those 2 versions.  Additionally, invoking the
+"                  command on a different file will close the previous vimdiff
+"                  buffers.
+"
+" CVSWatch         Takes an argument which must be one of [on|off|add|remove].
+"                  Performs "cvs watch" with the given argument on the current
+"                  file.
+"
+" CVSWatchers      Performs "cvs watchers" on the current file.
+"
+" CVSWatchAdd      Alias for "CVSWatch add"
+"
+" CVSWatchOn       Alias for "CVSWatch on"
+"
+" CVSWatchOff      Alias for "CVSWatch off"
+"
+" CVSWatchRemove   Alias for "CVSWatch remove"
+"
+" Mapping documentation: {{{2
+"
+" By default, a mapping is defined for each command.  User-provided mappings
+" can be used instead by mapping to <Plug>CommandName, for instance:
+"
+" nnoremap ,ca <Plug>CVSAdd
+"
+" The default mappings are as follow:
+"
+"   <Leader>ca CVSAdd
+"   <Leader>cn CVSAnnotate
+"   <Leader>cc CVSCommit
+"   <Leader>cd CVSDiff
+"   <Leader>ce CVSEdit
+"   <Leader>ci CVSEditors
+"   <Leader>cg CVSGotoOriginal
+"   <Leader>cG CVSGotoOriginal!
+"   <Leader>cl CVSLog
+"   <Leader>cr CVSReview
+"   <Leader>cs CVSStatus
+"   <Leader>ct CVSUnedit
+"   <Leader>cu CVSUpdate
+"   <Leader>cv CVSVimDiff
+"   <Leader>cwv CVSWatchers
+"   <Leader>cwa CVSWatchAdd
+"   <Leader>cwn CVSWatchOn
+"   <Leader>cwa CVSWatchOff
+"   <Leader>cwr CVSWatchRemove
+"
+" Options documentation: {{{2
+"
+" Several variables are checked by the script to determine behavior as follow:
+"
+" CVSCommandAnnotateParent
+"   This variable, if set to a non-zero value, causes the zero-argument form
+"   of CVSAnnotate when invoked on a CVSAnnotate buffer to go to the version
+"   previous to that displayed on the current line.  If not set, it defaults
+"   to 0.
+"
+" CVSCommandCommitOnWrite
+"   This variable, if set to a non-zero value, causes the pending cvs commit
+"   to take place immediately as soon as the log message buffer is written.
+"   If set to zero, only the CVSCommit mapping will cause the pending commit
+"   to occur.  If not set, it defaults to 1.
+"
+" CVSCommandDeleteOnHide
+"   This variable, if set to a non-zero value, causes the temporary CVS result
+"   buffers to automatically delete themselves when hidden.
+"
+" CVSCommandDiffOpt
+"   This variable, if set, determines the options passed to the diff command
+"   of CVS.  If not set, it defaults to 'wbBc'.
+"
+" CVSCommandDiffSplit
+"   This variable overrides the CVSCommandSplit variable, but only for buffers
+"   created with CVSVimDiff.
+"
+" CVSCommandEdit
+"   This variable controls whether the original buffer is replaced ('edit') or
+"   split ('split').  If not set, it defaults to 'edit'.
+"
+" CVSCommandEnableBufferSetup
+"   This variable, if set to a non-zero value, activates CVS buffer management
+"   mode.  This mode means that two buffer variables, 'CVSRevision' and
+"   'CVSBranch', are set if the file is CVS-controlled.  This is useful for
+"   displaying version information in the status bar.
+"
+" CVSCommandInteractive
+"   This variable, if set to a non-zero value, causes appropriate functions (for
+"   the moment, only CVSReview) to query the user for a revision to use
+"   instead of the current revision if none is specified.
+"
+" CVSCommandNameMarker
+"   This variable, if set, configures the special attention-getting characters
+"   that appear on either side of the cvs buffer type in the buffer name.
+"   This has no effect unless 'CVSCommandNameResultBuffers' is set to a true
+"   value.  If not set, it defaults to '_'.  
+"
+" CVSCommandNameResultBuffers
+"   This variable, if set to a true value, causes the cvs result buffers to be
+"   named in the old way ('<source file name> _<cvs command>_').  If not set
+"   or set to a false value, the result buffer is nameless.
+"
+" CVSCommandSplit
+"   This variable controls the orientation of the various window splits that
+"   may occur (such as with CVSVimDiff, when using a CVS command on a CVS
+"   command buffer, or when the 'CVSCommandEdit' variable is set to 'split'.
+"   If set to 'horizontal', the resulting windows will be on stacked on top of
+"   one another.  If set to 'vertical', the resulting windows will be
+"   side-by-side.  If not set, it defaults to 'horizontal' for all but
+"   CVSVimDiff windows.
+"
+" Event documentation {{{2
+"   For additional customization, cvscommand.vim uses User event autocommand
+"   hooks.  Each event is in the CVSCommand group, and different patterns
+"   match the various hooks.
+"
+"   For instance, the following could be added to the vimrc to provide a 'q'
+"   mapping to quit a CVS buffer:
+"
+"   augroup CVSCommand
+"     au CVSCommand User CVSBufferCreated silent! nmap <unique> <buffer> q :bwipeout<cr> 
+"   augroup END
+"
+"   The following hooks are available:
+"
+"   CVSBufferCreated           This event is fired just after a cvs command
+"                              result buffer is created and filled with the
+"                              result of a cvs command.  It is executed within
+"                              the context of the new buffer.
+"
+"   CVSBufferSetup             This event is fired just after CVS buffer setup
+"                              occurs, if enabled.
+"
+"   CVSPluginInit              This event is fired when the CVSCommand plugin
+"                              first loads.
+"
+"   CVSPluginFinish            This event is fired just after the CVSCommand
+"                              plugin loads.
+"
+"   CVSVimDiffFinish           This event is fired just after the CVSVimDiff
+"                              command executes to allow customization of,
+"                              for instance, window placement and focus.
+"
+" Section: Plugin header {{{1
+
+" loaded_cvscommand is set to 1 when the initialization begins, and 2 when it
+" completes.  This allows various actions to only be taken by functions after
+" system initialization.
+
+if exists("loaded_cvscommand")
+   finish
+endif
+let loaded_cvscommand = 1
+
+if v:version < 602
+  echohl WarningMsg|echomsg "CVSCommand 1.69 or later requires VIM 6.2 or later"|echohl None
+  finish
+endif
+
+" Section: Event group setup {{{1
+
+augroup CVSCommand
+augroup END
+
+" Section: Plugin initialization {{{1
+silent do CVSCommand User CVSPluginInit
+
+" Section: Script variable initialization {{{1
+
+let s:CVSCommandEditFileRunning = 0
+unlet! s:vimDiffRestoreCmd
+unlet! s:vimDiffSourceBuffer
+unlet! s:vimDiffBufferCount
+unlet! s:vimDiffScratchList
+
+" Section: Utility functions {{{1
+
+" Function: s:CVSResolveLink() {{{2
+" Fully resolve the given file name to remove shortcuts or symbolic links.
+
+function! s:CVSResolveLink(fileName)
+  let resolved = resolve(a:fileName)
+  if resolved != a:fileName
+    let resolved = s:CVSResolveLink(resolved)
+  endif
+  return resolved
+endfunction
+
+" Function: s:CVSChangeToCurrentFileDir() {{{2
+" Go to the directory in which the current CVS-controlled file is located.
+" If this is a CVS command buffer, first switch to the original file.
+
+function! s:CVSChangeToCurrentFileDir(fileName)
+  let oldCwd=getcwd()
+  let fileName=s:CVSResolveLink(a:fileName)
+  let newCwd=fnamemodify(fileName, ':h')
+  if strlen(newCwd) > 0
+    execute 'cd' escape(newCwd, ' ')
+  endif
+  return oldCwd
+endfunction
+
+" Function: s:CVSGetOption(name, default) {{{2
+" Grab a user-specified option to override the default provided.  Options are
+" searched in the window, buffer, then global spaces.
+
+function! s:CVSGetOption(name, default)
+  if exists("s:" . a:name . "Override")
+    execute "return s:".a:name."Override"
+  elseif exists("w:" . a:name)
+    execute "return w:".a:name
+  elseif exists("b:" . a:name)
+    execute "return b:".a:name
+  elseif exists("g:" . a:name)
+    execute "return g:".a:name
+  else
+    return a:default
+  endif
+endfunction
+
+" Function: s:CVSEditFile(name, origBuffNR) {{{2
+" Wrapper around the 'edit' command to provide some helpful error text if the
+" current buffer can't be abandoned.  If name is provided, it is used;
+" otherwise, a nameless scratch buffer is used.
+" Returns: 0 if successful, -1 if an error occurs.
+
+function! s:CVSEditFile(name, origBuffNR)
+  "Name parameter will be pasted into expression.
+  let name = escape(a:name, ' *?\')
+
+  let editCommand = s:CVSGetOption('CVSCommandEdit', 'edit')
+  if editCommand != 'edit'
+    if s:CVSGetOption('CVSCommandSplit', 'horizontal') == 'horizontal'
+      if name == ""
+        let editCommand = 'rightbelow new'
+      else
+        let editCommand = 'rightbelow split ' . name
+      endif
+    else
+      if name == ""
+        let editCommand = 'vert rightbelow new'
+      else
+        let editCommand = 'vert rightbelow split ' . name
+      endif
+    endif
+  else
+    if name == ""
+      let editCommand = 'enew'
+    else
+      let editCommand = 'edit ' . name
+    endif
+  endif
+
+  " Protect against useless buffer set-up
+  let s:CVSCommandEditFileRunning = s:CVSCommandEditFileRunning + 1
+  try
+    execute editCommand
+  finally
+    let s:CVSCommandEditFileRunning = s:CVSCommandEditFileRunning - 1
+  endtry
+
+  let b:CVSOrigBuffNR=a:origBuffNR
+  let b:CVSCommandEdit='split'
+endfunction
+
+" Function: s:CVSCreateCommandBuffer(cmd, cmdName, statusText, filename) {{{2
+" Creates a new scratch buffer and captures the output from execution of the
+" given command.  The name of the scratch buffer is returned.
+
+function! s:CVSCreateCommandBuffer(cmd, cmdName, statusText, origBuffNR)
+  let fileName=bufname(a:origBuffNR)
+
+  let resultBufferName=''
+
+  if s:CVSGetOption("CVSCommandNameResultBuffers", 0)
+    let nameMarker = s:CVSGetOption("CVSCommandNameMarker", '_')
+    if strlen(a:statusText) > 0
+      let bufName=a:cmdName . ' -- ' . a:statusText
+    else
+      let bufName=a:cmdName
+    endif
+    let bufName=fileName . ' ' . nameMarker . bufName . nameMarker
+    let counter=0
+    let resultBufferName = bufName
+    while buflisted(resultBufferName)
+      let counter=counter + 1
+      let resultBufferName=bufName . ' (' . counter . ')'
+    endwhile
+  endif
+
+  let cvsCommand = s:CVSGetOption("CVSCommandCVSExec", "cvs") . " " . a:cmd
+  let cvsOut = system(cvsCommand)
+  " HACK:  diff command does not return proper error codes
+  if v:shell_error && a:cmdName != 'cvsdiff'
+    if strlen(cvsOut) == 0
+      echoerr "CVS command failed"
+    else
+      echoerr "CVS command failed:  " . cvsOut
+    endif
+    return -1
+  endif
+  if strlen(cvsOut) == 0
+    " Handle case of no output.  In this case, it is important to check the
+    " file status, especially since cvs edit/unedit may change the attributes
+    " of the file with no visible output.
+
+    echomsg "No output from CVS command"
+    checktime
+    return -1
+  endif
+
+  if s:CVSEditFile(resultBufferName, a:origBuffNR) == -1
+    return -1
+  endif
+
+  set buftype=nofile
+  set noswapfile
+  set filetype=
+
+  if s:CVSGetOption("CVSCommandDeleteOnHide", 0)
+    set bufhidden=delete
+  endif
+
+  silent 0put=cvsOut
+
+  " The last command left a blank line at the end of the buffer.  If the
+  " last line is folded (a side effect of the 'put') then the attempt to
+  " remove the blank line will kill the last fold.
+  "
+  " This could be fixed by explicitly detecting whether the last line is
+  " within a fold, but I prefer to simply unfold the result buffer altogether.
+
+  if has('folding')
+    normal zR
+  endif
+
+  $d
+  1
+
+  " Define the environment and execute user-defined hooks.
+
+  let b:CVSSourceFile=fileName
+  let b:CVSCommand=a:cmdName
+  if a:statusText != ""
+    let b:CVSStatusText=a:statusText
+  endif
+
+  silent do CVSCommand User CVSBufferCreated
+  return bufnr("%")
+endfunction
+
+" Function: s:CVSBufferCheck(cvsBuffer) {{{2
+" Attempts to locate the original file to which CVS operations were applied
+" for a given buffer.
+
+function! s:CVSBufferCheck(cvsBuffer)
+  let origBuffer = getbufvar(a:cvsBuffer, "CVSOrigBuffNR")
+  if origBuffer
+    if bufexists(origBuffer)
+      return origBuffer
+    else
+      " Original buffer no longer exists.
+      return -1 
+    endif
+  else
+    " No original buffer
+    return a:cvsBuffer
+  endif
+endfunction
+
+" Function: s:CVSCurrentBufferCheck() {{{2
+" Attempts to locate the original file to which CVS operations were applied
+" for the current buffer.
+
+function! s:CVSCurrentBufferCheck()
+  return s:CVSBufferCheck(bufnr("%"))
+endfunction
+
+" Function: s:CVSToggleDeleteOnHide() {{{2
+" Toggles on and off the delete-on-hide behavior of CVS buffers
+
+function! s:CVSToggleDeleteOnHide()
+  if exists("g:CVSCommandDeleteOnHide")
+    unlet g:CVSCommandDeleteOnHide
+  else
+    let g:CVSCommandDeleteOnHide=1
+  endif
+endfunction
+
+" Function: s:CVSDoCommand(cvscmd, cmdName, statusText) {{{2
+" General skeleton for CVS function execution.
+" Returns: name of the new command buffer containing the command results
+
+function! s:CVSDoCommand(cmd, cmdName, statusText)
+  let cvsBufferCheck=s:CVSCurrentBufferCheck()
+  if cvsBufferCheck == -1 
+    echo "Original buffer no longer exists, aborting."
+    return -1
+  endif
+
+  let fileName=bufname(cvsBufferCheck)
+  if isdirectory(fileName)
+    let fileName=fileName . "/" . getline(".")
+  endif
+  let realFileName = fnamemodify(s:CVSResolveLink(fileName), ':t')
+  let oldCwd=s:CVSChangeToCurrentFileDir(fileName)
+  try
+    if !filereadable('CVS/Root')
+      throw fileName . ' is not a CVS-controlled file.'
+    endif
+    let fullCmd = a:cmd . ' "' . realFileName . '"'
+    let resultBuffer=s:CVSCreateCommandBuffer(fullCmd, a:cmdName, a:statusText, cvsBufferCheck)
+    return resultBuffer
+  catch
+    echoerr v:exception
+    return -1
+  finally
+    execute 'cd' escape(oldCwd, ' ')
+  endtry
+endfunction
+
+
+" Function: s:CVSGetStatusVars(revision, branch, repository) {{{2
+"
+" Obtains a CVS revision number and branch name.  The 'revisionVar',
+" 'branchVar'and 'repositoryVar' arguments, if non-empty, contain the names of variables to hold
+" the corresponding results.
+"
+" Returns: string to be exec'd that sets the multiple return values.
+
+function! s:CVSGetStatusVars(revisionVar, branchVar, repositoryVar)
+  let cvsBufferCheck=s:CVSCurrentBufferCheck()
+  if cvsBufferCheck == -1 
+    return ""
+  endif
+  let fileName=bufname(cvsBufferCheck)
+  let realFileName = fnamemodify(s:CVSResolveLink(fileName), ':t')
+  let oldCwd=s:CVSChangeToCurrentFileDir(fileName)
+  try
+    if !filereadable('CVS/Root')
+      return ""
+    endif
+    let cvsCommand = s:CVSGetOption("CVSCommandCVSExec", "cvs") . " status " . escape(realFileName, ' *?\')
+    let statustext=system(cvsCommand)
+    if(v:shell_error)
+      return ""
+    endif
+    let revision=substitute(statustext, '^\_.*Working revision:\s*\(\d\+\%(\.\d\+\)\+\|New file!\)\_.*$', '\1', "")
+
+    " We can still be in a CVS-controlled directory without this being a CVS
+    " file
+    if match(revision, '^New file!$') >= 0 
+      let revision="NEW"
+    elseif match(revision, '^\d\+\.\d\+\%(\.\d\+\.\d\+\)*$') >=0
+    else
+      return ""
+    endif
+
+    let returnExpression = "let " . a:revisionVar . "='" . revision . "'"
+
+    if a:branchVar != ""
+      let branch=substitute(statustext, '^\_.*Sticky Tag:\s\+\(\d\+\%(\.\d\+\)\+\|\a[A-Za-z0-9-_]*\|(none)\).*$', '\1', "")
+      let returnExpression=returnExpression . " | let " . a:branchVar . "='" . branch . "'"
+    endif
+
+    if a:repositoryVar != ""
+      let repository=substitute(statustext, '^\_.*Repository revision:\s*\(\d\+\%(\.\d\+\)\+\|New file!\|No revision control file\)\_.*$', '\1', "")
+      let repository=substitute(repository, '^New file!\|No revision control file$', 'NEW', "")
+      let returnExpression=returnExpression . " | let " . a:repositoryVar . "='" . repository . "'"
+    endif
+
+    return returnExpression
+  finally
+    execute 'cd' escape(oldCwd, ' ')
+  endtry
+endfunction
+
+" Function: s:CVSSetupBuffer() {{{2
+" Attempts to set the b:CVSBranch, b:CVSRevision and b:CVSRepository variables.
+
+function! s:CVSSetupBuffer()
+  if (exists("b:CVSBufferSetup") && b:CVSBufferSetup)
+    " This buffer is already set up.
+    return
+  endif
+
+  if !s:CVSGetOption("CVSCommandEnableBufferSetup", 0)
+        \ || @% == ""
+        \ || s:CVSCommandEditFileRunning > 0
+        \ || exists("b:CVSOrigBuffNR")
+    unlet! b:CVSRevision
+    unlet! b:CVSBranch
+    unlet! b:CVSRepository
+    return
+  endif
+
+  if !filereadable(expand("%"))
+    return -1
+  endif
+
+  let revision=""
+  let branch=""
+  let repository=""
+
+  exec s:CVSGetStatusVars('revision', 'branch', 'repository')
+  if revision != ""
+    let b:CVSRevision=revision
+  else
+    unlet! b:CVSRevision
+  endif
+  if branch != ""
+    let b:CVSBranch=branch
+  else
+    unlet! b:CVSBranch
+  endif
+  if repository != ""
+     let b:CVSRepository=repository
+  else
+     unlet! b:CVSRepository
+  endif
+  silent do CVSCommand User CVSBufferSetup
+  let b:CVSBufferSetup=1
+endfunction
+
+" Function: s:CVSMarkOrigBufferForSetup(cvsbuffer) {{{2
+" Resets the buffer setup state of the original buffer for a given CVS buffer.
+" Returns:  The CVS buffer number in a passthrough mode.
+
+function! s:CVSMarkOrigBufferForSetup(cvsBuffer)
+  checktime
+  if a:cvsBuffer != -1
+    let origBuffer = s:CVSBufferCheck(a:cvsBuffer)
+    "This should never not work, but I'm paranoid
+    if origBuffer != a:cvsBuffer
+      call setbufvar(origBuffer, "CVSBufferSetup", 0)
+    endif
+  endif
+  return a:cvsBuffer
+endfunction
+
+" Function: s:CVSOverrideOption(option, [value]) {{{2
+" Provides a temporary override for the given CVS option.  If no value is
+" passed, the override is disabled.
+
+function! s:CVSOverrideOption(option, ...)
+  if a:0 == 0
+    unlet! s:{a:option}Override
+  else
+    let s:{a:option}Override = a:1
+  endif
+endfunction
+
+" Function: s:CVSWipeoutCommandBuffers() {{{2
+" Clears all current CVS buffers of the specified type for a given source.
+
+function! s:CVSWipeoutCommandBuffers(originalBuffer, cvsCommand)
+  let buffer = 1
+  while buffer <= bufnr('$')
+    if getbufvar(buffer, 'CVSOrigBuffNR') == a:originalBuffer
+      if getbufvar(buffer, 'CVSCommand') == a:cvsCommand
+        execute 'bw' buffer
+      endif
+    endif
+    let buffer = buffer + 1
+  endwhile
+endfunction
+
+" Section: Public functions {{{1
+
+" Function: CVSGetRevision() {{{2
+" Global function for retrieving the current buffer's CVS revision number.
+" Returns: Revision number or an empty string if an error occurs.
+
+function! CVSGetRevision()
+  let revision=""
+  exec s:CVSGetStatusVars('revision', '', '')
+  return revision
+endfunction
+
+" Function: CVSDisableBufferSetup() {{{2
+" Global function for deactivating the buffer autovariables.
+
+function! CVSDisableBufferSetup()
+  let g:CVSCommandEnableBufferSetup=0
+  silent! augroup! CVSCommandPlugin
+endfunction
+
+" Function: CVSEnableBufferSetup() {{{2
+" Global function for activating the buffer autovariables.
+
+function! CVSEnableBufferSetup()
+  let g:CVSCommandEnableBufferSetup=1
+  augroup CVSCommandPlugin
+    au!
+    au BufEnter * call s:CVSSetupBuffer()
+  augroup END
+
+  " Only auto-load if the plugin is fully loaded.  This gives other plugins a
+  " chance to run.
+  if g:loaded_cvscommand == 2
+    call s:CVSSetupBuffer()
+  endif
+endfunction
+
+" Function: CVSGetStatusLine() {{{2
+" Default (sample) status line entry for CVS files.  This is only useful if
+" CVS-managed buffer mode is on (see the CVSCommandEnableBufferSetup variable
+" for how to do this).
+
+function! CVSGetStatusLine()
+  if exists('b:CVSSourceFile')
+    " This is a result buffer
+    let value='[' . b:CVSCommand . ' ' . b:CVSSourceFile
+    if exists('b:CVSStatusText')
+      let value=value . ' ' . b:CVSStatusText
+    endif
+    let value = value . ']'
+    return value
+  endif
+
+  if exists('b:CVSRevision')
+        \ && b:CVSRevision != ''
+        \ && exists('b:CVSBranch')
+        \ && b:CVSBranch != ''
+        \ && exists('b:CVSRepository')
+        \ && b:CVSRepository != ''
+        \ && exists('g:CVSCommandEnableBufferSetup')
+        \ && g:CVSCommandEnableBufferSetup
+    if b:CVSRevision == b:CVSRepository
+      return '[CVS ' . b:CVSBranch . '/' . b:CVSRevision . ']'
+    else
+      return '[CVS ' . b:CVSBranch . '/' . b:CVSRevision . '/' . b:CVSRepository . ']'
+    endif
+  else
+    return ''
+  endif
+endfunction
+
+" Section: CVS command functions {{{1
+
+" Function: s:CVSAdd() {{{2
+function! s:CVSAdd()
+  return s:CVSMarkOrigBufferForSetup(s:CVSDoCommand('add', 'cvsadd', ''))
+endfunction
+
+" Function: s:CVSAnnotate(...) {{{2
+function! s:CVSAnnotate(...)
+  if a:0 == 0
+    if &filetype == "CVSAnnotate"
+      " This is a CVSAnnotate buffer.  Perform annotation of the version
+      " indicated by the current line.
+      let revision = substitute(getline("."),'\(^[0-9.]*\).*','\1','')
+      let revmin = substitute(revision,'^[0-9.]*\.\([0-9]\+\)','\1','')
+      let revmaj = substitute(revision,'^\([0-9.]*\)\.[0-9]\+','\1','')
+      if s:CVSGetOption('CVSCommandAnnotateParent', 0) != 0
+        let revmin = revmin - 1
+      endif
+      if revmin == 0
+        " Jump to ancestor branch
+        let revision = substitute(revmaj,'^\([0-9.]*\)\.[0-9]\+','\1','')
+      else
+        let revision=revmaj . "." .  revmin
+      endif
+    else
+      let revision=CVSGetRevision()
+      if revision == ""
+        echoerr "Unable to obtain CVS version information."
+        return -1
+      endif
+    endif
+  else
+    let revision=a:1
+  endif
+
+  if revision == "NEW"
+    echo "No annotatation available for new file."
+    return -1
+  endif
+
+  let resultBuffer=s:CVSDoCommand('-q annotate -r ' . revision, 'cvsannotate', revision) 
+  if resultBuffer !=  -1
+    set filetype=CVSAnnotate
+    " Remove header lines from standard error
+    silent v/^\d\+\%(\.\d\+\)\+/d
+  endif
+
+  return resultBuffer
+endfunction
+
+" Function: s:CVSCommit() {{{2
+function! s:CVSCommit(...)
+  " Handle the commit message being specified.  If a message is supplied, it
+  " is used; if bang is supplied, an empty message is used; otherwise, the
+  " user is provided a buffer from which to edit the commit message.
+  if a:2 != "" || a:1 == "!"
+    return s:CVSMarkOrigBufferForSetup(s:CVSDoCommand('commit -m "' . a:2 . '"', 'cvscommit', ''))
+  endif
+
+  let cvsBufferCheck=s:CVSCurrentBufferCheck()
+  if cvsBufferCheck ==  -1
+    echo "Original buffer no longer exists, aborting."
+    return -1
+  endif
+
+  " Protect against windows' backslashes in paths.  They confuse exec'd
+  " commands.
+
+  let shellSlashBak = &shellslash
+  try
+    set shellslash
+
+    let messageFileName = tempname()
+
+    let fileName=bufname(cvsBufferCheck)
+    let realFilePath=s:CVSResolveLink(fileName)
+    let newCwd=fnamemodify(realFilePath, ':h')
+    if strlen(newCwd) == 0
+      " Account for autochdir being in effect, which will make this blank, but
+      " we know we'll be in the current directory for the original file.
+      let newCwd = getcwd()
+    endif
+
+    let realFileName=fnamemodify(realFilePath, ':t')
+
+    if s:CVSEditFile(messageFileName, cvsBufferCheck) == -1
+      return
+    endif
+
+    " Protect against case and backslash issues in Windows.
+    let autoPattern = '\c' . messageFileName
+
+    " Ensure existance of group
+    augroup CVSCommit
+    augroup END
+
+    execute 'au CVSCommit BufDelete' autoPattern 'call delete("' . messageFileName . '")'
+    execute 'au CVSCommit BufDelete' autoPattern 'au! CVSCommit * ' autoPattern
+
+    " Create a commit mapping.  The mapping must clear all autocommands in case
+    " it is invoked when CVSCommandCommitOnWrite is active, as well as to not
+    " invoke the buffer deletion autocommand.
+
+    execute 'nnoremap <silent> <buffer> <Plug>CVSCommit '.
+          \ ':au! CVSCommit * ' . autoPattern . '<CR>'.
+          \ ':g/^CVS:/d<CR>'.
+          \ ':update<CR>'.
+          \ ':call <SID>CVSFinishCommit("' . messageFileName . '",' .
+          \                             '"' . newCwd . '",' .
+          \                             '"' . realFileName . '",' .
+          \                             cvsBufferCheck . ')<CR>'
+
+    silent 0put ='CVS: ----------------------------------------------------------------------'
+    silent put =\"CVS: Enter Log.  Lines beginning with `CVS:' are removed automatically\"
+    silent put ='CVS: Type <leader>cc (or your own <Plug>CVSCommit mapping)'
+
+    if s:CVSGetOption('CVSCommandCommitOnWrite', 1) == 1
+      execute 'au CVSCommit BufWritePre' autoPattern 'g/^CVS:/d'
+      execute 'au CVSCommit BufWritePost' autoPattern 'call s:CVSFinishCommit("' . messageFileName . '", "' . newCwd . '", "' . realFileName . '", ' . cvsBufferCheck . ') | au! * ' autoPattern
+      silent put ='CVS: or write this buffer'
+    endif
+
+    silent put ='CVS: to finish this commit operation'
+    silent put ='CVS: ----------------------------------------------------------------------'
+    $
+    let b:CVSSourceFile=fileName
+    let b:CVSCommand='CVSCommit'
+    set filetype=cvs
+  finally
+    let &shellslash = shellSlashBak
+  endtry
+
+endfunction
+
+" Function: s:CVSDiff(...) {{{2
+function! s:CVSDiff(...)
+  if a:0 == 1
+    let revOptions = '-r' . a:1
+    let caption = a:1 . ' -> current'
+  elseif a:0 == 2
+    let revOptions = '-r' . a:1 . ' -r' . a:2
+    let caption = a:1 . ' -> ' . a:2
+  else
+    let revOptions = ''
+    let caption = ''
+  endif
+
+  let cvsdiffopt=s:CVSGetOption('CVSCommandDiffOpt', 'wbBc')
+
+  if cvsdiffopt == ""
+    let diffoptionstring=""
+  else
+    let diffoptionstring=" -" . cvsdiffopt . " "
+  endif
+
+  let resultBuffer = s:CVSDoCommand('diff ' . diffoptionstring . revOptions , 'cvsdiff', caption)
+  if resultBuffer != -1 
+    set filetype=diff
+  endif
+  return resultBuffer
+endfunction
+
+" Function: s:CVSEdit() {{{2
+function! s:CVSEdit()
+  return s:CVSDoCommand('edit', 'cvsedit', '')
+endfunction
+
+" Function: s:CVSEditors() {{{2
+function! s:CVSEditors()
+  return s:CVSDoCommand('editors', 'cvseditors', '')
+endfunction
+
+" Function: s:CVSGotoOriginal(["!]) {{{2
+function! s:CVSGotoOriginal(...)
+  let origBuffNR = s:CVSCurrentBufferCheck()
+  if origBuffNR > 0
+    let origWinNR = bufwinnr(origBuffNR)
+    if origWinNR == -1
+      execute 'buffer' origBuffNR
+    else
+      execute origWinNR . 'wincmd w'
+    endif
+    if a:0 == 1
+      if a:1 == "!"
+        let buffnr = 1
+        let buffmaxnr = bufnr("$")
+        while buffnr <= buffmaxnr
+          if getbufvar(buffnr, "CVSOrigBuffNR") == origBuffNR
+            execute "bw" buffnr
+          endif
+          let buffnr = buffnr + 1
+        endwhile
+      endif
+    endif
+  endif
+endfunction
+
+" Function: s:CVSFinishCommit(messageFile, targetDir, targetFile) {{{2
+function! s:CVSFinishCommit(messageFile, targetDir, targetFile, origBuffNR)
+  if filereadable(a:messageFile)
+    let oldCwd=getcwd()
+    if strlen(a:targetDir) > 0
+      execute 'cd' escape(a:targetDir, ' ')
+    endif
+    let resultBuffer=s:CVSCreateCommandBuffer('commit -F "' . a:messageFile . '" "'. a:targetFile . '"', 'cvscommit', '', a:origBuffNR)
+    execute 'cd' escape(oldCwd, ' ')
+    execute 'bw' escape(a:messageFile, ' *?\')
+    silent execute 'call delete("' . a:messageFile . '")'
+    return s:CVSMarkOrigBufferForSetup(resultBuffer)
+  else
+    echoerr "Can't read message file; no commit is possible."
+    return -1
+  endif
+endfunction
+
+" Function: s:CVSLog() {{{2
+function! s:CVSLog(...)
+  if a:0 == 0
+    let versionOption = ""
+    let caption = ''
+  else
+    let versionOption=" -r" . a:1
+    let caption = a:1
+  endif
+
+  let resultBuffer=s:CVSDoCommand('log' . versionOption, 'cvslog', caption)
+  if resultBuffer != ""
+    set filetype=rcslog
+  endif
+  return resultBuffer
+endfunction
+
+" Function: s:CVSRevert() {{{2
+function! s:CVSRevert()
+  return s:CVSMarkOrigBufferForSetup(s:CVSDoCommand('update -C', 'cvsrevert', ''))
+endfunction
+
+" Function: s:CVSReview(...) {{{2
+function! s:CVSReview(...)
+  if a:0 == 0
+    let versiontag=""
+    if s:CVSGetOption('CVSCommandInteractive', 0)
+      let versiontag=input('Revision:  ')
+    endif
+    if versiontag == ""
+      let versiontag="(current)"
+      let versionOption=""
+    else
+      let versionOption=" -r " . versiontag . " "
+    endif
+  else
+    let versiontag=a:1
+    let versionOption=" -r " . versiontag . " "
+  endif
+
+  let resultBuffer = s:CVSDoCommand('-q update -p' . versionOption, 'cvsreview', versiontag)
+  if resultBuffer > 0
+    let &filetype=getbufvar(b:CVSOrigBuffNR, '&filetype')
+  endif
+
+  return resultBuffer
+endfunction
+
+" Function: s:CVSStatus() {{{2
+function! s:CVSStatus()
+  return s:CVSDoCommand('status', 'cvsstatus', '')
+endfunction
+
+" Function: s:CVSUnedit() {{{2
+function! s:CVSUnedit()
+  return s:CVSDoCommand('unedit', 'cvsunedit', '')
+endfunction
+
+" Function: s:CVSUpdate() {{{2
+function! s:CVSUpdate()
+  return s:CVSMarkOrigBufferForSetup(s:CVSDoCommand('update', 'update', ''))
+endfunction
+
+" Function: s:CVSVimDiff(...) {{{2
+function! s:CVSVimDiff(...)
+  let originalBuffer = s:CVSCurrentBufferCheck()
+  let s:CVSCommandEditFileRunning = s:CVSCommandEditFileRunning + 1
+  try
+    " If there's already a VimDiff'ed window, restore it.
+    " There may only be one CVSVimDiff original window at a time.
+
+    if exists("s:vimDiffSourceBuffer") && s:vimDiffSourceBuffer != originalBuffer
+      " Clear the existing vimdiff setup by removing the result buffers.
+      call s:CVSWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff')
+    endif
+
+    " Split and diff
+    if(a:0 == 2)
+      " Reset the vimdiff system, as 2 explicit versions were provided.
+      if exists('s:vimDiffSourceBuffer')
+        call s:CVSWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff')
+      endif
+      let resultBuffer = s:CVSReview(a:1)
+      if resultBuffer < 0
+        echomsg "Can't open CVS revision " . a:1
+        return resultBuffer
+      endif
+      let b:CVSCommand = 'vimdiff'
+      diffthis
+      let s:vimDiffBufferCount = 1
+      let s:vimDiffScratchList = '{'. resultBuffer . '}'
+      " If no split method is defined, cheat, and set it to vertical.
+      try
+        call s:CVSOverrideOption('CVSCommandSplit', s:CVSGetOption('CVSCommandDiffSplit', s:CVSGetOption('CVSCommandSplit', 'vertical')))
+        let resultBuffer=s:CVSReview(a:2)
+      finally
+        call s:CVSOverrideOption('CVSCommandSplit')
+      endtry
+      if resultBuffer < 0
+        echomsg "Can't open CVS revision " . a:1
+        return resultBuffer
+      endif
+      let b:CVSCommand = 'vimdiff'
+      diffthis
+      let s:vimDiffBufferCount = 2
+      let s:vimDiffScratchList = s:vimDiffScratchList . '{'. resultBuffer . '}'
+    else
+      " Add new buffer
+      try
+        " Force splitting behavior, otherwise why use vimdiff?
+        call s:CVSOverrideOption("CVSCommandEdit", "split")
+        call s:CVSOverrideOption("CVSCommandSplit", s:CVSGetOption('CVSCommandDiffSplit', s:CVSGetOption('CVSCommandSplit', 'vertical')))
+        if(a:0 == 0)
+          let resultBuffer=s:CVSReview()
+        else
+          let resultBuffer=s:CVSReview(a:1)
+        endif
+      finally
+        call s:CVSOverrideOption("CVSCommandEdit")
+        call s:CVSOverrideOption("CVSCommandSplit")
+      endtry
+      if resultBuffer < 0
+        echomsg "Can't open current CVS revision"
+        return resultBuffer
+      endif
+      let b:CVSCommand = 'vimdiff'
+      diffthis
+
+      if !exists('s:vimDiffBufferCount')
+        " New instance of vimdiff.
+        let s:vimDiffBufferCount = 2
+        let s:vimDiffScratchList = '{' . resultBuffer . '}'
+
+        " This could have been invoked on a CVS result buffer, not the
+        " original buffer.
+        wincmd W
+        execute 'buffer' originalBuffer
+        " Store info for later original buffer restore
+        let s:vimDiffRestoreCmd = 
+              \    "call setbufvar(".originalBuffer.", \"&diff\", ".getbufvar(originalBuffer, '&diff').")"
+              \ . "|call setbufvar(".originalBuffer.", \"&foldcolumn\", ".getbufvar(originalBuffer, '&foldcolumn').")"
+              \ . "|call setbufvar(".originalBuffer.", \"&foldenable\", ".getbufvar(originalBuffer, '&foldenable').")"
+              \ . "|call setbufvar(".originalBuffer.", \"&foldmethod\", '".getbufvar(originalBuffer, '&foldmethod')."')"
+              \ . "|call setbufvar(".originalBuffer.", \"&scrollbind\", ".getbufvar(originalBuffer, '&scrollbind').")"
+              \ . "|call setbufvar(".originalBuffer.", \"&wrap\", ".getbufvar(originalBuffer, '&wrap').")"
+              \ . "|if &foldmethod=='manual'|execute 'normal zE'|endif"
+        diffthis
+        wincmd w
+      else
+        " Adding a window to an existing vimdiff
+        let s:vimDiffBufferCount = s:vimDiffBufferCount + 1
+        let s:vimDiffScratchList = s:vimDiffScratchList . '{' . resultBuffer . '}'
+      endif
+    endif
+
+    let s:vimDiffSourceBuffer = originalBuffer
+
+    " Avoid executing the modeline in the current buffer after the autocommand.
+
+    let currentBuffer = bufnr('%')
+    let saveModeline = getbufvar(currentBuffer, '&modeline')
+    try
+      call setbufvar(currentBuffer, '&modeline', 0)
+      silent do CVSCommand User CVSVimDiffFinish
+    finally
+      call setbufvar(currentBuffer, '&modeline', saveModeline)
+    endtry
+    return resultBuffer
+  finally
+    let s:CVSCommandEditFileRunning = s:CVSCommandEditFileRunning - 1
+  endtry
+endfunction
+
+" Function: s:CVSWatch(onoff) {{{2
+function! s:CVSWatch(onoff)
+  if a:onoff !~ '^\c\%(on\|off\|add\|remove\)$'
+    echoerr "Argument to CVSWatch must be one of [on|off|add|remove]"
+    return -1
+  end
+  return s:CVSDoCommand('watch ' . tolower(a:onoff), 'cvswatch', '')
+endfunction
+
+" Function: s:CVSWatchers() {{{2
+function! s:CVSWatchers()
+  return s:CVSDoCommand('watchers', 'cvswatchers', '')
+endfunction
+
+" Section: Command definitions {{{1
+" Section: Primary commands {{{2
+com! CVSAdd call s:CVSAdd()
+com! -nargs=? CVSAnnotate call s:CVSAnnotate(<f-args>)
+com! -bang -nargs=? CVSCommit call s:CVSCommit(<q-bang>, <q-args>)
+com! -nargs=* CVSDiff call s:CVSDiff(<f-args>)
+com! CVSEdit call s:CVSEdit()
+com! CVSEditors call s:CVSEditors()
+com! -bang CVSGotoOriginal call s:CVSGotoOriginal(<q-bang>)
+com! -nargs=? CVSLog call s:CVSLog(<f-args>)
+com! CVSRevert call s:CVSRevert()
+com! -nargs=? CVSReview call s:CVSReview(<f-args>)
+com! CVSStatus call s:CVSStatus()
+com! CVSUnedit call s:CVSUnedit()
+com! CVSUpdate call s:CVSUpdate()
+com! -nargs=* CVSVimDiff call s:CVSVimDiff(<f-args>)
+com! -nargs=1 CVSWatch call s:CVSWatch(<f-args>)
+com! CVSWatchAdd call s:CVSWatch('add')
+com! CVSWatchOn call s:CVSWatch('on')
+com! CVSWatchOff call s:CVSWatch('off')
+com! CVSWatchRemove call s:CVSWatch('remove')
+com! CVSWatchers call s:CVSWatchers()
+
+" Section: CVS buffer management commands {{{2
+com! CVSDisableBufferSetup call CVSDisableBufferSetup()
+com! CVSEnableBufferSetup call CVSEnableBufferSetup()
+
+" Allow reloading cvscommand.vim
+com! CVSReload unlet! loaded_cvscommand | runtime plugin/cvscommand.vim
+
+" Section: Plugin command mappings {{{1
+nnoremap <silent> <Plug>CVSAdd :CVSAdd<CR>
+nnoremap <silent> <Plug>CVSAnnotate :CVSAnnotate<CR>
+nnoremap <silent> <Plug>CVSCommit :CVSCommit<CR>
+nnoremap <silent> <Plug>CVSDiff :CVSDiff<CR>
+nnoremap <silent> <Plug>CVSEdit :CVSEdit<CR>
+nnoremap <silent> <Plug>CVSEditors :CVSEditors<CR>
+nnoremap <silent> <Plug>CVSGotoOriginal :CVSGotoOriginal<CR>
+nnoremap <silent> <Plug>CVSClearAndGotoOriginal :CVSGotoOriginal!<CR>
+nnoremap <silent> <Plug>CVSLog :CVSLog<CR>
+nnoremap <silent> <Plug>CVSRevert :CVSRevert<CR>
+nnoremap <silent> <Plug>CVSReview :CVSReview<CR>
+nnoremap <silent> <Plug>CVSStatus :CVSStatus<CR>
+nnoremap <silent> <Plug>CVSUnedit :CVSUnedit<CR>
+nnoremap <silent> <Plug>CVSUpdate :CVSUpdate<CR>
+nnoremap <silent> <Plug>CVSVimDiff :CVSVimDiff<CR>
+nnoremap <silent> <Plug>CVSWatchers :CVSWatchers<CR>
+nnoremap <silent> <Plug>CVSWatchAdd :CVSWatchAdd<CR>
+nnoremap <silent> <Plug>CVSWatchOn :CVSWatchOn<CR>
+nnoremap <silent> <Plug>CVSWatchOff :CVSWatchOff<CR>
+nnoremap <silent> <Plug>CVSWatchRemove :CVSWatchRemove<CR>
+
+" Section: Default mappings {{{1
+if !hasmapto('<Plug>CVSAdd')
+  nmap <unique> <Leader>ca <Plug>CVSAdd
+endif
+if !hasmapto('<Plug>CVSAnnotate')
+  nmap <unique> <Leader>cn <Plug>CVSAnnotate
+endif
+if !hasmapto('<Plug>CVSClearAndGotoOriginal')
+  nmap <unique> <Leader>cG <Plug>CVSClearAndGotoOriginal
+endif
+if !hasmapto('<Plug>CVSCommit')
+  nmap <unique> <Leader>cc <Plug>CVSCommit
+endif
+if !hasmapto('<Plug>CVSDiff')
+  nmap <unique> <Leader>cd <Plug>CVSDiff
+endif
+if !hasmapto('<Plug>CVSEdit')
+  nmap <unique> <Leader>ce <Plug>CVSEdit
+endif
+if !hasmapto('<Plug>CVSEditors')
+  nmap <unique> <Leader>ci <Plug>CVSEditors
+endif
+if !hasmapto('<Plug>CVSGotoOriginal')
+  nmap <unique> <Leader>cg <Plug>CVSGotoOriginal
+endif
+if !hasmapto('<Plug>CVSLog')
+  nmap <unique> <Leader>cl <Plug>CVSLog
+endif
+if !hasmapto('<Plug>CVSRevert')
+  nmap <unique> <Leader>cq <Plug>CVSRevert
+endif
+if !hasmapto('<Plug>CVSReview')
+  nmap <unique> <Leader>cr <Plug>CVSReview
+endif
+if !hasmapto('<Plug>CVSStatus')
+  nmap <unique> <Leader>cs <Plug>CVSStatus
+endif
+if !hasmapto('<Plug>CVSUnedit')
+  nmap <unique> <Leader>ct <Plug>CVSUnedit
+endif
+if !hasmapto('<Plug>CVSUpdate')
+  nmap <unique> <Leader>cu <Plug>CVSUpdate
+endif
+if !hasmapto('<Plug>CVSVimDiff')
+  nmap <unique> <Leader>cv <Plug>CVSVimDiff
+endif
+if !hasmapto('<Plug>CVSWatchers')
+  nmap <unique> <Leader>cwv <Plug>CVSWatchers
+endif
+if !hasmapto('<Plug>CVSWatchAdd')
+  nmap <unique> <Leader>cwa <Plug>CVSWatchAdd
+endif
+if !hasmapto('<Plug>CVSWatchOn')
+  nmap <unique> <Leader>cwn <Plug>CVSWatchOn
+endif
+if !hasmapto('<Plug>CVSWatchOff')
+  nmap <unique> <Leader>cwf <Plug>CVSWatchOff
+endif
+if !hasmapto('<Plug>CVSWatchRemove')
+  nmap <unique> <Leader>cwr <Plug>CVSWatchRemove
+endif
+
+" Section: Menu items {{{1
+silent! aunmenu Plugin.CVS
+amenu <silent> &Plugin.CVS.&Add        <Plug>CVSAdd
+amenu <silent> &Plugin.CVS.A&nnotate   <Plug>CVSAnnotate
+amenu <silent> &Plugin.CVS.&Commit     <Plug>CVSCommit
+amenu <silent> &Plugin.CVS.&Diff       <Plug>CVSDiff
+amenu <silent> &Plugin.CVS.&Edit       <Plug>CVSEdit
+amenu <silent> &Plugin.CVS.Ed&itors    <Plug>CVSEditors
+amenu <silent> &Plugin.CVS.&Log        <Plug>CVSLog
+amenu <silent> &Plugin.CVS.Revert      <Plug>CVSRevert
+amenu <silent> &Plugin.CVS.&Review     <Plug>CVSReview
+amenu <silent> &Plugin.CVS.&Status     <Plug>CVSStatus
+amenu <silent> &Plugin.CVS.Unedi&t     <Plug>CVSUnedit
+amenu <silent> &Plugin.CVS.&Update     <Plug>CVSUpdate
+amenu <silent> &Plugin.CVS.&VimDiff    <Plug>CVSVimDiff
+amenu <silent> &Plugin.CVS.&Watchers   <Plug>CVSWatchers
+amenu <silent> &Plugin.CVS.WatchAdd    <Plug>CVSWatchAdd
+amenu <silent> &Plugin.CVS.WatchOn     <Plug>CVSWatchOn
+amenu <silent> &Plugin.CVS.WatchOff    <Plug>CVSWatchOff
+amenu <silent> &Plugin.CVS.WatchRemove <Plug>CVSWatchRemove
+
+" Section: Autocommands to restore vimdiff state {{{1
+function! s:CVSVimDiffRestore(vimDiffBuff)
+  let s:CVSCommandEditFileRunning = s:CVSCommandEditFileRunning + 1
+  try
+    if exists("s:vimDiffSourceBuffer")
+      if a:vimDiffBuff == s:vimDiffSourceBuffer
+        " Original file is being removed.
+        unlet! s:vimDiffSourceBuffer
+        unlet! s:vimDiffBufferCount
+        unlet! s:vimDiffRestoreCmd
+        unlet! s:vimDiffScratchList
+      elseif match(s:vimDiffScratchList, '{' . a:vimDiffBuff . '}') >= 0
+        let s:vimDiffScratchList = substitute(s:vimDiffScratchList, '{' . a:vimDiffBuff . '}', '', '')
+        let s:vimDiffBufferCount = s:vimDiffBufferCount - 1
+        if s:vimDiffBufferCount == 1 && exists('s:vimDiffRestoreCmd')
+          " All scratch buffers are gone, reset the original.
+          " Only restore if the source buffer is still in Diff mode
+
+          let sourceWinNR=bufwinnr(s:vimDiffSourceBuffer)
+          if sourceWinNR != -1
+            " The buffer is visible in at least one window
+            let currentWinNR = winnr()
+            while winbufnr(sourceWinNR) != -1
+              if winbufnr(sourceWinNR) == s:vimDiffSourceBuffer
+                execute sourceWinNR . 'wincmd w'
+                if getwinvar('', "&diff")
+                  execute s:vimDiffRestoreCmd
+                endif
+              endif
+              let sourceWinNR = sourceWinNR + 1
+            endwhile
+            execute currentWinNR . 'wincmd w'
+          else
+            " The buffer is hidden.  It must be visible in order to set the
+            " diff option.
+            let currentBufNR = bufnr('')
+            execute "hide buffer" s:vimDiffSourceBuffer
+            if getwinvar('', "&diff")
+              execute s:vimDiffRestoreCmd
+            endif
+            execute "hide buffer" currentBufNR
+          endif
+
+          unlet s:vimDiffRestoreCmd
+          unlet s:vimDiffSourceBuffer
+          unlet s:vimDiffBufferCount
+          unlet s:vimDiffScratchList
+        elseif s:vimDiffBufferCount == 0
+          " All buffers are gone.
+          unlet s:vimDiffSourceBuffer
+          unlet s:vimDiffBufferCount
+          unlet s:vimDiffScratchList
+        endif
+      endif
+    endif
+  finally
+    let s:CVSCommandEditFileRunning = s:CVSCommandEditFileRunning - 1
+  endtry
+endfunction
+
+augroup CVSVimDiffRestore
+  au!
+  au BufUnload * call s:CVSVimDiffRestore(expand("<abuf>"))
+augroup END
+
+" Section: Optional activation of buffer management {{{1
+
+if s:CVSGetOption('CVSCommandEnableBufferSetup', 0)
+  call CVSEnableBufferSetup()
+endif
+
+" Section: Plugin completion {{{1
+
+let loaded_cvscommand=2
+silent do CVSCommand User CVSPluginFinish