utils 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. data/Rakefile +68 -0
  2. data/VERSION +1 -0
  3. data/bin/chroot-exec +12 -0
  4. data/bin/chroot-libs +18 -0
  5. data/bin/classify +37 -0
  6. data/bin/discover +137 -0
  7. data/bin/edit +74 -0
  8. data/bin/errf +32 -0
  9. data/bin/git-empty +8 -0
  10. data/bin/myex +90 -0
  11. data/bin/number_files +26 -0
  12. data/bin/same_files +37 -0
  13. data/bin/search +205 -0
  14. data/bin/sedit +3 -0
  15. data/bin/sshscreen +68 -0
  16. data/bin/term +21 -0
  17. data/bin/unquarantine_apps +8 -0
  18. data/bin/untest +17 -0
  19. data/bin/utils-install-config +10 -0
  20. data/bin/vacuum_firefox_sqlite +22 -0
  21. data/bin/xmp +74 -0
  22. data/lib/utils.rb +8 -0
  23. data/lib/utils/config.rb +23 -0
  24. data/lib/utils/config/gdb/asm +179 -0
  25. data/lib/utils/config/gdb/ruby +528 -0
  26. data/lib/utils/config/gdbinit +8 -0
  27. data/lib/utils/config/irbrc +455 -0
  28. data/lib/utils/config/rdebugrc +2 -0
  29. data/lib/utils/config/screenrc +143 -0
  30. data/lib/utils/config/vim/autoload/Align.vim +1029 -0
  31. data/lib/utils/config/vim/autoload/AlignMaps.vim +330 -0
  32. data/lib/utils/config/vim/autoload/rails.vim +4744 -0
  33. data/lib/utils/config/vim/autoload/rubycomplete.vim +801 -0
  34. data/lib/utils/config/vim/autoload/sqlcomplete.vim +741 -0
  35. data/lib/utils/config/vim/autoload/vimball.vim +750 -0
  36. data/lib/utils/config/vim/colors/flori.vim +113 -0
  37. data/lib/utils/config/vim/compiler/eruby.vim +40 -0
  38. data/lib/utils/config/vim/compiler/ruby.vim +67 -0
  39. data/lib/utils/config/vim/compiler/rubyunit.vim +34 -0
  40. data/lib/utils/config/vim/ftdetect/ragel.vim +2 -0
  41. data/lib/utils/config/vim/ftdetect/ruby.vim +17 -0
  42. data/lib/utils/config/vim/ftplugin/eruby.vim +100 -0
  43. data/lib/utils/config/vim/ftplugin/ruby.vim +260 -0
  44. data/lib/utils/config/vim/ftplugin/xml.vim +941 -0
  45. data/lib/utils/config/vim/indent/IndentAnything_html.vim +35 -0
  46. data/lib/utils/config/vim/indent/eruby.vim +77 -0
  47. data/lib/utils/config/vim/indent/javascript.vim +116 -0
  48. data/lib/utils/config/vim/indent/ruby.vim +377 -0
  49. data/lib/utils/config/vim/plugin/AlignMapsPlugin.vim +242 -0
  50. data/lib/utils/config/vim/plugin/AlignPlugin.vim +41 -0
  51. data/lib/utils/config/vim/plugin/Decho.vim +592 -0
  52. data/lib/utils/config/vim/plugin/IndentAnything.vim +675 -0
  53. data/lib/utils/config/vim/plugin/bufexplorer.vim +1144 -0
  54. data/lib/utils/config/vim/plugin/cecutil.vim +482 -0
  55. data/lib/utils/config/vim/plugin/fugitive.vim +1703 -0
  56. data/lib/utils/config/vim/plugin/lusty-explorer.vim +1509 -0
  57. data/lib/utils/config/vim/plugin/rails.vim +340 -0
  58. data/lib/utils/config/vim/plugin/rubyextra.vim +193 -0
  59. data/lib/utils/config/vim/plugin/surround.vim +628 -0
  60. data/lib/utils/config/vim/plugin/taglist.vim +4546 -0
  61. data/lib/utils/config/vim/plugin/test/IndentAnything/test.js +131 -0
  62. data/lib/utils/config/vim/plugin/vimballPlugin.vim +40 -0
  63. data/lib/utils/config/vim/syntax/Decho.vim +101 -0
  64. data/lib/utils/config/vim/syntax/eruby.vim +73 -0
  65. data/lib/utils/config/vim/syntax/javascript.vim +246 -0
  66. data/lib/utils/config/vim/syntax/ragel.vim +165 -0
  67. data/lib/utils/config/vim/syntax/ruby.vim +367 -0
  68. data/lib/utils/config/vimrc +461 -0
  69. data/lib/utils/file.rb +49 -0
  70. data/lib/utils/find.rb +54 -0
  71. data/lib/utils/md5.rb +23 -0
  72. data/lib/utils/patterns.rb +34 -0
  73. data/lib/utils/version.rb +8 -0
  74. data/utils.gemspec +33 -0
  75. metadata +183 -0
@@ -0,0 +1,1703 @@
1
+ " fugitive.vim - A Git wrapper so awesome, it should be illegal
2
+ " Maintainer: Tim Pope <vimNOSPAM@tpope.org>
3
+ " Version: 1.1
4
+ " GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim
5
+
6
+ if exists('g:loaded_fugitive') || &cp
7
+ finish
8
+ endif
9
+ let g:loaded_fugitive = 1
10
+
11
+ if !exists('g:fugitive_git_executable')
12
+ let g:fugitive_git_executable = 'git'
13
+ endif
14
+
15
+ " Utility {{{1
16
+
17
+ function! s:function(name) abort
18
+ return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
19
+ endfunction
20
+
21
+ function! s:sub(str,pat,rep) abort
22
+ return substitute(a:str,'\v\C'.a:pat,a:rep,'')
23
+ endfunction
24
+
25
+ function! s:gsub(str,pat,rep) abort
26
+ return substitute(a:str,'\v\C'.a:pat,a:rep,'g')
27
+ endfunction
28
+
29
+ function! s:shellesc(arg) abort
30
+ if a:arg =~ '^[A-Za-z0-9_/.-]\+$'
31
+ return a:arg
32
+ elseif &shell =~# 'cmd' && a:arg !~# '"'
33
+ return '"'.a:arg.'"'
34
+ else
35
+ return shellescape(a:arg)
36
+ endif
37
+ endfunction
38
+
39
+ function! s:fnameescape(file) abort
40
+ if exists('*fnameescape')
41
+ return fnameescape(a:file)
42
+ else
43
+ return escape(a:file," \t\n*?[{`$\\%#'\"|!<")
44
+ endif
45
+ endfunction
46
+
47
+ function! s:throw(string) abort
48
+ let v:errmsg = 'fugitive: '.a:string
49
+ throw v:errmsg
50
+ endfunction
51
+
52
+ function! s:warn(str)
53
+ echohl WarningMsg
54
+ echomsg a:str
55
+ echohl None
56
+ let v:warningmsg = a:str
57
+ endfunction
58
+
59
+ function! s:shellslash(path)
60
+ if exists('+shellslash') && !&shellslash
61
+ return s:gsub(a:path,'\\','/')
62
+ else
63
+ return a:path
64
+ endif
65
+ endfunction
66
+
67
+ function! s:add_methods(namespace, method_names) abort
68
+ for name in a:method_names
69
+ let s:{a:namespace}_prototype[name] = s:function('s:'.a:namespace.'_'.name)
70
+ endfor
71
+ endfunction
72
+
73
+ let s:commands = []
74
+ function! s:command(definition) abort
75
+ let s:commands += [a:definition]
76
+ endfunction
77
+
78
+ function! s:define_commands()
79
+ for command in s:commands
80
+ exe 'command! -buffer '.command
81
+ endfor
82
+ endfunction
83
+
84
+ function! s:compatibility_check()
85
+ if exists('b:git_dir') && exists('*GitBranchInfoCheckGitDir') && !exists('g:fugitive_did_compatibility_warning')
86
+ let g:fugitive_did_compatibility_warning = 1
87
+ call s:warn("See http://github.com/tpope/vim-fugitive/issues#issue/1 for why you should remove git-branch-info.vim")
88
+ endif
89
+ endfunction
90
+
91
+ augroup fugitive_utility
92
+ autocmd!
93
+ autocmd User Fugitive call s:define_commands()
94
+ autocmd VimEnter * call s:compatibility_check()
95
+ augroup END
96
+
97
+ let s:abstract_prototype = {}
98
+
99
+ " }}}1
100
+ " Initialization {{{1
101
+
102
+ function! s:ExtractGitDir(path) abort
103
+ let path = s:shellslash(a:path)
104
+ if path =~? '^fugitive://.*//'
105
+ return matchstr(path,'fugitive://\zs.\{-\}\ze//')
106
+ endif
107
+ let fn = fnamemodify(path,':s?[\/]$??')
108
+ let ofn = ""
109
+ let nfn = fn
110
+ while fn != ofn
111
+ if isdirectory(fn . '/.git')
112
+ return s:sub(simplify(fnamemodify(fn . '/.git',':p')),'\W$','')
113
+ elseif fn =~ '\.git$' && filereadable(fn . '/HEAD')
114
+ return s:sub(simplify(fnamemodify(fn,':p')),'\W$','')
115
+ endif
116
+ let ofn = fn
117
+ let fn = fnamemodify(ofn,':h')
118
+ endwhile
119
+ return ''
120
+ endfunction
121
+
122
+ function! s:Detect(path)
123
+ if exists('b:git_dir') && b:git_dir ==# ''
124
+ unlet b:git_dir
125
+ endif
126
+ if !exists('b:git_dir')
127
+ let dir = s:ExtractGitDir(a:path)
128
+ if dir != ''
129
+ let b:git_dir = dir
130
+ endif
131
+ endif
132
+ if exists('b:git_dir')
133
+ silent doautocmd User Fugitive
134
+ cnoremap <expr> <buffer> <C-R><C-G> fugitive#buffer().rev()
135
+ if expand('%:p') =~# '//'
136
+ let buffer = fugitive#buffer()
137
+ call buffer.setvar('&path',s:sub(buffer.getvar('&path'),'^\.%(,|$)',''))
138
+ endif
139
+ endif
140
+ endfunction
141
+
142
+ augroup fugitive
143
+ autocmd!
144
+ autocmd BufNewFile,BufReadPost * call s:Detect(expand('<amatch>:p'))
145
+ autocmd FileType netrw call s:Detect(expand('<amatch>:p'))
146
+ autocmd VimEnter * if expand('<amatch>')==''|call s:Detect(getcwd())|endif
147
+ autocmd BufWinLeave * execute getbufvar(+expand('<abuf>'), 'fugitive_restore')
148
+ augroup END
149
+
150
+ " }}}1
151
+ " Repository {{{1
152
+
153
+ let s:repo_prototype = {}
154
+ let s:repos = {}
155
+
156
+ function! s:repo(...) abort
157
+ let dir = a:0 ? a:1 : (exists('b:git_dir') && b:git_dir !=# '' ? b:git_dir : s:ExtractGitDir(expand('%:p')))
158
+ if dir !=# ''
159
+ if has_key(s:repos,dir)
160
+ let repo = get(s:repos,dir)
161
+ else
162
+ let repo = {'git_dir': dir}
163
+ let s:repos[dir] = repo
164
+ endif
165
+ return extend(extend(repo,s:repo_prototype,'keep'),s:abstract_prototype,'keep')
166
+ endif
167
+ call s:throw('not a git repository: '.expand('%:p'))
168
+ endfunction
169
+
170
+ function! s:repo_dir(...) dict abort
171
+ return join([self.git_dir]+a:000,'/')
172
+ endfunction
173
+
174
+ function! s:repo_tree(...) dict abort
175
+ if !self.bare()
176
+ let dir = fnamemodify(self.git_dir,':h')
177
+ return join([dir]+a:000,'/')
178
+ endif
179
+ call s:throw('no work tree')
180
+ endfunction
181
+
182
+ function! s:repo_bare() dict abort
183
+ return self.dir() !~# '/\.git$'
184
+ endfunction
185
+
186
+ function! s:repo_translate(spec) dict abort
187
+ if a:spec ==# '.' || a:spec ==# '/.'
188
+ return self.bare() ? self.dir() : self.tree()
189
+ elseif a:spec =~# '^/'
190
+ return fnamemodify(self.dir(),':h').a:spec
191
+ elseif a:spec =~# '^:[0-3]:'
192
+ return 'fugitive://'.self.dir().'//'.a:spec[1].'/'.a:spec[3:-1]
193
+ elseif a:spec ==# ':'
194
+ if $GIT_INDEX_FILE =~# '/[^/]*index[^/]*\.lock$' && fnamemodify($GIT_INDEX_FILE,':p')[0:strlen(s:repo().dir())] ==# s:repo().dir('') && filereadable($GIT_INDEX_FILE)
195
+ return fnamemodify($GIT_INDEX_FILE,':p')
196
+ else
197
+ return self.dir('index')
198
+ endif
199
+ elseif a:spec =~# '^:/'
200
+ let ref = self.rev_parse(matchstr(a:spec,'.[^:]*'))
201
+ return 'fugitive://'.self.dir().'//'.ref
202
+ elseif a:spec =~# '^:'
203
+ return 'fugitive://'.self.dir().'//0/'.a:spec[1:-1]
204
+ elseif a:spec =~# 'HEAD\|^refs/' && a:spec !~ ':' && filereadable(self.dir(a:spec))
205
+ return self.dir(a:spec)
206
+ elseif filereadable(s:repo().dir('refs/'.a:spec))
207
+ return self.dir('refs/'.a:spec)
208
+ elseif filereadable(s:repo().dir('refs/tags/'.a:spec))
209
+ return self.dir('refs/tags/'.a:spec)
210
+ elseif filereadable(s:repo().dir('refs/heads/'.a:spec))
211
+ return self.dir('refs/heads/'.a:spec)
212
+ elseif filereadable(s:repo().dir('refs/remotes/'.a:spec))
213
+ return self.dir('refs/remotes/'.a:spec)
214
+ elseif filereadable(s:repo().dir('refs/remotes/'.a:spec.'/HEAD'))
215
+ return self.dir('refs/remotes/'.a:spec,'/HEAD')
216
+ else
217
+ try
218
+ let ref = self.rev_parse(matchstr(a:spec,'[^:]*'))
219
+ let path = s:sub(matchstr(a:spec,':.*'),'^:','/')
220
+ return 'fugitive://'.self.dir().'//'.ref.path
221
+ catch /^fugitive:/
222
+ return self.tree(a:spec)
223
+ endtry
224
+ endif
225
+ endfunction
226
+
227
+ call s:add_methods('repo',['dir','tree','bare','translate'])
228
+
229
+ function! s:repo_git_command(...) dict abort
230
+ let git = g:fugitive_git_executable . ' --git-dir='.s:shellesc(self.git_dir)
231
+ return git.join(map(copy(a:000),'" ".s:shellesc(v:val)'),'')
232
+ endfunction
233
+
234
+ function! s:repo_git_chomp(...) dict abort
235
+ return s:sub(system(call(self.git_command,a:000,self)),'\n$','')
236
+ endfunction
237
+
238
+ function! s:repo_git_chomp_in_tree(...) dict abort
239
+ let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
240
+ let dir = getcwd()
241
+ try
242
+ execute cd.'`=s:repo().tree()`'
243
+ return call(s:repo().git_chomp, a:000, s:repo())
244
+ finally
245
+ execute cd.'`=dir`'
246
+ endtry
247
+ endfunction
248
+
249
+ function! s:repo_rev_parse(rev) dict abort
250
+ let hash = self.git_chomp('rev-parse','--verify',a:rev)
251
+ if hash =~ '^\x\{40\}$'
252
+ return hash
253
+ endif
254
+ call s:throw('rev-parse '.a:rev.': '.hash)
255
+ endfunction
256
+
257
+ call s:add_methods('repo',['git_command','git_chomp','git_chomp_in_tree','rev_parse'])
258
+
259
+ function! s:repo_dirglob(base) dict abort
260
+ let base = s:sub(a:base,'^/','')
261
+ let matches = split(glob(self.tree(s:gsub(base,'/','*&').'*/')),"\n")
262
+ call map(matches,'v:val[ strlen(self.tree())+(a:base !~ "^/") : -1 ]')
263
+ return matches
264
+ endfunction
265
+
266
+ function! s:repo_superglob(base) dict abort
267
+ if a:base =~# '^/' || a:base !~# ':'
268
+ let results = []
269
+ if a:base !~# '^/'
270
+ let heads = ["HEAD","ORIG_HEAD","FETCH_HEAD","MERGE_HEAD"]
271
+ let heads += sort(split(s:repo().git_chomp("rev-parse","--symbolic","--branches","--tags","--remotes"),"\n"))
272
+ call filter(heads,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base')
273
+ let results += heads
274
+ endif
275
+ if !self.bare()
276
+ let base = s:sub(a:base,'^/','')
277
+ let matches = split(glob(self.tree(s:gsub(base,'/','*&').'*')),"\n")
278
+ call map(matches,'s:shellslash(v:val)')
279
+ call map(matches,'v:val !~ "/$" && isdirectory(v:val) ? v:val."/" : v:val')
280
+ call map(matches,'v:val[ strlen(self.tree())+(a:base !~ "^/") : -1 ]')
281
+ let results += matches
282
+ endif
283
+ return results
284
+
285
+ elseif a:base =~# '^:'
286
+ let entries = split(self.git_chomp('ls-files','--stage'),"\n")
287
+ call map(entries,'s:sub(v:val,".*(\\d)\\t(.*)",":\\1:\\2")')
288
+ if a:base !~# '^:[0-3]\%(:\|$\)'
289
+ call filter(entries,'v:val[1] == "0"')
290
+ call map(entries,'v:val[2:-1]')
291
+ endif
292
+ call filter(entries,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base')
293
+ return entries
294
+
295
+ else
296
+ let tree = matchstr(a:base,'.*[:/]')
297
+ let entries = split(self.git_chomp('ls-tree',tree),"\n")
298
+ call map(entries,'s:sub(v:val,"^04.*\\zs$","/")')
299
+ call map(entries,'tree.s:sub(v:val,".*\t","")')
300
+ return filter(entries,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base')
301
+ endif
302
+ endfunction
303
+
304
+ call s:add_methods('repo',['dirglob','superglob'])
305
+
306
+ function! s:repo_keywordprg() dict abort
307
+ let args = ' --git-dir='.escape(self.dir(),"\\\"' ").' show'
308
+ if has('gui_running') && !has('win32')
309
+ return g:fugitive_git_executable . ' --no-pager' . args
310
+ else
311
+ return g:fugitive_git_executable . args
312
+ endif
313
+ endfunction
314
+
315
+ call s:add_methods('repo',['keywordprg'])
316
+
317
+ " }}}1
318
+ " Buffer {{{1
319
+
320
+ let s:buffer_prototype = {}
321
+
322
+ function! s:buffer(...) abort
323
+ let buffer = {'#': bufnr(a:0 ? a:1 : '%')}
324
+ call extend(extend(buffer,s:buffer_prototype,'keep'),s:abstract_prototype,'keep')
325
+ if buffer.getvar('git_dir') !=# ''
326
+ return buffer
327
+ endif
328
+ call s:throw('not a git repository: '.expand('%:p'))
329
+ endfunction
330
+
331
+ function! fugitive#buffer(...) abort
332
+ return s:buffer(a:0 ? a:1 : '%')
333
+ endfunction
334
+
335
+ function! s:buffer_getvar(var) dict abort
336
+ return getbufvar(self['#'],a:var)
337
+ endfunction
338
+
339
+ function! s:buffer_setvar(var,value) dict abort
340
+ return setbufvar(self['#'],a:var,a:value)
341
+ endfunction
342
+
343
+ function! s:buffer_getline(lnum) dict abort
344
+ return getbufline(self['#'],a:lnum)[0]
345
+ endfunction
346
+
347
+ function! s:buffer_repo() dict abort
348
+ return s:repo(self.getvar('git_dir'))
349
+ endfunction
350
+
351
+ function! s:buffer_type(...) dict abort
352
+ if self.getvar('fugitive_type') != ''
353
+ let type = self.getvar('fugitive_type')
354
+ elseif fnamemodify(self.name(),':p') =~# '.\git/refs/\|\.git/\w*HEAD$'
355
+ let type = 'head'
356
+ elseif self.getline(1) =~ '^tree \x\{40\}$' && self.getline(2) == ''
357
+ let type = 'tree'
358
+ elseif self.getline(1) =~ '^\d\{6\} \w\{4\} \x\{40\}\>\t'
359
+ let type = 'tree'
360
+ elseif self.getline(1) =~ '^\d\{6\} \x\{40\}\> \d\t'
361
+ let type = 'index'
362
+ elseif isdirectory(self.name())
363
+ let type = 'directory'
364
+ elseif self.name() == ''
365
+ let type = 'null'
366
+ elseif filereadable(self.name())
367
+ let type = 'file'
368
+ else
369
+ let type = ''
370
+ endif
371
+ if a:0
372
+ return !empty(filter(copy(a:000),'v:val ==# type'))
373
+ else
374
+ return type
375
+ endif
376
+ endfunction
377
+
378
+ function! s:buffer_name() dict abort
379
+ let bufname = bufname(self['#'])
380
+ return s:shellslash(bufname == '' ? '' : fnamemodify(bufname,':p'))
381
+ endfunction
382
+
383
+ function! s:buffer_commit() dict abort
384
+ return matchstr(self.name(),'^fugitive://.\{-\}//\zs\w*')
385
+ endfunction
386
+
387
+ function! s:buffer_path(...) dict abort
388
+ let rev = matchstr(self.name(),'^fugitive://.\{-\}//\zs.*')
389
+ if rev != ''
390
+ let rev = s:sub(rev,'\w*','')
391
+ else
392
+ let rev = self.name()[strlen(self.repo().tree()) : -1]
393
+ endif
394
+ return s:sub(rev,'^/',a:0 ? a:1 : '')
395
+ endfunction
396
+
397
+ function! s:buffer_rev() dict abort
398
+ let rev = matchstr(self.name(),'^fugitive://.\{-\}//\zs.*')
399
+ if rev =~ '^\x/'
400
+ return ':'.rev[0].':'.rev[2:-1]
401
+ elseif rev =~ '.'
402
+ return s:sub(rev,'/',':')
403
+ elseif self.name() =~ '\.git/index$'
404
+ return ':'
405
+ elseif self.name() =~ '\.git/refs/\|\.git/.*HEAD$'
406
+ return self.name()[strlen(self.repo().dir())+1 : -1]
407
+ else
408
+ return self.path()
409
+ endif
410
+ endfunction
411
+
412
+ function! s:buffer_sha1() dict abort
413
+ if self.name() =~ '^fugitive://' || self.name() =~ '\.git/refs/\|\.git/.*HEAD$'
414
+ return self.repo().rev_parse(self.rev())
415
+ else
416
+ return ''
417
+ endif
418
+ endfunction
419
+
420
+ function! s:buffer_expand(rev) dict abort
421
+ if a:rev =~# '^:[0-3]$'
422
+ let file = a:rev.self.path(':')
423
+ elseif a:rev =~# '^-'
424
+ let file = 'HEAD^{}'.a:rev[1:-1].self.path(':')
425
+ elseif a:rev =~# '^@{'
426
+ let file = 'HEAD'.a:rev.self.path(':')
427
+ elseif a:rev =~# '^[~^]'
428
+ let commit = s:sub(self.commit(),'^\d=$','HEAD')
429
+ let file = commit.a:rev.self.path(':')
430
+ else
431
+ let file = a:rev
432
+ endif
433
+ return s:sub(file,'\%$',self.path())
434
+ endfunction
435
+
436
+ function! s:buffer_containing_commit() dict abort
437
+ if self.commit() =~# '^\d$'
438
+ return ':'
439
+ elseif self.commit() =~# '.'
440
+ return self.commit()
441
+ else
442
+ return 'HEAD'
443
+ endif
444
+ endfunction
445
+
446
+ call s:add_methods('buffer',['getvar','setvar','getline','repo','type','name','commit','path','rev','sha1','expand','containing_commit'])
447
+
448
+ " }}}1
449
+ " Git {{{1
450
+
451
+ call s:command("-bang -nargs=? -complete=customlist,s:GitComplete Git :execute s:Git(<bang>0,<q-args>)")
452
+
453
+ function! s:ExecuteInTree(cmd) abort
454
+ let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
455
+ let dir = getcwd()
456
+ try
457
+ execute cd.'`=s:repo().tree()`'
458
+ execute a:cmd
459
+ finally
460
+ execute cd.'`=dir`'
461
+ endtry
462
+ endfunction
463
+
464
+ function! s:Git(bang,cmd) abort
465
+ let git = s:repo().git_command()
466
+ if has('gui_running') && !has('win32')
467
+ let git .= ' --no-pager'
468
+ endif
469
+ let cmd = matchstr(a:cmd,'\v\C.{-}%($|\\@<!%(\\\\)*\|)@=')
470
+ call s:ExecuteInTree('!'.git.' '.cmd)
471
+ call fugitive#reload_status()
472
+ return matchstr(a:cmd,'\v\C\\@<!%(\\\\)*\|\zs.*')
473
+ endfunction
474
+
475
+ function! s:GitComplete(A,L,P) abort
476
+ if !exists('s:exec_path')
477
+ let s:exec_path = s:sub(system(g:fugitive_git_executable.' --exec-path'),'\n$','')
478
+ endif
479
+ let cmds = map(split(glob(s:exec_path.'/git-*'),"\n"),'s:sub(v:val[strlen(s:exec_path)+5 : -1],"\\.exe$","")')
480
+ if a:L =~ ' [[:alnum:]-]\+ '
481
+ return s:repo().superglob(a:A)
482
+ elseif a:A == ''
483
+ return cmds
484
+ else
485
+ return filter(cmds,'v:val[0 : strlen(a:A)-1] ==# a:A')
486
+ endif
487
+ endfunction
488
+
489
+ " }}}1
490
+ " Gcd, Glcd {{{1
491
+
492
+ function! s:DirComplete(A,L,P) abort
493
+ let matches = s:repo().dirglob(a:A)
494
+ return matches
495
+ endfunction
496
+
497
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Gcd :cd<bang> `=s:repo().bare() ? s:repo().dir(<q-args>) : s:repo().tree(<q-args>)`")
498
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Glcd :lcd<bang> `=s:repo().bare() ? s:repo().dir(<q-args>) : s:repo().tree(<q-args>)`")
499
+
500
+ " }}}1
501
+ " Gstatus {{{1
502
+
503
+ call s:command("-bar Gstatus :execute s:Status()")
504
+
505
+ function! s:Status() abort
506
+ try
507
+ Gpedit :
508
+ wincmd P
509
+ nnoremap <buffer> <silent> q :<C-U>bdelete<CR>
510
+ catch /^fugitive:/
511
+ return 'echoerr v:errmsg'
512
+ endtry
513
+ return ''
514
+ endfunction
515
+
516
+ function! fugitive#reload_status() abort
517
+ let mytab = tabpagenr()
518
+ for tab in [mytab] + range(1,tabpagenr('$'))
519
+ for winnr in range(1,tabpagewinnr(tab,'$'))
520
+ if getbufvar(tabpagebuflist(tab)[winnr-1],'fugitive_type') ==# 'index'
521
+ execute 'tabnext '.tab
522
+ if winnr != winnr()
523
+ execute winnr.'wincmd w'
524
+ let restorewinnr = 1
525
+ endif
526
+ try
527
+ if !&modified
528
+ call s:BufReadIndex()
529
+ endif
530
+ finally
531
+ if exists('restorewinnr')
532
+ wincmd p
533
+ endif
534
+ execute 'tabnext '.mytab
535
+ endtry
536
+ endif
537
+ endfor
538
+ endfor
539
+ endfunction
540
+
541
+ function! s:StageDiff() abort
542
+ let section = getline(search('^# .*:$','bnW'))
543
+ let line = getline('.')
544
+ let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*')
545
+ if filename ==# '' && section == '# Changes to be committed:'
546
+ return 'Git diff --cached'
547
+ elseif filename ==# ''
548
+ return 'Git diff'
549
+ elseif line =~# '^#\trenamed:' && filename =~ ' -> '
550
+ let [old, new] = split(filename,' -> ')
551
+ execute 'Gedit '.s:fnameescape(':0:'.new)
552
+ return 'Gdiff HEAD:'.s:fnameescape(old)
553
+ elseif section == '# Changes to be committed:'
554
+ execute 'Gedit '.s:fnameescape(':0:'.filename)
555
+ return 'Gdiff -'
556
+ else
557
+ execute 'Gedit '.s:fnameescape('/'.filename)
558
+ return 'Gdiff'
559
+ endif
560
+ endfunction
561
+
562
+ function! s:StageToggle(lnum1,lnum2) abort
563
+ try
564
+ let output = ''
565
+ for lnum in range(a:lnum1,a:lnum2)
566
+ let line = getline(lnum)
567
+ if getline('.') == '# Changes to be committed:'
568
+ return 'Gcommit'
569
+ endif
570
+ let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*')
571
+ if filename ==# ''
572
+ continue
573
+ endif
574
+ if !exists('first_filename')
575
+ let first_filename = filename
576
+ endif
577
+ execute lnum
578
+ let section = getline(search('^# .*:$','bnW'))
579
+ if line =~# '^#\trenamed:' && filename =~ ' -> '
580
+ let cmd = ['mv','--'] + reverse(split(filename,' -> '))
581
+ let filename = cmd[-1]
582
+ elseif section =~? ' to be '
583
+ let cmd = ['reset','-q','--',filename]
584
+ elseif line =~# '^#\tdeleted:'
585
+ let cmd = ['rm','--',filename]
586
+ else
587
+ let cmd = ['add','--',filename]
588
+ endif
589
+ let output .= call(s:repo().git_chomp_in_tree,cmd,s:repo())."\n"
590
+ endfor
591
+ if exists('first_filename')
592
+ let jump = first_filename
593
+ let f = matchstr(getline(a:lnum1-1),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*')
594
+ if f !=# '' | let jump = f | endif
595
+ let f = matchstr(getline(a:lnum2+1),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*')
596
+ if f !=# '' | let jump = f | endif
597
+ silent! edit!
598
+ 1
599
+ redraw
600
+ call search('^#\t\%([[:alpha:] ]\+: *\)\=\V'.jump.'\$','W')
601
+ endif
602
+ echo s:sub(s:gsub(output,'\n+','\n'),'\n$','')
603
+ catch /^fugitive:/
604
+ return 'echoerr v:errmsg'
605
+ endtry
606
+ return 'checktime'
607
+ endfunction
608
+
609
+ function! s:StagePatch(lnum1,lnum2) abort
610
+ let add = []
611
+ let reset = []
612
+
613
+ for lnum in range(a:lnum1,a:lnum2)
614
+ let line = getline(lnum)
615
+ if line == '# Changes to be committed:'
616
+ return 'Git reset --patch'
617
+ elseif line == '# Changed but not updated:'
618
+ return 'Git add --patch'
619
+ endif
620
+ let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*')
621
+ if filename ==# ''
622
+ continue
623
+ endif
624
+ if !exists('first_filename')
625
+ let first_filename = filename
626
+ endif
627
+ execute lnum
628
+ let section = getline(search('^# .*:$','bnW'))
629
+ if line =~# '^#\trenamed:' && filename =~ ' -> '
630
+ let reset += [split(filename,' -> ')[1]]
631
+ elseif section =~? ' to be '
632
+ let reset += [filename]
633
+ elseif line !~# '^#\tdeleted:'
634
+ let add += [filename]
635
+ endif
636
+ endfor
637
+ try
638
+ if !empty(add)
639
+ execute "Git add --patch -- ".join(map(add,'s:shellesc(v:val)'))
640
+ endif
641
+ if !empty(reset)
642
+ execute "Git reset --patch -- ".join(map(add,'s:shellesc(v:val)'))
643
+ endif
644
+ if exists('first_filename')
645
+ silent! edit!
646
+ 1
647
+ redraw
648
+ call search('^#\t\%([[:alpha:] ]\+: *\)\=\V'.first_filename.'\$','W')
649
+ endif
650
+ catch /^fugitive:/
651
+ return 'echoerr v:errmsg'
652
+ endtry
653
+ return 'checktime'
654
+ endfunction
655
+
656
+ " }}}1
657
+ " Gcommit {{{1
658
+
659
+ call s:command("-nargs=? -complete=customlist,s:CommitComplete Gcommit :execute s:Commit(<q-args>)")
660
+
661
+ function! s:Commit(args) abort
662
+ let old_type = s:buffer().type()
663
+ let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
664
+ let dir = getcwd()
665
+ let msgfile = s:repo().dir('COMMIT_EDITMSG')
666
+ let outfile = tempname()
667
+ let errorfile = tempname()
668
+ try
669
+ execute cd.'`=s:repo().tree()`'
670
+ let command = ''
671
+ if &shell =~# 'cmd'
672
+ let old_editor = $GIT_EDITOR
673
+ let $GIT_EDITOR = 'false'
674
+ elseif &shell !~# 'csh'
675
+ let command = 'GIT_EDITOR=false '
676
+ endif
677
+ let command .= s:repo().git_command('commit').' '.a:args
678
+ if &shell =~# 'csh'
679
+ silent execute '!setenv GIT_EDITOR false; ('.command.' > '.outfile.') >& '.errorfile
680
+ elseif a:args =~# '\%(^\| \)--interactive\>'
681
+ execute '!'.command.' 2> '.errorfile
682
+ else
683
+ silent execute '!'.command.' > '.outfile.' 2> '.errorfile
684
+ endif
685
+ if !v:shell_error
686
+ if filereadable(outfile)
687
+ for line in readfile(outfile)
688
+ echo line
689
+ endfor
690
+ endif
691
+ return ''
692
+ else
693
+ let error = get(readfile(errorfile,'',1),0,'!')
694
+ if error =~# "'false'\\.$"
695
+ let args = a:args
696
+ let args = s:gsub(args,'%(%(^| )-- )@<!%(^| )@<=%(-[se]|--edit|--interactive)%($| )','')
697
+ let args = s:gsub(args,'%(%(^| )-- )@<!%(^| )@<=%(-F|--file|-m|--message)%(\s+|\=)%(''[^'']*''|"%(\\.|[^"])*"|\\.|\S)*','')
698
+ let args = s:gsub(args,'%(^| )@<=[%#]%(:\w)*','\=expand(submatch(0))')
699
+ let args = '-F '.s:shellesc(msgfile).' '.args
700
+ if args !~# '\%(^\| \)--cleanup\>'
701
+ let args = '--cleanup=strip '.args
702
+ endif
703
+ if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod
704
+ edit `=msgfile`
705
+ else
706
+ split `=msgfile`
707
+ endif
708
+ if old_type ==# 'index'
709
+ bdelete #
710
+ endif
711
+ let b:fugitive_commit_arguments = args
712
+ setlocal bufhidden=delete filetype=gitcommit
713
+ return '1'
714
+ elseif error ==# '!'
715
+ return s:Status()
716
+ else
717
+ call s:throw(error)
718
+ endif
719
+ endif
720
+ catch /^fugitive:/
721
+ return 'echoerr v:errmsg'
722
+ finally
723
+ if exists('old_editor')
724
+ let $GIT_EDITOR = old_editor
725
+ endif
726
+ call delete(outfile)
727
+ call delete(errorfile)
728
+ execute cd.'`=dir`'
729
+ call fugitive#reload_status()
730
+ endtry
731
+ endfunction
732
+
733
+ function! s:CommitComplete(A,L,P) abort
734
+ if a:A =~ '^-' || type(a:A) == type(0) " a:A is 0 on :Gcommit -<Tab>
735
+ let args = ['-C', '-F', '-a', '-c', '-e', '-i', '-m', '-n', '-o', '-q', '-s', '-t', '-u', '-v', '--all', '--allow-empty', '--amend', '--author=', '--cleanup=', '--dry-run', '--edit', '--file=', '--include', '--interactive', '--message=', '--no-verify', '--only', '--quiet', '--reedit-message=', '--reuse-message=', '--signoff', '--template=', '--untracked-files', '--verbose']
736
+ return filter(args,'v:val[0 : strlen(a:A)-1] ==# a:A')
737
+ else
738
+ return s:repo().superglob(a:A)
739
+ endif
740
+ endfunction
741
+
742
+ function! s:FinishCommit()
743
+ let args = getbufvar(+expand('<abuf>'),'fugitive_commit_arguments')
744
+ let g:args = args
745
+ if !empty(args)
746
+ call setbufvar(+expand('<abuf>'),'fugitive_commit_arguments','')
747
+ return s:Commit(args)
748
+ endif
749
+ return ''
750
+ endfunction
751
+
752
+ augroup fugitive_commit
753
+ autocmd!
754
+ autocmd VimLeavePre,BufDelete *.git/COMMIT_EDITMSG execute s:sub(s:FinishCommit(), '^echoerr (.*)', 'echohl ErrorMsg|echo \1|echohl NONE')
755
+ augroup END
756
+
757
+ " }}}1
758
+ " Ggrep, Glog {{{1
759
+
760
+ if !exists('g:fugitive_summary_format')
761
+ let g:fugitive_summary_format = '%s'
762
+ endif
763
+
764
+ call s:command("-bang -nargs=? -complete=customlist,s:EditComplete Ggrep :execute s:Grep(<bang>0,<q-args>)")
765
+ call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Glog :execute s:Log('grep<bang>',<f-args>)")
766
+
767
+ function! s:Grep(bang,arg) abort
768
+ let grepprg = &grepprg
769
+ let grepformat = &grepformat
770
+ let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
771
+ let dir = getcwd()
772
+ try
773
+ execute cd.'`=s:repo().tree()`'
774
+ let &grepprg = s:repo().git_command('--no-pager', 'grep', '-n')
775
+ let &grepformat = '%f:%l:%m'
776
+ exe 'grep! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|')
777
+ let list = getqflist()
778
+ for entry in list
779
+ if bufname(entry.bufnr) =~ ':'
780
+ let entry.filename = s:repo().translate(bufname(entry.bufnr))
781
+ unlet! entry.bufnr
782
+ elseif a:arg =~# '\%(^\| \)--cached\>'
783
+ let entry.filename = s:repo().translate(':0:'.bufname(entry.bufnr))
784
+ unlet! entry.bufnr
785
+ endif
786
+ endfor
787
+ call setqflist(list,'r')
788
+ if !a:bang && !empty(list)
789
+ return 'cfirst'.matchstr(a:arg,'\v\C[''" ]\zs\|.*')
790
+ else
791
+ return matchstr(a:arg,'\v\C[''" ]\|\zs.*')
792
+ endif
793
+ finally
794
+ let &grepprg = grepprg
795
+ let &grepformat = grepformat
796
+ execute cd.'`=dir`'
797
+ endtry
798
+ endfunction
799
+
800
+ function! s:Log(cmd,...)
801
+ let path = s:buffer().path('/')
802
+ if path =~# '^/\.git\%(/\|$\)' || index(a:000,'--') != -1
803
+ let path = ''
804
+ endif
805
+ let cmd = ['--no-pager', 'log', '--no-color']
806
+ let cmd += [escape('--pretty=format:fugitive://'.s:repo().dir().'//%H'.path.'::'.g:fugitive_summary_format,'%')]
807
+ if empty(filter(a:000[0 : index(a:000,'--')],'v:val !~# "^-"'))
808
+ if s:buffer().commit() =~# '\x\{40\}'
809
+ let cmd += [s:buffer().commit()]
810
+ elseif s:buffer().path() =~# '^\.git/refs/\|^\.git/.*HEAD$'
811
+ let cmd += [s:buffer().path()[5:-1]]
812
+ endif
813
+ end
814
+ let cmd += map(copy(a:000),'s:sub(v:val,"^\\%(%(:\\w)*)","\\=fnamemodify(s:buffer().path(),submatch(1))")')
815
+ if path =~# '/.'
816
+ let cmd += ['--',path[1:-1]]
817
+ endif
818
+ let grepformat = &grepformat
819
+ let grepprg = &grepprg
820
+ let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
821
+ let dir = getcwd()
822
+ try
823
+ execute cd.'`=s:repo().tree()`'
824
+ let &grepprg = call(s:repo().git_command,cmd,s:repo())
825
+ let &grepformat = '%f::%m'
826
+ exe a:cmd
827
+ finally
828
+ let &grepformat = grepformat
829
+ let &grepprg = grepprg
830
+ execute cd.'`=dir`'
831
+ endtry
832
+ endfunction
833
+
834
+ " }}}1
835
+ " Gedit, Gpedit, Gsplit, Gvsplit, Gtabedit, Gread {{{1
836
+
837
+ function! s:Edit(cmd,...) abort
838
+ if a:0 && a:1 == ''
839
+ return ''
840
+ elseif a:0
841
+ let file = s:buffer().expand(a:1)
842
+ elseif s:buffer().commit() ==# '' && s:buffer().path('/') !~# '^/.git\>'
843
+ let file = s:buffer().path(':')
844
+ else
845
+ let file = s:buffer().path('/')
846
+ endif
847
+ try
848
+ let file = s:repo().translate(file)
849
+ catch /^fugitive:/
850
+ return 'echoerr v:errmsg'
851
+ endtry
852
+ if a:cmd =~# 'read!$' || a:cmd ==# 'read'
853
+ if a:cmd =~# '!$'
854
+ call s:warn(':Gread! is deprecated. Use :Gread')
855
+ endif
856
+ return 'silent %delete|read '.s:fnameescape(file).'|silent 1delete_|diffupdate|'.line('.')
857
+ else
858
+ if &previewwindow && getbufvar('','fugitive_type') ==# 'index'
859
+ wincmd p
860
+ endif
861
+ return a:cmd.' '.s:fnameescape(file)
862
+ endif
863
+ endfunction
864
+
865
+ function! s:EditComplete(A,L,P) abort
866
+ return s:repo().superglob(a:A)
867
+ endfunction
868
+
869
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Ge :execute s:Edit('edit<bang>',<f-args>)")
870
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gedit :execute s:Edit('edit<bang>',<f-args>)")
871
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gpedit :execute s:Edit('pedit<bang>',<f-args>)")
872
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gsplit :execute s:Edit('split<bang>',<f-args>)")
873
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gvsplit :execute s:Edit('vsplit<bang>',<f-args>)")
874
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gtabedit :execute s:Edit('tabedit<bang>',<f-args>)")
875
+ call s:command("-bar -bang -nargs=? -count -complete=customlist,s:EditComplete Gread :execute s:Edit((!<count> && <line1> ? '' : <count>).'read<bang>',<f-args>)")
876
+
877
+ " }}}1
878
+ " Gwrite {{{1
879
+
880
+ call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gwrite :execute s:Write(<bang>0,<f-args>)")
881
+
882
+ function! s:Write(force,...) abort
883
+ if exists('b:fugitive_commit_arguments')
884
+ return 'write|bdelete'
885
+ elseif expand('%:t') == 'COMMIT_EDITMSG' && $GIT_INDEX_FILE != ''
886
+ return 'wq'
887
+ elseif s:buffer().type() == 'index'
888
+ return 'Gcommit'
889
+ endif
890
+ let mytab = tabpagenr()
891
+ let mybufnr = bufnr('')
892
+ let path = a:0 ? a:1 : s:buffer().path()
893
+ if path =~# '^:\d\>'
894
+ return 'write'.(a:force ? '! ' : ' ').s:fnameescape(s:repo().translate(s:buffer().expand(path)))
895
+ endif
896
+ let always_permitted = (s:buffer().path() ==# path && s:buffer().commit() =~# '^0\=$')
897
+ if !always_permitted && !a:force && s:repo().git_chomp_in_tree('diff','--name-status','HEAD','--',path) . s:repo().git_chomp_in_tree('ls-files','--others','--',path) !=# ''
898
+ let v:errmsg = 'fugitive: file has uncommitted changes (use ! to override)'
899
+ return 'echoerr v:errmsg'
900
+ endif
901
+ let file = s:repo().translate(path)
902
+ let treebufnr = 0
903
+ for nr in range(1,bufnr('$'))
904
+ if fnamemodify(bufname(nr),':p') ==# file
905
+ let treebufnr = nr
906
+ endif
907
+ endfor
908
+
909
+ if treebufnr > 0 && treebufnr != bufnr('')
910
+ let temp = tempname()
911
+ silent execute '%write '.temp
912
+ for tab in [mytab] + range(1,tabpagenr('$'))
913
+ for winnr in range(1,tabpagewinnr(tab,'$'))
914
+ if tabpagebuflist(tab)[winnr-1] == treebufnr
915
+ execute 'tabnext '.tab
916
+ if winnr != winnr()
917
+ execute winnr.'wincmd w'
918
+ let restorewinnr = 1
919
+ endif
920
+ try
921
+ let lnum = line('.')
922
+ let last = line('$')
923
+ silent execute '$read '.temp
924
+ silent execute '1,'.last.'delete_'
925
+ silent write!
926
+ silent execute lnum
927
+ let did = 1
928
+ finally
929
+ if exists('restorewinnr')
930
+ wincmd p
931
+ endif
932
+ execute 'tabnext '.mytab
933
+ endtry
934
+ endif
935
+ endfor
936
+ endfor
937
+ if !exists('did')
938
+ call writefile(readfile(temp,'b'),file,'b')
939
+ endif
940
+ else
941
+ execute 'write! '.s:fnameescape(s:repo().translate(path))
942
+ endif
943
+
944
+ let error = s:repo().git_chomp_in_tree('add', file)
945
+ if v:shell_error
946
+ let v:errmsg = 'fugitive: '.error
947
+ return 'echoerr v:errmsg'
948
+ endif
949
+ if s:buffer().path() ==# path && s:buffer().commit() =~# '^\d$'
950
+ set nomodified
951
+ endif
952
+
953
+ let one = s:repo().translate(':1:'.path)
954
+ let two = s:repo().translate(':2:'.path)
955
+ let three = s:repo().translate(':3:'.path)
956
+ for nr in range(1,bufnr('$'))
957
+ if bufloaded(nr) && !getbufvar(nr,'&modified') && (bufname(nr) == one || bufname(nr) == two || bufname(nr) == three)
958
+ execute nr.'bdelete'
959
+ endif
960
+ endfor
961
+
962
+ unlet! restorewinnr
963
+ let zero = s:repo().translate(':0:'.path)
964
+ for tab in range(1,tabpagenr('$'))
965
+ for winnr in range(1,tabpagewinnr(tab,'$'))
966
+ let bufnr = tabpagebuflist(tab)[winnr-1]
967
+ let bufname = bufname(bufnr)
968
+ if bufname ==# zero && bufnr != mybufnr
969
+ execute 'tabnext '.tab
970
+ if winnr != winnr()
971
+ execute winnr.'wincmd w'
972
+ let restorewinnr = 1
973
+ endif
974
+ try
975
+ let lnum = line('.')
976
+ let last = line('$')
977
+ silent $read `=file`
978
+ silent execute '1,'.last.'delete_'
979
+ silent execute lnum
980
+ set nomodified
981
+ diffupdate
982
+ finally
983
+ if exists('restorewinnr')
984
+ wincmd p
985
+ endif
986
+ execute 'tabnext '.mytab
987
+ endtry
988
+ break
989
+ endif
990
+ endfor
991
+ endfor
992
+ call fugitive#reload_status()
993
+ return 'checktime'
994
+ endfunction
995
+
996
+ " }}}1
997
+ " Gdiff {{{1
998
+
999
+ call s:command("-bar -nargs=? -complete=customlist,s:EditComplete Gdiff :execute s:Diff(<f-args>)")
1000
+
1001
+ augroup fugitive_diff
1002
+ autocmd BufWinLeave * if winnr('$') == 2 && &diff && getbufvar(+expand('<abuf>'), 'git_dir') !=# '' | diffoff! | endif
1003
+ autocmd BufWinEnter * if winnr('$') == 1 && &diff && getbufvar(+expand('<abuf>'), 'git_dir') !=# '' | diffoff | endif
1004
+ augroup END
1005
+
1006
+ function! s:buffer_compare_age(commit) dict abort
1007
+ let scores = {':0': 1, ':1': 2, ':2': 3, ':': 4, ':3': 5}
1008
+ let my_score = get(scores,':'.self.commit(),0)
1009
+ let their_score = get(scores,':'.a:commit,0)
1010
+ if my_score || their_score
1011
+ return my_score < their_score ? -1 : my_score != their_score
1012
+ elseif self.commit() ==# a:commit
1013
+ return 0
1014
+ endif
1015
+ let base = self.repo().git_chomp('merge-base',self.commit(),a:commit)
1016
+ if base ==# self.commit()
1017
+ return -1
1018
+ elseif base ==# a:commit
1019
+ return 1
1020
+ endif
1021
+ let my_time = +self.repo().git_chomp('log','--max-count=1','--pretty=format:%at',self.commit())
1022
+ let their_time = +self.repo().git_chomp('log','--max-count=1','--pretty=format:%at',a:commit)
1023
+ return my_time < their_time ? -1 : my_time != their_time
1024
+ endfunction
1025
+
1026
+ call s:add_methods('buffer',['compare_age'])
1027
+
1028
+ function! s:Diff(...) abort
1029
+ if exists(':DiffGitCached')
1030
+ return 'DiffGitCached'
1031
+ elseif (!a:0 || a:1 == ':') && s:buffer().commit() =~# '^[0-1]\=$' && s:repo().git_chomp_in_tree('ls-files', '--unmerged', '--', s:buffer().path()) !=# ''
1032
+ leftabove vsplit `=fugitive#buffer().repo().translate(s:buffer().expand(':2'))`
1033
+ diffthis
1034
+ wincmd p
1035
+ rightbelow vsplit `=fugitive#buffer().repo().translate(s:buffer().expand(':3'))`
1036
+ diffthis
1037
+ wincmd p
1038
+ diffthis
1039
+ return ''
1040
+ elseif a:0
1041
+ if a:1 ==# ''
1042
+ return ''
1043
+ elseif a:1 ==# '/'
1044
+ let file = s:buffer().path('/')
1045
+ elseif a:1 ==# ':'
1046
+ let file = s:buffer().path(':0:')
1047
+ elseif a:1 =~# '^:/'
1048
+ try
1049
+ let file = s:repo().rev_parse(a:1).s:buffer().path(':')
1050
+ catch /^fugitive:/
1051
+ return 'echoerr v:errmsg'
1052
+ endtry
1053
+ else
1054
+ let file = s:buffer().expand(a:1)
1055
+ endif
1056
+ if file !~# ':' && file !~# '^/' && s:repo().git_chomp('cat-file','-t',file) =~# '^\%(tag\|commit\)$'
1057
+ let file = file.s:buffer().path(':')
1058
+ endif
1059
+ else
1060
+ let file = s:buffer().path(s:buffer().commit() == '' ? ':0:' : '/')
1061
+ endif
1062
+ try
1063
+ let spec = s:repo().translate(file)
1064
+ let commit = matchstr(spec,'\C[^:/]//\zs\x\+')
1065
+ if s:buffer().compare_age(commit) < 0
1066
+ rightbelow vsplit `=spec`
1067
+ else
1068
+ leftabove vsplit `=spec`
1069
+ endif
1070
+ diffthis
1071
+ wincmd p
1072
+ diffthis
1073
+ return ''
1074
+ catch /^fugitive:/
1075
+ return 'echoerr v:errmsg'
1076
+ endtry
1077
+ endfunction
1078
+
1079
+ " }}}1
1080
+ " Gmove, Gremove {{{1
1081
+
1082
+ function! s:Move(force,destination)
1083
+ if a:destination =~# '^/'
1084
+ let destination = a:destination[1:-1]
1085
+ else
1086
+ let destination = fnamemodify(s:sub(a:destination,'[%#]%(:\w)*','\=expand(submatch(0))'),':p')
1087
+ if destination[0:strlen(s:repo().tree())] ==# s:repo().tree('')
1088
+ let destination = destination[strlen(s:repo().tree('')):-1]
1089
+ endif
1090
+ endif
1091
+ let message = call(s:repo().git_chomp_in_tree,['mv']+(a:force ? ['-f'] : [])+['--', s:buffer().path(), destination], s:repo())
1092
+ if v:shell_error
1093
+ let v:errmsg = 'fugitive: '.message
1094
+ return 'echoerr v:errmsg'
1095
+ endif
1096
+ let destination = s:repo().tree(destination)
1097
+ if isdirectory(destination)
1098
+ let destination = fnamemodify(s:sub(destination,'/$','').'/'.expand('%:t'),':.')
1099
+ endif
1100
+ call fugitive#reload_status()
1101
+ if s:buffer().commit() == ''
1102
+ return 'saveas! '.s:fnameescape(destination)
1103
+ else
1104
+ return 'file '.s:fnameescape(s:repo().translate(':0:'.destination)
1105
+ endif
1106
+ endfunction
1107
+
1108
+ function! s:MoveComplete(A,L,P)
1109
+ if a:A =~ '^/'
1110
+ return s:repo().superglob(a:A)
1111
+ else
1112
+ let matches = split(glob(a:A.'*'),"\n")
1113
+ call map(matches,'v:val !~ "/$" && isdirectory(v:val) ? v:val."/" : v:val')
1114
+ return matches
1115
+ endif
1116
+ endfunction
1117
+
1118
+ function! s:Remove(force)
1119
+ if s:buffer().commit() ==# ''
1120
+ let cmd = ['rm']
1121
+ elseif s:buffer().commit() ==# '0'
1122
+ let cmd = ['rm','--cached']
1123
+ else
1124
+ let v:errmsg = 'fugitive: rm not supported here'
1125
+ return 'echoerr v:errmsg'
1126
+ endif
1127
+ if a:force
1128
+ let cmd += ['--force']
1129
+ endif
1130
+ let message = call(s:repo().git_chomp_in_tree,cmd+['--',s:buffer().path()],s:repo())
1131
+ if v:shell_error
1132
+ let v:errmsg = 'fugitive: '.s:sub(message,'error:.*\zs\n\(.*-f.*',' (add ! to force)')
1133
+ return 'echoerr '.string(v:errmsg)
1134
+ else
1135
+ call fugitive#reload_status()
1136
+ return 'bdelete'.(a:force ? '!' : '')
1137
+ endif
1138
+ endfunction
1139
+
1140
+ augroup fugitive_remove
1141
+ autocmd!
1142
+ autocmd User Fugitive if s:buffer().commit() =~# '^0\=$' |
1143
+ \ exe "command! -buffer -bar -bang -nargs=1 -complete=customlist,s:MoveComplete Gmove :execute s:Move(<bang>0,<q-args>)" |
1144
+ \ exe "command! -buffer -bar -bang Gremove :execute s:Remove(<bang>0)" |
1145
+ \ endif
1146
+ augroup END
1147
+
1148
+ " }}}1
1149
+ " Gblame {{{1
1150
+
1151
+ augroup fugitive_blame
1152
+ autocmd!
1153
+ autocmd BufReadPost *.fugitiveblame setfiletype fugitiveblame
1154
+ autocmd FileType fugitiveblame setlocal nomodeline | if exists('b:git_dir') | let &l:keywordprg = s:repo().keywordprg() | endif
1155
+ autocmd Syntax fugitiveblame call s:BlameSyntax()
1156
+ autocmd User Fugitive if s:buffer().type('file', 'blob') | exe "command! -buffer -bar -bang -range=0 -nargs=* Gblame :execute s:Blame(<bang>0,<line1>,<line2>,<count>,[<f-args>])" | endif
1157
+ augroup END
1158
+
1159
+ function! s:Blame(bang,line1,line2,count,args) abort
1160
+ try
1161
+ if s:buffer().path() == ''
1162
+ call s:throw('file or blob required')
1163
+ endif
1164
+ if filter(copy(a:args),'v:val !~# "^\\%(--root\|--show-name\\|-\\=\\%([ltwfs]\\|[MC]\\d*\\)\\+\\)$"') != []
1165
+ call s:throw('unsupported option')
1166
+ endif
1167
+ call map(a:args,'s:sub(v:val,"^\\ze[^-]","-")')
1168
+ let git_dir = s:repo().dir()
1169
+ let cmd = ['--no-pager', 'blame', '--show-number'] + a:args
1170
+ if s:buffer().commit() =~# '\D\|..'
1171
+ let cmd += [s:buffer().commit()]
1172
+ else
1173
+ let cmd += ['--contents', '-']
1174
+ endif
1175
+ let basecmd = call(s:repo().git_command,cmd+['--',s:buffer().path()],s:repo())
1176
+ try
1177
+ let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
1178
+ if !s:repo().bare()
1179
+ let dir = getcwd()
1180
+ execute cd.'`=s:repo().tree()`'
1181
+ endif
1182
+ if a:count
1183
+ execute 'write !'.substitute(basecmd,' blame ',' blame -L '.a:line1.','.a:line2.' ','g')
1184
+ else
1185
+ let error = tempname()
1186
+ let temp = error.'.fugitiveblame'
1187
+ silent! exe '%write !'.basecmd.' > '.temp.' 2> '.error
1188
+ if v:shell_error
1189
+ call s:throw(join(readfile(error),"\n"))
1190
+ endif
1191
+ let bufnr = bufnr('')
1192
+ let restore = 'call setbufvar('.bufnr.',"&scrollbind",0)'
1193
+ if &l:wrap
1194
+ let restore .= '|call setbufvar('.bufnr.',"&wrap",1)'
1195
+ endif
1196
+ if &l:foldenable
1197
+ let restore .= '|call setbufvar('.bufnr.',"&foldenable",1)'
1198
+ endif
1199
+ let winnr = winnr()
1200
+ windo set noscrollbind
1201
+ exe winnr.'wincmd w'
1202
+ setlocal scrollbind nowrap nofoldenable
1203
+ let top = line('w0') + &scrolloff
1204
+ let current = line('.')
1205
+ exe 'leftabove vsplit '.temp
1206
+ let b:git_dir = git_dir
1207
+ let b:fugitive_type = 'blame'
1208
+ let b:fugitive_blamed_bufnr = bufnr
1209
+ let b:fugitive_restore = restore
1210
+ let b:fugitive_blame_arguments = join(a:args,' ')
1211
+ call s:Detect(expand('%:p'))
1212
+ execute top
1213
+ normal! zt
1214
+ execute current
1215
+ execute "vertical resize ".(match(getline('.'),'\s\+\d\+)')+1)
1216
+ setlocal nomodified nomodifiable bufhidden=delete nonumber scrollbind nowrap foldcolumn=0 nofoldenable filetype=fugitiveblame
1217
+ nnoremap <buffer> <silent> q :<C-U>bdelete<CR>
1218
+ nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>BlameJump('')<CR>
1219
+ nnoremap <buffer> <silent> P :<C-U>exe <SID>BlameJump('^'.v:count1)<CR>
1220
+ nnoremap <buffer> <silent> ~ :<C-U>exe <SID>BlameJump('~'.v:count1)<CR>
1221
+ nnoremap <buffer> <silent> o :<C-U>exe <SID>Edit((&splitbelow ? "botright" : "topleft")." split", matchstr(getline('.'),'\x\+'))<CR>
1222
+ nnoremap <buffer> <silent> O :<C-U>exe <SID>Edit("tabedit", matchstr(getline('.'),'\x\+'))<CR>
1223
+ syncbind
1224
+ endif
1225
+ finally
1226
+ if exists('l:dir')
1227
+ execute cd.'`=dir`'
1228
+ endif
1229
+ endtry
1230
+ return ''
1231
+ catch /^fugitive:/
1232
+ return 'echoerr v:errmsg'
1233
+ endtry
1234
+ endfunction
1235
+
1236
+ function! s:BlameJump(suffix) abort
1237
+ let commit = matchstr(getline('.'),'^\^\=\zs\x\+')
1238
+ if commit =~# '^0\+$'
1239
+ let commit = ':0'
1240
+ endif
1241
+ let lnum = matchstr(getline('.'),'\d\+\ze\s\+[([:digit:]]')
1242
+ let path = matchstr(getline('.'),'^\^\=\zs\x\+\s\+\zs.\{-\}\ze\s*\d\+ ')
1243
+ if path ==# ''
1244
+ let path = s:buffer(b:fugitive_blamed_bufnr).path()
1245
+ endif
1246
+ let args = b:fugitive_blame_arguments
1247
+ let offset = line('.') - line('w0')
1248
+ let bufnr = bufnr('%')
1249
+ let winnr = bufwinnr(b:fugitive_blamed_bufnr)
1250
+ if winnr > 0
1251
+ exe winnr.'wincmd w'
1252
+ endif
1253
+ execute s:Edit('edit',commit.a:suffix.':'.path)
1254
+ if winnr > 0
1255
+ exe bufnr.'bdelete'
1256
+ endif
1257
+ execute 'Gblame '.args
1258
+ execute lnum
1259
+ let delta = line('.') - line('w0') - offset
1260
+ if delta > 0
1261
+ execute 'norm! 'delta."\<C-E>"
1262
+ elseif delta < 0
1263
+ execute 'norm! '(-delta)."\<C-Y>"
1264
+ endif
1265
+ syncbind
1266
+ return ''
1267
+ endfunction
1268
+
1269
+ function! s:BlameSyntax() abort
1270
+ let b:current_syntax = 'fugitiveblame'
1271
+ syn match FugitiveblameBoundary "^\^"
1272
+ syn match FugitiveblameBlank "^\s\+\s\@=" nextgroup=FugitiveblameAnnotation,fugitiveblameOriginalFile,FugitiveblameOriginalLineNumber skipwhite
1273
+ syn match FugitiveblameHash "\%(^\^\=\)\@<=\x\{7,40\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite
1274
+ syn match FugitiveblameUncommitted "\%(^\^\=\)\@<=0\{7,40\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite
1275
+ syn region FugitiveblameAnnotation matchgroup=FugitiveblameDelimiter start="(" end="\%( \d\+\)\@<=)" contained keepend oneline
1276
+ syn match FugitiveblameTime "[0-9:/+-][0-9:/+ -]*[0-9:/+-]\%( \+\d\+)\)\@=" contained containedin=FugitiveblameAnnotation
1277
+ syn match FugitiveblameLineNumber " \@<=\d\+)\@=" contained containedin=FugitiveblameAnnotation
1278
+ syn match FugitiveblameOriginalFile " \%(\f\+\D\@<=\|\D\@=\f\+\)\%(\%(\s\+\d\+\)\=\s\%((\|\s*\d\+)\)\)\@=" contained nextgroup=FugitiveblameOriginalLineNumber,FugitiveblameAnnotation skipwhite
1279
+ syn match FugitiveblameOriginalLineNumber " \@<=\d\+\%(\s(\)\@=" contained nextgroup=FugitiveblameAnnotation skipwhite
1280
+ syn match FugitiveblameOriginalLineNumber " \@<=\d\+\%(\s\+\d\+)\)\@=" contained nextgroup=FugitiveblameShort skipwhite
1281
+ syn match FugitiveblameShort "\d\+)" contained contains=FugitiveblameLineNumber
1282
+ syn match FugitiveblameNotCommittedYet "(\@<=Not Committed Yet\>" contained containedin=FugitiveblameAnnotation
1283
+ hi def link FugitiveblameBoundary Keyword
1284
+ hi def link FugitiveblameHash Identifier
1285
+ hi def link FugitiveblameUncommitted Function
1286
+ hi def link FugitiveblameTime PreProc
1287
+ hi def link FugitiveblameLineNumber Number
1288
+ hi def link FugitiveblameOriginalFile String
1289
+ hi def link FugitiveblameOriginalLineNumber Float
1290
+ hi def link FugitiveblameShort FugitiveblameDelimiter
1291
+ hi def link FugitiveblameDelimiter Delimiter
1292
+ hi def link FugitiveblameNotCommittedYet Comment
1293
+ endfunction
1294
+
1295
+ " }}}1
1296
+ " File access {{{1
1297
+
1298
+ function! s:ReplaceCmd(cmd,...) abort
1299
+ let fn = bufname('')
1300
+ let tmp = tempname()
1301
+ let aw = &autowrite
1302
+ let prefix = ''
1303
+ try
1304
+ if a:0 && a:1 != ''
1305
+ if &shell =~# 'cmd'
1306
+ let old_index = $GIT_INDEX_FILE
1307
+ let $GIT_INDEX_FILE = a:1
1308
+ elseif &shell =~# 'csh'
1309
+ let prefix = 'setenv GIT_INDEX_FILE '.s:shellesc(a:1).'; '
1310
+ else
1311
+ let prefix = 'GIT_INDEX_FILE='.s:shellesc(a:1).' '
1312
+ endif
1313
+ endif
1314
+ set noautowrite
1315
+ silent exe '!'.escape(prefix.a:cmd,'%#').' > '.tmp
1316
+ finally
1317
+ let &autowrite = aw
1318
+ if exists('old_index')
1319
+ let $GIT_INDEX_FILE = old_index
1320
+ endif
1321
+ endtry
1322
+ silent exe 'keepalt file '.tmp
1323
+ silent edit!
1324
+ silent exe 'keepalt file '.s:fnameescape(fn)
1325
+ call delete(tmp)
1326
+ silent exe 'doau BufReadPost '.s:fnameescape(fn)
1327
+ endfunction
1328
+
1329
+ function! s:BufReadIndex()
1330
+ if !exists('b:fugitive_display_format')
1331
+ let b:fugitive_display_format = filereadable(expand('%').'.lock')
1332
+ endif
1333
+ let b:fugitive_display_format = b:fugitive_display_format % 2
1334
+ let b:fugitive_type = 'index'
1335
+ try
1336
+ let b:git_dir = s:repo().dir()
1337
+ setlocal noro ma
1338
+ if fnamemodify($GIT_INDEX_FILE !=# '' ? $GIT_INDEX_FILE : b:git_dir . '/index', ':p') ==# expand('%:p')
1339
+ let index = ''
1340
+ else
1341
+ let index = expand('%')
1342
+ endif
1343
+ if b:fugitive_display_format
1344
+ call s:ReplaceCmd(s:repo().git_command('ls-files','--stage'),index)
1345
+ set ft=git nospell
1346
+ else
1347
+ let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
1348
+ let dir = getcwd()
1349
+ try
1350
+ execute cd.'`=s:repo().tree()`'
1351
+ call s:ReplaceCmd(s:repo().git_command('status'),index)
1352
+ finally
1353
+ execute cd.'`=dir`'
1354
+ endtry
1355
+ set ft=gitcommit
1356
+ endif
1357
+ setlocal ro noma nomod nomodeline bufhidden=delete
1358
+ nnoremap <buffer> <silent> a :<C-U>let b:fugitive_display_format += 1<Bar>exe <SID>BufReadIndex()<CR>
1359
+ nnoremap <buffer> <silent> i :<C-U>let b:fugitive_display_format -= 1<Bar>exe <SID>BufReadIndex()<CR>
1360
+ nnoremap <buffer> <silent> D :<C-U>execute <SID>StageDiff()<CR>
1361
+ nnoremap <buffer> <silent> - :<C-U>execute <SID>StageToggle(line('.'),line('.')+v:count1-1)<CR>
1362
+ xnoremap <buffer> <silent> - :<C-U>execute <SID>StageToggle(line("'<"),line("'>"))<CR>
1363
+ nnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>
1364
+ xnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR>
1365
+ call s:JumpInit()
1366
+ nunmap <buffer> P
1367
+ nunmap <buffer> ~
1368
+ nnoremap <buffer> <silent> C :<C-U>Gcommit<CR>
1369
+ catch /^fugitive:/
1370
+ return 'echoerr v:errmsg'
1371
+ endtry
1372
+ endfunction
1373
+
1374
+ function! s:FileRead()
1375
+ try
1376
+ let repo = s:repo(s:ExtractGitDir(expand('<amatch>')))
1377
+ let path = s:sub(s:sub(matchstr(expand('<amatch>'),'fugitive://.\{-\}//\zs.*'),'/',':'),'^\d:',':&')
1378
+ let hash = repo.rev_parse(path)
1379
+ if path =~ '^:'
1380
+ let type = 'blob'
1381
+ else
1382
+ let type = repo.git_chomp('cat-file','-t',hash)
1383
+ endif
1384
+ " TODO: use count, if possible
1385
+ return "read !".escape(repo.git_command('cat-file',type,hash),'%#\')
1386
+ catch /^fugitive:/
1387
+ return 'echoerr v:errmsg'
1388
+ endtry
1389
+ endfunction
1390
+
1391
+ function! s:BufReadIndexFile()
1392
+ try
1393
+ let b:fugitive_type = 'blob'
1394
+ let b:git_dir = s:repo().dir()
1395
+ call s:ReplaceCmd(s:repo().git_command('cat-file','blob',s:buffer().sha1()))
1396
+ return ''
1397
+ catch /^fugitive: rev-parse/
1398
+ silent exe 'doau BufNewFile '.s:fnameescape(bufname(''))
1399
+ return ''
1400
+ catch /^fugitive:/
1401
+ return 'echoerr v:errmsg'
1402
+ endtry
1403
+ endfunction
1404
+
1405
+ function! s:BufWriteIndexFile()
1406
+ let tmp = tempname()
1407
+ try
1408
+ let path = matchstr(expand('<amatch>'),'//\d/\zs.*')
1409
+ let stage = matchstr(expand('<amatch>'),'//\zs\d')
1410
+ silent execute 'write !'.s:repo().git_command('hash-object','-w','--stdin').' > '.tmp
1411
+ let sha1 = readfile(tmp)[0]
1412
+ let old_mode = matchstr(s:repo().git_chomp('ls-files','--stage',path),'^\d\+')
1413
+ if old_mode == ''
1414
+ let old_mode = executable(s:repo().tree(path)) ? '100755' : '100644'
1415
+ endif
1416
+ let info = old_mode.' '.sha1.' '.stage."\t".path
1417
+ call writefile([info],tmp)
1418
+ let error = system(s:repo().git_command('update-index','--index-info').' < '.tmp)
1419
+ if v:shell_error == 0
1420
+ setlocal nomodified
1421
+ silent execute 'doautocmd BufWritePost '.s:fnameescape(expand('%:p'))
1422
+ call fugitive#reload_status()
1423
+ return ''
1424
+ else
1425
+ return 'echoerr '.string('fugitive: '.error)
1426
+ endif
1427
+ finally
1428
+ call delete(tmp)
1429
+ endtry
1430
+ endfunction
1431
+
1432
+ function! s:BufReadObject()
1433
+ try
1434
+ setlocal noro ma
1435
+ let b:git_dir = s:repo().dir()
1436
+ let hash = s:buffer().sha1()
1437
+ if !exists("b:fugitive_type")
1438
+ let b:fugitive_type = s:repo().git_chomp('cat-file','-t',hash)
1439
+ endif
1440
+ if b:fugitive_type !~# '^\%(tag\|commit\|tree\|blob\)$'
1441
+ return "echoerr 'fugitive: unrecognized git type'"
1442
+ endif
1443
+ let firstline = getline('.')
1444
+ if !exists('b:fugitive_display_format') && b:fugitive_type != 'blob'
1445
+ let b:fugitive_display_format = +getbufvar('#','fugitive_display_format')
1446
+ endif
1447
+
1448
+ let pos = getpos('.')
1449
+ silent %delete
1450
+ setlocal endofline
1451
+
1452
+ if b:fugitive_type == 'tree'
1453
+ let b:fugitive_display_format = b:fugitive_display_format % 2
1454
+ if b:fugitive_display_format
1455
+ call s:ReplaceCmd(s:repo().git_command('ls-tree',hash))
1456
+ else
1457
+ call s:ReplaceCmd(s:repo().git_command('show',hash))
1458
+ endif
1459
+ elseif b:fugitive_type == 'tag'
1460
+ let b:fugitive_display_format = b:fugitive_display_format % 2
1461
+ if b:fugitive_display_format
1462
+ call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash))
1463
+ else
1464
+ call s:ReplaceCmd(s:repo().git_command('cat-file','-p',hash))
1465
+ endif
1466
+ elseif b:fugitive_type == 'commit'
1467
+ let b:fugitive_display_format = b:fugitive_display_format % 2
1468
+ if b:fugitive_display_format
1469
+ call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash))
1470
+ else
1471
+ call s:ReplaceCmd(s:repo().git_command('show','--pretty=format:tree %T%nparent %P%nauthor %an <%ae> %ad%ncommitter %cn <%ce> %cd%nencoding %e%n%n%s%n%n%b',hash))
1472
+ call search('^parent ')
1473
+ if getline('.') ==# 'parent '
1474
+ silent delete_
1475
+ else
1476
+ silent s/\%(^parent\)\@<! /\rparent /ge
1477
+ endif
1478
+ if search('^encoding \%(<unknown>\)\=$','W',line('.')+3)
1479
+ silent delete_
1480
+ end
1481
+ 1
1482
+ endif
1483
+ elseif b:fugitive_type ==# 'blob'
1484
+ call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash))
1485
+ endif
1486
+ call setpos('.',pos)
1487
+ setlocal ro noma nomod nomodeline
1488
+ if b:fugitive_type !=# 'blob'
1489
+ set filetype=git
1490
+ nnoremap <buffer> <silent> a :<C-U>let b:fugitive_display_format += v:count1<Bar>exe <SID>BufReadObject()<CR>
1491
+ nnoremap <buffer> <silent> i :<C-U>let b:fugitive_display_format -= v:count1<Bar>exe <SID>BufReadObject()<CR>
1492
+ else
1493
+ call s:JumpInit()
1494
+ endif
1495
+
1496
+ return ''
1497
+ catch /^fugitive:/
1498
+ return 'echoerr v:errmsg'
1499
+ endtry
1500
+ endfunction
1501
+
1502
+ augroup fugitive_files
1503
+ autocmd!
1504
+ autocmd BufReadCmd *.git/index exe s:BufReadIndex()
1505
+ autocmd BufReadCmd *.git/*index*.lock exe s:BufReadIndex()
1506
+ autocmd FileReadCmd fugitive://**//[0-3]/** exe s:FileRead()
1507
+ autocmd BufReadCmd fugitive://**//[0-3]/** exe s:BufReadIndexFile()
1508
+ autocmd BufWriteCmd fugitive://**//[0-3]/** exe s:BufWriteIndexFile()
1509
+ autocmd BufReadCmd fugitive://**//[0-9a-f][0-9a-f]* exe s:BufReadObject()
1510
+ autocmd FileReadCmd fugitive://**//[0-9a-f][0-9a-f]* exe s:FileRead()
1511
+ autocmd FileType git call s:JumpInit()
1512
+ augroup END
1513
+
1514
+ " }}}1
1515
+ " Go to file {{{1
1516
+
1517
+ function! s:JumpInit() abort
1518
+ nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>GF("edit")<CR>
1519
+ if !&modifiable
1520
+ nnoremap <buffer> <silent> o :<C-U>exe <SID>GF("split")<CR>
1521
+ nnoremap <buffer> <silent> O :<C-U>exe <SID>GF("tabedit")<CR>
1522
+ nnoremap <buffer> <silent> P :<C-U>exe <SID>Edit('edit',<SID>buffer().commit().'^'.v:count1.<SID>buffer().path(':'))<CR>
1523
+ nnoremap <buffer> <silent> ~ :<C-U>exe <SID>Edit('edit',<SID>buffer().commit().'~'.v:count1.<SID>buffer().path(':'))<CR>
1524
+ nnoremap <buffer> <silent> C :<C-U>exe <SID>Edit('edit',<SID>buffer().containing_commit())<CR>
1525
+ nnoremap <buffer> <silent> cc :<C-U>exe <SID>Edit('edit',<SID>buffer().containing_commit())<CR>
1526
+ nnoremap <buffer> <silent> co :<C-U>exe <SID>Edit('split',<SID>buffer().containing_commit())<CR>
1527
+ nnoremap <buffer> <silent> cO :<C-U>exe <SID>Edit('tabedit',<SID>buffer().containing_commit())<CR>
1528
+ nnoremap <buffer> <silent> cp :<C-U>exe <SID>Edit('pedit',<SID>buffer().containing_commit())<CR>
1529
+ endif
1530
+ endfunction
1531
+
1532
+ function! s:GF(mode) abort
1533
+ try
1534
+ let buffer = s:buffer()
1535
+ let myhash = buffer.sha1()
1536
+
1537
+ if buffer.type('tree')
1538
+ let showtree = (getline(1) =~# '^tree ' && getline(2) == "")
1539
+ if showtree && line('.') == 1
1540
+ return ""
1541
+ elseif showtree && line('.') > 2
1542
+ return s:Edit(a:mode,buffer.commit().':'.(buffer.path() == '' ? '' : buffer.path().'/').s:sub(getline('.'),'/$',''))
1543
+ elseif getline('.') =~# '^\d\{6\} \l\{3,8\} \x\{40\}\t'
1544
+ return s:Edit(a:mode,buffer.commit().':'.(buffer.path() == '' ? '' : buffer.path().'/').s:sub(matchstr(getline('.'),'\t\zs.*'),'/$',''))
1545
+ endif
1546
+
1547
+ elseif buffer.type('blob')
1548
+ let ref = expand("<cfile>")
1549
+ try
1550
+ let sha1 = buffer.repo().rev_parse(ref)
1551
+ catch /^fugitive:/
1552
+ endtry
1553
+ if exists('sha1')
1554
+ return s:Edit(a:mode,ref)
1555
+ endif
1556
+
1557
+ else
1558
+
1559
+ " Index
1560
+ if getline('.') =~# '^\d\{6\} \x\{40\} \d\t'
1561
+ let ref = matchstr(getline('.'),'\x\{40\}')
1562
+ let file = ':'.s:sub(matchstr(getline('.'),'\d\t.*'),'\t',':')
1563
+ return s:Edit(a:mode,file)
1564
+
1565
+ elseif getline('.') =~# '^#\trenamed:.* -> '
1566
+ let file = '/'.matchstr(getline('.'),' -> \zs.*')
1567
+ return s:Edit(a:mode,file)
1568
+ elseif getline('.') =~# '^#\t[[:alpha:] ]\+: *.'
1569
+ let file = '/'.matchstr(getline('.'),': *\zs.*')
1570
+ return s:Edit(a:mode,file)
1571
+ elseif getline('.') =~# '^#\t.'
1572
+ let file = '/'.matchstr(getline('.'),'#\t\zs.*')
1573
+ return s:Edit(a:mode,file)
1574
+ elseif getline('.') =~# ': needs merge$'
1575
+ let file = '/'.matchstr(getline('.'),'.*\ze: needs merge$')
1576
+ return s:Edit(a:mode,file).'|Gdiff'
1577
+
1578
+ elseif getline('.') ==# '# Not currently on any branch.'
1579
+ return s:Edit(a:mode,'HEAD')
1580
+ elseif getline('.') =~# '^# On branch '
1581
+ let file = 'refs/heads/'.getline('.')[12:]
1582
+ return s:Edit(a:mode,file)
1583
+ elseif getline('.') =~# "^# Your branch .*'"
1584
+ let file = matchstr(getline('.'),"'\\zs\\S\\+\\ze'")
1585
+ return s:Edit(a:mode,file)
1586
+ endif
1587
+
1588
+ let showtree = (getline(1) =~# '^tree ' && getline(2) == "")
1589
+
1590
+ if getline('.') =~# '^ref: '
1591
+ let ref = strpart(getline('.'),5)
1592
+
1593
+ elseif getline('.') =~# '^parent \x\{40\}\>'
1594
+ let ref = matchstr(getline('.'),'\x\{40\}')
1595
+ let line = line('.')
1596
+ let parent = 0
1597
+ while getline(line) =~# '^parent '
1598
+ let parent += 1
1599
+ let line -= 1
1600
+ endwhile
1601
+ return s:Edit(a:mode,ref)
1602
+
1603
+ elseif getline('.') =~ '^tree \x\{40\}$'
1604
+ let ref = matchstr(getline('.'),'\x\{40\}')
1605
+ if s:repo().rev_parse(myhash.':') == ref
1606
+ let ref = myhash.':'
1607
+ endif
1608
+ return s:Edit(a:mode,ref)
1609
+
1610
+ elseif getline('.') =~# '^object \x\{40\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$'
1611
+ let ref = matchstr(getline('.'),'\x\{40\}')
1612
+ let type = matchstr(getline(line('.')+1),'type \zs.*')
1613
+
1614
+ elseif getline('.') =~# '^\l\{3,8\} '.myhash.'$'
1615
+ return ''
1616
+
1617
+ elseif getline('.') =~# '^\l\{3,8\} \x\{40\}\>'
1618
+ let ref = matchstr(getline('.'),'\x\{40\}')
1619
+ echoerr "warning: unknown context ".matchstr(getline('.'),'^\l*')
1620
+
1621
+ elseif getline('.') =~# '^[+-]\{3\} [ab/]'
1622
+ let ref = getline('.')[4:]
1623
+
1624
+ elseif getline('.') =~# '^rename from '
1625
+ let ref = 'a/'.getline('.')[12:]
1626
+ elseif getline('.') =~# '^rename to '
1627
+ let ref = 'b/'.getline('.')[10:]
1628
+
1629
+ elseif getline('.') =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)'
1630
+ let dref = matchstr(getline('.'),'\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)')
1631
+ let ref = matchstr(getline('.'),'\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)')
1632
+
1633
+ elseif line('$') == 1 && getline('.') =~ '^\x\{40\}$'
1634
+ let ref = getline('.')
1635
+ else
1636
+ let ref = ''
1637
+ endif
1638
+
1639
+ if myhash ==# ''
1640
+ let ref = s:sub(ref,'^a/','HEAD:')
1641
+ let ref = s:sub(ref,'^b/',':0:')
1642
+ if exists('dref')
1643
+ let dref = s:sub(dref,'^a/','HEAD:')
1644
+ endif
1645
+ else
1646
+ let ref = s:sub(ref,'^a/',myhash.'^:')
1647
+ let ref = s:sub(ref,'^b/',myhash.':')
1648
+ if exists('dref')
1649
+ let dref = s:sub(dref,'^a/',myhash.'^:')
1650
+ endif
1651
+ endif
1652
+
1653
+ if ref ==# '/dev/null'
1654
+ " Empty blob
1655
+ let ref = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'
1656
+ endif
1657
+
1658
+ if exists('dref')
1659
+ return s:Edit(a:mode,ref) . '|Gdiff '.s:fnameescape(dref)
1660
+ elseif ref != ""
1661
+ return s:Edit(a:mode,ref)
1662
+ endif
1663
+
1664
+ endif
1665
+ return ''
1666
+ catch /^fugitive:/
1667
+ return 'echoerr v:errmsg'
1668
+ endtry
1669
+ endfunction
1670
+
1671
+ " }}}1
1672
+ " Statusline {{{1
1673
+
1674
+ function! s:repo_head_ref() dict abort
1675
+ return readfile(s:repo().dir('HEAD'))[0]
1676
+ endfunction
1677
+
1678
+ call s:add_methods('repo',['head_ref'])
1679
+
1680
+ function! fugitive#statusline(...)
1681
+ if !exists('b:git_dir')
1682
+ return ''
1683
+ endif
1684
+ let status = ''
1685
+ if s:buffer().commit() != ''
1686
+ let status .= ':' . s:buffer().commit()[0:7]
1687
+ endif
1688
+ let head = s:repo().head_ref()
1689
+ if head =~# '^ref: '
1690
+ let status .= s:sub(head,'^ref: %(refs/%(heads/|remotes/|tags/)=)=','(').')'
1691
+ elseif head =~# '^\x\{40\}$'
1692
+ let status .= '('.head[0:7].')'
1693
+ endif
1694
+ if &statusline =~# '%[MRHWY]' && &statusline !~# '%[mrhwy]'
1695
+ return ',GIT'.status
1696
+ else
1697
+ return '[Git'.status.']'
1698
+ endif
1699
+ endfunction
1700
+
1701
+ " }}}1
1702
+
1703
+ " vim:set ft=vim ts=8 sw=2 sts=2: