/vim/plugin/vcscommand.vim
Vim Script | 1344 lines | 718 code | 149 blank | 477 comment | 142 complexity | bb6bb1fbde0b62f5634cb355d5294f0c MD5 | raw file
1" vim600: set foldmethod=marker:
2"
3" Vim plugin to assist in working with files under control of various Version
4" Control Systems, such as CVS, SVN, SVK, and git.
5"
6" Version: 1.99.31
7" Maintainer: Bob Hiestand <bob.hiestand@gmail.com>
8" License:
9" Copyright (c) 2008 Bob Hiestand
10"
11" Permission is hereby granted, free of charge, to any person obtaining a copy
12" of this software and associated documentation files (the "Software"), to
13" deal in the Software without restriction, including without limitation the
14" rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
15" sell copies of the Software, and to permit persons to whom the Software is
16" furnished to do so, subject to the following conditions:
17"
18" The above copyright notice and this permission notice shall be included in
19" all copies or substantial portions of the Software.
20"
21" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27" IN THE SOFTWARE.
28"
29" Section: Documentation {{{1
30"
31" Provides functions to invoke various source control commands on the current
32" file (either the current buffer, or, in the case of an directory buffer, the
33" directory and all subdirectories associated with the current buffer). The
34" output of the commands is captured in a new scratch window.
35"
36" This plugin needs additional extension plugins, each specific to a source
37" control system, to function. Those plugins should be placed in a
38" subdirectory of the standard plugin directory named 'vcscommand'. Several
39" options include the name of the version control system in the option name.
40" Such options use the placeholder text '{VCSType}', which would be replaced
41" in actual usage with 'CVS' or 'SVN', for instance.
42"
43" Command documentation {{{2
44"
45" VCSAdd Adds the current file to source control.
46"
47" VCSAnnotate[!] Displays the current file with each line annotated with the
48" version in which it was most recently changed. If an
49" argument is given, the argument is used as a revision
50" number to display. If not given an argument, it uses the
51" most recent version of the file on the current branch.
52" Additionally, if the current buffer is a VCSAnnotate buffer
53" already, the version number on the current line is used.
54"
55" If '!' is used, the view of the annotated buffer is split
56" so that the annotation is in a separate window from the
57" content, and each is highlighted separately.
58"
59" VCSBlame Alias for 'VCSAnnotate'.
60"
61" VCSCommit[!] Commits changes to the current file to source control.
62"
63" If called with arguments, the arguments are the log message.
64"
65" If '!' is used, an empty log message is committed.
66"
67" If called with no arguments, this is a two-step command.
68" The first step opens a buffer to accept a log message.
69" When that buffer is written, it is automatically closed and
70" the file is committed using the information from that log
71" message. The commit can be abandoned if the log message
72" buffer is deleted or wiped before being written.
73"
74" VCSDelete Deletes the current file and removes it from source control.
75"
76" VCSDiff With no arguments, this displays the differences between
77" the current file and its parent version under source
78" control in a new scratch buffer.
79"
80" With one argument, the diff is performed on the
81" current file against the specified revision.
82"
83" With two arguments, the diff is performed between the
84" specified revisions of the current file.
85"
86" This command uses the 'VCSCommand{VCSType}DiffOpt' variable
87" to specify diff options. If that variable does not exist,
88" a plugin-specific default is used. If you wish to have no
89" options, then set it to the empty string.
90"
91" VCSGotoOriginal Jumps to the source buffer if the current buffer is a VCS
92" scratch buffer. If VCSGotoOriginal[!] is used, remove all
93" VCS scratch buffers associated with the original file.
94"
95" VCSInfo Displays extended information about the current file in a
96" new scratch buffer.
97"
98" VCSLock Locks the current file in order to prevent other users from
99" concurrently modifying it. The exact semantics of this
100" command depend on the underlying VCS.
101"
102" VCSLog Displays the version history of the current file in a new
103" scratch buffer.
104"
105" VCSRemove Alias for 'VCSDelete'.
106"
107" VCSRevert Replaces the modified version of the current file with the
108" most recent version from the repository.
109"
110" VCSReview Displays a particular version of the current file in a new
111" scratch buffer. If no argument is given, the most recent
112" version of the file on the current branch is retrieved.
113"
114" VCSStatus Displays versioning information about the current file in a
115" new scratch buffer.
116"
117" VCSUnlock Unlocks the current file in order to allow other users from
118" concurrently modifying it. The exact semantics of this
119" command depend on the underlying VCS.
120"
121" VCSUpdate Updates the current file with any relevant changes from the
122" repository.
123"
124" VCSVimDiff Uses vimdiff to display differences between versions of the
125" current file.
126"
127" If no revision is specified, the most recent version of the
128" file on the current branch is used. With one argument,
129" that argument is used as the revision as above. With two
130" arguments, the differences between the two revisions is
131" displayed using vimdiff.
132"
133" With either zero or one argument, the original buffer is
134" used to perform the vimdiff. When the scratch buffer is
135" closed, the original buffer will be returned to normal
136" mode.
137"
138" Once vimdiff mode is started using the above methods,
139" additional vimdiff buffers may be added by passing a single
140" version argument to the command. There may be up to 4
141" vimdiff buffers total.
142"
143" Using the 2-argument form of the command resets the vimdiff
144" to only those 2 versions. Additionally, invoking the
145" command on a different file will close the previous vimdiff
146" buffers.
147"
148" Mapping documentation: {{{2
149"
150" By default, a mapping is defined for each command. User-provided mappings
151" can be used instead by mapping to <Plug>CommandName, for instance:
152"
153" nmap ,ca <Plug>VCSAdd
154"
155" The default mappings are as follow:
156"
157" <Leader>ca VCSAdd
158" <Leader>cn VCSAnnotate
159" <Leader>cN VCSAnnotate!
160" <Leader>cc VCSCommit
161" <Leader>cD VCSDelete
162" <Leader>cd VCSDiff
163" <Leader>cg VCSGotoOriginal
164" <Leader>cG VCSGotoOriginal!
165" <Leader>ci VCSInfo
166" <Leader>cl VCSLog
167" <Leader>cL VCSLock
168" <Leader>cr VCSReview
169" <Leader>cs VCSStatus
170" <Leader>cu VCSUpdate
171" <Leader>cU VCSUnlock
172" <Leader>cv VCSVimDiff
173"
174" Options documentation: {{{2
175"
176" Several variables are checked by the script to determine behavior as follow:
177"
178" VCSCommandCommitOnWrite
179" This variable, if set to a non-zero value, causes the pending commit to
180" take place immediately as soon as the log message buffer is written. If
181" set to zero, only the VCSCommit mapping will cause the pending commit to
182" occur. If not set, it defaults to 1.
183"
184" VCSCommandDeleteOnHide
185" This variable, if set to a non-zero value, causes the temporary VCS result
186" buffers to automatically delete themselves when hidden.
187"
188" VCSCommand{VCSType}DiffOpt
189" This variable, if set, determines the options passed to the diff command
190" of the underlying VCS. Each VCS plugin defines a default value.
191"
192" VCSCommandDiffSplit
193" This variable overrides the VCSCommandSplit variable, but only for buffers
194" created with VCSVimDiff.
195"
196" VCSCommandDisableAll
197" This variable, if set, prevents the plugin or any extensions from loading
198" at all. This is useful when a single runtime distribution is used on
199" multiple systems with varying versions.
200"
201" VCSCommandDisableMappings
202" This variable, if set to a non-zero value, prevents the default command
203" mappings from being set.
204"
205" VCSCommandDisableExtensionMappings
206" This variable, if set to a non-zero value, prevents the default command
207" mappings from being set for commands specific to an individual VCS.
208"
209" VCSCommandEdit
210" This variable controls whether to split the current window to display a
211" scratch buffer ('split'), or to display it in the current buffer ('edit').
212" If not set, it defaults to 'split'.
213"
214" VCSCommandEnableBufferSetup
215" This variable, if set to a non-zero value, activates VCS buffer management
216" mode. This mode means that the buffer variable 'VCSRevision' is set if
217" the file is VCS-controlled. This is useful for displaying version
218" information in the status bar. Additional options may be set by
219" individual VCS plugins.
220"
221" VCSCommandMappings
222" This variable, if set, overrides the default mappings used for shortcuts.
223" It should be a List of 2-element Lists, each containing a shortcut and
224" function name pair.
225"
226" VCSCommandMapPrefix
227" This variable, if set, overrides the default mapping prefix ('<Leader>c').
228" This allows customization of the mapping space used by the vcscommand
229" shortcuts.
230"
231" VCSCommandResultBufferNameExtension
232" This variable, if set to a non-blank value, is appended to the name of the
233" VCS command output buffers. For example, '.vcs'. Using this option may
234" help avoid problems caused by autocommands dependent on file extension.
235"
236" VCSCommandResultBufferNameFunction
237" This variable, if set, specifies a custom function for naming VCS command
238" output buffers. This function will be passed the following arguments:
239"
240" command - name of the VCS command being executed (such as 'Log' or
241" 'Diff').
242"
243" originalBuffer - buffer number of the source file.
244"
245" vcsType - type of VCS controlling this file (such as 'CVS' or 'SVN').
246"
247" statusText - extra text associated with the VCS action (such as version
248" numbers).
249"
250" VCSCommandSplit
251" This variable controls the orientation of the various window splits that
252" may occur (such as with VCSVimDiff, when using a VCS command on a VCS
253" command buffer, or when the 'VCSCommandEdit' variable is set to 'split'.
254" If set to 'horizontal', the resulting windows will be on stacked on top of
255" one another. If set to 'vertical', the resulting windows will be
256" side-by-side. If not set, it defaults to 'horizontal' for all but
257" VCSVimDiff windows.
258"
259" VCSCommandVCSTypeOverride
260" This variable allows the VCS type detection to be overridden on a
261" path-by-path basis. The value of this variable is expected to be a List
262" of Lists. Each high-level List item is a List containing two elements.
263" The first element is a regular expression that will be matched against the
264" full file name of a given buffer. If it matches, the second element will
265" be used as the VCS type.
266"
267" Event documentation {{{2
268" For additional customization, VCSCommand.vim uses User event autocommand
269" hooks. Each event is in the VCSCommand group, and different patterns
270" match the various hooks.
271"
272" For instance, the following could be added to the vimrc to provide a 'q'
273" mapping to quit a VCS scratch buffer:
274"
275" augroup VCSCommand
276" au VCSCommand User VCSBufferCreated silent! nmap <unique> <buffer> q :bwipeout<cr>
277" augroup END
278"
279" The following hooks are available:
280"
281" VCSBufferCreated This event is fired just after a VCS command
282" output buffer is created. It is executed
283" within the context of the new buffer.
284"
285" VCSBufferSetup This event is fired just after VCS buffer setup
286" occurs, if enabled.
287"
288" VCSPluginInit This event is fired when the VCSCommand plugin
289" first loads.
290"
291" VCSPluginFinish This event is fired just after the VCSCommand
292" plugin loads.
293"
294" VCSVimDiffFinish This event is fired just after the VCSVimDiff
295" command executes to allow customization of,
296" for instance, window placement and focus.
297"
298" Section: Plugin header {{{1
299
300" loaded_VCSCommand is set to 1 when the initialization begins, and 2 when it
301" completes. This allows various actions to only be taken by functions after
302" system initialization.
303
304if exists('VCSCommandDisableAll')
305 finish
306endif
307
308if exists('loaded_VCSCommand')
309 finish
310endif
311let loaded_VCSCommand = 1
312
313if v:version < 700
314 echohl WarningMsg|echomsg 'VCSCommand requires at least VIM 7.0'|echohl None
315 finish
316endif
317
318let s:save_cpo=&cpo
319set cpo&vim
320
321" Section: Event group setup {{{1
322
323augroup VCSCommand
324augroup END
325
326augroup VCSCommandCommit
327augroup END
328
329" Section: Plugin initialization {{{1
330silent do VCSCommand User VCSPluginInit
331
332" Section: Constants declaration {{{1
333
334let g:VCSCOMMAND_IDENTIFY_EXACT = 1
335let g:VCSCOMMAND_IDENTIFY_INEXACT = -1
336
337" Section: Script variable initialization {{{1
338
339" plugin-specific information: {vcs -> [script, {command -> function}, {key -> mapping}]}
340let s:plugins = {}
341
342" temporary values of overridden configuration variables
343let s:optionOverrides = {}
344
345" state flag used to vary behavior of certain automated actions
346let s:isEditFileRunning = 0
347
348" commands needed to restore diff buffers to their original state
349unlet! s:vimDiffRestoreCmd
350
351" original buffer currently reflected in vimdiff windows
352unlet! s:vimDiffSourceBuffer
353
354"
355unlet! s:vimDiffScratchList
356
357" Section: Utility functions {{{1
358
359" Function: s:ReportError(mapping) {{{2
360" Displays the given error in a consistent faction. This is intended to be
361" invoked from a catch statement.
362
363function! s:ReportError(error)
364 echohl WarningMsg|echomsg 'VCSCommand: ' . a:error|echohl None
365endfunction
366
367
368" Function: s:CreateMapping(shortcut, expansion, display) {{{2
369" Creates the given mapping by prepending the contents of
370" 'VCSCommandMapPrefix' (by default '<Leader>c') to the given shortcut and
371" mapping it to the given plugin function. If a mapping exists for the
372" specified shortcut + prefix, emit an error but continue. If a mapping
373" exists for the specified function, do nothing.
374
375function! s:CreateMapping(shortcut, expansion, display)
376 let lhs = VCSCommandGetOption('VCSCommandMapPrefix', '<Leader>c') . a:shortcut
377 if !hasmapto(a:expansion)
378 try
379 execute 'nmap <silent> <unique>' lhs a:expansion
380 catch /^Vim(.*):E227:/
381 if(&verbose != 0)
382 echohl WarningMsg|echomsg 'VCSCommand: mapping ''' . lhs . ''' already exists, refusing to overwrite. The mapping for ' . a:display . ' will not be available.'|echohl None
383 endif
384 endtry
385 endif
386endfunction
387
388" Function: s:ExecuteExtensionMapping(mapping) {{{2
389" Invokes the appropriate extension mapping depending on the type of the
390" current buffer.
391
392function! s:ExecuteExtensionMapping(mapping)
393 let buffer = bufnr('%')
394 let vcsType = VCSCommandGetVCSType(buffer)
395 if !has_key(s:plugins, vcsType)
396 throw 'Unknown VCS type: ' . vcsType
397 endif
398 if !has_key(s:plugins[vcsType][2], a:mapping)
399 throw 'This extended mapping is not defined for ' . vcsType
400 endif
401 silent execute 'normal' ':' . s:plugins[vcsType][2][a:mapping] . "\<CR>"
402endfunction
403
404" Function: s:ExecuteVCSCommand(command, argList) {{{2
405" Calls the indicated plugin-specific VCS command on the current buffer.
406" Returns: buffer number of resulting output scratch buffer, or -1 if an error
407" occurs.
408
409function! s:ExecuteVCSCommand(command, argList)
410 try
411 let buffer = bufnr('%')
412
413 let vcsType = VCSCommandGetVCSType(buffer)
414 if !has_key(s:plugins, vcsType)
415 throw 'Unknown VCS type: ' . vcsType
416 endif
417
418 let originalBuffer = VCSCommandGetOriginalBuffer(buffer)
419 let bufferName = bufname(originalBuffer)
420
421 " It is already known that the directory is under VCS control. No further
422 " checks are needed. Otherwise, perform some basic sanity checks to avoid
423 " VCS-specific error messages from confusing things.
424 if !isdirectory(bufferName)
425 if !filereadable(bufferName)
426 throw 'No such file ' . bufferName
427 endif
428 endif
429
430 let functionMap = s:plugins[vcsType][1]
431 if !has_key(functionMap, a:command)
432 throw 'Command ''' . a:command . ''' not implemented for ' . vcsType
433 endif
434 return functionMap[a:command](a:argList)
435 catch
436 call s:ReportError(v:exception)
437 return -1
438 endtry
439endfunction
440
441" Function: s:GenerateResultBufferName(command, originalBuffer, vcsType, statusText) {{{2
442" Default method of generating the name for VCS result buffers. This can be
443" overridden with the VCSResultBufferNameFunction variable.
444
445function! s:GenerateResultBufferName(command, originalBuffer, vcsType, statusText)
446 let fileName = bufname(a:originalBuffer)
447 let bufferName = a:vcsType . ' ' . a:command
448 if strlen(a:statusText) > 0
449 let bufferName .= ' ' . a:statusText
450 endif
451 let bufferName .= ' ' . fileName
452 let counter = 0
453 let versionedBufferName = bufferName
454 while buflisted(versionedBufferName)
455 let counter += 1
456 let versionedBufferName = bufferName . ' (' . counter . ')'
457 endwhile
458 return versionedBufferName
459endfunction
460
461" Function: s:GenerateResultBufferNameWithExtension(command, originalBuffer, vcsType, statusText) {{{2
462" Method of generating the name for VCS result buffers that uses the original
463" file name with the VCS type and command appended as extensions.
464
465function! s:GenerateResultBufferNameWithExtension(command, originalBuffer, vcsType, statusText)
466 let fileName = bufname(a:originalBuffer)
467 let bufferName = a:vcsType . ' ' . a:command
468 if strlen(a:statusText) > 0
469 let bufferName .= ' ' . a:statusText
470 endif
471 let bufferName .= ' ' . fileName . VCSCommandGetOption('VCSCommandResultBufferNameExtension', '.vcs')
472 let counter = 0
473 let versionedBufferName = bufferName
474 while buflisted(versionedBufferName)
475 let counter += 1
476 let versionedBufferName = '(' . counter . ') ' . bufferName
477 endwhile
478 return versionedBufferName
479endfunction
480
481" Function: s:EditFile(command, originalBuffer, statusText) {{{2
482" Creates a new buffer of the given name and associates it with the given
483" original buffer.
484
485function! s:EditFile(command, originalBuffer, statusText)
486 let vcsType = getbufvar(a:originalBuffer, 'VCSCommandVCSType')
487
488 " Protect against useless buffer set-up
489 let s:isEditFileRunning += 1
490 try
491 let editCommand = VCSCommandGetOption('VCSCommandEdit', 'split')
492 if editCommand == 'split'
493 if VCSCommandGetOption('VCSCommandSplit', 'horizontal') == 'horizontal'
494 rightbelow split
495 else
496 vert rightbelow split
497 endif
498 endif
499
500 enew
501
502 call s:SetupScratchBuffer(a:command, vcsType, a:originalBuffer, a:statusText)
503
504 finally
505 let s:isEditFileRunning -= 1
506 endtry
507endfunction
508
509" Function: s:SetupScratchBuffer(command, vcsType, originalBuffer, statusText) {{{2
510" Creates convenience buffer variables and the name of a vcscommand result
511" buffer.
512
513function! s:SetupScratchBuffer(command, vcsType, originalBuffer, statusText)
514 let nameExtension = VCSCommandGetOption('VCSCommandResultBufferNameExtension', '')
515 if nameExtension == ''
516 let nameFunction = VCSCommandGetOption('VCSCommandResultBufferNameFunction', 's:GenerateResultBufferName')
517 else
518 let nameFunction = VCSCommandGetOption('VCSCommandResultBufferNameFunction', 's:GenerateResultBufferNameWithExtension')
519 endif
520
521 let name = call(nameFunction, [a:command, a:originalBuffer, a:vcsType, a:statusText])
522
523 let b:VCSCommandCommand = a:command
524 let b:VCSCommandOriginalBuffer = a:originalBuffer
525 let b:VCSCommandSourceFile = bufname(a:originalBuffer)
526 let b:VCSCommandVCSType = a:vcsType
527 if a:statusText != ''
528 let b:VCSCommandStatusText = a:statusText
529 endif
530
531 setlocal buftype=nofile
532 setlocal noswapfile
533 let &filetype = a:vcsType . a:command
534
535 if VCSCommandGetOption('VCSCommandDeleteOnHide', 0)
536 setlocal bufhidden=delete
537 endif
538 silent noautocmd file `=name`
539endfunction
540
541" Function: s:SetupBuffer() {{{2
542" Attempts to set the b:VCSCommandBufferInfo variable
543
544function! s:SetupBuffer()
545 if (exists('b:VCSCommandBufferSetup') && b:VCSCommandBufferSetup)
546 " This buffer is already set up.
547 return
548 endif
549
550 if !isdirectory(@%) && (strlen(&buftype) > 0 || !filereadable(@%))
551 " No special status for special buffers other than directory buffers.
552 return
553 endif
554
555 if !VCSCommandGetOption('VCSCommandEnableBufferSetup', 0) || s:isEditFileRunning > 0
556 unlet! b:VCSCommandBufferSetup
557 return
558 endif
559
560 try
561 let vcsType = VCSCommandGetVCSType(bufnr('%'))
562 let b:VCSCommandBufferInfo = s:plugins[vcsType][1].GetBufferInfo()
563 silent do VCSCommand User VCSBufferSetup
564 catch /No suitable plugin/
565 " This is not a VCS-controlled file.
566 let b:VCSCommandBufferInfo = []
567 endtry
568
569 let b:VCSCommandBufferSetup = 1
570endfunction
571
572" Function: s:MarkOrigBufferForSetup(buffer) {{{2
573" Resets the buffer setup state of the original buffer for a given VCS scratch
574" buffer.
575" Returns: The VCS buffer number in a passthrough mode.
576
577function! s:MarkOrigBufferForSetup(buffer)
578 checktime
579 if a:buffer > 0
580 let origBuffer = VCSCommandGetOriginalBuffer(a:buffer)
581 " This should never not work, but I'm paranoid
582 if origBuffer != a:buffer
583 call setbufvar(origBuffer, 'VCSCommandBufferSetup', 0)
584 endif
585 endif
586 return a:buffer
587endfunction
588
589" Function: s:OverrideOption(option, [value]) {{{2
590" Provides a temporary override for the given VCS option. If no value is
591" passed, the override is disabled.
592
593function! s:OverrideOption(option, ...)
594 if a:0 == 0
595 call remove(s:optionOverrides[a:option], -1)
596 else
597 if !has_key(s:optionOverrides, a:option)
598 let s:optionOverrides[a:option] = []
599 endif
600 call add(s:optionOverrides[a:option], a:1)
601 endif
602endfunction
603
604" Function: s:WipeoutCommandBuffers() {{{2
605" Clears all current VCS output buffers of the specified type for a given source.
606
607function! s:WipeoutCommandBuffers(originalBuffer, VCSCommand)
608 let buffer = 1
609 while buffer <= bufnr('$')
610 if getbufvar(buffer, 'VCSCommandOriginalBuffer') == a:originalBuffer
611 if getbufvar(buffer, 'VCSCommandCommand') == a:VCSCommand
612 execute 'bw' buffer
613 endif
614 endif
615 let buffer = buffer + 1
616 endwhile
617endfunction
618
619" Function: s:VimDiffRestore(vimDiffBuff) {{{2
620" Checks whether the given buffer is one whose deletion should trigger
621" restoration of an original buffer after it was diffed. If so, it executes
622" the appropriate setting command stored with that original buffer.
623
624function! s:VimDiffRestore(vimDiffBuff)
625 let s:isEditFileRunning += 1
626 try
627 if exists('s:vimDiffSourceBuffer')
628 if a:vimDiffBuff == s:vimDiffSourceBuffer
629 " Original file is being removed.
630 unlet! s:vimDiffSourceBuffer
631 unlet! s:vimDiffRestoreCmd
632 unlet! s:vimDiffScratchList
633 else
634 let index = index(s:vimDiffScratchList, a:vimDiffBuff)
635 if index >= 0
636 call remove(s:vimDiffScratchList, index)
637 if len(s:vimDiffScratchList) == 0
638 if exists('s:vimDiffRestoreCmd')
639 " All scratch buffers are gone, reset the original.
640 " Only restore if the source buffer is still in Diff mode
641
642 let sourceWinNR = bufwinnr(s:vimDiffSourceBuffer)
643 if sourceWinNR != -1
644 " The buffer is visible in at least one window
645 let currentWinNR = winnr()
646 while winbufnr(sourceWinNR) != -1
647 if winbufnr(sourceWinNR) == s:vimDiffSourceBuffer
648 execute sourceWinNR . 'wincmd w'
649 if getwinvar(0, '&diff')
650 execute s:vimDiffRestoreCmd
651 endif
652 endif
653 let sourceWinNR = sourceWinNR + 1
654 endwhile
655 execute currentWinNR . 'wincmd w'
656 else
657 " The buffer is hidden. It must be visible in order to set the
658 " diff option.
659 let currentBufNR = bufnr('')
660 execute 'hide buffer' s:vimDiffSourceBuffer
661 if getwinvar(0, '&diff')
662 execute s:vimDiffRestoreCmd
663 endif
664 execute 'hide buffer' currentBufNR
665 endif
666
667 unlet s:vimDiffRestoreCmd
668 endif
669 " All buffers are gone.
670 unlet s:vimDiffSourceBuffer
671 unlet s:vimDiffScratchList
672 endif
673 endif
674 endif
675 endif
676 finally
677 let s:isEditFileRunning -= 1
678 endtry
679endfunction
680
681" Section: Generic VCS command functions {{{1
682
683" Function: s:VCSAnnotate(...) {{{2
684function! s:VCSAnnotate(bang, ...)
685 try
686 let annotateBuffer = s:ExecuteVCSCommand('Annotate', a:000)
687 if annotateBuffer == -1
688 return -1
689 endif
690 if a:bang == '!' && VCSCommandGetOption('VCSCommandDisableSplitAnnotate', 0) == 0
691 let vcsType = VCSCommandGetVCSType(annotateBuffer)
692 let functionMap = s:plugins[vcsType][1]
693 let splitRegex = ''
694 if has_key(s:plugins[vcsType][1], 'AnnotateSplitRegex')
695 let splitRegex = s:plugins[vcsType][1]['AnnotateSplitRegex']
696 endif
697 let splitRegex = VCSCommandGetOption('VCSCommand' . vcsType . 'AnnotateSplitRegex', splitRegex)
698 if splitRegex == ''
699 return annotateBuffer
700 endif
701 let originalBuffer = VCSCommandGetOriginalBuffer(annotateBuffer)
702 let originalFileType = getbufvar(originalBuffer, '&ft')
703 let annotateFileType = getbufvar(annotateBuffer, '&ft')
704 execute "normal 0zR\<c-v>G/" . splitRegex . "/e\<cr>d"
705 call setbufvar('%', '&filetype', getbufvar(originalBuffer, '&filetype'))
706 set scrollbind
707 leftabove vert new
708 normal 0P
709 execute "normal" . col('$') . "\<c-w>|"
710 call s:SetupScratchBuffer('annotate', vcsType, originalBuffer, 'header')
711 wincmd l
712 endif
713 return annotateBuffer
714 catch
715 call s:ReportError(v:exception)
716 return -1
717 endtry
718endfunction
719
720" Function: s:VCSCommit() {{{2
721function! s:VCSCommit(bang, message)
722 try
723 let vcsType = VCSCommandGetVCSType(bufnr('%'))
724 if !has_key(s:plugins, vcsType)
725 throw 'Unknown VCS type: ' . vcsType
726 endif
727
728 let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
729
730 " Handle the commit message being specified. If a message is supplied, it
731 " is used; if bang is supplied, an empty message is used; otherwise, the
732 " user is provided a buffer from which to edit the commit message.
733
734 if strlen(a:message) > 0 || a:bang == '!'
735 return s:VCSFinishCommit([a:message], originalBuffer)
736 endif
737
738 call s:EditFile('commitlog', originalBuffer, '')
739 setlocal ft=vcscommit
740
741 " Create a commit mapping.
742
743 nnoremap <silent> <buffer> <Plug>VCSCommit :call <SID>VCSFinishCommitWithBuffer()<CR>
744
745 silent 0put ='VCS: ----------------------------------------------------------------------'
746 silent put ='VCS: Please enter log message. Lines beginning with ''VCS:'' are removed automatically.'
747 silent put ='VCS: To finish the commit, Type <leader>cc (or your own <Plug>VCSCommit mapping)'
748
749 if VCSCommandGetOption('VCSCommandCommitOnWrite', 1) == 1
750 setlocal buftype=acwrite
751 au VCSCommandCommit BufWriteCmd <buffer> call s:VCSFinishCommitWithBuffer()
752 silent put ='VCS: or write this buffer'
753 endif
754
755 silent put ='VCS: ----------------------------------------------------------------------'
756 $
757 setlocal nomodified
758 catch
759 call s:ReportError(v:exception)
760 return -1
761 endtry
762endfunction
763
764" Function: s:VCSFinishCommitWithBuffer() {{{2
765" Wrapper for s:VCSFinishCommit which is called only from a commit log buffer
766" which removes all lines starting with 'VCS:'.
767
768function! s:VCSFinishCommitWithBuffer()
769 setlocal nomodified
770 let currentBuffer = bufnr('%')
771 let logMessageList = getbufline('%', 1, '$')
772 call filter(logMessageList, 'v:val !~ ''^\s*VCS:''')
773 let resultBuffer = s:VCSFinishCommit(logMessageList, b:VCSCommandOriginalBuffer)
774 if resultBuffer >= 0
775 execute 'bw' currentBuffer
776 endif
777 return resultBuffer
778endfunction
779
780" Function: s:VCSFinishCommit(logMessageList, originalBuffer) {{{2
781function! s:VCSFinishCommit(logMessageList, originalBuffer)
782 let shellSlashBak = &shellslash
783 try
784 set shellslash
785 let messageFileName = tempname()
786 call writefile(a:logMessageList, messageFileName)
787 try
788 let resultBuffer = s:ExecuteVCSCommand('Commit', [messageFileName])
789 if resultBuffer < 0
790 return resultBuffer
791 endif
792 return s:MarkOrigBufferForSetup(resultBuffer)
793 finally
794 call delete(messageFileName)
795 endtry
796 finally
797 let &shellslash = shellSlashBak
798 endtry
799endfunction
800
801" Function: s:VCSGotoOriginal(bang) {{{2
802function! s:VCSGotoOriginal(bang)
803 let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
804 if originalBuffer > 0
805 let origWinNR = bufwinnr(originalBuffer)
806 if origWinNR == -1
807 execute 'buffer' originalBuffer
808 else
809 execute origWinNR . 'wincmd w'
810 endif
811 if a:bang == '!'
812 let buffnr = 1
813 let buffmaxnr = bufnr('$')
814 while buffnr <= buffmaxnr
815 if getbufvar(buffnr, 'VCSCommandOriginalBuffer') == originalBuffer
816 execute 'bw' buffnr
817 endif
818 let buffnr = buffnr + 1
819 endwhile
820 endif
821 endif
822endfunction
823
824" Function: s:VCSVimDiff(...) {{{2
825function! s:VCSVimDiff(...)
826 try
827 let vcsType = VCSCommandGetVCSType(bufnr('%'))
828 if !has_key(s:plugins, vcsType)
829 throw 'Unknown VCS type: ' . vcsType
830 endif
831 let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
832 let s:isEditFileRunning = s:isEditFileRunning + 1
833 try
834 " If there's already a VimDiff'ed window, restore it.
835 " There may only be one VCSVimDiff original window at a time.
836
837 if exists('s:vimDiffSourceBuffer') && s:vimDiffSourceBuffer != originalBuffer
838 " Clear the existing vimdiff setup by removing the result buffers.
839 call s:WipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff')
840 endif
841
842 let orientation = &diffopt =~ 'horizontal' ? 'horizontal' : 'vertical'
843 let orientation = VCSCommandGetOption('VCSCommandSplit', orientation)
844 let orientation = VCSCommandGetOption('VCSCommandDiffSplit', orientation)
845
846 " Split and diff
847 if(a:0 == 2)
848 " Reset the vimdiff system, as 2 explicit versions were provided.
849 if exists('s:vimDiffSourceBuffer')
850 call s:WipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff')
851 endif
852 let resultBuffer = s:plugins[vcsType][1].Review([a:1])
853 if resultBuffer < 0
854 echomsg 'Can''t open revision ' . a:1
855 return resultBuffer
856 endif
857 let b:VCSCommandCommand = 'vimdiff'
858 diffthis
859 let s:vimDiffScratchList = [resultBuffer]
860 " If no split method is defined, cheat, and set it to vertical.
861 try
862 call s:OverrideOption('VCSCommandSplit', orientation)
863 let resultBuffer = s:plugins[vcsType][1].Review([a:2])
864 finally
865 call s:OverrideOption('VCSCommandSplit')
866 endtry
867 if resultBuffer < 0
868 echomsg 'Can''t open revision ' . a:1
869 return resultBuffer
870 endif
871 let b:VCSCommandCommand = 'vimdiff'
872 diffthis
873 let s:vimDiffScratchList += [resultBuffer]
874 else
875 " Add new buffer
876 call s:OverrideOption('VCSCommandEdit', 'split')
877 try
878 " Force splitting behavior, otherwise why use vimdiff?
879 call s:OverrideOption('VCSCommandSplit', orientation)
880 try
881 if(a:0 == 0)
882 let resultBuffer = s:plugins[vcsType][1].Review([])
883 else
884 let resultBuffer = s:plugins[vcsType][1].Review([a:1])
885 endif
886 finally
887 call s:OverrideOption('VCSCommandSplit')
888 endtry
889 finally
890 call s:OverrideOption('VCSCommandEdit')
891 endtry
892 if resultBuffer < 0
893 echomsg 'Can''t open current revision'
894 return resultBuffer
895 endif
896 let b:VCSCommandCommand = 'vimdiff'
897 diffthis
898
899 if !exists('s:vimDiffSourceBuffer')
900 " New instance of vimdiff.
901 let s:vimDiffScratchList = [resultBuffer]
902
903 " This could have been invoked on a VCS result buffer, not the
904 " original buffer.
905 wincmd W
906 execute 'buffer' originalBuffer
907 " Store info for later original buffer restore
908 let s:vimDiffRestoreCmd =
909 \ 'call setbufvar('.originalBuffer.', ''&diff'', '.getbufvar(originalBuffer, '&diff').')'
910 \ . '|call setbufvar('.originalBuffer.', ''&foldcolumn'', '.getbufvar(originalBuffer, '&foldcolumn').')'
911 \ . '|call setbufvar('.originalBuffer.', ''&foldenable'', '.getbufvar(originalBuffer, '&foldenable').')'
912 \ . '|call setbufvar('.originalBuffer.', ''&foldmethod'', '''.getbufvar(originalBuffer, '&foldmethod').''')'
913 \ . '|call setbufvar('.originalBuffer.', ''&foldlevel'', '''.getbufvar(originalBuffer, '&foldlevel').''')'
914 \ . '|call setbufvar('.originalBuffer.', ''&scrollbind'', '.getbufvar(originalBuffer, '&scrollbind').')'
915 \ . '|call setbufvar('.originalBuffer.', ''&wrap'', '.getbufvar(originalBuffer, '&wrap').')'
916 \ . '|if &foldmethod==''manual''|execute ''normal zE''|endif'
917 diffthis
918 wincmd w
919 else
920 " Adding a window to an existing vimdiff
921 let s:vimDiffScratchList += [resultBuffer]
922 endif
923 endif
924
925 let s:vimDiffSourceBuffer = originalBuffer
926
927 " Avoid executing the modeline in the current buffer after the autocommand.
928
929 let currentBuffer = bufnr('%')
930 let saveModeline = getbufvar(currentBuffer, '&modeline')
931 try
932 call setbufvar(currentBuffer, '&modeline', 0)
933 silent do VCSCommand User VCSVimDiffFinish
934 finally
935 call setbufvar(currentBuffer, '&modeline', saveModeline)
936 endtry
937 return resultBuffer
938 finally
939 let s:isEditFileRunning = s:isEditFileRunning - 1
940 endtry
941 catch
942 call s:ReportError(v:exception)
943 return -1
944 endtry
945endfunction
946
947" Section: Public functions {{{1
948
949" Function: VCSCommandGetVCSType() {{{2
950" Sets the b:VCSCommandVCSType variable in the given buffer to the
951" appropriate source control system name.
952"
953" This uses the Identify extension function to test the buffer. If the
954" Identify function returns VCSCOMMAND_IDENTIFY_EXACT, the match is considered
955" exact. If the Identify function returns VCSCOMMAND_IDENTIFY_INEXACT, the
956" match is considered inexact, and is only applied if no exact match is found.
957" Multiple inexact matches is currently considered an error.
958
959function! VCSCommandGetVCSType(buffer)
960 let vcsType = getbufvar(a:buffer, 'VCSCommandVCSType')
961 if strlen(vcsType) > 0
962 return vcsType
963 endif
964 if exists("g:VCSCommandVCSTypeOverride")
965 let fullpath = fnamemodify(bufname(a:buffer), ':p')
966 for [path, vcsType] in g:VCSCommandVCSTypeOverride
967 if match(fullpath, path) > -1
968 call setbufvar(a:buffer, 'VCSCommandVCSType', vcsType)
969 return vcsType
970 endif
971 endfor
972 endif
973 let matches = []
974 for vcsType in keys(s:plugins)
975 let identified = s:plugins[vcsType][1].Identify(a:buffer)
976 if identified
977 if identified == g:VCSCOMMAND_IDENTIFY_EXACT
978 let matches = [vcsType]
979 break
980 else
981 let matches += [vcsType]
982 endif
983 endif
984 endfor
985 if len(matches) == 1
986 call setbufvar(a:buffer, 'VCSCommandVCSType', matches[0])
987 return matches[0]
988 elseif len(matches) == 0
989 throw 'No suitable plugin'
990 else
991 throw 'Too many matching VCS: ' . join(matches)
992 endif
993endfunction
994
995" Function: VCSCommandChdir(directory) {{{2
996" Changes the current directory, respecting :lcd changes.
997
998function! VCSCommandChdir(directory)
999 let command = 'cd'
1000 if exists("*haslocaldir") && haslocaldir()
1001 let command = 'lcd'
1002 endif
1003 execute command escape(a:directory, ' ')
1004endfunction
1005
1006" Function: VCSCommandChangeToCurrentFileDir() {{{2
1007" Go to the directory in which the given file is located.
1008
1009function! VCSCommandChangeToCurrentFileDir(fileName)
1010 let oldCwd = getcwd()
1011 let newCwd = fnamemodify(resolve(a:fileName), ':p:h')
1012 if strlen(newCwd) > 0
1013 call VCSCommandChdir(newCwd)
1014 endif
1015 return oldCwd
1016endfunction
1017
1018" Function: VCSCommandGetOriginalBuffer(vcsBuffer) {{{2
1019" Attempts to locate the original file to which VCS operations were applied
1020" for a given buffer.
1021
1022function! VCSCommandGetOriginalBuffer(vcsBuffer)
1023 let origBuffer = getbufvar(a:vcsBuffer, 'VCSCommandOriginalBuffer')
1024 if origBuffer
1025 if bufexists(origBuffer)
1026 return origBuffer
1027 else
1028 " Original buffer no longer exists.
1029 throw 'Original buffer for this VCS buffer no longer exists.'
1030 endif
1031 else
1032 " No original buffer
1033 return a:vcsBuffer
1034 endif
1035endfunction
1036
1037" Function: VCSCommandRegisterModule(name, file, commandMap) {{{2
1038" Allows VCS modules to register themselves.
1039
1040function! VCSCommandRegisterModule(name, path, commandMap, mappingMap)
1041 let s:plugins[a:name] = [a:path, a:commandMap, a:mappingMap]
1042 if !empty(a:mappingMap)
1043 \ && !VCSCommandGetOption('VCSCommandDisableMappings', 0)
1044 \ && !VCSCommandGetOption('VCSCommandDisableExtensionMappings', 0)
1045 for shortcut in keys(a:mappingMap)
1046 let expansion = ":call <SID>ExecuteExtensionMapping('" . shortcut . "')<CR>"
1047 call s:CreateMapping(shortcut, expansion, a:name . " extension mapping " . shortcut)
1048 endfor
1049 endif
1050endfunction
1051
1052" Function: VCSCommandDoCommand(cmd, cmdName, statusText, [options]) {{{2
1053" General skeleton for VCS function execution. The given command is executed
1054" after appending the current buffer name (or substituting it for
1055" <VCSCOMMANDFILE>, if such a token is present). The output is captured in a
1056" new buffer.
1057"
1058" The optional 'options' Dictionary may contain the following options:
1059" allowNonZeroExit: if non-zero, if the underlying VCS command has a
1060" non-zero exit status, the command is still considered
1061" successfuly. This defaults to zero.
1062" Returns: name of the new command buffer containing the command results
1063
1064function! VCSCommandDoCommand(cmd, cmdName, statusText, options)
1065 let allowNonZeroExit = 0
1066 if has_key(a:options, 'allowNonZeroExit')
1067 let allowNonZeroExit = a:options.allowNonZeroExit
1068 endif
1069
1070 let originalBuffer = VCSCommandGetOriginalBuffer(bufnr('%'))
1071 if originalBuffer == -1
1072 throw 'Original buffer no longer exists, aborting.'
1073 endif
1074
1075 let path = resolve(bufname(originalBuffer))
1076
1077 " Work with netrw or other systems where a directory listing is displayed in
1078 " a buffer.
1079
1080 if isdirectory(path)
1081 let fileName = '.'
1082 else
1083 let fileName = fnamemodify(path, ':t')
1084 endif
1085
1086 if match(a:cmd, '<VCSCOMMANDFILE>') > 0
1087 let fullCmd = substitute(a:cmd, '<VCSCOMMANDFILE>', fileName, 'g')
1088 else
1089 let fullCmd = a:cmd . ' "' . fileName . '"'
1090 endif
1091
1092 " Change to the directory of the current buffer. This is done for CVS, but
1093 " is left in for other systems as it does not affect them negatively.
1094
1095 let oldCwd = VCSCommandChangeToCurrentFileDir(path)
1096 try
1097 let output = system(fullCmd)
1098 finally
1099 call VCSCommandChdir(oldCwd)
1100 endtry
1101
1102 " HACK: if line endings in the repository have been corrupted, the output
1103 " of the command will be confused.
1104 let output = substitute(output, "\r", '', 'g')
1105
1106 if v:shell_error && !allowNonZeroExit
1107 if strlen(output) == 0
1108 throw 'Version control command failed'
1109 else
1110 let output = substitute(output, '\n', ' ', 'g')
1111 throw 'Version control command failed: ' . output
1112 endif
1113 endif
1114
1115 if strlen(output) == 0
1116 " Handle case of no output. In this case, it is important to check the
1117 " file status, especially since cvs edit/unedit may change the attributes
1118 " of the file with no visible output.
1119
1120 checktime
1121 return 0
1122 endif
1123
1124 call s:EditFile(a:cmdName, originalBuffer, a:statusText)
1125
1126 silent 0put=output
1127
1128 " The last command left a blank line at the end of the buffer. If the
1129 " last line is folded (a side effect of the 'put') then the attempt to
1130 " remove the blank line will kill the last fold.
1131 "
1132 " This could be fixed by explicitly detecting whether the last line is
1133 " within a fold, but I prefer to simply unfold the result buffer altogether.
1134
1135 if has('folding')
1136 normal zR
1137 endif
1138
1139 $d
1140 1
1141
1142 " Define the environment and execute user-defined hooks.
1143
1144 silent do VCSCommand User VCSBufferCreated
1145 return bufnr('%')
1146endfunction
1147
1148" Function: VCSCommandGetOption(name, default) {{{2
1149" Grab a user-specified option to override the default provided. Options are
1150" searched in the window, buffer, then global spaces.
1151
1152function! VCSCommandGetOption(name, default)
1153 if has_key(s:optionOverrides, a:name) && len(s:optionOverrides[a:name]) > 0
1154 return s:optionOverrides[a:name][-1]
1155 elseif exists('w:' . a:name)
1156 return w:{a:name}
1157 elseif exists('b:' . a:name)
1158 return b:{a:name}
1159 elseif exists('g:' . a:name)
1160 return g:{a:name}
1161 else
1162 return a:default
1163 endif
1164endfunction
1165
1166" Function: VCSCommandDisableBufferSetup() {{{2
1167" Global function for deactivating the buffer autovariables.
1168
1169function! VCSCommandDisableBufferSetup()
1170 let g:VCSCommandEnableBufferSetup = 0
1171 silent! augroup! VCSCommandPlugin
1172endfunction
1173
1174" Function: VCSCommandEnableBufferSetup() {{{2
1175" Global function for activating the buffer autovariables.
1176
1177function! VCSCommandEnableBufferSetup()
1178 let g:VCSCommandEnableBufferSetup = 1
1179 augroup VCSCommandPlugin
1180 au!
1181 au BufEnter * call s:SetupBuffer()
1182 augroup END
1183
1184 " Only auto-load if the plugin is fully loaded. This gives other plugins a
1185 " chance to run.
1186 if g:loaded_VCSCommand == 2
1187 call s:SetupBuffer()
1188 endif
1189endfunction
1190
1191" Function: VCSCommandGetStatusLine() {{{2
1192" Default (sample) status line entry for VCS-controlled files. This is only
1193" useful if VCS-managed buffer mode is on (see the VCSCommandEnableBufferSetup
1194" variable for how to do this).
1195
1196function! VCSCommandGetStatusLine()
1197 if exists('b:VCSCommandCommand')
1198 " This is a result buffer. Return nothing because the buffer name
1199 " contains information already.
1200 return ''
1201 endif
1202
1203 if exists('b:VCSCommandVCSType')
1204 \ && exists('g:VCSCommandEnableBufferSetup')
1205 \ && g:VCSCommandEnableBufferSetup
1206 \ && exists('b:VCSCommandBufferInfo')
1207 return '[' . join(extend([b:VCSCommandVCSType], b:VCSCommandBufferInfo), ' ') . ']'
1208 else
1209 return ''
1210 endif
1211endfunction
1212
1213" Section: Command definitions {{{1
1214" Section: Primary commands {{{2
1215com! -nargs=* VCSAdd call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Add', [<f-args>]))
1216com! -nargs=* -bang VCSAnnotate call s:VCSAnnotate(<q-bang>, <f-args>)
1217com! -nargs=* -bang VCSBlame call s:VCSAnnotate(<q-bang>, <f-args>)
1218com! -nargs=? -bang VCSCommit call s:VCSCommit(<q-bang>, <q-args>)
1219com! -nargs=* VCSDelete call s:ExecuteVCSCommand('Delete', [<f-args>])
1220com! -nargs=* VCSDiff call s:ExecuteVCSCommand('Diff', [<f-args>])
1221com! -nargs=0 -bang VCSGotoOriginal call s:VCSGotoOriginal(<q-bang>)
1222com! -nargs=* VCSInfo call s:ExecuteVCSCommand('Info', [<f-args>])
1223com! -nargs=* VCSLock call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Lock', [<f-args>]))
1224com! -nargs=* VCSLog call s:ExecuteVCSCommand('Log', [<f-args>])
1225com! -nargs=* VCSRemove call s:ExecuteVCSCommand('Delete', [<f-args>])
1226com! -nargs=0 VCSRevert call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Revert', []))
1227com! -nargs=? VCSReview call s:ExecuteVCSCommand('Review', [<f-args>])
1228com! -nargs=* VCSStatus call s:ExecuteVCSCommand('Status', [<f-args>])
1229com! -nargs=* VCSUnlock call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Unlock', [<f-args>]))
1230com! -nargs=0 VCSUpdate call s:MarkOrigBufferForSetup(s:ExecuteVCSCommand('Update', []))
1231com! -nargs=* VCSVimDiff call s:VCSVimDiff(<f-args>)
1232
1233" Section: VCS buffer management commands {{{2
1234com! VCSCommandDisableBufferSetup call VCSCommandDisableBufferSetup()
1235com! VCSCommandEnableBufferSetup call VCSCommandEnableBufferSetup()
1236
1237" Allow reloading VCSCommand.vim
1238com! VCSReload let savedPlugins = s:plugins|let s:plugins = {}|aunmenu Plugin.VCS|unlet! g:loaded_VCSCommand|runtime plugin/vcscommand.vim|for plugin in values(savedPlugins)|execute 'source' plugin[0]|endfor|unlet savedPlugins
1239
1240" Section: Plugin command mappings {{{1
1241nnoremap <silent> <Plug>VCSAdd :VCSAdd<CR>
1242nnoremap <silent> <Plug>VCSAnnotate :VCSAnnotate<CR>
1243nnoremap <silent> <Plug>VCSCommit :VCSCommit<CR>
1244nnoremap <silent> <Plug>VCSDelete :VCSDelete<CR>
1245nnoremap <silent> <Plug>VCSDiff :VCSDiff<CR>
1246nnoremap <silent> <Plug>VCSGotoOriginal :VCSGotoOriginal<CR>
1247nnoremap <silent> <Plug>VCSClearAndGotoOriginal :VCSGotoOriginal!<CR>
1248nnoremap <silent> <Plug>VCSInfo :VCSInfo<CR>
1249nnoremap <silent> <Plug>VCSLock :VCSLock<CR>
1250nnoremap <silent> <Plug>VCSLog :VCSLog<CR>
1251nnoremap <silent> <Plug>VCSRevert :VCSRevert<CR>
1252nnoremap <silent> <Plug>VCSReview :VCSReview<CR>
1253nnoremap <silent> <Plug>VCSSplitAnnotate :VCSAnnotate!<CR>
1254nnoremap <silent> <Plug>VCSStatus :VCSStatus<CR>
1255nnoremap <silent> <Plug>VCSUnlock :VCSUnlock<CR>
1256nnoremap <silent> <Plug>VCSUpdate :VCSUpdate<CR>
1257nnoremap <silent> <Plug>VCSVimDiff :VCSVimDiff<CR>
1258
1259" Section: Default mappings {{{1
1260
1261let s:defaultMappings = [
1262 \['a', 'VCSAdd'],
1263 \['c', 'VCSCommit'],
1264 \['D', 'VCSDelete'],
1265 \['d', 'VCSDiff'],
1266 \['G', 'VCSClearAndGotoOriginal'],
1267 \['g', 'VCSGotoOriginal'],
1268 \['i', 'VCSInfo'],
1269 \['L', 'VCSLock'],
1270 \['l', 'VCSLog'],
1271 \['N', 'VCSSplitAnnotate'],
1272 \['n', 'VCSAnnotate'],
1273 \['q', 'VCSRevert'],
1274 \['r', 'VCSReview'],
1275 \['s', 'VCSStatus'],
1276 \['U', 'VCSUnlock'],
1277 \['u', 'VCSUpdate'],
1278 \['v', 'VCSVimDiff'],
1279 \]
1280
1281if !VCSCommandGetOption('VCSCommandDisableMappings', 0)
1282 for [shortcut, vcsFunction] in VCSCommandGetOption('VCSCommandMappings', s:defaultMappings)
1283 call s:CreateMapping(shortcut, '<Plug>' . vcsFunction, '''' . vcsFunction . '''')
1284 endfor
1285endif
1286
1287" Section: Menu items {{{1
1288amenu <silent> &Plugin.VCS.&Add <Plug>VCSAdd
1289amenu <silent> &Plugin.VCS.A&nnotate <Plug>VCSAnnotate
1290amenu <silent> &Plugin.VCS.&Commit <Plug>VCSCommit
1291amenu <silent> &Plugin.VCS.Delete <Plug>VCSDelete
1292amenu <silent> &Plugin.VCS.&Diff <Plug>VCSDiff
1293amenu <silent> &Plugin.VCS.&Info <Plug>VCSInfo
1294amenu <silent> &Plugin.VCS.&Log <Plug>VCSLog
1295amenu <silent> &Plugin.VCS.Revert <Plug>VCSRevert
1296amenu <silent> &Plugin.VCS.&Review <Plug>VCSReview
1297amenu <silent> &Plugin.VCS.&Status <Plug>VCSStatus
1298amenu <silent> &Plugin.VCS.&Update <Plug>VCSUpdate
1299amenu <silent> &Plugin.VCS.&VimDiff <Plug>VCSVimDiff
1300
1301" Section: Autocommands to restore vimdiff state {{{1
1302augroup VimDiffRestore
1303 au!
1304 au BufUnload * call s:VimDiffRestore(str2nr(expand('<abuf>')))
1305augroup END
1306
1307" Section: Optional activation of buffer management {{{1
1308
1309if VCSCommandGetOption('VCSCommandEnableBufferSetup', 0)
1310 call VCSCommandEnableBufferSetup()
1311endif
1312
1313" Section: VIM shutdown hook {{{1
1314
1315" Close all result buffers when VIM exits, to prevent them from being restored
1316" via viminfo.
1317
1318" Function: s:CloseAllResultBuffers() {{{2
1319" Closes all vcscommand result buffers.
1320function! s:CloseAllResultBuffers()
1321 " This avoids using bufdo as that may load buffers already loaded in another
1322 " vim process, resulting in an error.
1323 let buffnr = 1
1324 let buffmaxnr = bufnr('$')
1325 while buffnr <= buffmaxnr
1326 if getbufvar(buffnr, 'VCSCommandOriginalBuffer') != ""
1327 execute 'bw' buffnr
1328 endif
1329 let buffnr = buffnr + 1
1330 endwhile
1331endfunction
1332
1333augroup VCSCommandVIMShutdown
1334 au!
1335 au VimLeavePre * call s:CloseAllResultBuffers()
1336augroup END
1337
1338" Section: Plugin completion {{{1
1339
1340let loaded_VCSCommand = 2
1341
1342silent do VCSCommand User VCSPluginFinish
1343
1344let &cpo = s:save_cpo