~spacexplorer/+junk/myenv

« back to all changes in this revision

Viewing changes to vim/vim/plugin/vcscommand.vim

  • Committer: Kim Allamandola
  • Date: 2011-05-02 05:39:17 UTC
  • Revision ID: spacexplorer@gmail.com-20110502053917-x0yl2lr9ri4yskr2
InitĀ import

Show diffs side-by-side

added added

removed removed

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