mirror of
https://github.com/facebook/sapling.git
synced 2024-10-09 16:31:02 +03:00
1388 lines
46 KiB
VimL
1388 lines
46 KiB
VimL
|
" 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
|