diff --git a/vimfiles/GetLatest/GetLatestVimScripts.dat b/vimfiles/GetLatest/GetLatestVimScripts.dat index 7b1d462..a2bae04 100644 --- a/vimfiles/GetLatest/GetLatestVimScripts.dat +++ b/vimfiles/GetLatest/GetLatestVimScripts.dat @@ -19,14 +19,14 @@ ScriptID SourceID Filename 1046 4249 Lusty Explorer 2043 7805 VimPdb (debugging python) 1776 7902 Vimgrep Replace -3745 16823 LineDiff +3745 22834 LineDiff 39 8196 matchit.vim 2092 8095 reloaded.vim (matrix colorscheme) 848 14668 SrchRplcHiGrp.vim (Search/Replace on Syntax Group) 294 19633 Align.vim 479 9276 MultipleSearch.vba 1066 7618 cecutil.vim -1173 21766 tComment.vim +1173 22422 tComment.vim 2701 18988 editsrec 3280 14334 Tabbi 642 15781 :AutoInstall: getscript.vim @@ -35,4 +35,4 @@ ScriptID SourceID Filename 3304 20505 Gundo 90 19809 vcscommand 974 4316 python.vim (indent) -2975 15542 fugitive.vim +2975 22815 fugitive.vim diff --git a/vimfiles/autoload/linediff/differ.vim b/vimfiles/autoload/linediff/differ.vim index 7eb5c9d..41dd683 100644 --- a/vimfiles/autoload/linediff/differ.vim +++ b/vimfiles/autoload/linediff/differ.vim @@ -16,7 +16,9 @@ function! linediff#differ#New(sign_name, sign_number) \ 'Init': function('linediff#differ#Init'), \ 'IsBlank': function('linediff#differ#IsBlank'), \ 'Reset': function('linediff#differ#Reset'), + \ 'CloseAndReset': function('linediff#differ#CloseAndReset'), \ 'Lines': function('linediff#differ#Lines'), + \ 'Indent': function('linediff#differ#Indent'), \ 'CreateDiffBuffer': function('linediff#differ#CreateDiffBuffer'), \ 'SetupDiffBuffer': function('linediff#differ#SetupDiffBuffer'), \ 'CloseDiffBuffer': function('linediff#differ#CloseDiffBuffer'), @@ -51,8 +53,6 @@ endfunction " Resets the differ to the blank state. Invoke `Init(from, to)` on it later to " make it usable again. function! linediff#differ#Reset() dict - call self.CloseDiffBuffer() - let self.original_buffer = -1 let self.diff_buffer = -1 let self.filetype = '' @@ -66,6 +66,13 @@ function! linediff#differ#Reset() dict let self.is_blank = 1 endfunction +" Closes the diff buffer and resets. The two actions are separate to avoid +" problems with closing already closed buffers. +function! linediff#differ#CloseAndReset(force) dict + call self.CloseDiffBuffer(a:force) + call self.Reset() +endfunction + " Extracts the relevant lines from the original buffer and returns them as a " list. function! linediff#differ#Lines() dict @@ -75,20 +82,41 @@ endfunction " Creates the buffer used for the diffing and connects it to this differ " object. function! linediff#differ#CreateDiffBuffer(edit_command) dict - let lines = self.Lines() - let temp_file = tempname() + let lines = self.Lines() - exe a:edit_command . " " . temp_file - call append(0, lines) - normal! Gdd - set nomodified + if g:linediff_buffer_type == 'tempfile' + let temp_file = tempname() + + silent exe a:edit_command . " " . temp_file + call append(0, lines) + silent $delete _ + + set nomodified + normal! gg + else " g:linediff_buffer_type == 'scratch' + silent exe a:edit_command + + call append(0, lines) + silent $delete _ + + setlocal buftype=acwrite + setlocal bufhidden=wipe + endif let self.diff_buffer = bufnr('%') call self.SetupDiffBuffer() + call self.Indent() diffthis endfunction +" Indents the current buffer content so that format can be ignored. +function! linediff#differ#Indent() dict + if g:linediff_indent + silent normal! gg=G + endif +endfunction + " Sets up the temporary buffer's filetype and statusline. " " Attempts to leave the current statusline as it is, and simply add the @@ -97,20 +125,30 @@ endfunction function! linediff#differ#SetupDiffBuffer() dict let b:differ = self - let statusline = printf('[%s:%%{b:differ.from}-%%{b:differ.to}]', bufname(self.original_buffer)) - if &statusline =~ '%[fF]' - let statusline = substitute(&statusline, '%[fF]', statusline, '') - endif - exe "setlocal statusline=" . escape(statusline, ' |') - exe "set filetype=" . self.filetype - setlocal bufhidden=hide + if g:linediff_buffer_type == 'tempfile' + let statusline = printf('[%s:%%{b:differ.from}-%%{b:differ.to}]', bufname(self.original_buffer)) + if &statusline =~ '%[fF]' + let statusline = substitute(&statusline, '%[fF]', escape(statusline, '\'), '') + endif + let &l:statusline = statusline + exe "set filetype=" . self.filetype + setlocal bufhidden=wipe - autocmd BufWrite silent call b:differ.UpdateOriginalBuffer() + autocmd BufWrite silent call b:differ.UpdateOriginalBuffer() + else " g:linediff_buffer_type == 'scratch' + let description = printf('[%s:%s-%s]', bufname(self.original_buffer), self.from, self.to) + silent exec 'keepalt file ' . escape(description, '[') + exe "set filetype=" . self.filetype + set nomodified + + autocmd BufWriteCmd silent call b:differ.UpdateOriginalBuffer() + endif endfunction -function! linediff#differ#CloseDiffBuffer() dict +function! linediff#differ#CloseDiffBuffer(force) dict if bufexists(self.diff_buffer) - exe "bdelete ".self.diff_buffer + let bang = a:force ? '!' : '' + exe "bdelete".bang." ".self.diff_buffer endif endfunction @@ -126,17 +164,25 @@ endfunction " update the other differ's data, provided a few conditions are met. See " linediff#differ#PossiblyUpdateOtherDiffer() for details. function! linediff#differ#UpdateOriginalBuffer() dict + if self.IsBlank() + return + endif + + let saved_diff_buffer_view = winsaveview() let new_lines = getbufline('%', 0, '$') " Switch to the original buffer, delete the relevant lines, add the new " ones, switch back to the diff buffer. + set bufhidden=hide call linediff#util#SwitchBuffer(self.original_buffer) - let saved_cursor = getpos('.') + let saved_original_buffer_view = winsaveview() call cursor(self.from, 1) + exe "silent! ".(self.to - self.from + 1)."foldopen!" exe "normal! ".(self.to - self.from + 1)."dd" call append(self.from - 1, new_lines) - call setpos('.', saved_cursor) + call winrestview(saved_original_buffer_view) call linediff#util#SwitchBuffer(self.diff_buffer) + set bufhidden=wipe " Keep the difference in lines to know how to update the other differ if " necessary. @@ -148,6 +194,7 @@ function! linediff#differ#UpdateOriginalBuffer() dict call self.SetupSigns() call self.PossiblyUpdateOtherDiffer(new_line_count - line_count) + call winrestview(saved_diff_buffer_view) endfunction " If the other differ originates from the same buffer and it's located below diff --git a/vimfiles/autoload/tcomment.vim b/vimfiles/autoload/tcomment.vim index eeecb11..34ff1e0 100644 --- a/vimfiles/autoload/tcomment.vim +++ b/vimfiles/autoload/tcomment.vim @@ -2,8 +2,8 @@ " @Website: http://www.vim.org/account/profile.php?user_id=4037 " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Created: 2007-09-17. -" @Last Change: 2014-02-05. -" @Revision: 1587 +" @Last Change: 2014-06-25. +" @Revision: 1656 " call tlog#Log('Load: '. expand('')) " vimtlib-sfile @@ -48,13 +48,15 @@ if !exists('g:tcommentOptions') endif if !exists('g:tcomment#options_comments') - " Options when using a the 'comments' option. - let g:tcomment#options_comments = {'whitespace': 'both'} "{{{2 + " Additional args for |tcomment#Comment()| when using the 'comments' + " option. + let g:tcomment#options_comments = {'whitespace': get(g:tcommentOptions, 'whitespace', 'both')} "{{{2 endif if !exists('g:tcomment#options_commentstring') - " Options when using a the 'commentstring' option. - let g:tcomment#options_commentstring = {'whitespace': 'both'} "{{{2 + " Additional args for |tcomment#Comment()| when using the + " 'commentstring' option. + let g:tcomment#options_commentstring = {'whitespace': get(g:tcommentOptions, 'whitespace', 'both')} "{{{2 endif if !exists('g:tcomment#ignore_char_type') @@ -252,6 +254,22 @@ if !exists('g:tcomment#ignore_comment_def') let g:tcomment#ignore_comment_def = [] "{{{2 endif +if !exists('g:tcomment#must_escape_expression_backslash') + " Users of vim earlier than 7.3 might have to set this variable to + " true. Set this variable to 0, if you see unexpected "\r" char + " sequences in comments. + " + " The reommended value was `!(v:version > 702 || (v:version == 702 && has('patch407')))`. + " It is now assumed though, that no unpatched versions of vim are in + " use. + " + " References: + " Patch 7.2.407 when using :s with an expression backslashes are dropped + " https://github.com/tomtom/tcomment_vim/issues/102 + let g:tcomment#must_escape_expression_backslash = 0 "{{{2 +endif + + let s:types_dirty = 1 let s:definitions = {} @@ -330,6 +348,7 @@ call tcomment#DefineType('ada', '-- %s' ) call tcomment#DefineType('apache', '# %s' ) call tcomment#DefineType('asciidoc', '// %s' ) call tcomment#DefineType('asm', '; %s' ) +call tcomment#DefineType('asterisk', '; %s' ) call tcomment#DefineType('blade', '{{-- %s --}}' ) call tcomment#DefineType('blade_block', '{{-- %s --}}' ) call tcomment#DefineType('blade_inline', '{{-- %s --}}' ) @@ -347,6 +366,7 @@ call tcomment#DefineType('clojurescript_inline', '; %s' ) call tcomment#DefineType('cmake', '# %s' ) call tcomment#DefineType('coffee', '# %s' ) call tcomment#DefineType('conf', '# %s' ) +call tcomment#DefineType('context', '%% %s' ) call tcomment#DefineType('conkyrc', '# %s' ) call tcomment#DefineType('cpp', '// %s' ) call tcomment#DefineType('cpp_block', g:tcommentBlockC ) @@ -371,6 +391,7 @@ call tcomment#DefineType('dsl', '; %s' ) call tcomment#DefineType('dustjs', '{! %s !}' ) call tcomment#DefineType('dylan', '// %s' ) call tcomment#DefineType('eiffel', '-- %s' ) +call tcomment#DefineType('elixir', '# %s' ) call tcomment#DefineType('erlang', '%%%% %s' ) call tcomment#DefineType('eruby', '<%%# %s' ) call tcomment#DefineType('esmtprc', '# %s' ) @@ -402,6 +423,7 @@ call tcomment#DefineType('htmljinja_block', "{%% comment %%}%s{%% endcomment %%} call tcomment#DefineType('hy', '; %s' ) call tcomment#DefineType('ini', '; %s' ) " php ini (/etc/php5/...) call tcomment#DefineType('io', '// %s' ) +call tcomment#DefineType('jade', '// %s' ) call tcomment#DefineType('jasmine', '# %s' ) call tcomment#DefineType('java', '/* %s */' ) call tcomment#DefineType('java_block', g:tcommentBlockC ) @@ -427,6 +449,7 @@ call tcomment#DefineType('msidl', '// %s' ) call tcomment#DefineType('msidl_block', g:tcommentBlockC ) call tcomment#DefineType('nginx', '# %s' ) call tcomment#DefineType('nroff', '.\\" %s' ) +call tcomment#DefineType('noweb', '%% %s' ) call tcomment#DefineType('nsis', '# %s' ) call tcomment#DefineType('objc', '/* %s */' ) call tcomment#DefineType('objc_block', g:tcommentBlockC ) @@ -449,6 +472,9 @@ call tcomment#DefineType('php_inline', g:tcommentInlineC ) call tcomment#DefineType('po', '# %s' ) call tcomment#DefineType('prolog', '%% %s' ) call tcomment#DefineType('puppet', '# %s' ) +call tcomment#DefineType('purescript', '-- %s' ) +call tcomment#DefineType('purescript_block', "{-%s-}\n " ) +call tcomment#DefineType('purescript_inline','{- %s -}' ) call tcomment#DefineType('python', '# %s' ) call tcomment#DefineType('qml', '// %s' ) call tcomment#DefineType('r', '# %s' ) @@ -588,11 +614,14 @@ let s:null_comment_string = '%s' " comment_mode (see also ¦g:tcommentModeExtra¦): " G ... guess the value of comment_mode " B ... block (use extra lines for the comment markers) +" L ... lines " i ... maybe inline, guess " I ... inline " R ... right (comment the line right of the cursor) " v ... visual " o ... operator +" C ... force comment +" U ... force uncomment (if U and C are present, U wins) " By default, each line in range will be commented by adding the comment " prefix and postfix. function! tcomment#Comment(beg, end, ...) @@ -634,9 +663,11 @@ function! tcomment#Comment(beg, end, ...) endif " TLogVAR comment_mode endif - if exists('s:temp_options') && has_key(s:temp_options, 'mode_extra') - let comment_mode = s:AddModeExtra(comment_mode, s:temp_options.mode_extra, lbeg, lend) - " TLogVAR comment_mode + let mode_extra = s:GetTempOption('mode_extra', '') + " TLogVAR mode_extra + if !empty(mode_extra) + let comment_mode = s:AddModeExtra(comment_mode, mode_extra, lbeg, lend) + " TLogVAR "mode_extra", comment_mode unlet s:temp_options.mode_extra endif " get the correct commentstring @@ -698,10 +729,10 @@ function! tcomment#Comment(beg, end, ...) " echom "DBG" string(a:000) let cms0 = s:BlockGetCommentRx(cdef) " TLogVAR cms0 - " make whitespace optional; this conflicts with comments that require some - " whitespace + "" make whitespace optional; this conflicts with comments that require some + "" whitespace let cmt_check = substitute(cms0, '\([ ]\)', '\1\\?', 'g') - " turn commentstring into a search pattern + "" turn commentstring into a search pattern " TLogVAR cmt_check let cmt_check = printf(cmt_check, '\(\_.\{-}\)') " TLogVAR cdef, cmt_check @@ -712,9 +743,12 @@ function! tcomment#Comment(beg, end, ...) " echom "DBG" string(s:cdef) let cbeg = get(s:cdef, 'col', cbeg) " TLogVAR cbeg - if comment_anyway + if mode_extra =~# 'U' + let uncomment = 1 + elseif mode_extra =~# 'C' || comment_anyway let uncomment = 0 endif + " TLogVAR comment_anyway, mode_extra, uncomment " go " TLogVAR comment_mode if comment_mode =~# 'B' @@ -805,6 +839,15 @@ else endif +function! s:GetTempOption(name, default) "{{{3 + if exists('s:temp_options') && has_key(s:temp_options, a:name) + return s:temp_options[a:name] + else + return a:default + endif +endf + + function! tcomment#SetOption(name, arg) "{{{3 " TLogVAR a:name, a:arg if !exists('s:temp_options') @@ -1063,7 +1106,7 @@ endf function! tcomment#OperatorLine(type) "{{{3 " TLogVAR a:type - call tcomment#Operator('line', 'G') + call tcomment#Operator('line', 'L') endf @@ -1075,7 +1118,7 @@ endf function! tcomment#OperatorLineAnyway(type) "{{{3 " TLogVAR a:type - call tcomment#Operator('line', 'G', '!') + call tcomment#Operator('line', 'L', '!') endf @@ -1235,12 +1278,12 @@ function! s:StartPosRx(comment_mode, line, col) endf -function! s:EndPosRx(comment_mode, line, col) - " TLogVAR a:comment_mode, a:line, a:col +function! s:EndPosRx(comment_mode, lnum, col) + " TLogVAR a:comment_mode, a:lnum, a:col " if a:comment_mode =~# 'I' - " return s:EndLineRx(a:line) . s:EndColRx(a:col) + " return s:EndLineRx(a:lnum) . s:EndColRx(a:col) " else - return s:EndColRx(a:comment_mode, a:col) + return s:EndColRx(a:comment_mode, a:lnum, a:col) " endif endf @@ -1276,9 +1319,12 @@ function! s:StartColRx(comment_mode, col, ...) endf -function! s:EndColRx(comment_mode, pos) - " TLogVAR a:comment_mode, a:pos - if a:pos == 0 +function! s:EndColRx(comment_mode, lnum, pos) + " TLogVAR a:comment_mode, a:lnum, a:pos + let line = getline(a:lnum) + let cend = s:Strdisplaywidth(line) + " TLogVAR cend + if a:pos == 0 || a:pos >= cend return '\$' else if a:comment_mode =~? 'i' && a:comment_mode =~# 'o' @@ -1302,7 +1348,7 @@ function! s:CommentDef(beg, end, checkRx, comment_mode, cbeg, cend) else let mdrx = '\V'. s:StartColRx(a:comment_mode, a:cbeg) .'\s\*' endif - let mdrx .= a:checkRx .'\s\*'. s:EndColRx(a:comment_mode, 0) + let mdrx .= a:checkRx .'\s\*'. s:EndColRx(a:comment_mode, a:end, 0) " let mdrx = '\V'. s:StartPosRx(a:comment_mode, beg, a:cbeg) .'\s\*'. a:checkRx .'\s\*'. s:EndPosRx(a:comment_mode, end, 0) " TLogVAR mdrx let line = getline(beg) @@ -1396,10 +1442,10 @@ function! s:ProcessLine(uncomment, match, checkRx, replace) endif endif " TLogVAR rv - if v:version > 702 || (v:version == 702 && has('patch407')) - let rv = escape(rv, "\r") - else + if g:tcomment#must_escape_expression_backslash let rv = escape(rv, "\\r") + else + let rv = escape(rv, "\r") endif " TLogVAR rv " let rv = substitute(rv, '\n', '\\\n', 'g') @@ -1482,8 +1528,10 @@ function! s:CommentBlock(beg, end, cbeg, cend, comment_mode, uncomment, checkRx, if a:uncomment let @t = substitute(@t, '\V\^\s\*'. a:checkRx .'\$', '\1', '') let tt = [] - let rx = '\V'. s:StartColRx(a:comment_mode, a:cbeg) . '\zs\s\*'. mx - " TLogVAR rx + " TODO: Correctly handle foreign comments with inconsistent + " whitespace around mx markers + let rx = '\V'. s:StartColRx(a:comment_mode, a:cbeg) . '\zs'. mx + " TLogVAR mx1, rx for line in split(@t, '\n') let line1 = substitute(line, rx, '', 'g') call add(tt, line1) @@ -1907,7 +1955,7 @@ function! s:GuessCustomCommentString(ft, comment_mode, ...) let default_cdef = a:0 >= 2 ? a:2 : {} let default_supports_comment_mode = get(default_cdef, 'comment_mode', custom_comment_mode) " TLogVAR default, default_supports_comment_mode - if comment_mode =~# '[IB]' && !empty(custom_comment_mode) + if comment_mode =~# '[ILB]' && !empty(custom_comment_mode) let def = tcomment#GetCommentDef(custom_comment_mode) " TLogVAR 1, def elseif !empty(custom_comment) diff --git a/vimfiles/doc/fugitive.txt b/vimfiles/doc/fugitive.txt index a5e61f5..0d186bf 100644 --- a/vimfiles/doc/fugitive.txt +++ b/vimfiles/doc/fugitive.txt @@ -1,38 +1,14 @@ *fugitive.txt* A Git wrapper so awesome, it should be illegal -Author: Tim Pope *fugitive-author* +Author: Tim Pope License: Same terms as Vim itself (see |license|) This plugin is only available if 'compatible' is not set. INTRODUCTION *fugitive* -Install in ~/.vim, or in ~\vimfiles if you're on Windows and feeling lucky. -Vim 7.2 is recommended as it ships with syntax highlighting for many Git file -types. - -If you're in a hurry to get started, here are some things to try: - -In any file in your repository, run |:Gedit| HEAD. Press to jump to the -current branch. Press again to jump to the top most commit. Keep using - to explore parent commits, trees, and blobs. Use C in a tree or blob to -get back to the commit. - -Edit a file in the work tree and make some changes. Use |:Gdiff| to open up -the indexed version. Use |do| and |dp| on various hunks to bring the files in -sync, or use |:Gread| to pull in all changes. Write the indexed version to -stage the file. - -Run |:Gstatus| to check your repository's status. Use "-" to stage and reset -files and "p" to add/reset --patch them. Invoke |:Gcommit| to commit your -changes. - -Run |:Gblame| in a work tree file to see a blame in a vertical split. Press - on any line to reopen and reblame that file as it stood in that commit. -Press o or O on any line to inspect that commit in a split or a tab. - -Run |:Ggrep| to search the work tree or history. Run |:Gmove| to rename a -file. Run |:Gremove| to delete a file. +Whenever you edit a file from a Git repository, a set of commands is defined +that serve as a gateway to Git. COMMANDS *fugitive-commands* @@ -43,6 +19,10 @@ that are part of Git repositories). :Git [args] Run an arbitrary git command. Similar to :!git [args] but chdir to the repository tree first. + *fugitive-:Git!* +:Git! [args] Like |:Git|, but capture the output into a temp file, + and edit that temp file. + *fugitive-:Gcd* :Gcd [directory] |:cd| relative to the repository. @@ -51,37 +31,87 @@ that are part of Git repositories). *fugitive-:Gstatus* :Gstatus Bring up the output of git-status in the preview - window. In addition to standard motions, you can - use and to jump from filename to - filename. Press C to invoke |:Gcommit|. Press D to - |:Gdiff| the file on the cursor line, or ds to - |:Gsdiff|. Press - to stage or unstage the file on - the cursor line. Press p to do so on a per hunk basis - (--patch). All of D, -, and p have a different, - sensible (and hopefully intuitive) behavior when - invoked on a heading rather than a file name. + window. The following maps, which work on the cursor + line file where sensible, are provided: + + g? show this help + next file + previous file + |:Gedit| + - |:Git| add + - |:Git| reset (staged files) + cA |:Gcommit| --amend --reuse-message=HEAD + ca |:Gcommit| --amend + cc |:Gcommit| + cva |:Gcommit| --amend --verbose + cvc |:Gcommit| --verbose + D |:Gdiff| + ds |:Gsdiff| + dp |:Git!| diff (p for patch; use :Gw to apply) + dp |:Git| add --intent-to-add (untracked files) + dv |:Gvdiff| + O |:Gtabedit| + o |:Gsplit| + p |:Git| add --patch + p |:Git| reset --patch (staged files) + q close status + r reload status + S |:Gvsplit| *fugitive-:Gcommit* :Gcommit [args] A wrapper around git-commit. If there is nothing to commit, |:Gstatus| is called instead. Unless the arguments given would skip the invocation of an editor (e.g., -m), a split window will be used to obtain a - commit message. Write and close that window (:wq or - |:Gwrite|) to finish the commit. Unlike when running - the actual git-commit command, it is possible (but - unadvisable) to muck with the index with commands like - git-add and git-reset while a commit message is - pending. + commit message, or a new tab if -v is given. Write + and close that window (:wq or |:Gwrite|) to finish the + commit. Unlike when running the actual git-commit + command, it is possible (but unadvisable) to alter the + index with commands like git-add and git-reset while a + commit message is pending. + + *fugitive-:Gmerge* +:Gmerge [args] Calls git-merge and loads errors and conflicted files + into the quickfix list. Opens a |:Gcommit| style + split window for the commit message if the merge + succeeds. If called during a merge conflict, the + conflicted files from the current index are loaded + into the quickfix list. + + *fugitive-:Gpull* +:Gpull [args] Like |:Gmerge|, but for git-pull. + + *fugitive-:Gpush* +:Gpush [args] Invoke git-push, load the results into the quickfix + list, and invoke |:cwindow| to reveal any errors. + |:Dispatch| is used if available for asynchronous + invocation. + + *fugitive-:Gfetch* +:Gfetch [args] Like |:Gpush|, but for git-fetch. *fugitive-:Ggrep* :Ggrep [args] |:grep| with git-grep as 'grepprg'. + *fugitive-:Glgrep* +:Glgrep [args] |:lgrep| with git-grep as 'grepprg'. + *fugitive-:Glog* :Glog [args] Load all previous revisions of the current file into the quickfix list. Additional git-log arguments can be given (for example, --reverse). If "--" appears as an argument, no file specific filtering is done, and - commits are loaded into the quickfix list. + previous commits rather than previous file revisions + are loaded. + +:{range}Glog [args] Use git-log -L to load previous revisions of the given + range of the current file into the quickfix list. The + cursor is positioned on the first line of the first + diff hunk for each commit. + + *fugitive-:Gllog* +:Gllog [args] Like |:Glog|, but use the location list instead of the + quickfix list. *fugitive-:Gedit* *fugitive-:Ge* :Gedit [revision] |:edit| a |fugitive-revision|. @@ -93,10 +123,15 @@ that are part of Git repositories). :Gvsplit [revision] |:vsplit| a |fugitive-revision|. *fugitive-:Gtabedit* -:Gtabedit [revision] |:tabedit| a |fugitive-revision| +:Gtabedit [revision] |:tabedit| a |fugitive-revision|. *fugitive-:Gpedit* -:Gpedit [revision] |:pedit| a |fugitive-revision| +:Gpedit [revision] |:pedit| a |fugitive-revision|. + +:Gsplit! [args] *fugitive-:Gsplit!* *fugitive-:Gvsplit!* +:Gvsplit! [args] *fugitive-:Gtabedit!* *fugitive-:Gpedit!* +:Gtabedit! [args] Like |:Git!|, but open the resulting temp file in a +:Gpedit! [args] split, tab, or preview window. *fugitive-:Gread* :Gread [revision] Empty the buffer and |:read| a |fugitive-revision|. @@ -107,7 +142,13 @@ that are part of Git repositories). :{range}Gread [revision] |:read| in a |fugitive-revision| after {range}. - *fugitive-:Gwrite* + *fugitive-:Gread!* +:Gread! [args] Empty the buffer and |:read| the output of a Git + command. For example, :Gread! show HEAD:%. + +:{range}Gread! [args] |:read| the output of a Git command after {range}. + + *fugitive-:Gw* *fugitive-:Gwrite* :Gwrite Write to the current file's path and stage the results. When run in a work tree file, it is effectively git add. Elsewhere, it is effectively git-checkout. A @@ -133,14 +174,16 @@ that are part of Git repositories). index is used (which means a three-way diff during a merge conflict, making it a git-mergetool alternative). The newer of the two files is placed - to the right. Use |do| and |dp| and write to the - index file to simulate "git add --patch". + to the right or bottom, depending on 'diffopt' and + the width of the window relative to 'textwidth'. Use + |do| and |dp| and write to the index file to simulate + "git add --patch". *fugitive-:Gsdiff* -:Gsdiff [revision] Like |:Gdiff|, but split horizontally. +:Gsdiff [revision] Like |:Gdiff|, but always split horizontally. *fugitive-:Gvdiff* -:Gvdiff [revision] Identical to |:Gdiff|. For symmetry with |:Gsdiff|. +:Gvdiff [revision] Like |:Gdiff|, but always split vertically. *fugitive-:Gmove* :Gmove {destination} Wrapper around git-mv that renames the buffer @@ -156,10 +199,23 @@ that are part of Git repositories). *fugitive-:Gblame* :Gblame [flags] Run git-blame on the file and open the results in a - scroll bound vertical split. Press enter on a line to - reblame the file as it was in that commit. You can - give any of ltwfsMC as flags and they will be passed - along to git-blame. + scroll bound vertical split. You can give any of + ltfnsewMC as flags and they will be passed along to + git-blame. The following maps, which work on the + cursor line commit where sensible, are provided: + + g? show this help + A resize to end of author column + C resize to end of commit column + D resize to end of date/time column + q close blame and return to blamed window + gq q, then |:Gedit| to return to work tree version + q, then open commit + o open commit in horizontal split + O open commit in new tab + - reblame at commit + ~ reblame at [count]th first grandparent + P reblame at [count]th parent (like HEAD^[count]) :[range]Gblame [flags] Run git-blame on the given range. @@ -172,6 +228,11 @@ that are part of Git repositories). "git instaweb" from a terminal). If a range is given, it is appropriately appended to the URL as an anchor. + To use with GitHub FI, point g:fugitive_github_domains + at a list of domains: +> + let g:fugitive_github_domains = ['https://example.com'] +~ :[range]Gbrowse! Like :Gbrowse, but put the URL on the clipboard rather than opening it. @@ -187,6 +248,16 @@ that are part of Git repositories). MAPPINGS *fugitive-mappings* +These maps are available everywhere. + + *fugitive-c_CTRL-R_CTRL-G* + On the command line, recall the path to the current + object (that is, a representation of the object + recognized by |:Gedit|). + + *fugitive-y_CTRL-G* +["x]y Yank the commit SHA and path to the current object. + These maps are available in Git objects. *fugitive-* @@ -195,9 +266,16 @@ These maps are available in Git objects. *fugitive-o* o Jump to the revision under the cursor in a new split. + *fugitive-S* +S Jump to the revision under the cursor in a new + vertical split. + *fugitive-O* O Jump to the revision under the cursor in a new tab. + *fugitive--* +- Go to the tree containing the current tree or blob. + *fugitive-~* ~ Go to the current file in the [count]th first ancestor. @@ -208,6 +286,10 @@ P Go to the current file in the [count]th parent. *fugitive-C* C Go to the commit containing the current file. + *fugitive-.* +. Start a |:| command line with the current revision + prepopulated at the end of the line. + *fugitive-a* a Show the current tag, commit, or tree in an alternate format. @@ -248,6 +330,12 @@ a statusline, this one matches the default when 'ruler' is set: > set statusline=%<%f\ %h%m%r%{fugitive#statusline()}%=%-14.(%l,%c%V%)\ %P < + *fugitive#head(...)* +Use fugitive#head() to return the name of the current branch. If the current +HEAD is detached, fugitive#head() will return the empty string, unless the +optional argument is given, in which case the hash of the current commit will +be truncated to the given number of characters. + ABOUT *fugitive-about* Grab the latest version or report a bug on GitHub: diff --git a/vimfiles/doc/linediff.txt b/vimfiles/doc/linediff.txt index e6e21ed..3d0757e 100644 --- a/vimfiles/doc/linediff.txt +++ b/vimfiles/doc/linediff.txt @@ -1,9 +1,12 @@ +*linediff.txt* Diff two blocks of text + ============================================================================== CONTENTS *linediff* *linediff-contents* Installation...........................: |linediff-installation| Usage..................................: |linediff-usage| Commands...............................: |linediff-commands| + Settings...............................: |linediff-settings| Internals..............................: |linediff-internals| Issues.................................: |linediff-issues| @@ -24,7 +27,7 @@ The command is (provided you're in ~/.vim): git submodule add git://github.com/AndrewRadev/linediff.vim.git bundle/linediff < -Another way is to simply copy all the essential directories inside the ~.vim/ +Another way is to simply copy all the essential directories inside the ~/.vim directory: plugin, autoload, doc. ============================================================================== @@ -87,10 +90,72 @@ COMMANDS *linediff-commands* *:LinediffReset* -:LinediffReset Removes the signs denoting the diffed regions and deletes +:LinediffReset[!] Removes the signs denoting the diffed regions and deletes the temporary buffers, used for the diff. The original buffers are untouched by this, which means that any updates to them, performed by the diff process will remain. + Specifying ! discards unsaved changes made in the temporary + buffers. + +============================================================================== +SETTINGS *linediff-settings* + + *g:linediff_indent* +> + let g:linediff_indent = 1 +< + +Default value: 0 + +If this flag is set to 1, linediff will reindent the diffed sections in order +to minimize differences caused by formatting. This may change the buffers' +contents. + + *g:linediff_buffer_type* +> + let g:linediff_buffer_type = 'scratch' +< +Default value: "tempfile" + +This variable can have one of two values, "scratch" or "tempfile". + +If it is set to "scratch", the created proxy buffer is not connected to any +file. The benefit is that the filename can then be set to be an informative +string instead of a weird temporary filename. The drawback is that you can't +run some external commands on this buffer, since there is no real backing +file. + +If it is set to "tempfile" (the default), the proxy buffer is actually a +temporary file. The benefit is that you run external commands that expect an +actual file (like executing |:make|). The drawback is that the only way to +display information on the proxy is by hacking the statusline, which may cause +issues and can't work reliably on all statuslines. + + *g:linediff_first_buffer_command* + *g:linediff_second_buffer_command* +> + let g:linediff_first_buffer_command = 'new' + let g:linediff_second_buffer_command = 'vertical new' +< + +Default values: "tabnew" and "rightbelow vertical new", respectively. + +These variables control what commands are used to open the two temporary +buffers. By default, the first one will open a blank new tab, and the second +one will split it vertically, from the right. This should ensure a pretty +sensible setup. + +As an example, you can set them like so: +> + let g:linediff_first_buffer_command = 'leftabove new' + let g:linediff_second_buffer_command = 'rightbelow vertical new' +< +With this, the buffers will be positioned in a split above the current buffer, +the first one on the left, and the second one on the right. + +You can control the positioning with judicious use of |:rightbelow| and +|:leftabove|. If you omit these commands, the view will simply follow your +default settings when opening new splits. ============================================================================== INTERNALS *linediff-internals* diff --git a/vimfiles/doc/tags b/vimfiles/doc/tags index 8d53934..2ea5303 100644 --- a/vimfiles/doc/tags +++ b/vimfiles/doc/tags @@ -1529,7 +1529,10 @@ ex-visincr-IYMD visincr.txt /*ex-visincr-IYMD* fetch pi_netrw.txt /*fetch* ftp pi_netrw.txt /*ftp* fugitive fugitive.txt /*fugitive* +fugitive#head(...) fugitive.txt /*fugitive#head(...)* fugitive#statusline() fugitive.txt /*fugitive#statusline()* +fugitive-- fugitive.txt /*fugitive--* +fugitive-. fugitive.txt /*fugitive-.* fugitive-:Gblame fugitive.txt /*fugitive-:Gblame* fugitive-:Gbrowse fugitive.txt /*fugitive-:Gbrowse* fugitive-:Gcd fugitive.txt /*fugitive-:Gcd* @@ -1537,34 +1540,49 @@ fugitive-:Gcommit fugitive.txt /*fugitive-:Gcommit* fugitive-:Gdiff fugitive.txt /*fugitive-:Gdiff* fugitive-:Ge fugitive.txt /*fugitive-:Ge* fugitive-:Gedit fugitive.txt /*fugitive-:Gedit* +fugitive-:Gfetch fugitive.txt /*fugitive-:Gfetch* fugitive-:Ggrep fugitive.txt /*fugitive-:Ggrep* fugitive-:Git fugitive.txt /*fugitive-:Git* +fugitive-:Git! fugitive.txt /*fugitive-:Git!* fugitive-:Glcd fugitive.txt /*fugitive-:Glcd* +fugitive-:Glgrep fugitive.txt /*fugitive-:Glgrep* +fugitive-:Gllog fugitive.txt /*fugitive-:Gllog* fugitive-:Glog fugitive.txt /*fugitive-:Glog* +fugitive-:Gmerge fugitive.txt /*fugitive-:Gmerge* fugitive-:Gmove fugitive.txt /*fugitive-:Gmove* fugitive-:Gpedit fugitive.txt /*fugitive-:Gpedit* +fugitive-:Gpedit! fugitive.txt /*fugitive-:Gpedit!* +fugitive-:Gpull fugitive.txt /*fugitive-:Gpull* +fugitive-:Gpush fugitive.txt /*fugitive-:Gpush* fugitive-:Gread fugitive.txt /*fugitive-:Gread* +fugitive-:Gread! fugitive.txt /*fugitive-:Gread!* fugitive-:Gremove fugitive.txt /*fugitive-:Gremove* fugitive-:Gsdiff fugitive.txt /*fugitive-:Gsdiff* fugitive-:Gsplit fugitive.txt /*fugitive-:Gsplit* +fugitive-:Gsplit! fugitive.txt /*fugitive-:Gsplit!* fugitive-:Gstatus fugitive.txt /*fugitive-:Gstatus* fugitive-:Gtabedit fugitive.txt /*fugitive-:Gtabedit* +fugitive-:Gtabedit! fugitive.txt /*fugitive-:Gtabedit!* fugitive-:Gvdiff fugitive.txt /*fugitive-:Gvdiff* fugitive-:Gvsplit fugitive.txt /*fugitive-:Gvsplit* +fugitive-:Gvsplit! fugitive.txt /*fugitive-:Gvsplit!* +fugitive-:Gw fugitive.txt /*fugitive-:Gw* fugitive-:Gwq fugitive.txt /*fugitive-:Gwq* fugitive-:Gwrite fugitive.txt /*fugitive-:Gwrite* fugitive- fugitive.txt /*fugitive-* fugitive-C fugitive.txt /*fugitive-C* fugitive-O fugitive.txt /*fugitive-O* fugitive-P fugitive.txt /*fugitive-P* +fugitive-S fugitive.txt /*fugitive-S* fugitive-a fugitive.txt /*fugitive-a* fugitive-about fugitive.txt /*fugitive-about* -fugitive-author fugitive.txt /*fugitive-author* +fugitive-c_CTRL-R_CTRL-G fugitive.txt /*fugitive-c_CTRL-R_CTRL-G* fugitive-commands fugitive.txt /*fugitive-commands* fugitive-mappings fugitive.txt /*fugitive-mappings* fugitive-o fugitive.txt /*fugitive-o* fugitive-revision fugitive.txt /*fugitive-revision* fugitive-statusline fugitive.txt /*fugitive-statusline* +fugitive-y_CTRL-G fugitive.txt /*fugitive-y_CTRL-G* fugitive-~ fugitive.txt /*fugitive-~* fugitive.txt fugitive.txt /*fugitive.txt* g% matchit.txt /*g%* @@ -1577,6 +1595,10 @@ g:Netrw_corehandler pi_netrw.txt /*g:Netrw_corehandler* g:Netrw_funcref pi_netrw.txt /*g:Netrw_funcref* g:alignmaps_euronumber Align.txt /*g:alignmaps_euronumber* g:alignmaps_usanumber Align.txt /*g:alignmaps_usanumber* +g:linediff_buffer_type linediff.txt /*g:linediff_buffer_type* +g:linediff_first_buffer_command linediff.txt /*g:linediff_first_buffer_command* +g:linediff_indent linediff.txt /*g:linediff_indent* +g:linediff_second_buffer_command linediff.txt /*g:linediff_second_buffer_command* g:netrw_altfile pi_netrw.txt /*g:netrw_altfile* g:netrw_alto pi_netrw.txt /*g:netrw_alto* g:netrw_altv pi_netrw.txt /*g:netrw_altv* @@ -1662,6 +1684,7 @@ g:netrw_xstrlen pi_netrw.txt /*g:netrw_xstrlen* g:tcomment#blank_lines tcomment.txt /*g:tcomment#blank_lines* g:tcomment#ignore_char_type tcomment.txt /*g:tcomment#ignore_char_type* g:tcomment#ignore_comment_def tcomment.txt /*g:tcomment#ignore_comment_def* +g:tcomment#must_escape_expression_backslash tcomment.txt /*g:tcomment#must_escape_expression_backslash* g:tcomment#options_comments tcomment.txt /*g:tcomment#options_comments* g:tcomment#options_commentstring tcomment.txt /*g:tcomment#options_commentstring* g:tcomment#replacements_c tcomment.txt /*g:tcomment#replacements_c* @@ -1685,8 +1708,9 @@ g:tcommentInlineC tcomment.txt /*g:tcommentInlineC* g:tcommentInlineXML tcomment.txt /*g:tcommentInlineXML* g:tcommentMapLeader1 tcomment.txt /*g:tcommentMapLeader1* g:tcommentMapLeader2 tcomment.txt /*g:tcommentMapLeader2* +g:tcommentMapLeaderCommentAnyway tcomment.txt /*g:tcommentMapLeaderCommentAnyway* g:tcommentMapLeaderOp1 tcomment.txt /*g:tcommentMapLeaderOp1* -g:tcommentMapLeaderOp2 tcomment.txt /*g:tcommentMapLeaderOp2* +g:tcommentMapLeaderUncommentAnyway tcomment.txt /*g:tcommentMapLeaderUncommentAnyway* g:tcommentMaps tcomment.txt /*g:tcommentMaps* g:tcommentModeExtra tcomment.txt /*g:tcommentModeExtra* g:tcommentOpModeExtra tcomment.txt /*g:tcommentOpModeExtra* @@ -1749,7 +1773,9 @@ linediff-contents linediff.txt /*linediff-contents* linediff-installation linediff.txt /*linediff-installation* linediff-internals linediff.txt /*linediff-internals* linediff-issues linediff.txt /*linediff-issues* +linediff-settings linediff.txt /*linediff-settings* linediff-usage linediff.txt /*linediff-usage* +linediff.txt linediff.txt /*linediff.txt* local_markfilelist pi_netrw.txt /*local_markfilelist* logipat LogiPat.txt /*logipat* logipat-arg LogiPat.txt /*logipat-arg* @@ -1790,9 +1816,12 @@ matchit-troubleshoot matchit.txt /*matchit-troubleshoot* matchit-v_% matchit.txt /*matchit-v_%* matchit.txt matchit.txt /*matchit.txt* matchit.vim matchit.txt /*matchit.vim* -n_TComment-gC tcomment.txt /*n_TComment-gC* -n_TComment-gCb tcomment.txt /*n_TComment-gCb* -n_TComment-gCc tcomment.txt /*n_TComment-gCc* +n_TComment-Comment tcomment.txt /*n_TComment-Comment* +n_TComment-Commentb tcomment.txt /*n_TComment-Commentb* +n_TComment-Commentc tcomment.txt /*n_TComment-Commentc* +n_TComment-Uncomment tcomment.txt /*n_TComment-Uncomment* +n_TComment-Uncommentb tcomment.txt /*n_TComment-Uncommentb* +n_TComment-Uncommentc tcomment.txt /*n_TComment-Uncommentc* n_TComment-gc tcomment.txt /*n_TComment-gc* n_TComment-gcb tcomment.txt /*n_TComment-gcb* n_TComment-gcc tcomment.txt /*n_TComment-gcc* @@ -2100,7 +2129,8 @@ visincr-usage visincr.txt /*visincr-usage* visincr.txt visincr.txt /*visincr.txt* x_TComment-__ tcomment.txt /*x_TComment-__* x_TComment-_i tcomment.txt /*x_TComment-_i* -x_TComment-gC tcomment.txt /*x_TComment-gC* +x_TComment-Comment tcomment.txt /*x_TComment-Comment* +x_TComment-Uncomment tcomment.txt /*x_TComment-Uncomment* x_TComment-gc tcomment.txt /*x_TComment-gc* xml-plugin-callbacks xml-plugin.txt /*xml-plugin-callbacks* xml-plugin-html xml-plugin.txt /*xml-plugin-html* diff --git a/vimfiles/doc/tcomment.txt b/vimfiles/doc/tcomment.txt index f2dea38..0917d60 100644 --- a/vimfiles/doc/tcomment.txt +++ b/vimfiles/doc/tcomment.txt @@ -40,8 +40,16 @@ and |g:tcommentMapLeaderOp2|): gcc{motion} :: Toggle comment text with count argument (see |tcomment#Comment()|) gcc :: Toggle comment for the current line - gC{motion} :: Comment region - gCc :: Comment the current line + +Explicit commenting/uncommenting: + + g<{motion} :: Uncomment region + g{motion} :: Comment region + g>c :: Comment the current line + g>b :: Comment the current region as block In visual mode: @@ -124,100 +132,106 @@ please make sure, you have the current version of vimball (vimscript ======================================================================== Contents~ - g:tcommentMaps ...................... |g:tcommentMaps| - g:tcommentMapLeader1 ................ |g:tcommentMapLeader1| - g:tcommentMapLeader2 ................ |g:tcommentMapLeader2| - g:tcommentMapLeaderOp1 .............. |g:tcommentMapLeaderOp1| - g:tcommentMapLeaderOp2 .............. |g:tcommentMapLeaderOp2| - g:tcommentTextObjectInlineComment ... |g:tcommentTextObjectInlineComment| - :TComment ........................... |:TComment| - :TCommentAs ......................... |:TCommentAs| - :TCommentRight ...................... |:TCommentRight| - :TCommentBlock ...................... |:TCommentBlock| - :TCommentInline ..................... |:TCommentInline| - :TCommentMaybeInline ................ |:TCommentMaybeInline| - TComment- ........... |TComment-| - v_TComment- ......... |v_TComment-| - i_TComment- ......... |i_TComment-| - TComment-p ............... |TComment-p| - i_TComment-p ............. |i_TComment-p| - TComment- ......... |TComment-| - i_TComment- ....... |i_TComment-| - i_TComment-r ............. |i_TComment-r| - TComment-r ............... |TComment-r| - v_TComment-i ............. |v_TComment-i| - TComment-i ............... |TComment-i| - i_TComment-i ............. |i_TComment-i| - TComment-b ............... |TComment-b| - i_TComment-b ............. |i_TComment-b| - TComment-a ............... |TComment-a| - i_TComment-a ............. |i_TComment-a| - TComment-n ............... |TComment-n| - i_TComment-n ............. |i_TComment-n| - TComment-s ............... |TComment-s| - i_TComment-s ............. |i_TComment-s| - TComment-cc .............. |TComment-cc| - TComment-ca .............. |TComment-ca| - TComment-__ ........... |TComment-__| - x_TComment-__ ......... |x_TComment-__| - TComment-_p ........... |TComment-_p| - TComment-_ ..... |TComment-_| - x_TComment-_i ......... |x_TComment-_i| - TComment-_r ........... |TComment-_r| - TComment-_b ........... |TComment-_b| - TComment-_a ........... |TComment-_a| - TComment-_n ........... |TComment-_n| - TComment-_s ........... |TComment-_s| - n_TComment-gC ................. |n_TComment-gC| - n_TComment-gCc ................ |n_TComment-gCc| - n_TComment-gCb ................ |n_TComment-gCb| - x_TComment-gC ................. |x_TComment-gC| - v_TComment-ic ................. |v_TComment-ic| - TComment-ic ................... |TComment-ic| - n_TComment-gcc ................ |n_TComment-gcc| - n_TComment-gcb ................ |n_TComment-gcb| - x_TComment-gc ................. |x_TComment-gc| - n_TComment-gc ................. |n_TComment-gc| - g:tcomment#blank_lines .............. |g:tcomment#blank_lines| - g:tcomment#rstrip_on_uncomment ...... |g:tcomment#rstrip_on_uncomment| - g:tcommentModeExtra ................. |g:tcommentModeExtra| - g:tcommentOpModeExtra ............... |g:tcommentOpModeExtra| - g:tcommentOptions ................... |g:tcommentOptions| - g:tcomment#options_comments ......... |g:tcomment#options_comments| - g:tcomment#options_commentstring .... |g:tcomment#options_commentstring| - g:tcomment#ignore_char_type ......... |g:tcomment#ignore_char_type| - g:tcommentGuessFileType ............. |g:tcommentGuessFileType| - g:tcommentGuessFileType_dsl ......... |g:tcommentGuessFileType_dsl| - g:tcommentGuessFileType_php ......... |g:tcommentGuessFileType_php| - g:tcommentGuessFileType_blade ....... |g:tcommentGuessFileType_blade| - g:tcommentGuessFileType_html ........ |g:tcommentGuessFileType_html| - g:tcommentGuessFileType_tskeleton ... |g:tcommentGuessFileType_tskeleton| - g:tcommentGuessFileType_vim ......... |g:tcommentGuessFileType_vim| - g:tcommentGuessFileType_django ...... |g:tcommentGuessFileType_django| - g:tcommentGuessFileType_eruby ....... |g:tcommentGuessFileType_eruby| - g:tcommentGuessFileType_smarty ...... |g:tcommentGuessFileType_smarty| - g:tcommentIgnoreTypes_php ........... |g:tcommentIgnoreTypes_php| - g:tcomment#syntax_substitute ........ |g:tcomment#syntax_substitute| - g:tcommentSyntaxMap ................. |g:tcommentSyntaxMap| - g:tcomment#replacements_c ........... |g:tcomment#replacements_c| - g:tcommentInlineC ................... |g:tcommentInlineC| - g:tcommentBlockC2 ................... |g:tcommentBlockC2| - g:tcomment#replacements_xml ......... |g:tcomment#replacements_xml| - g:tcommentBlockXML .................. |g:tcommentBlockXML| - g:tcommentInlineXML ................. |g:tcommentInlineXML| - g:tcomment#ignore_comment_def ....... |g:tcomment#ignore_comment_def| - tcomment#DefineType ................. |tcomment#DefineType()| - tcomment#GetCommentDef .............. |tcomment#GetCommentDef()| - g:tcomment_types .................... |g:tcomment_types| - tcomment#Comment .................... |tcomment#Comment()| - tcomment#SetOption .................. |tcomment#SetOption()| - tcomment#Operator ................... |tcomment#Operator()| - tcomment#OperatorLine ............... |tcomment#OperatorLine()| - tcomment#OperatorAnyway ............. |tcomment#OperatorAnyway()| - tcomment#OperatorLineAnyway ......... |tcomment#OperatorLineAnyway()| - tcomment#CommentAs .................. |tcomment#CommentAs()| - tcomment#GuessCommentType ........... |tcomment#GuessCommentType()| - tcomment#TextObjectInlineComment .... |tcomment#TextObjectInlineComment()| + g:tcommentMaps ................................ |g:tcommentMaps| + g:tcommentMapLeader1 .......................... |g:tcommentMapLeader1| + g:tcommentMapLeader2 .......................... |g:tcommentMapLeader2| + g:tcommentMapLeaderOp1 ........................ |g:tcommentMapLeaderOp1| + g:tcommentMapLeaderUncommentAnyway ............ |g:tcommentMapLeaderUncommentAnyway| + g:tcommentMapLeaderCommentAnyway .............. |g:tcommentMapLeaderCommentAnyway| + g:tcommentTextObjectInlineComment ............. |g:tcommentTextObjectInlineComment| + :TComment ..................................... |:TComment| + :TCommentAs ................................... |:TCommentAs| + :TCommentRight ................................ |:TCommentRight| + :TCommentBlock ................................ |:TCommentBlock| + :TCommentInline ............................... |:TCommentInline| + :TCommentMaybeInline .......................... |:TCommentMaybeInline| + TComment- ..................... |TComment-| + v_TComment- ................... |v_TComment-| + i_TComment- ................... |i_TComment-| + TComment-p ......................... |TComment-p| + i_TComment-p ....................... |i_TComment-p| + TComment- ................... |TComment-| + i_TComment- ................. |i_TComment-| + i_TComment-r ....................... |i_TComment-r| + TComment-r ......................... |TComment-r| + v_TComment-i ....................... |v_TComment-i| + TComment-i ......................... |TComment-i| + i_TComment-i ....................... |i_TComment-i| + TComment-b ......................... |TComment-b| + i_TComment-b ....................... |i_TComment-b| + TComment-a ......................... |TComment-a| + i_TComment-a ....................... |i_TComment-a| + TComment-n ......................... |TComment-n| + i_TComment-n ....................... |i_TComment-n| + TComment-s ......................... |TComment-s| + i_TComment-s ....................... |i_TComment-s| + TComment-cc ........................ |TComment-cc| + TComment-ca ........................ |TComment-ca| + TComment-__ ..................... |TComment-__| + x_TComment-__ ................... |x_TComment-__| + TComment-_p ..................... |TComment-_p| + TComment-_ ............... |TComment-_| + x_TComment-_i ................... |x_TComment-_i| + TComment-_r ..................... |TComment-_r| + TComment-_b ..................... |TComment-_b| + TComment-_a ..................... |TComment-_a| + TComment-_n ..................... |TComment-_n| + TComment-_s ..................... |TComment-_s| + n_TComment-Uncomment .................... |n_TComment-Uncomment| + n_TComment-Uncommentc ................... |n_TComment-Uncommentc| + n_TComment-Uncommentb ................... |n_TComment-Uncommentb| + x_TComment-Uncomment .................... |x_TComment-Uncomment| + n_TComment-Comment ...................... |n_TComment-Comment| + n_TComment-Commentc ..................... |n_TComment-Commentc| + n_TComment-Commentb ..................... |n_TComment-Commentb| + x_TComment-Comment ...................... |x_TComment-Comment| + v_TComment-ic ........................... |v_TComment-ic| + TComment-ic ............................. |TComment-ic| + n_TComment-gcc .......................... |n_TComment-gcc| + n_TComment-gcb .......................... |n_TComment-gcb| + x_TComment-gc ........................... |x_TComment-gc| + n_TComment-gc ........................... |n_TComment-gc| + g:tcomment#blank_lines ........................ |g:tcomment#blank_lines| + g:tcomment#rstrip_on_uncomment ................ |g:tcomment#rstrip_on_uncomment| + g:tcommentModeExtra ........................... |g:tcommentModeExtra| + g:tcommentOpModeExtra ......................... |g:tcommentOpModeExtra| + g:tcommentOptions ............................. |g:tcommentOptions| + g:tcomment#options_comments ................... |g:tcomment#options_comments| + g:tcomment#options_commentstring .............. |g:tcomment#options_commentstring| + g:tcomment#ignore_char_type ................... |g:tcomment#ignore_char_type| + g:tcommentGuessFileType ....................... |g:tcommentGuessFileType| + g:tcommentGuessFileType_dsl ................... |g:tcommentGuessFileType_dsl| + g:tcommentGuessFileType_php ................... |g:tcommentGuessFileType_php| + g:tcommentGuessFileType_blade ................. |g:tcommentGuessFileType_blade| + g:tcommentGuessFileType_html .................. |g:tcommentGuessFileType_html| + g:tcommentGuessFileType_tskeleton ............. |g:tcommentGuessFileType_tskeleton| + g:tcommentGuessFileType_vim ................... |g:tcommentGuessFileType_vim| + g:tcommentGuessFileType_django ................ |g:tcommentGuessFileType_django| + g:tcommentGuessFileType_eruby ................. |g:tcommentGuessFileType_eruby| + g:tcommentGuessFileType_smarty ................ |g:tcommentGuessFileType_smarty| + g:tcommentIgnoreTypes_php ..................... |g:tcommentIgnoreTypes_php| + g:tcomment#syntax_substitute .................. |g:tcomment#syntax_substitute| + g:tcommentSyntaxMap ........................... |g:tcommentSyntaxMap| + g:tcomment#replacements_c ..................... |g:tcomment#replacements_c| + g:tcommentInlineC ............................. |g:tcommentInlineC| + g:tcommentBlockC2 ............................. |g:tcommentBlockC2| + g:tcomment#replacements_xml ................... |g:tcomment#replacements_xml| + g:tcommentBlockXML ............................ |g:tcommentBlockXML| + g:tcommentInlineXML ........................... |g:tcommentInlineXML| + g:tcomment#ignore_comment_def ................. |g:tcomment#ignore_comment_def| + g:tcomment#must_escape_expression_backslash ... |g:tcomment#must_escape_expression_backslash| + tcomment#DefineType ........................... |tcomment#DefineType()| + tcomment#GetCommentDef ........................ |tcomment#GetCommentDef()| + g:tcomment_types .............................. |g:tcomment_types| + tcomment#Comment .............................. |tcomment#Comment()| + tcomment#SetOption ............................ |tcomment#SetOption()| + tcomment#Operator ............................. |tcomment#Operator()| + tcomment#OperatorLine ......................... |tcomment#OperatorLine()| + tcomment#OperatorAnyway ....................... |tcomment#OperatorAnyway()| + tcomment#OperatorLineAnyway ................... |tcomment#OperatorLineAnyway()| + tcomment#CommentAs ............................ |tcomment#CommentAs()| + tcomment#GuessCommentType ..................... |tcomment#GuessCommentType()| + tcomment#TextObjectInlineComment .............. |tcomment#TextObjectInlineComment()| ======================================================================== @@ -241,8 +255,12 @@ g:tcommentMapLeader2 (default: '_') g:tcommentMapLeaderOp1 (default: 'gc') See |tcomment-operator|. - *g:tcommentMapLeaderOp2* -g:tcommentMapLeaderOp2 (default: 'gC') + *g:tcommentMapLeaderUncommentAnyway* +g:tcommentMapLeaderUncommentAnyway (default: 'g<') + See |tcomment-operator|. + + *g:tcommentMapLeaderCommentAnyway* +g:tcommentMapLeaderCommentAnyway (default: 'g>') See |tcomment-operator|. *g:tcommentTextObjectInlineComment* @@ -402,17 +420,29 @@ x_TComment-_i ... :TCommentInline *TComment-_s* TComment-_s ... :TCommentAs =&ft_ - *n_TComment-gC* -n_TComment-gC ... :let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ + *n_TComment-Uncomment* +n_TComment-Uncomment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ - *n_TComment-gCc* -n_TComment-gCc ... :let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ + *n_TComment-Uncommentc* +n_TComment-Uncommentc ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ - *n_TComment-gCb* -n_TComment-gCb ... :let w:tcommentPos = getpos(".") \| call tcomment#SetOption("mode_extra", "B") \| set opfunc=tcomment#OperatorLineg@ + *n_TComment-Uncommentb* +n_TComment-Uncommentb ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "UB") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@ - *x_TComment-gC* -x_TComment-gC ... :TCommentMaybeInline! + *x_TComment-Uncomment* +x_TComment-Uncomment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| '<,'>TCommentMaybeInline + + *n_TComment-Comment* +n_TComment-Comment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ + + *n_TComment-Commentc* +n_TComment-Commentc ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ + + *n_TComment-Commentb* +n_TComment-Commentb ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "B") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@ + + *x_TComment-Comment* +x_TComment-Comment ... :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| '<,'>TCommentMaybeInline! *v_TComment-ic* v_TComment-ic ... :call tcomment#TextObjectInlineComment() @@ -473,12 +503,14 @@ g:tcommentOptions (default: {}) < *g:tcomment#options_comments* -g:tcomment#options_comments (default: {'whitespace': 'both'}) - Options when using a the 'comments' option. +g:tcomment#options_comments (default: {'whitespace': get(g:tcommentOptions, 'whitespace', 'both')}) + Additional args for |tcomment#Comment()| when using the 'comments' + option. *g:tcomment#options_commentstring* -g:tcomment#options_commentstring (default: {'whitespace': 'both'}) - Options when using a the 'commentstring' option. +g:tcomment#options_commentstring (default: {'whitespace': get(g:tcommentOptions, 'whitespace', 'both')}) + Additional args for |tcomment#Comment()| when using the + 'commentstring' option. *g:tcomment#ignore_char_type* g:tcomment#ignore_char_type (default: 1) @@ -582,6 +614,20 @@ g:tcomment#ignore_comment_def (default: []) This variable should be set before loading autoload/tcomment.vim. + *g:tcomment#must_escape_expression_backslash* +g:tcomment#must_escape_expression_backslash (default: 0) + Users of vim earlier than 7.3 might have to set this variable to + true. Set this variable to 0, if you see unexpected "\r" char + sequences in comments. + + The reommended value was `!(v:version > 702 || (v:version == 702 && has('patch407')))`. + It is now assumed though, that no unpatched versions of vim are in + use. + + References: + Patch 7.2.407 when using :s with an expression backslashes are dropped + https://github.com/tomtom/tcomment_vim/issues/102 + *tcomment#DefineType()* tcomment#DefineType(name, commentdef, ?cdef={}, ?anyway=0) If you don't explicitly define a comment style, |:TComment| will use @@ -670,11 +716,14 @@ tcomment#Comment(beg, end, ...) comment_mode (see also ¦g:tcommentModeExtra¦): G ... guess the value of comment_mode B ... block (use extra lines for the comment markers) + L ... lines i ... maybe inline, guess I ... inline R ... right (comment the line right of the cursor) v ... visual o ... operator + C ... force comment + U ... force uncomment (if U and C are present, U wins) By default, each line in range will be commented by adding the comment prefix and postfix. @@ -724,4 +773,4 @@ tcomment#TextObjectInlineComment() -vim:tw=78:fo=tcq2:isk=!-~,^*,^|,^":ts=8:ft=help:norl: +vim:tw=78:fo=w2croql:isk=!-~,^*,^|,^":ts=8:ft=help:norl: diff --git a/vimfiles/plugin/fugitive.vim b/vimfiles/plugin/fugitive.vim index 048089e..c880351 100644 --- a/vimfiles/plugin/fugitive.vim +++ b/vimfiles/plugin/fugitive.vim @@ -1,6 +1,6 @@ " fugitive.vim - A Git wrapper so awesome, it should be illegal -" Maintainer: Tim Pope -" Version: 1.2 +" Maintainer: Tim Pope +" Version: 2.2 " GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim if exists('g:loaded_fugitive') || &cp @@ -12,7 +12,7 @@ if !exists('g:fugitive_git_executable') let g:fugitive_git_executable = 'git' endif -" Utility {{{1 +" Section: Utility function! s:function(name) abort return function(substitute(a:name,'^s:',matchstr(expand(''), '\d\+_'),'')) @@ -26,11 +26,15 @@ function! s:gsub(str,pat,rep) abort return substitute(a:str,'\v\C'.a:pat,a:rep,'g') endfunction +function! s:winshell() abort + return &shell =~? 'cmd' || exists('+shellslash') && !&shellslash +endfunction + function! s:shellesc(arg) abort if a:arg =~ '^[A-Za-z0-9_/.-]\+$' return a:arg - elseif &shell =~# 'cmd' && a:arg !~# '"' - return '"'.a:arg.'"' + elseif s:winshell() + return '"'.s:gsub(s:gsub(a:arg, '"', '""'), '\%', '"%"').'"' else return shellescape(a:arg) endif @@ -49,21 +53,48 @@ function! s:throw(string) abort throw v:errmsg endfunction -function! s:warn(str) +function! s:warn(str) abort echohl WarningMsg echomsg a:str echohl None let v:warningmsg = a:str endfunction -function! s:shellslash(path) - if exists('+shellslash') && !&shellslash +function! s:shellslash(path) abort + if s:winshell() return s:gsub(a:path,'\\','/') else return a:path endif endfunction +let s:git_versions = {} + +function! fugitive#git_version(...) abort + if !has_key(s:git_versions, g:fugitive_git_executable) + let s:git_versions[g:fugitive_git_executable] = matchstr(system(g:fugitive_git_executable.' --version'), "\\S\\+\n") + endif + return s:git_versions[g:fugitive_git_executable] +endfunction + +function! s:recall() abort + let rev = s:sub(s:buffer().rev(), '^/', '') + if rev ==# ':' + return matchstr(getline('.'),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$\|^\d\{6} \x\{40\} \d\t\zs.*') + elseif s:buffer().type('tree') + let file = matchstr(getline('.'), '\t\zs.*') + if empty(file) && line('.') > 2 + let file = s:sub(getline('.'), '/$', '') + endif + if !empty(file) && rev !~# ':$' + return rev . '/' . file + else + return rev . file + endif + endif + return rev +endfunction + function! s:add_methods(namespace, method_names) abort for name in a:method_names let s:{a:namespace}_prototype[name] = s:function('s:'.a:namespace.'_'.name) @@ -75,129 +106,209 @@ function! s:command(definition) abort let s:commands += [a:definition] endfunction -function! s:define_commands() +function! s:define_commands() abort for command in s:commands exe 'command! -buffer '.command endfor endfunction -function! s:compatibility_check() - if exists('b:git_dir') && exists('*GitBranchInfoCheckGitDir') && !exists('g:fugitive_did_compatibility_warning') - let g:fugitive_did_compatibility_warning = 1 - call s:warn("See http://github.com/tpope/vim-fugitive/issues#issue/1 for why you should remove git-branch-info.vim") - endif -endfunction - augroup fugitive_utility autocmd! autocmd User Fugitive call s:define_commands() - autocmd VimEnter * call s:compatibility_check() augroup END let s:abstract_prototype = {} -" }}}1 -" Initialization {{{1 +" Section: Initialization -function! s:ExtractGitDir(path) abort - let path = s:shellslash(a:path) - if path =~? '^fugitive://.*//' - return matchstr(path,'fugitive://\zs.\{-\}\ze//') +function! fugitive#is_git_dir(path) abort + let path = s:sub(a:path, '[\/]$', '') . '/' + return isdirectory(path.'objects') && isdirectory(path.'refs') && getfsize(path.'HEAD') > 10 +endfunction + +function! fugitive#extract_git_dir(path) abort + if s:shellslash(a:path) =~# '^fugitive://.*//' + return matchstr(s:shellslash(a:path), '\C^fugitive://\zs.\{-\}\ze//') endif - let fn = fnamemodify(path,':s?[\/]$??') - let ofn = "" - let nfn = fn - while fn != ofn - if filereadable(fn . '/.git/HEAD') - return s:sub(simplify(fnamemodify(fn . '/.git',':p')),'\W$','') - elseif fn =~ '\.git$' && filereadable(fn . '/HEAD') - return s:sub(simplify(fnamemodify(fn,':p')),'\W$','') + let root = s:shellslash(simplify(fnamemodify(a:path, ':p:s?[\/]$??'))) + let previous = "" + while root !=# previous + if root =~# '\v^//%([^/]+/?)?$' + " This is for accessing network shares from Cygwin Vim. There won't be + " any git directory called //.git or //serverName/.git so let's avoid + " checking for them since such checks are extremely slow. + break endif - let ofn = fn - let fn = fnamemodify(ofn,':h') + if index(split($GIT_CEILING_DIRECTORIES, ':'), root) >= 0 + break + endif + if root ==# $GIT_WORK_TREE && fugitive#is_git_dir($GIT_DIR) + return $GIT_DIR + endif + if fugitive#is_git_dir($GIT_DIR) + " Ensure that we've cached the worktree + call s:configured_tree($GIT_DIR) + if has_key(s:dir_for_worktree, root) + return s:dir_for_worktree[root] + endif + endif + let dir = s:sub(root, '[\/]$', '') . '/.git' + let type = getftype(dir) + if type ==# 'dir' && fugitive#is_git_dir(dir) + return dir + elseif type ==# 'link' && fugitive#is_git_dir(dir) + return resolve(dir) + elseif type !=# '' && filereadable(dir) + let line = get(readfile(dir, '', 1), 0, '') + if line =~# '^gitdir: \.' && fugitive#is_git_dir(root.'/'.line[8:-1]) + return simplify(root.'/'.line[8:-1]) + elseif line =~# '^gitdir: ' && fugitive#is_git_dir(line[8:-1]) + return line[8:-1] + endif + elseif fugitive#is_git_dir(root) + return root + endif + let previous = root + let root = fnamemodify(root, ':h') endwhile return '' endfunction -function! s:Detect(path) - if exists('b:git_dir') && b:git_dir ==# '' +function! fugitive#detect(path) abort + if exists('b:git_dir') && (b:git_dir ==# '' || b:git_dir =~# '/$') unlet b:git_dir endif if !exists('b:git_dir') - let dir = s:ExtractGitDir(a:path) - if dir != '' + let dir = fugitive#extract_git_dir(a:path) + if dir !=# '' let b:git_dir = dir endif endif if exists('b:git_dir') - silent doautocmd User Fugitive - cnoremap fugitive#buffer().rev() + if exists('#User#FugitiveBoot') + try + let [save_mls, &modelines] = [&mls, 0] + doautocmd User FugitiveBoot + finally + let &mls = save_mls + endtry + endif + cnoremap fnameescape(recall()) + nnoremap y :call setreg(v:register, recall()) let buffer = fugitive#buffer() if expand('%:p') =~# '//' - call buffer.setvar('&path',s:sub(buffer.getvar('&path'),'^\.%(,|$)','')) + call buffer.setvar('&path', s:sub(buffer.getvar('&path'), '^\.%(,|$)', '')) endif - if b:git_dir !~# ',' && stridx(buffer.getvar('&tags'),b:git_dir.'/tags') == -1 - if &filetype != '' - call buffer.setvar('&tags',buffer.getvar('&tags').','.b:git_dir.'/'.&filetype.'.tags') + if stridx(buffer.getvar('&tags'), escape(b:git_dir, ', ')) == -1 + if filereadable(b:git_dir.'/tags') + call buffer.setvar('&tags', escape(b:git_dir.'/tags', ', ').','.buffer.getvar('&tags')) + endif + if &filetype !=# '' && filereadable(b:git_dir.'/'.&filetype.'.tags') + call buffer.setvar('&tags', escape(b:git_dir.'/'.&filetype.'.tags', ', ').','.buffer.getvar('&tags')) endif - call buffer.setvar('&tags',buffer.getvar('&tags').','.b:git_dir.'/tags') endif + try + let [save_mls, &modelines] = [&mls, 0] + doautocmd User Fugitive + finally + let &mls = save_mls + endtry endif endfunction augroup fugitive autocmd! - autocmd BufNewFile,BufReadPost * call s:Detect(expand(':p')) - autocmd FileType netrw call s:Detect(expand(':p')) - autocmd VimEnter * if expand('')==''|call s:Detect(getcwd())|endif - autocmd BufWinLeave * execute getwinvar(+winnr(), 'fugitive_restore') + autocmd BufNewFile,BufReadPost * call fugitive#detect(expand(':p')) + autocmd FileType netrw call fugitive#detect(expand('%:p')) + autocmd User NERDTreeInit,NERDTreeNewRoot call fugitive#detect(b:NERDTreeRoot.path.str()) + autocmd VimEnter * if expand('')==''|call fugitive#detect(getcwd())|endif + autocmd CmdWinEnter * call fugitive#detect(expand('#:p')) + autocmd BufWinLeave * execute getwinvar(+bufwinnr(+expand('')), 'fugitive_leave') augroup END -" }}}1 -" Repository {{{1 +" Section: Repository let s:repo_prototype = {} let s:repos = {} +let s:worktree_for_dir = {} +let s:dir_for_worktree = {} function! s:repo(...) abort - let dir = a:0 ? a:1 : (exists('b:git_dir') && b:git_dir !=# '' ? b:git_dir : s:ExtractGitDir(expand('%:p'))) + let dir = a:0 ? a:1 : (exists('b:git_dir') && b:git_dir !=# '' ? b:git_dir : fugitive#extract_git_dir(expand('%:p'))) if dir !=# '' - if has_key(s:repos,dir) - let repo = get(s:repos,dir) + if has_key(s:repos, dir) + let repo = get(s:repos, dir) else let repo = {'git_dir': dir} let s:repos[dir] = repo endif - return extend(extend(repo,s:repo_prototype,'keep'),s:abstract_prototype,'keep') + return extend(extend(repo, s:repo_prototype, 'keep'), s:abstract_prototype, 'keep') endif call s:throw('not a git repository: '.expand('%:p')) endfunction +function! fugitive#repo(...) abort + return call('s:repo', a:000) +endfunction + function! s:repo_dir(...) dict abort return join([self.git_dir]+a:000,'/') endfunction +function! s:configured_tree(git_dir) abort + if !has_key(s:worktree_for_dir, a:git_dir) + let s:worktree_for_dir[a:git_dir] = '' + let config_file = a:git_dir . '/config' + if filereadable(config_file) + let config = readfile(config_file,'',10) + call filter(config,'v:val =~# "^\\s*worktree *="') + if len(config) == 1 + let s:worktree_for_dir[a:git_dir] = matchstr(config[0], '= *\zs.*') + let s:dir_for_worktree[s:worktree_for_dir[a:git_dir]] = a:git_dir + endif + endif + endif + if s:worktree_for_dir[a:git_dir] =~# '^\.' + return simplify(a:git_dir . '/' . s:worktree_for_dir[a:git_dir]) + else + return s:worktree_for_dir[a:git_dir] + endif +endfunction + function! s:repo_tree(...) dict abort - if !self.bare() - let dir = fnamemodify(self.git_dir,':h') + if self.dir() =~# '/\.git$' + let dir = self.dir()[0:-6] + else + let dir = s:configured_tree(self.git_dir) + endif + if dir ==# '' + call s:throw('no work tree') + else return join([dir]+a:000,'/') endif - call s:throw('no work tree') endfunction function! s:repo_bare() dict abort - return self.dir() !~# '/\.git$' + if self.dir() =~# '/\.git$' + return 0 + else + return s:configured_tree(self.git_dir) ==# '' + endif endfunction function! s:repo_translate(spec) dict abort if a:spec ==# '.' || a:spec ==# '/.' return self.bare() ? self.dir() : self.tree() + elseif a:spec =~# '^/\=\.git$' && self.bare() + return self.dir() + elseif a:spec =~# '^/\=\.git/' + return self.dir(s:sub(a:spec, '^/=\.git/', '')) elseif a:spec =~# '^/' - return fnamemodify(self.dir(),':h').a:spec + return self.tree().a:spec elseif a:spec =~# '^:[0-3]:' return 'fugitive://'.self.dir().'//'.a:spec[1].'/'.a:spec[3:-1] elseif a:spec ==# ':' - if $GIT_INDEX_FILE =~# '/[^/]*index[^/]*\.lock$' && fnamemodify($GIT_INDEX_FILE,':p')[0:strlen(s:repo().dir())] ==# s:repo().dir('') && filereadable($GIT_INDEX_FILE) + if $GIT_INDEX_FILE =~# '/[^/]*index[^/]*\.lock$' && fnamemodify($GIT_INDEX_FILE,':p')[0:strlen(self.dir())] ==# self.dir('') && filereadable($GIT_INDEX_FILE) return fnamemodify($GIT_INDEX_FILE,':p') else return self.dir('index') @@ -209,15 +320,15 @@ function! s:repo_translate(spec) dict abort return 'fugitive://'.self.dir().'//0/'.a:spec[1:-1] elseif a:spec =~# 'HEAD\|^refs/' && a:spec !~ ':' && filereadable(self.dir(a:spec)) return self.dir(a:spec) - elseif filereadable(s:repo().dir('refs/'.a:spec)) + elseif filereadable(self.dir('refs/'.a:spec)) return self.dir('refs/'.a:spec) - elseif filereadable(s:repo().dir('refs/tags/'.a:spec)) + elseif filereadable(self.dir('refs/tags/'.a:spec)) return self.dir('refs/tags/'.a:spec) - elseif filereadable(s:repo().dir('refs/heads/'.a:spec)) + elseif filereadable(self.dir('refs/heads/'.a:spec)) return self.dir('refs/heads/'.a:spec) - elseif filereadable(s:repo().dir('refs/remotes/'.a:spec)) + elseif filereadable(self.dir('refs/remotes/'.a:spec)) return self.dir('refs/remotes/'.a:spec) - elseif filereadable(s:repo().dir('refs/remotes/'.a:spec.'/HEAD')) + elseif filereadable(self.dir('refs/remotes/'.a:spec.'/HEAD')) return self.dir('refs/remotes/'.a:spec,'/HEAD') else try @@ -230,7 +341,23 @@ function! s:repo_translate(spec) dict abort endif endfunction -call s:add_methods('repo',['dir','tree','bare','translate']) +function! s:repo_head(...) dict abort + let head = s:repo().head_ref() + + if head =~# '^ref: ' + let branch = s:sub(head,'^ref: %(refs/%(heads/|remotes/|tags/)=)=','') + elseif head =~# '^\x\{40\}$' + " truncate hash to a:1 characters if we're in detached head mode + let len = a:0 ? a:1 : 0 + let branch = len ? head[0:len-1] : '' + else + return '' + endif + + return branch +endfunction + +call s:add_methods('repo',['dir','tree','bare','translate','head']) function! s:repo_git_command(...) dict abort let git = g:fugitive_git_executable . ' --git-dir='.s:shellesc(self.git_dir) @@ -309,19 +436,40 @@ endfunction call s:add_methods('repo',['dirglob','superglob']) +function! s:repo_config(conf) dict abort + return matchstr(system(s:repo().git_command('config').' '.a:conf),"[^\r\n]*") +endfun + +function! s:repo_user() dict abort + let username = s:repo().config('user.name') + let useremail = s:repo().config('user.email') + return username.' <'.useremail.'>' +endfun + +function! s:repo_aliases() dict abort + if !has_key(self,'_aliases') + let self._aliases = {} + for line in split(self.git_chomp('config','--get-regexp','^alias[.]'),"\n") + let self._aliases[matchstr(line,'\.\zs\S\+')] = matchstr(line,' \zs.*') + endfor + endif + return self._aliases +endfunction + +call s:add_methods('repo',['config', 'user', 'aliases']) + function! s:repo_keywordprg() dict abort - let args = ' --git-dir='.escape(self.dir(),"\\\"' ").' show' + let args = ' --git-dir='.escape(self.dir(),"\\\"' ") if has('gui_running') && !has('win32') - return g:fugitive_git_executable . ' --no-pager' . args + return g:fugitive_git_executable . ' --no-pager' . args . ' log -1' else - return g:fugitive_git_executable . args + return g:fugitive_git_executable . args . ' show' endif endfunction call s:add_methods('repo',['keywordprg']) -" }}}1 -" Buffer {{{1 +" Section: Buffer let s:buffer_prototype = {} @@ -347,7 +495,7 @@ function! s:buffer_setvar(var,value) dict abort endfunction function! s:buffer_getline(lnum) dict abort - return getbufline(self['#'],a:lnum)[0] + return get(getbufline(self['#'], a:lnum), 0, '') endfunction function! s:buffer_repo() dict abort @@ -369,10 +517,8 @@ function! s:buffer_type(...) dict abort let type = 'directory' elseif self.spec() == '' let type = 'null' - elseif filereadable(self.spec()) - let type = 'file' else - let type = '' + let type = 'file' endif if a:0 return !empty(filter(copy(a:000),'v:val ==# type')) @@ -413,7 +559,9 @@ function! s:buffer_path(...) dict abort let rev = matchstr(self.spec(),'^fugitive://.\{-\}//\zs.*') if rev != '' let rev = s:sub(rev,'\w*','') - else + elseif self.spec()[0 : len(self.repo().dir())] ==# self.repo().dir() . '/' + let rev = '/.git'.self.spec()[strlen(self.repo().dir()) : -1] + elseif !self.repo().bare() && self.spec()[0 : len(self.repo().tree())] ==# self.repo().tree() . '/' let rev = self.spec()[strlen(self.repo().tree()) : -1] endif return s:sub(s:sub(rev,'.\zs/$',''),'^/',a:0 ? a:1 : '') @@ -430,7 +578,7 @@ function! s:buffer_rev() dict abort elseif self.spec() =~ '\.git/refs/\|\.git/.*HEAD$' return self.spec()[strlen(self.repo().dir())+1 : -1] else - return self.path() + return self.path('/') endif endfunction @@ -470,10 +618,33 @@ function! s:buffer_containing_commit() dict abort endif endfunction -call s:add_methods('buffer',['getvar','setvar','getline','repo','type','spec','name','commit','path','rev','sha1','expand','containing_commit']) +function! s:buffer_up(...) dict abort + let rev = self.rev() + let c = a:0 ? a:1 : 1 + while c + if rev =~# '^[/:]$' + let rev = 'HEAD' + elseif rev =~# '^:' + let rev = ':' + elseif rev =~# '^refs/[^^~:]*$\|^[^^~:]*HEAD$' + let rev .= '^{}' + elseif rev =~# '^/\|:.*/' + let rev = s:sub(rev, '.*\zs/.*', '') + elseif rev =~# ':.' + let rev = matchstr(rev, '^[^:]*:') + elseif rev =~# ':$' + let rev = rev[0:-2] + else + return rev.'~'.c + endif + let c -= 1 + endwhile + return rev +endfunction -" }}}1 -" Git {{{1 +call s:add_methods('buffer',['getvar','setvar','getline','repo','type','spec','name','commit','path','rev','sha1','expand','containing_commit','up']) + +" Section: Git call s:command("-bang -nargs=? -complete=customlist,s:GitComplete Git :execute s:Git(0,)") @@ -488,33 +659,37 @@ function! s:ExecuteInTree(cmd) abort endtry endfunction -function! s:Git(bang,cmd) abort - let git = s:repo().git_command() +function! s:Git(bang, args) abort + if a:bang + return s:Edit('edit', 1, a:args) + endif + let git = g:fugitive_git_executable if has('gui_running') && !has('win32') let git .= ' --no-pager' endif - let cmd = matchstr(a:cmd,'\v\C.{-}%($|\\@ `=s:repo().bare() ? s:repo().dir() : s:repo().tree()`") call s:command("-bar -bang -nargs=? -complete=customlist,s:DirComplete Glcd :lcd `=s:repo().bare() ? s:repo().dir() : s:repo().tree()`") -" }}}1 -" Gstatus {{{1 +" Section: Gstatus call s:command("-bar Gstatus :execute s:Status()") +augroup fugitive_status + autocmd! + if !has('win32') + autocmd FocusGained,ShellCmdPost * call fugitive#reload_status() + endif +augroup END function! s:Status() abort try Gpedit : wincmd P + setlocal foldmethod=syntax foldlevel=1 nnoremap q :bdelete catch /^fugitive:/ return 'echoerr v:errmsg' @@ -541,115 +722,215 @@ function! s:Status() abort endfunction function! fugitive#reload_status() abort - let mytab = tabpagenr() - for tab in [mytab] + range(1,tabpagenr('$')) - for winnr in range(1,tabpagewinnr(tab,'$')) - if getbufvar(tabpagebuflist(tab)[winnr-1],'fugitive_type') ==# 'index' - execute 'tabnext '.tab - if winnr != winnr() - execute winnr.'wincmd w' - let restorewinnr = 1 + if exists('s:reloading_status') + return + endif + try + let s:reloading_status = 1 + let mytab = tabpagenr() + for tab in [mytab] + range(1,tabpagenr('$')) + for winnr in range(1,tabpagewinnr(tab,'$')) + if getbufvar(tabpagebuflist(tab)[winnr-1],'fugitive_type') ==# 'index' + execute 'tabnext '.tab + if winnr != winnr() + execute winnr.'wincmd w' + let restorewinnr = 1 + endif + try + if !&modified + call s:BufReadIndex() + endif + finally + if exists('restorewinnr') + wincmd p + endif + execute 'tabnext '.mytab + endtry endif - try - if !&modified - call s:BufReadIndex() - endif - finally - if exists('restorewinnr') - wincmd p - endif - execute 'tabnext '.mytab - endtry - endif + endfor endfor - endfor + finally + unlet! s:reloading_status + endtry endfunction -function! s:StageDiff(...) abort - let cmd = a:0 ? a:1 : 'Gdiff' - let section = getline(search('^# .*:$','bnW')) - let line = getline('.') - let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( (new commits)\)\=$') - if filename ==# '' && section == '# Changes to be committed:' - return 'Git diff --cached' +function! s:stage_info(lnum) abort + let filename = matchstr(getline(a:lnum),'^#\t\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$') + let lnum = a:lnum + if has('multi_byte_encoding') + let colon = '\%(:\|\%uff1a\)' + else + let colon = ':' + endif + while lnum && getline(lnum) !~# colon.'$' + let lnum -= 1 + endwhile + if !lnum + return ['', ''] + elseif (getline(lnum+1) =~# '^# .*\$' + return 'CtrlP '.fnameescape(s:repo().tree()) + else + for i in range(a:count) + call search('^#\t.*','Wbe') + endfor + return '.' + endif +endfunction + +function! s:StageReloadSeek(target,lnum1,lnum2) abort + let jump = a:target + let f = matchstr(getline(a:lnum1-1),'^#\t\%([[:alpha:] ]\+: *\|.*\%uff1a *\)\=\zs.*') + if f !=# '' | let jump = f | endif + let f = matchstr(getline(a:lnum2+1),'^#\t\%([[:alpha:] ]\+: *\|.*\%uff1a *\)\=\zs.*') + if f !=# '' | let jump = f | endif + silent! edit! + 1 + redraw + call search('^#\t\%([[:alpha:] ]\+: *\|.*\%uff1a *\)\=\V'.jump.'\%( ([^()[:digit:]]\+)\)\=\$','W') +endfunction + +function! s:StageUndo() abort + let [filename, section] = s:stage_info(line('.')) + if empty(filename) + return '' + endif + let repo = s:repo() + let hash = repo.git_chomp('hash-object', '-w', filename) + if !empty(hash) + if section ==# 'untracked' + call delete(s:repo().tree(filename)) + elseif section ==# 'unstaged' + call repo.git_chomp_in_tree('checkout', '--', filename) + else + call repo.git_chomp_in_tree('checkout', 'HEAD', '--', filename) + endif + call s:StageReloadSeek(filename, line('.'), line('.')) + let @" = hash + return 'checktime|redraw|echomsg ' . + \ string('To restore, :Git cat-file blob '.hash[0:6].' > '.filename) + endif +endfunction + +function! s:StageDiff(diff) abort + let [filename, section] = s:stage_info(line('.')) + if filename ==# '' && section ==# 'staged' + return 'Git! diff --no-ext-diff --cached' elseif filename ==# '' - return 'Git diff' - elseif line =~# '^#\trenamed:' && filename =~ ' -> ' + return 'Git! diff --no-ext-diff' + elseif filename =~# ' -> ' let [old, new] = split(filename,' -> ') execute 'Gedit '.s:fnameescape(':0:'.new) - return cmd.' HEAD:'.s:fnameescape(old) - elseif section == '# Changes to be committed:' + return a:diff.' HEAD:'.s:fnameescape(old) + elseif section ==# 'staged' execute 'Gedit '.s:fnameescape(':0:'.filename) - return cmd.' -' + return a:diff.' -' else execute 'Gedit '.s:fnameescape('/'.filename) - return cmd + return a:diff + endif +endfunction + +function! s:StageDiffEdit() abort + let [filename, section] = s:stage_info(line('.')) + let arg = (filename ==# '' ? '.' : filename) + if section ==# 'staged' + return 'Git! diff --no-ext-diff --cached '.s:shellesc(arg) + elseif section ==# 'untracked' + let repo = s:repo() + call repo.git_chomp_in_tree('add','--intent-to-add',arg) + if arg ==# '.' + silent! edit! + 1 + if !search('^# .*:\n#.*\n# .*"git checkout \|^# Changes not staged for commit:$','W') + call search('^# .*:$','W') + endif + else + call s:StageReloadSeek(arg,line('.'),line('.')) + endif + return '' + else + return 'Git! diff --no-ext-diff '.s:shellesc(arg) endif endfunction function! s:StageToggle(lnum1,lnum2) abort + if a:lnum1 == 1 && a:lnum2 == 1 + return 'Gedit /.git|call search("^index$", "wc")' + endif try let output = '' for lnum in range(a:lnum1,a:lnum2) - let line = getline(lnum) + let [filename, section] = s:stage_info(lnum) let repo = s:repo() - if line ==# '# Changes to be committed:' - call repo.git_chomp_in_tree('reset','-q') - silent! edit! - 1 - if !search('^# Untracked files:$','W') - call search('^# Change','W') + if getline('.') =~# '^# .*:$' + if section ==# 'staged' + call repo.git_chomp_in_tree('reset','-q') + silent! edit! + 1 + if !search('^# .*:\n# .*"git add .*\n#\n\|^# Untracked files:$','W') + call search('^# .*:$','W') + endif + return '' + elseif section ==# 'unstaged' + call repo.git_chomp_in_tree('add','-u') + silent! edit! + 1 + if !search('^# .*:\n# .*"git add .*\n#\n\|^# Untracked files:$','W') + call search('^# .*:$','W') + endif + return '' + else + call repo.git_chomp_in_tree('add','.') + silent! edit! + 1 + call search('^# .*:$','W') + return '' endif - return '' - elseif line =~# '^# Change\%(d but not updated\|s not staged for commit\):$' - call repo.git_chomp_in_tree('add','-u') - silent! edit! - 1 - if !search('^# Untracked files:$','W') - call search('^# Change','W') - endif - return '' - elseif line ==# '# Untracked files:' - " Work around Vim parser idiosyncrasy - call repo.git_chomp_in_tree('add','-N','.') - silent! edit! - 1 - if !search('^# Change\%(d but not updated\|s not staged for commit\):$','W') - call search('^# Change','W') - endif - return '' endif - let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( (\a\+ [[:alpha:], ]\+)\)\=$') if filename ==# '' continue endif + execute lnum + if filename =~ ' -> ' + let cmd = ['mv','--'] + reverse(split(filename,' -> ')) + let filename = cmd[-1] + elseif section ==# 'staged' + let cmd = ['reset','-q','--',filename] + elseif getline(lnum) =~# '^#\tdeleted:' + let cmd = ['rm','--',filename] + elseif getline(lnum) =~# '^#\tmodified:' + let cmd = ['add','--',filename] + else + let cmd = ['add','-A','--',filename] + endif if !exists('first_filename') let first_filename = filename endif - execute lnum - let section = getline(search('^# .*:$','bnW')) - if line =~# '^#\trenamed:' && filename =~ ' -> ' - let cmd = ['mv','--'] + reverse(split(filename,' -> ')) - let filename = cmd[-1] - elseif section =~? ' to be ' - let cmd = ['reset','-q','--',filename] - elseif line =~# '^#\tdeleted:' - let cmd = ['rm','--',filename] - else - let cmd = ['add','--',filename] - endif let output .= call(repo.git_chomp_in_tree,cmd,s:repo())."\n" endfor if exists('first_filename') - let jump = first_filename - let f = matchstr(getline(a:lnum1-1),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*') - if f !=# '' | let jump = f | endif - let f = matchstr(getline(a:lnum2+1),'^#\t\%([[:alpha:] ]\+: *\)\=\zs.*') - if f !=# '' | let jump = f | endif - silent! edit! - 1 - redraw - call search('^#\t\%([[:alpha:] ]\+: *\)\=\V'.jump.'\%( (new commits)\)\=\$','W') + call s:StageReloadSeek(first_filename,a:lnum1,a:lnum2) endif echo s:sub(s:gsub(output,'\n+','\n'),'\n$','') catch /^fugitive:/ @@ -663,26 +944,25 @@ function! s:StagePatch(lnum1,lnum2) abort let reset = [] for lnum in range(a:lnum1,a:lnum2) - let line = getline(lnum) - if line ==# '# Changes to be committed:' + let [filename, section] = s:stage_info(lnum) + if getline('.') =~# '^# .*:$' && section ==# 'staged' return 'Git reset --patch' - elseif line =~# '^# Change\%(d but not updated\|s not staged for commit\):$' + elseif getline('.') =~# '^# .*:$' && section ==# 'unstaged' return 'Git add --patch' - endif - let filename = matchstr(line,'^#\t\%([[:alpha:] ]\+: *\)\=\zs.\{-\}\ze\%( (new commits)\)\=$') - if filename ==# '' + elseif getline('.') =~# '^# .*:$' && section ==# 'untracked' + return 'Git add -N .' + elseif filename ==# '' continue endif if !exists('first_filename') let first_filename = filename endif execute lnum - let section = getline(search('^# .*:$','bnW')) - if line =~# '^#\trenamed:' && filename =~ ' -> ' + if filename =~ ' -> ' let reset += [split(filename,' -> ')[1]] - elseif section =~? ' to be ' + elseif section ==# 'staged' let reset += [filename] - elseif line !~# '^#\tdeleted:' + elseif getline(lnum) !~# '^#\tdeleted:' let add += [filename] endif endfor @@ -697,7 +977,7 @@ function! s:StagePatch(lnum1,lnum2) abort silent! edit! 1 redraw - call search('^#\t\%([[:alpha:] ]\+: *\)\=\V'.first_filename.'\%( (new commits)\)\=\$','W') + call search('^#\t\%([[:alpha:] ]\+: *\)\=\V'.first_filename.'\%( ([^()[:digit:]]\+)\)\=\$','W') endif catch /^fugitive:/ return 'echoerr v:errmsg' @@ -705,34 +985,40 @@ function! s:StagePatch(lnum1,lnum2) abort return 'checktime' endfunction -" }}}1 -" Gcommit {{{1 +" Section: Gcommit call s:command("-nargs=? -complete=customlist,s:CommitComplete Gcommit :execute s:Commit()") -function! s:Commit(args) abort - let old_type = s:buffer().type() +function! s:Commit(args, ...) abort + let repo = a:0 ? a:1 : s:repo() let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let dir = getcwd() - let msgfile = s:repo().dir('COMMIT_EDITMSG') + let msgfile = repo.dir('COMMIT_EDITMSG') let outfile = tempname() let errorfile = tempname() try - execute cd.'`=s:repo().tree()`' - if &shell =~# 'cmd' - let command = '' - let old_editor = $GIT_EDITOR - let $GIT_EDITOR = 'false' - else - let command = 'env GIT_EDITOR=false ' - endif - let command .= s:repo().git_command('commit').' '.a:args - if &shell =~# 'csh' - silent execute '!('.command.' > '.outfile.') >& '.errorfile - elseif a:args =~# '\%(^\| \)--interactive\>' - execute '!'.command.' 2> '.errorfile - else - silent execute '!'.command.' > '.outfile.' 2> '.errorfile + try + execute cd.s:fnameescape(repo.tree()) + if s:winshell() + let command = '' + let old_editor = $GIT_EDITOR + let $GIT_EDITOR = 'false' + else + let command = 'env GIT_EDITOR=false ' + endif + let command .= repo.git_command('commit').' '.a:args + if &shell =~# 'csh' + noautocmd silent execute '!('.command.' > '.outfile.') >& '.errorfile + elseif a:args =~# '\%(^\| \)-\%(-interactive\|p\|-patch\)\>' + noautocmd execute '!'.command.' 2> '.errorfile + else + noautocmd silent execute '!'.command.' > '.outfile.' 2> '.errorfile + endif + finally + execute cd.'`=dir`' + endtry + if !has('gui_running') + redraw! endif if !v:shell_error if filereadable(outfile) @@ -744,26 +1030,29 @@ function! s:Commit(args) abort else let errors = readfile(errorfile) let error = get(errors,-2,get(errors,-1,'!')) - if error =~# '\' let args = '--cleanup=strip '.args endif - let old_nr = bufnr('') if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod - edit `=msgfile` + execute 'keepalt edit '.s:fnameescape(msgfile) + elseif a:args =~# '\%(^\| \)-\%(-verbose\|\w*v\)\>' + execute 'keepalt tabedit '.s:fnameescape(msgfile) + elseif s:buffer().type() ==# 'index' + execute 'keepalt edit '.s:fnameescape(msgfile) + execute (search('^#','n')+1).'wincmd+' + setlocal nopreviewwindow else - keepalt split `=msgfile` - endif - if old_type ==# 'index' - execute 'bdelete '.old_nr + execute 'keepalt split '.s:fnameescape(msgfile) endif let b:fugitive_commit_arguments = args - setlocal bufhidden=delete filetype=gitcommit + setlocal bufhidden=wipe filetype=gitcommit return '1' elseif error ==# '!' return s:Status() @@ -779,7 +1068,6 @@ function! s:Commit(args) abort endif call delete(outfile) call delete(errorfile) - execute cd.'`=dir`' call fugitive#reload_status() endtry endfunction @@ -793,31 +1081,146 @@ function! s:CommitComplete(A,L,P) abort endif endfunction -function! s:FinishCommit() +function! s:FinishCommit() abort let args = getbufvar(+expand(''),'fugitive_commit_arguments') if !empty(args) call setbufvar(+expand(''),'fugitive_commit_arguments','') - return s:Commit(args) + return s:Commit(args, s:repo(getbufvar(+expand(''),'git_dir'))) endif return '' endfunction -augroup fugitive_commit - autocmd! - autocmd VimLeavePre,BufDelete *.git/COMMIT_EDITMSG execute s:sub(s:FinishCommit(), '^echoerr (.*)', 'echohl ErrorMsg|echo \1|echohl NONE') -augroup END +" Section: Gmerge, Gpull -" }}}1 -" Ggrep, Glog {{{1 +call s:command("-nargs=? -bang -complete=custom,s:RevisionComplete Gmerge " . + \ "execute s:Merge('merge', 0, )") +call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gpull " . + \ "execute s:Merge('pull --progress', 0, )") + +function! s:RevisionComplete(A, L, P) abort + return s:repo().git_chomp('rev-parse', '--symbolic', '--branches', '--tags', '--remotes') + \ . "\nHEAD\nFETCH_HEAD\nORIG_HEAD" +endfunction + +function! s:RemoteComplete(A, L, P) abort + let remote = matchstr(a:L, ' \zs\S\+\ze ') + if !empty(remote) + let matches = split(s:repo().git_chomp('ls-remote', remote), "\n") + call filter(matches, 'v:val =~# "\t" && v:val !~# "{"') + call map(matches, 's:sub(v:val, "^.*\t%(refs/%(heads/|tags/)=)=", "")') + else + let matches = split(s:repo().git_chomp('remote'), "\n") + endif + return join(matches, "\n") +endfunction + +function! fugitive#cwindow() abort + if &buftype == 'quickfix' + cwindow + else + botright cwindow + if &buftype == 'quickfix' + wincmd p + endif + endif +endfunction + +let s:common_efm = '' + \ . '%+Egit:%.%#,' + \ . '%+Eusage:%.%#,' + \ . '%+Eerror:%.%#,' + \ . '%+Efatal:%.%#,' + \ . '%-G%.%#%\e[K%.%#,' + \ . '%-G%.%#%\r%.%\+' + +function! s:Merge(cmd, bang, args) abort + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' + let cwd = getcwd() + let [mp, efm] = [&l:mp, &l:efm] + let had_merge_msg = filereadable(s:repo().dir('MERGE_MSG')) + try + let &l:errorformat = '' + \ . '%-Gerror:%.%#false''.,' + \ . '%-G%.%# ''git commit'' %.%#,' + \ . '%+Emerge:%.%#,' + \ . s:common_efm . ',' + \ . '%+ECannot %.%#: You have unstaged changes.,' + \ . '%+ECannot %.%#: Your index contains uncommitted changes.,' + \ . '%+EThere is no tracking information for the current branch.,' + \ . '%+EYou are not currently on a branch. Please specify which,' + \ . 'CONFLICT (%m): %f deleted in %.%#,' + \ . 'CONFLICT (%m): Merge conflict in %f,' + \ . 'CONFLICT (%m): Rename \"%f\"->%.%#,' + \ . 'CONFLICT (%m): Rename %.%#->%f %.%#,' + \ . 'CONFLICT (%m): There is a directory with name %f in %.%#,' + \ . '%+ECONFLICT %.%#,' + \ . '%+EKONFLIKT %.%#,' + \ . '%+ECONFLIT %.%#,' + \ . "%+EXUNG \u0110\u1ed8T %.%#," + \ . "%+E\u51b2\u7a81 %.%#," + \ . 'U%\t%f' + if a:cmd =~# '^merge' && empty(a:args) && + \ (had_merge_msg || isdirectory(s:repo().dir('rebase-apply')) || + \ !empty(s:repo().git_chomp('diff-files', '--diff-filter=U'))) + let &l:makeprg = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U' + else + let &l:makeprg = s:sub(g:fugitive_git_executable.' -c core.editor=false '. + \ a:cmd . (a:args =~# ' \%(--no-edit\|--abort\|-m\)\>' ? '' : ' --edit') . ' ' . a:args, + \ ' *$', '') + endif + if !empty($GIT_EDITOR) + let old_editor = $GIT_EDITOR + let $GIT_EDITOR = 'false' + endif + execute cd fnameescape(s:repo().tree()) + silent noautocmd make! + catch /^Vim\%((\a\+)\)\=:E211/ + let err = v:exception + finally + redraw! + let [&l:mp, &l:efm] = [mp, efm] + if exists('old_editor') + let $GIT_EDITOR = old_editor + endif + execute cd fnameescape(cwd) + endtry + call fugitive#reload_status() + if empty(filter(getqflist(),'v:val.valid')) + if !had_merge_msg && filereadable(s:repo().dir('MERGE_MSG')) + cclose + return 'Gcommit --no-status -n -t '.s:shellesc(s:repo().dir('MERGE_MSG')) + endif + endif + let qflist = getqflist() + let found = 0 + for e in qflist + if !empty(e.bufnr) + let found = 1 + let e.pattern = '^<<<<<<<' + endif + endfor + call fugitive#cwindow() + if found + call setqflist(qflist, 'r') + if !a:bang + return 'cfirst' + endif + endif + return exists('err') ? 'echoerr '.string(err) : '' +endfunction + +" Section: Ggrep, Glog if !exists('g:fugitive_summary_format') let g:fugitive_summary_format = '%s' endif -call s:command("-bang -nargs=? -complete=customlist,s:EditComplete Ggrep :execute s:Grep(0,)") -call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Glog :execute s:Log('grep',)") +call s:command("-bang -nargs=? -complete=customlist,s:EditComplete Ggrep :execute s:Grep('grep',0,)") +call s:command("-bang -nargs=? -complete=customlist,s:EditComplete Glgrep :execute s:Grep('lgrep',0,)") +call s:command("-bar -bang -nargs=* -range=0 -complete=customlist,s:EditComplete Glog :call s:Log('grep',,,)") +call s:command("-bar -bang -nargs=* -range=0 -complete=customlist,s:EditComplete Gllog :call s:Log('lgrep',,,)") -function! s:Grep(bang,arg) abort +function! s:Grep(cmd,bang,arg) abort let grepprg = &grepprg let grepformat = &grepformat let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' @@ -826,20 +1229,26 @@ function! s:Grep(bang,arg) abort execute cd.'`=s:repo().tree()`' let &grepprg = s:repo().git_command('--no-pager', 'grep', '-n') let &grepformat = '%f:%l:%m' - exe 'grep! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|') - let list = getqflist() + exe a:cmd.'! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|') + let list = a:cmd =~# '^l' ? getloclist(0) : getqflist() for entry in list if bufname(entry.bufnr) =~ ':' let entry.filename = s:repo().translate(bufname(entry.bufnr)) unlet! entry.bufnr + let changed = 1 elseif a:arg =~# '\%(^\| \)--cached\>' let entry.filename = s:repo().translate(':0:'.bufname(entry.bufnr)) unlet! entry.bufnr + let changed = 1 endif endfor - call setqflist(list,'r') + if a:cmd =~# '^l' && exists('changed') + call setloclist(0, list, 'r') + elseif exists('changed') + call setqflist(list, 'r') + endif if !a:bang && !empty(list) - return 'cfirst'.matchstr(a:arg,'\v\C[''" ]\zs\|.*') + return (a:cmd =~# '^l' ? 'l' : 'c').'first'.matchstr(a:arg,'\v\C[''" ]\zs\|.*') else return matchstr(a:arg,'\v\C[''" ]\|\zs.*') endif @@ -850,13 +1259,13 @@ function! s:Grep(bang,arg) abort endtry endfunction -function! s:Log(cmd,...) +function! s:Log(cmd, line1, line2, ...) abort let path = s:buffer().path('/') if path =~# '^/\.git\%(/\|$\)' || index(a:000,'--') != -1 let path = '' endif let cmd = ['--no-pager', 'log', '--no-color'] - let cmd += [escape('--pretty=format:fugitive://'.s:repo().dir().'//%H'.path.'::'.g:fugitive_summary_format,'%')] + let cmd += ['--pretty=format:fugitive://'.s:repo().dir().'//%H'.path.'::'.g:fugitive_summary_format] if empty(filter(a:000[0 : index(a:000,'--')],'v:val !~# "^-"')) if s:buffer().commit() =~# '\x\{40\}' let cmd += [s:buffer().commit()] @@ -866,7 +1275,11 @@ function! s:Log(cmd,...) end let cmd += map(copy(a:000),'s:sub(v:val,"^\\%(%(:\\w)*)","\\=fnamemodify(s:buffer().path(),submatch(1))")') if path =~# '/.' - let cmd += ['--',path[1:-1]] + if a:line2 + let cmd += ['-L', a:line1 . ',' . a:line2 . ':' . path[1:-1]] + else + let cmd += ['--', path[1:-1]] + endif endif let grepformat = &grepformat let grepprg = &grepprg @@ -874,8 +1287,8 @@ function! s:Log(cmd,...) let dir = getcwd() try execute cd.'`=s:repo().tree()`' - let &grepprg = call(s:repo().git_command,cmd,s:repo()) - let &grepformat = '%f::%m' + let &grepprg = escape(call(s:repo().git_command,cmd,s:repo()),'%#') + let &grepformat = '%Cdiff %.%#,%C--- %.%#,%C+++ %.%#,%Z@@ -%\d%\+\,%\d%\+ +%l\,%\d%\+ @@,%-G-%.%#,%-G+%.%#,%-G %.%#,%A%f::%m,%-G%.%#' exe a:cmd finally let &grepformat = grepformat @@ -884,52 +1297,110 @@ function! s:Log(cmd,...) endtry endfunction -" }}}1 -" Gedit, Gpedit, Gsplit, Gvsplit, Gtabedit, Gread {{{1 +" Section: Gedit, Gpedit, Gsplit, Gvsplit, Gtabedit, Gread + +function! s:Edit(cmd,bang,...) abort + let buffer = s:buffer() + if a:cmd !~# 'read' + if &previewwindow && getbufvar('','fugitive_type') ==# 'index' + wincmd p + if &diff + let mywinnr = winnr() + for winnr in range(winnr('$'),1,-1) + if winnr != mywinnr && getwinvar(winnr,'&diff') + execute winnr.'wincmd w' + close + if winnr('$') > 1 + wincmd p + endif + endif + endfor + endif + endif + endif + + if a:bang + let arglist = map(copy(a:000), 's:gsub(v:val, ''\\@>>>>>> + if getline(1) !~# '^diff ' + setlocal readonly nomodifiable + endif + if a:cmd =~# 'pedit' + wincmd p + endif + return echo + endif + return '' + endif -function! s:Edit(cmd,...) abort if a:0 && a:1 == '' return '' elseif a:0 - let file = s:buffer().expand(a:1) - elseif s:buffer().commit() ==# '' && s:buffer().path('/') !~# '^/.git\>' - let file = s:buffer().path(':') + let file = buffer.expand(join(a:000, ' ')) + elseif expand('%') ==# '' + let file = ':' + elseif buffer.commit() ==# '' && buffer.path('/') !~# '^/.git\>' + let file = buffer.path(':') else - let file = s:buffer().path('/') + let file = buffer.path('/') endif try - let file = s:repo().translate(file) + let file = buffer.repo().translate(file) catch /^fugitive:/ return 'echoerr v:errmsg' endtry if a:cmd ==# 'read' return 'silent %delete_|read '.s:fnameescape(file).'|silent 1delete_|diffupdate|'.line('.') else - if &previewwindow && getbufvar('','fugitive_type') ==# 'index' - wincmd p - endif return a:cmd.' '.s:fnameescape(file) endif endfunction function! s:EditComplete(A,L,P) abort - return s:repo().superglob(a:A) + return map(s:repo().superglob(a:A), 'fnameescape(v:val)') endfunction -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Ge :execute s:Edit('edit',)") -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gedit :execute s:Edit('edit',)") -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gpedit :execute s:Edit('pedit',)") -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gsplit :execute s:Edit('split',)") -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gvsplit :execute s:Edit('vsplit',)") -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gtabedit :execute s:Edit('tabedit',)") -call s:command("-bar -bang -nargs=? -count -complete=customlist,s:EditComplete Gread :execute s:Edit((! && ? '' : ).'read',)") +function! s:EditRunComplete(A,L,P) abort + if a:L =~# '^\w\+!' + return s:GitComplete(a:A,a:L,a:P) + else + return s:repo().superglob(a:A) + endif +endfunction -" }}}1 -" Gwrite, Gwq {{{1 +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Ge :execute s:Edit('edit',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Gedit :execute s:Edit('edit',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditRunComplete Gpedit :execute s:Edit('pedit',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditRunComplete Gsplit :execute s:Edit('split',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditRunComplete Gvsplit :execute s:Edit('vsplit',0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditRunComplete Gtabedit :execute s:Edit('tabedit',0,)") +call s:command("-bar -bang -nargs=* -count -complete=customlist,s:EditRunComplete Gread :execute s:Edit((! && ? '' : ).'read',0,)") -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gwrite :execute s:Write(0,)") -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gw :execute s:Write(0,)") -call s:command("-bar -bang -nargs=? -complete=customlist,s:EditComplete Gwq :execute s:Wq(0,)") +" Section: Gwrite, Gwq + +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Gwrite :execute s:Write(0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Gw :execute s:Write(0,)") +call s:command("-bar -bang -nargs=* -complete=customlist,s:EditComplete Gwq :execute s:Wq(0,)") function! s:Write(force,...) abort if exists('b:fugitive_commit_arguments') @@ -938,10 +1409,28 @@ function! s:Write(force,...) abort return 'wq' elseif s:buffer().type() == 'index' return 'Gcommit' + elseif s:buffer().path() ==# '' && getline(4) =~# '^+++ ' + let filename = getline(4)[6:-1] + setlocal buftype= + silent write + setlocal buftype=nowrite + if matchstr(getline(2),'index [[:xdigit:]]\+\.\.\zs[[:xdigit:]]\{7\}') ==# s:repo().rev_parse(':0:'.filename)[0:6] + let err = s:repo().git_chomp('apply','--cached','--reverse',s:buffer().spec()) + else + let err = s:repo().git_chomp('apply','--cached',s:buffer().spec()) + endif + if err !=# '' + let v:errmsg = split(err,"\n")[0] + return 'echoerr v:errmsg' + elseif a:force + return 'bdelete' + else + return 'Gedit '.fnameescape(filename) + endif endif let mytab = tabpagenr() let mybufnr = bufnr('') - let path = a:0 ? a:1 : s:buffer().path() + let path = a:0 ? join(a:000, ' ') : s:buffer().path() if path =~# '^:\d\>' return 'write'.(a:force ? '! ' : ' ').s:fnameescape(s:repo().translate(s:buffer().expand(path))) endif @@ -994,9 +1483,9 @@ function! s:Write(force,...) abort endif if a:force - let error = s:repo().git_chomp_in_tree('add', '--force', file) + let error = s:repo().git_chomp_in_tree('add', '--force', '--', path) else - let error = s:repo().git_chomp_in_tree('add', file) + let error = s:repo().git_chomp_in_tree('add', '--', path) endif if v:shell_error let v:errmsg = 'fugitive: '.error @@ -1010,7 +1499,8 @@ function! s:Write(force,...) abort let two = s:repo().translate(':2:'.path) let three = s:repo().translate(':3:'.path) for nr in range(1,bufnr('$')) - if bufloaded(nr) && !getbufvar(nr,'&modified') && (bufname(nr) == one || bufname(nr) == two || bufname(nr) == three) + let name = fnamemodify(bufname(nr), ':p') + if bufloaded(nr) && !getbufvar(nr,'&modified') && (name ==# one || name ==# two || name ==# three) execute nr.'bdelete' endif endfor @@ -1020,7 +1510,7 @@ function! s:Write(force,...) abort for tab in range(1,tabpagenr('$')) for winnr in range(1,tabpagewinnr(tab,'$')) let bufnr = tabpagebuflist(tab)[winnr-1] - let bufname = bufname(bufnr) + let bufname = fnamemodify(bufname(bufnr), ':p') if bufname ==# zero && bufnr != mybufnr execute 'tabnext '.tab if winnr != winnr() @@ -1030,7 +1520,7 @@ function! s:Write(force,...) abort try let lnum = line('.') let last = line('$') - silent $read `=file` + silent execute '$read '.s:fnameescape(file) silent execute '1,'.last.'delete_' silent execute lnum set nomodified @@ -1062,20 +1552,82 @@ function! s:Wq(force,...) abort endif endfunction -" }}}1 -" Gdiff {{{1 +augroup fugitive_commit + autocmd! + autocmd VimLeavePre,BufDelete COMMIT_EDITMSG execute s:sub(s:FinishCommit(), '^echoerr (.*)', 'echohl ErrorMsg|echo \1|echohl NONE') +augroup END -call s:command("-bang -bar -nargs=? -complete=customlist,s:EditComplete Gdiff :execute s:Diff(0,)") -call s:command("-bar -nargs=? -complete=customlist,s:EditComplete Gvdiff :execute s:Diff(0,)") -call s:command("-bar -nargs=? -complete=customlist,s:EditComplete Gsdiff :execute s:Diff(1,)") +" Section: Gpush, Gfetch + +call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gpush execute s:Dispatch('', 'push '.)") +call s:command("-nargs=? -bang -complete=custom,s:RemoteComplete Gfetch execute s:Dispatch('', 'fetch '.)") + +function! s:Dispatch(bang, args) + let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' + let cwd = getcwd() + let [mp, efm, cc] = [&l:mp, &l:efm, get(b:, 'current_compiler', '')] + try + let b:current_compiler = 'git' + let &l:errorformat = s:common_efm + let &l:makeprg = g:fugitive_git_executable . ' ' . a:args + execute cd fnameescape(s:repo().tree()) + if exists(':Make') == 2 + noautocmd Make + else + silent noautocmd make! + redraw! + return 'call fugitive#cwindow()' + endif + return '' + finally + let [&l:mp, &l:efm, b:current_compiler] = [mp, efm, cc] + if empty(cc) | unlet! b:current_compiler | endif + execute cd fnameescape(cwd) + endtry +endfunction + +" Section: Gdiff + +call s:command("-bang -bar -nargs=* -complete=customlist,s:EditComplete Gdiff :execute s:Diff('',)") +call s:command("-bar -nargs=* -complete=customlist,s:EditComplete Gvdiff :execute s:Diff('keepalt vert ',)") +call s:command("-bar -nargs=* -complete=customlist,s:EditComplete Gsdiff :execute s:Diff('keepalt ',)") augroup fugitive_diff autocmd! - autocmd BufWinLeave * if s:diff_window_count() == 2 && &diff && getbufvar(+expand(''), 'git_dir') !=# '' | call s:diff_off_all(getbufvar(+expand(''), 'git_dir')) | endif - autocmd BufWinEnter * if s:diff_window_count() == 1 && &diff && getbufvar(+expand(''), 'git_dir') !=# '' | diffoff | endif + autocmd BufWinLeave * + \ if s:can_diffoff(+expand('')) && s:diff_window_count() == 2 | + \ call s:diffoff_all(getbufvar(+expand(''), 'git_dir')) | + \ endif + autocmd BufWinEnter * + \ if s:can_diffoff(+expand('')) && s:diff_window_count() == 1 | + \ call s:diffoff() | + \ endif augroup END -function! s:diff_window_count() +function! s:can_diffoff(buf) abort + return getwinvar(bufwinnr(a:buf), '&diff') && + \ !empty(getbufvar(a:buf, 'git_dir')) && + \ !empty(getwinvar(bufwinnr(a:buf), 'fugitive_diff_restore')) +endfunction + +function! fugitive#can_diffoff(buf) abort + return s:can_diffoff(a:buf) +endfunction + +function! s:diff_modifier(count) abort + let fdc = matchstr(&diffopt, 'foldcolumn:\zs\d\+') + if &diffopt =~# 'horizontal' && &diffopt !~# 'vertical' + return 'keepalt ' + elseif &diffopt =~# 'vertical' + return 'keepalt vert ' + elseif winwidth(0) <= a:count * ((&tw ? &tw : 80) + (empty(fdc) ? 2 : fdc)) + return 'keepalt ' + else + return 'keepalt vert ' + endif +endfunction + +function! s:diff_window_count() abort let c = 0 for nr in range(1,winnr('$')) let c += getwinvar(nr,'&diff') @@ -1083,7 +1635,38 @@ function! s:diff_window_count() return c endfunction -function! s:diff_off_all(dir) +function! s:diff_restore() abort + let restore = 'setlocal nodiff noscrollbind' + \ . ' scrollopt=' . &l:scrollopt + \ . (&l:wrap ? ' wrap' : ' nowrap') + \ . ' foldlevel=999' + \ . ' foldmethod=' . &l:foldmethod + \ . ' foldcolumn=' . &l:foldcolumn + \ . ' foldlevel=' . &l:foldlevel + \ . (&l:foldenable ? ' foldenable' : ' nofoldenable') + if has('cursorbind') + let restore .= (&l:cursorbind ? ' ' : ' no') . 'cursorbind' + endif + return restore +endfunction + +function! s:diffthis() abort + if !&diff + let w:fugitive_diff_restore = s:diff_restore() + diffthis + endif +endfunction + +function! s:diffoff() abort + if exists('w:fugitive_diff_restore') + execute w:fugitive_diff_restore + unlet w:fugitive_diff_restore + else + diffoff + endif +endfunction + +function! s:diffoff_all(dir) abort for nr in range(1,winnr('$')) if getwinvar(nr,'&diff') if nr != winnr() @@ -1091,10 +1674,7 @@ function! s:diff_off_all(dir) let restorewinnr = 1 endif if exists('b:git_dir') && b:git_dir ==# a:dir - diffoff - endif - if exists('restorewinnr') - wincmd p + call s:diffoff() endif endif endfor @@ -1122,37 +1702,39 @@ endfunction call s:add_methods('buffer',['compare_age']) -function! s:Diff(bang,...) abort - let split = a:bang ? 'split' : 'vsplit' +function! s:Diff(vert,...) abort + let vert = empty(a:vert) ? s:diff_modifier(2) : a:vert if exists(':DiffGitCached') return 'DiffGitCached' elseif (!a:0 || a:1 == ':') && s:buffer().commit() =~# '^[0-1]\=$' && s:repo().git_chomp_in_tree('ls-files', '--unmerged', '--', s:buffer().path()) !=# '' + let vert = empty(a:vert) ? s:diff_modifier(3) : a:vert let nr = bufnr('') - execute 'leftabove '.split.' `=fugitive#buffer().repo().translate(s:buffer().expand('':2''))`' + execute 'leftabove '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':2''))`' execute 'nnoremap dp :diffput '.nr.'diffupdate' - diffthis + call s:diffthis() wincmd p - execute 'rightbelow '.split.' `=fugitive#buffer().repo().translate(s:buffer().expand('':3''))`' + execute 'rightbelow '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':3''))`' execute 'nnoremap dp :diffput '.nr.'diffupdate' - diffthis + call s:diffthis() wincmd p - diffthis + call s:diffthis() return '' elseif a:0 - if a:1 ==# '' + let arg = join(a:000, ' ') + if arg ==# '' return '' - elseif a:1 ==# '/' + elseif arg ==# '/' let file = s:buffer().path('/') - elseif a:1 ==# ':' + elseif arg ==# ':' let file = s:buffer().path(':0:') - elseif a:1 =~# '^:/.' + elseif arg =~# '^:/.' try - let file = s:repo().rev_parse(a:1).s:buffer().path(':') + let file = s:repo().rev_parse(arg).s:buffer().path(':') catch /^fugitive:/ return 'echoerr v:errmsg' endtry else - let file = s:buffer().expand(a:1) + let file = s:buffer().expand(arg) endif if file !~# ':' && file !~# '^/' && s:repo().git_chomp('cat-file','-t',file) =~# '^\%(tag\|commit\)$' let file = file.s:buffer().path(':') @@ -1163,33 +1745,40 @@ function! s:Diff(bang,...) abort try let spec = s:repo().translate(file) let commit = matchstr(spec,'\C[^:/]//\zs\x\+') - if s:buffer().compare_age(commit) < 0 - execute 'rightbelow '.split.' `=spec`' - else - execute 'leftabove '.split.' `=spec`' + let restore = s:diff_restore() + if exists('+cursorbind') + setlocal cursorbind + endif + let w:fugitive_diff_restore = restore + if s:buffer().compare_age(commit) < 0 + execute 'rightbelow '.vert.'diffsplit '.s:fnameescape(spec) + else + execute 'leftabove '.vert.'diffsplit '.s:fnameescape(spec) + endif + let w:fugitive_diff_restore = restore + let winnr = winnr() + if getwinvar('#', '&diff') + wincmd p + call feedkeys("\p", 'n') endif - diffthis - wincmd p - diffthis return '' catch /^fugitive:/ return 'echoerr v:errmsg' endtry endfunction -" }}}1 -" Gmove, Gremove {{{1 +" Section: Gmove, Gremove -function! s:Move(force,destination) +function! s:Move(force,destination) abort if a:destination =~# '^/' let destination = a:destination[1:-1] else - let destination = fnamemodify(s:sub(a:destination,'[%#]%(:\w)*','\=expand(submatch(0))'),':p') + let destination = s:shellslash(fnamemodify(s:sub(a:destination,'[%#]%(:\w)*','\=expand(submatch(0))'),':p')) if destination[0:strlen(s:repo().tree())] ==# s:repo().tree('') let destination = destination[strlen(s:repo().tree('')):-1] endif endif - if isdirectory(s:buffer().name()) + if isdirectory(s:buffer().spec()) " Work around Vim parser idiosyncrasy let discarded = s:buffer().setvar('&swapfile',0) endif @@ -1205,16 +1794,16 @@ function! s:Move(force,destination) call fugitive#reload_status() if s:buffer().commit() == '' if isdirectory(destination) - return 'edit '.s:fnameescape(destination) + return 'keepalt edit '.s:fnameescape(destination) else - return 'saveas! '.s:fnameescape(destination) + return 'keepalt saveas! '.s:fnameescape(destination) endif else - return 'file '.s:fnameescape(s:repo().translate(':0:'.destination) + return 'file '.s:fnameescape(s:repo().translate(':0:'.destination)) endif endfunction -function! s:MoveComplete(A,L,P) +function! s:MoveComplete(A,L,P) abort if a:A =~ '^/' return s:repo().superglob(a:A) else @@ -1224,7 +1813,7 @@ function! s:MoveComplete(A,L,P) endif endfunction -function! s:Remove(force) +function! s:Remove(force) abort if s:buffer().commit() ==# '' let cmd = ['rm'] elseif s:buffer().commit() ==# '0' @@ -1254,8 +1843,7 @@ augroup fugitive_remove \ endif augroup END -" }}}1 -" Gblame {{{1 +" Section: Gblame augroup fugitive_blame autocmd! @@ -1263,25 +1851,39 @@ augroup fugitive_blame autocmd FileType fugitiveblame setlocal nomodeline | if exists('b:git_dir') | let &l:keywordprg = s:repo().keywordprg() | endif autocmd Syntax fugitiveblame call s:BlameSyntax() autocmd User Fugitive if s:buffer().type('file', 'blob') | exe "command! -buffer -bar -bang -range=0 -nargs=* Gblame :execute s:Blame(0,,,,[])" | endif + autocmd ColorScheme,GUIEnter * call s:RehighlightBlame() augroup END +function! s:linechars(pattern) abort + let chars = strlen(s:gsub(matchstr(getline('.'), a:pattern), '.', '.')) + if exists('*synconcealed') && &conceallevel > 1 + for col in range(1, chars) + let chars -= synconcealed(line('.'), col)[0] + endfor + endif + return chars +endfunction + function! s:Blame(bang,line1,line2,count,args) abort + if exists('b:fugitive_blamed_bufnr') + return 'bdelete' + endif try if s:buffer().path() == '' call s:throw('file or blob required') endif - if filter(copy(a:args),'v:val !~# "^\\%(--root\|--show-name\\|-\\=\\%([ltwfs]\\|[MC]\\d*\\)\\+\\)$"') != [] + if filter(copy(a:args),'v:val !~# "^\\%(--root\|--show-name\\|-\\=\\%([ltfnsew]\\|[MC]\\d*\\)\\+\\)$"') != [] call s:throw('unsupported option') endif call map(a:args,'s:sub(v:val,"^\\ze[^-]","-")') - let git_dir = s:repo().dir() let cmd = ['--no-pager', 'blame', '--show-number'] + a:args if s:buffer().commit() =~# '\D\|..' let cmd += [s:buffer().commit()] else let cmd += ['--contents', '-'] endif - let basecmd = call(s:repo().git_command,cmd+['--',s:buffer().path()],s:repo()) + let cmd += ['--', s:buffer().path()] + let basecmd = escape(call(s:repo().git_command,cmd,s:repo()),'!') try let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' if !s:repo().bare() @@ -1291,7 +1893,7 @@ function! s:Blame(bang,line1,line2,count,args) abort if a:count execute 'write !'.substitute(basecmd,' blame ',' blame -L '.a:line1.','.a:line2.' ','g') else - let error = tempname() + let error = resolve(tempname()) let temp = error.'.fugitiveblame' if &shell =~# 'csh' silent! execute '%write !('.basecmd.' > '.temp.') >& '.error @@ -1305,38 +1907,66 @@ function! s:Blame(bang,line1,line2,count,args) abort if v:shell_error call s:throw(join(readfile(error),"\n")) endif + for winnr in range(winnr('$'),1,-1) + call setwinvar(winnr, '&scrollbind', 0) + if exists('+cursorbind') + call setwinvar(winnr, '&cursorbind', 0) + endif + if getbufvar(winbufnr(winnr), 'fugitive_blamed_bufnr') + execute winbufnr(winnr).'bdelete' + endif + endfor let bufnr = bufnr('') let restore = 'call setwinvar(bufwinnr('.bufnr.'),"&scrollbind",0)' + if exists('+cursorbind') + let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&cursorbind",0)' + endif if &l:wrap let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&wrap",1)' endif if &l:foldenable let restore .= '|call setwinvar(bufwinnr('.bufnr.'),"&foldenable",1)' endif - let winnr = winnr() - windo set noscrollbind - exe winnr.'wincmd w' setlocal scrollbind nowrap nofoldenable + if exists('+cursorbind') + setlocal cursorbind + endif let top = line('w0') + &scrolloff let current = line('.') - exe 'leftabove vsplit '.temp - let b:git_dir = git_dir - let b:fugitive_type = 'blame' + let s:temp_files[tolower(temp)] = { 'dir': s:repo().dir(), 'args': cmd } + exe 'keepalt leftabove vsplit '.temp let b:fugitive_blamed_bufnr = bufnr - let w:fugitive_restore = restore + let w:fugitive_leave = restore let b:fugitive_blame_arguments = join(a:args,' ') - call s:Detect(expand('%:p')) execute top normal! zt execute current - execute "vertical resize ".(match(getline('.'),'\s\+\d\+)')+1) - setlocal nomodified nomodifiable bufhidden=delete nonumber scrollbind nowrap foldcolumn=0 nofoldenable filetype=fugitiveblame - nnoremap q :bdelete - nnoremap :exe BlameJump('') + if exists('+cursorbind') + setlocal cursorbind + endif + setlocal nomodified nomodifiable nonumber scrollbind nowrap foldcolumn=0 nofoldenable winfixwidth filetype=fugitiveblame + if exists('+concealcursor') + setlocal concealcursor=nc conceallevel=2 + endif + if exists('+relativenumber') + setlocal norelativenumber + endif + execute "vertical resize ".(s:linechars('.\{-\}\ze\s\+\d\+)')+1) + nnoremap :help fugitive-:Gblame + nnoremap g? :help fugitive-:Gblame + nnoremap q :exe substitute(bufwinnr(b:fugitive_blamed_bufnr).' wincmd w'.bufnr('').'bdelete','^-1','','') + nnoremap gq :exe substitute(bufwinnr(b:fugitive_blamed_bufnr).' wincmd w'.bufnr('').'bdeleteif expand("%:p") =~# "^fugitive:[\\/][\\/]"Geditendif','^-1','','') + nnoremap :exe BlameCommit("exe 'norm q'edit") + nnoremap - :exe BlameJump('') nnoremap P :exe BlameJump('^'.v:count1) nnoremap ~ :exe BlameJump('~'.v:count1) - nnoremap o :exe Edit((&splitbelow ? "botright" : "topleft")." split", matchstr(getline('.'),'\x\+')) - nnoremap O :exe Edit("tabedit", matchstr(getline('.'),'\x\+')) + nnoremap i :exe BlameCommit("exe 'norm q'edit") + nnoremap o :exe BlameCommit((&splitbelow ? "botright" : "topleft")." split") + nnoremap O :exe BlameCommit("tabedit") + nnoremap A :exe "vertical resize ".(linechars('.\{-\}\ze [0-9:/+-][0-9:/+ -]* \d\+)')+1+v:count) + nnoremap C :exe "vertical resize ".(linechars('^\S\+')+1+v:count) + nnoremap D :exe "vertical resize ".(linechars('.\{-\}\ze\d\ze\s\+\d\+)')+1-v:count) + redraw syncbind endif finally @@ -1350,13 +1980,54 @@ function! s:Blame(bang,line1,line2,count,args) abort endtry endfunction +function! s:BlameCommit(cmd) abort + let cmd = s:Edit(a:cmd, 0, matchstr(getline('.'),'\x\+')) + if cmd =~# '^echoerr' + return cmd + endif + let lnum = matchstr(getline('.'),' \zs\d\+\ze\s\+[([:digit:]]') + let path = matchstr(getline('.'),'^\^\=\x\+\s\+\zs.\{-\}\ze\s*\d\+ ') + if path ==# '' + let path = s:buffer(b:fugitive_blamed_bufnr).path() + endif + execute cmd + if search('^diff .* b/\M'.escape(path,'\').'$','W') + call search('^+++') + let head = line('.') + while search('^@@ \|^diff ') && getline('.') =~# '^@@ ' + let top = +matchstr(getline('.'),' +\zs\d\+') + let len = +matchstr(getline('.'),' +\d\+,\zs\d\+') + if lnum >= top && lnum <= top + len + let offset = lnum - top + if &scrolloff + + + normal! zt + else + normal! zt + + + endif + while offset > 0 && line('.') < line('$') + + + if getline('.') =~# '^[ +]' + let offset -= 1 + endif + endwhile + return 'normal! zv' + endif + endwhile + execute head + normal! zt + endif + return '' +endfunction + function! s:BlameJump(suffix) abort let commit = matchstr(getline('.'),'^\^\=\zs\x\+') if commit =~# '^0\+$' let commit = ':0' endif - let lnum = matchstr(getline('.'),'\d\+\ze\s\+[([:digit:]]') - let path = matchstr(getline('.'),'^\^\=\zs\x\+\s\+\zs.\{-\}\ze\s*\d\+ ') + let lnum = matchstr(getline('.'),' \zs\d\+\ze\s\+[([:digit:]]') + let path = matchstr(getline('.'),'^\^\=\x\+\s\+\zs.\{-\}\ze\s*\d\+ ') if path ==# '' let path = s:buffer(b:fugitive_blamed_bufnr).path() endif @@ -1367,7 +2038,8 @@ function! s:BlameJump(suffix) abort if winnr > 0 exe winnr.'wincmd w' endif - execute s:Edit('edit',commit.a:suffix.':'.path) + execute s:Edit('edit', 0, commit.a:suffix.':'.path) + execute lnum if winnr > 0 exe bufnr.'bdelete' endif @@ -1375,31 +2047,35 @@ function! s:BlameJump(suffix) abort execute lnum let delta = line('.') - line('w0') - offset if delta > 0 - execute 'norm! 'delta."\" + execute 'normal! '.delta."\" elseif delta < 0 - execute 'norm! '(-delta)."\" + execute 'normal! '.(-delta)."\" endif syncbind return '' endfunction +let s:hash_colors = {} + function! s:BlameSyntax() abort let b:current_syntax = 'fugitiveblame' + let conceal = has('conceal') ? ' conceal' : '' + let arg = exists('b:fugitive_blame_arguments') ? b:fugitive_blame_arguments : '' syn match FugitiveblameBoundary "^\^" syn match FugitiveblameBlank "^\s\+\s\@=" nextgroup=FugitiveblameAnnotation,fugitiveblameOriginalFile,FugitiveblameOriginalLineNumber skipwhite syn match FugitiveblameHash "\%(^\^\=\)\@<=\x\{7,40\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite syn match FugitiveblameUncommitted "\%(^\^\=\)\@<=0\{7,40\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite syn region FugitiveblameAnnotation matchgroup=FugitiveblameDelimiter start="(" end="\%( \d\+\)\@<=)" contained keepend oneline syn match FugitiveblameTime "[0-9:/+-][0-9:/+ -]*[0-9:/+-]\%( \+\d\+)\)\@=" contained containedin=FugitiveblameAnnotation - syn match FugitiveblameLineNumber " \@<=\d\+)\@=" contained containedin=FugitiveblameAnnotation - syn match FugitiveblameOriginalFile " \%(\f\+\D\@<=\|\D\@=\f\+\)\%(\%(\s\+\d\+\)\=\s\%((\|\s*\d\+)\)\)\@=" contained nextgroup=FugitiveblameOriginalLineNumber,FugitiveblameAnnotation skipwhite - syn match FugitiveblameOriginalLineNumber " \@<=\d\+\%(\s(\)\@=" contained nextgroup=FugitiveblameAnnotation skipwhite - syn match FugitiveblameOriginalLineNumber " \@<=\d\+\%(\s\+\d\+)\)\@=" contained nextgroup=FugitiveblameShort skipwhite - syn match FugitiveblameShort "\d\+)" contained contains=FugitiveblameLineNumber + exec 'syn match FugitiveblameLineNumber " *\d\+)\@=" contained containedin=FugitiveblameAnnotation'.conceal + exec 'syn match FugitiveblameOriginalFile " \%(\f\+\D\@<=\|\D\@=\f\+\)\%(\%(\s\+\d\+\)\=\s\%((\|\s*\d\+)\)\)\@=" contained nextgroup=FugitiveblameOriginalLineNumber,FugitiveblameAnnotation skipwhite'.(arg =~# 'f' ? '' : conceal) + exec 'syn match FugitiveblameOriginalLineNumber " *\d\+\%(\s(\)\@=" contained nextgroup=FugitiveblameAnnotation skipwhite'.(arg =~# 'n' ? '' : conceal) + exec 'syn match FugitiveblameOriginalLineNumber " *\d\+\%(\s\+\d\+)\)\@=" contained nextgroup=FugitiveblameShort skipwhite'.(arg =~# 'n' ? '' : conceal) + syn match FugitiveblameShort " \d\+)" contained contains=FugitiveblameLineNumber syn match FugitiveblameNotCommittedYet "(\@<=Not Committed Yet\>" contained containedin=FugitiveblameAnnotation hi def link FugitiveblameBoundary Keyword hi def link FugitiveblameHash Identifier - hi def link FugitiveblameUncommitted Function + hi def link FugitiveblameUncommitted Ignore hi def link FugitiveblameTime PreProc hi def link FugitiveblameLineNumber Number hi def link FugitiveblameOriginalFile String @@ -1407,16 +2083,46 @@ function! s:BlameSyntax() abort hi def link FugitiveblameShort FugitiveblameDelimiter hi def link FugitiveblameDelimiter Delimiter hi def link FugitiveblameNotCommittedYet Comment + let seen = {} + for lnum in range(1, line('$')) + let hash = matchstr(getline(lnum), '^\^\=\zs\x\{6\}') + if hash ==# '' || hash ==# '000000' || has_key(seen, hash) + continue + endif + let seen[hash] = 1 + if &t_Co > 16 && exists('g:CSApprox_loaded') + \ && empty(get(s:hash_colors, hash)) + let [s, r, g, b; __] = map(matchlist(hash, '\(\x\x\)\(\x\x\)\(\x\x\)'), 'str2nr(v:val,16)') + let color = csapprox#per_component#Approximate(r, g, b) + if color == 16 && &background ==# 'dark' + let color = 8 + endif + let s:hash_colors[hash] = ' ctermfg='.color + else + let s:hash_colors[hash] = '' + endif + exe 'syn match FugitiveblameHash'.hash.' "\%(^\^\=\)\@<='.hash.'\x\{1,34\}\>" nextgroup=FugitiveblameAnnotation,FugitiveblameOriginalLineNumber,fugitiveblameOriginalFile skipwhite' + endfor + call s:RehighlightBlame() endfunction -" }}}1 -" Gbrowse {{{1 +function! s:RehighlightBlame() abort + for [hash, cterm] in items(s:hash_colors) + if !empty(cterm) || has('gui_running') + exe 'hi FugitiveblameHash'.hash.' guifg=#'.hash.get(s:hash_colors, hash, '') + else + exe 'hi link FugitiveblameHash'.hash.' Identifier' + endif + endfor +endfunction -call s:command("-bar -bang -count=0 -nargs=? -complete=customlist,s:EditComplete Gbrowse :execute s:Browse(0,,,)") +" Section: Gbrowse + +call s:command("-bar -bang -range -nargs=* -complete=customlist,s:EditComplete Gbrowse :execute s:Browse(0,,,)") function! s:Browse(bang,line1,count,...) abort try - let rev = a:0 ? substitute(a:1,'@[[:alnum:]_-]*\%(://.\{-\}\)\=$','','') : '' + let rev = a:0 ? substitute(join(a:000, ' '),'@[[:alnum:]_-]*\%(://.\{-\}\)\=$','','') : '' if rev ==# '' let expanded = s:buffer().rev() elseif rev ==# ':' @@ -1459,8 +2165,8 @@ function! s:Browse(bang,line1,count,...) abort endif endif - if a:0 && a:1 =~# '@[[:alnum:]_-]*\%(://.\{-\}\)\=$' - let remote = matchstr(a:1,'@\zs[[:alnum:]_-]\+\%(://.\{-\}\)\=$') + if a:0 && join(a:000, ' ') =~# '@[[:alnum:]_-]*\%(://.\{-\}\)\=$' + let remote = matchstr(join(a:000, ' '),'@\zs[[:alnum:]_-]\+\%(://.\{-\}\)\=$') elseif path =~# '^\.git/refs/remotes/.' let remote = matchstr(path,'^\.git/refs/remotes/\zs[^/]\+') else @@ -1478,7 +2184,7 @@ function! s:Browse(bang,line1,count,...) abort endif if branch != '' let remote = s:repo().git_chomp('config','branch.'.branch.'.remote') - if remote ==# '' + if remote =~# '^\.\=$' let remote = 'origin' elseif rev[0:strlen(branch)-1] ==# branch && rev[strlen(branch)] =~# '[:^~@]' let rev = s:repo().git_chomp('config','branch.'.branch.'.merge')[11:-1] . rev[strlen(branch):-1] @@ -1492,35 +2198,61 @@ function! s:Browse(bang,line1,count,...) abort let raw = remote endif - let url = s:github_url(s:repo(),raw,rev,commit,path,type,a:line1,a:count) - if url == '' - let url = s:instaweb_url(s:repo(),rev,commit,path,type,a:count ? a:line1 : 0) - endif + for Handler in g:fugitive_browse_handlers + let url = call(Handler, [{ + \ 'repo': s:repo(), + \ 'remote': raw, + \ 'revision': rev, + \ 'commit': commit, + \ 'path': path, + \ 'type': type, + \ 'line1': a:count > 0 ? a:line1 : 0, + \ 'line2': a:count > 0 ? a:count : 0}]) + if !empty(url) + break + endif + endfor - if url == '' - call s:throw("Instaweb failed to start and '".remote."' is not a GitHub remote") + if empty(url) + call s:throw("Instaweb failed to start and '".remote."' is not a supported remote") endif if a:bang - let @* = url + if has('clipboard') + let @* = url + endif return 'echomsg '.string(url) + elseif exists(':Browse') == 2 + return 'echomsg '.string(url).'|Browse '.url else - return 'echomsg '.string(url).'|silent Git web--browse '.shellescape(url,1) + return 'echomsg '.string(url).'|call netrw#NetrwBrowseX('.string(url).', 0)' endif catch /^fugitive:/ return 'echoerr v:errmsg' endtry endfunction -function! s:github_url(repo,url,rev,commit,path,type,line1,line2) abort - let path = a:path - let repo_path = matchstr(a:url,'^\%(https\=://\|git://\|git@\)github\.com[/:]\zs.\{-\}\ze\%(\.git\)\=$') - if repo_path ==# '' +function! s:github_url(opts, ...) abort + if a:0 || type(a:opts) != type({}) return '' endif - let root = 'https://github.com/' . repo_path + let domain_pattern = 'github\.com' + let domains = exists('g:fugitive_github_domains') ? g:fugitive_github_domains : [] + for domain in domains + let domain_pattern .= '\|' . escape(split(domain, '://')[-1], '.') + endfor + let repo = matchstr(get(a:opts, 'remote'), '^\%(https\=://\|git://\|git@\)\=\zs\('.domain_pattern.'\)[/:].\{-\}\ze\%(\.git\)\=$') + if repo ==# '' + return '' + endif + let path = a:opts.path + if index(domains, 'http://' . matchstr(repo, '^[^:/]*')) >= 0 + let root = 'http://' . s:sub(repo,':','/') + else + let root = 'https://' . s:sub(repo,':','/') + endif if path =~# '^\.git/refs/heads/' - let branch = a:repo.git_chomp('config','branch.'.path[16:-1].'.merge')[11:-1] + let branch = a:opts.repo.git_chomp('config','branch.'.path[16:-1].'.merge')[11:-1] if branch ==# '' return root . '/commits/' . path[16:-1] else @@ -1533,27 +2265,27 @@ function! s:github_url(repo,url,rev,commit,path,type,line1,line2) abort elseif path =~# '^\.git\>' return root endif - if a:rev =~# '^[[:alnum:]._-]\+:' - let commit = matchstr(a:rev,'^[^:]*') - elseif a:commit =~# '^\d\=$' - let local = matchstr(a:repo.head_ref(),'\' + if a:opts.path =~# '^\.git/refs/.' + return root . ';a=shortlog;h=' . matchstr(a:opts.path,'^\.git/\zs.*') + elseif a:opts.path =~# '^\.git\>' return root endif let url = root - if a:commit =~# '^\x\{40\}$' - if a:type ==# 'commit' + if a:opts.commit =~# '^\x\{40\}$' + if a:opts.type ==# 'commit' let url .= ';a=commit' endif - let url .= ';h=' . a:repo.rev_parse(a:commit . (a:path == '' ? '' : ':' . a:path)) + let url .= ';h=' . a:opts.repo.rev_parse(a:opts.commit . (a:opts.path == '' ? '' : ':' . a:opts.path)) else - if a:type ==# 'blob' + if a:opts.type ==# 'blob' let tmp = tempname() - silent execute 'write !'.a:repo.git_command('hash-object','-w','--stdin').' > '.tmp + silent execute 'write !'.a:opts.repo.git_command('hash-object','-w','--stdin').' > '.tmp let url .= ';h=' . readfile(tmp)[0] else try - let url .= ';h=' . a:repo.rev_parse((a:commit == '' ? 'HEAD' : ':' . a:commit) . ':' . a:path) + let url .= ';h=' . a:opts.repo.rev_parse((a:opts.commit == '' ? 'HEAD' : ':' . a:opts.commit) . ':' . a:opts.path) catch /^fugitive:/ call s:throw('fugitive: cannot browse uncommitted file') endtry endif - let root .= ';hb=' . matchstr(a:repo.head_ref(),'[^ ]\+$') + let root .= ';hb=' . matchstr(a:opts.repo.head_ref(),'[^ ]\+$') endif - if a:path !=# '' - let url .= ';f=' . a:path + if a:opts.path !=# '' + let url .= ';f=' . a:opts.path endif - if a:0 && a:1 - let url .= '#l' . a:1 + if get(a:opts, 'line1') + let url .= '#l' . a:opts.line1 endif return url endfunction -" }}}1 -" File access {{{1 +if !exists('g:fugitive_browse_handlers') + let g:fugitive_browse_handlers = [] +endif + +call extend(g:fugitive_browse_handlers, + \ [s:function('s:github_url'), s:function('s:instaweb_url')]) + +" Section: File access function! s:ReplaceCmd(cmd,...) abort - let fn = bufname('') + let fn = expand('%:p') let tmp = tempname() - let aw = &autowrite let prefix = '' try if a:0 && a:1 != '' - if &shell =~# 'cmd' + if s:winshell() let old_index = $GIT_INDEX_FILE let $GIT_INDEX_FILE = a:1 else let prefix = 'env GIT_INDEX_FILE='.s:shellesc(a:1).' ' endif endif - set noautowrite - silent exe '!'.escape(prefix.a:cmd,'%#').' > '.tmp + if s:winshell() + let cmd_escape_char = &shellxquote == '(' ? '^' : '^^^' + call system('cmd /c "'.prefix.s:gsub(a:cmd,'[<>]', cmd_escape_char.'&').' > '.tmp.'"') + else + call system(' ('.prefix.a:cmd.' > '.tmp.') ') + endif finally - let &autowrite = aw if exists('old_index') let $GIT_INDEX_FILE = old_index endif endtry silent exe 'keepalt file '.tmp - silent edit! - silent exe 'keepalt file '.s:fnameescape(fn) - call delete(tmp) - silent exe 'doau BufReadPost '.s:fnameescape(fn) + try + silent edit! + finally + try + silent exe 'keepalt file '.s:fnameescape(fn) + catch /^Vim\%((\a\+)\)\=:E302/ + endtry + call delete(tmp) + if fnamemodify(bufname('$'), ':p') ==# tmp + silent execute 'bwipeout '.bufnr('$') + endif + silent exe 'doau BufReadPost '.s:fnameescape(fn) + endtry endfunction -function! s:BufReadIndex() +function! s:BufReadIndex() abort if !exists('b:fugitive_display_format') let b:fugitive_display_format = filereadable(expand('%').'.lock') endif @@ -1643,7 +2392,7 @@ function! s:BufReadIndex() let b:fugitive_type = 'index' try let b:git_dir = s:repo().dir() - setlocal noro ma + setlocal noro ma nomodeline if fnamemodify($GIT_INDEX_FILE !=# '' ? $GIT_INDEX_FILE : b:git_dir . '/index', ':p') ==# expand('%:p') let index = '' else @@ -1655,40 +2404,65 @@ function! s:BufReadIndex() else let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' let dir = getcwd() + if fugitive#git_version() =~# '^0\|^1\.[1-7]\.' + let cmd = s:repo().git_command('status') + else + let cmd = s:repo().git_command( + \ '-c', 'status.displayCommentPrefix=true', + \ '-c', 'color.status=false', + \ '-c', 'status.short=false', + \ 'status') + endif try execute cd.'`=s:repo().tree()`' - call s:ReplaceCmd(s:repo().git_command('status'),index) + call s:ReplaceCmd(cmd, index) finally execute cd.'`=dir`' endtry set ft=gitcommit + set foldtext=fugitive#foldtext() + endif + setlocal ro noma nomod noswapfile + if &bufhidden ==# '' + setlocal bufhidden=delete endif - setlocal ro noma nomod nomodeline bufhidden=delete - nnoremap a :let b:fugitive_display_format += 1exe BufReadIndex() - nnoremap i :let b:fugitive_display_format -= 1exe BufReadIndex() - nnoremap D :execute StageDiff() - nnoremap dd :execute StageDiff() - nnoremap dh :execute StageDiff('Gsdiff') - nnoremap ds :execute StageDiff('Gsdiff') - nnoremap dv :execute StageDiff() - nnoremap - :execute StageToggle(line('.'),line('.')+v:count1-1) - xnoremap - :execute StageToggle(line("'<"),line("'>")) - nnoremap p :execute StagePatch(line('.'),line('.')+v:count1-1) - xnoremap p :execute StagePatch(line("'<"),line("'>")) - nnoremap :call search('^#\t.*','W'). - nnoremap :call search('^#\t.*','Wbe'). call s:JumpInit() nunmap P nunmap ~ + nnoremap :execute StageNext(v:count1) + nnoremap :execute StagePrevious(v:count1) + nnoremap - :silent execute StageToggle(line('.'),line('.')+v:count1-1) + xnoremap - :silent execute StageToggle(line("'<"),line("'>")) + nnoremap a :let b:fugitive_display_format += 1exe BufReadIndex() + nnoremap i :let b:fugitive_display_format -= 1exe BufReadIndex() nnoremap C :Gcommit + nnoremap cA :Gcommit --amend --reuse-message=HEAD + nnoremap ca :Gcommit --amend + nnoremap cc :Gcommit + nnoremap cva :Gcommit --amend --verbose + nnoremap cvc :Gcommit --verbose + nnoremap D :execute StageDiff('Gdiff') + nnoremap dd :execute StageDiff('Gdiff') + nnoremap dh :execute StageDiff('Gsdiff') + nnoremap ds :execute StageDiff('Gsdiff') + nnoremap dp :execute StageDiffEdit() + nnoremap dv :execute StageDiff('Gvdiff') + nnoremap p :execute StagePatch(line('.'),line('.')+v:count1-1) + xnoremap p :execute StagePatch(line("'<"),line("'>")) + nnoremap q :if bufnr('$') == 1quitelsebdeleteendif + nnoremap r :edit + nnoremap R :edit + nnoremap U :execute StageUndo() + nnoremap g? :help fugitive-:Gstatus + nnoremap :help fugitive-:Gstatus catch /^fugitive:/ return 'echoerr v:errmsg' endtry endfunction -function! s:FileRead() +function! s:FileRead() abort try - let repo = s:repo(s:ExtractGitDir(expand(''))) + let repo = s:repo(fugitive#extract_git_dir(expand(''))) let path = s:sub(s:sub(matchstr(expand(''),'fugitive://.\{-\}//\zs.*'),'/',':'),'^\d:',':&') let hash = repo.rev_parse(path) if path =~ '^:' @@ -1703,21 +2477,28 @@ function! s:FileRead() endtry endfunction -function! s:BufReadIndexFile() +function! s:BufReadIndexFile() abort try let b:fugitive_type = 'blob' let b:git_dir = s:repo().dir() - call s:ReplaceCmd(s:repo().git_command('cat-file','blob',s:buffer().sha1())) + try + call s:ReplaceCmd(s:repo().git_command('cat-file','blob',s:buffer().sha1())) + finally + if &bufhidden ==# '' + setlocal bufhidden=delete + endif + setlocal noswapfile + endtry return '' catch /^fugitive: rev-parse/ - silent exe 'doau BufNewFile '.s:fnameescape(bufname('')) + silent exe 'doau BufNewFile '.s:fnameescape(expand('%:p')) return '' catch /^fugitive:/ return 'echoerr v:errmsg' endtry endfunction -function! s:BufWriteIndexFile() +function! s:BufWriteIndexFile() abort let tmp = tempname() try let path = matchstr(expand(''),'//\d/\zs.*') @@ -1730,14 +2511,16 @@ function! s:BufWriteIndexFile() endif let info = old_mode.' '.sha1.' '.stage."\t".path call writefile([info],tmp) - if has('win32') - let error = system('type '.tmp.'|'.s:repo().git_command('update-index','--index-info')) + if s:winshell() + let error = system('type '.s:gsub(tmp,'/','\\').'|'.s:repo().git_command('update-index','--index-info')) else let error = system(s:repo().git_command('update-index','--index-info').' < '.tmp) endif if v:shell_error == 0 setlocal nomodified - silent execute 'doautocmd BufWritePost '.s:fnameescape(expand('%:p')) + if exists('#BufWritePost') + execute 'doautocmd BufWritePost '.s:fnameescape(expand('%:p')) + endif call fugitive#reload_status() return '' else @@ -1748,7 +2531,7 @@ function! s:BufWriteIndexFile() endtry endfunction -function! s:BufReadObject() +function! s:BufReadObject() abort try setlocal noro ma let b:git_dir = s:repo().dir() @@ -1764,53 +2547,65 @@ function! s:BufReadObject() let b:fugitive_display_format = +getbufvar('#','fugitive_display_format') endif + if b:fugitive_type !=# 'blob' + setlocal nomodeline + endif + let pos = getpos('.') - silent %delete + silent keepjumps %delete_ setlocal endofline - if b:fugitive_type == 'tree' - let b:fugitive_display_format = b:fugitive_display_format % 2 - if b:fugitive_display_format - call s:ReplaceCmd(s:repo().git_command('ls-tree',hash)) - else - call s:ReplaceCmd(s:repo().git_command('show',hash)) - endif - elseif b:fugitive_type == 'tag' - let b:fugitive_display_format = b:fugitive_display_format % 2 - if b:fugitive_display_format - call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) - else - call s:ReplaceCmd(s:repo().git_command('cat-file','-p',hash)) - endif - elseif b:fugitive_type == 'commit' - let b:fugitive_display_format = b:fugitive_display_format % 2 - if b:fugitive_display_format - call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) - else - 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)) - call search('^parent ') - if getline('.') ==# 'parent ' - silent delete_ + try + if b:fugitive_type ==# 'tree' + let b:fugitive_display_format = b:fugitive_display_format % 2 + if b:fugitive_display_format + call s:ReplaceCmd(s:repo().git_command('ls-tree',hash)) else - silent s/\%(^parent\)\@\)\=$','W',line('.')+3) - silent delete_ - end - 1 + elseif b:fugitive_type ==# 'tag' + let b:fugitive_display_format = b:fugitive_display_format % 2 + if b:fugitive_display_format + call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) + else + call s:ReplaceCmd(s:repo().git_command('cat-file','-p',hash)) + endif + elseif b:fugitive_type ==# 'commit' + let b:fugitive_display_format = b:fugitive_display_format % 2 + if b:fugitive_display_format + call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) + else + call s:ReplaceCmd(s:repo().git_command('show','--no-color','--pretty=format:tree %T%nparent %P%nauthor %an <%ae> %ad%ncommitter %cn <%ce> %cd%nencoding %e%n%n%s%n%n%b',hash)) + keepjumps call search('^parent ') + if getline('.') ==# 'parent ' + silent keepjumps delete_ + else + silent keepjumps s/\%(^parent\)\@\)\=$','W',line('.')+3) + if lnum + silent keepjumps delete_ + end + keepjumps 1 + endif + elseif b:fugitive_type ==# 'blob' + call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) + setlocal nomodeline endif - elseif b:fugitive_type ==# 'blob' - call s:ReplaceCmd(s:repo().git_command('cat-file',b:fugitive_type,hash)) - endif - call setpos('.',pos) - setlocal ro noma nomod nomodeline - if b:fugitive_type !=# 'blob' - set filetype=git - nnoremap a :let b:fugitive_display_format += v:count1exe BufReadObject() - nnoremap i :let b:fugitive_display_format -= v:count1exe BufReadObject() - else - call s:JumpInit() - endif + finally + keepjumps call setpos('.',pos) + setlocal ro noma nomod noswapfile + if &bufhidden ==# '' + setlocal bufhidden=delete + endif + if b:fugitive_type !=# 'blob' + setlocal filetype=git foldmethod=syntax + nnoremap a :let b:fugitive_display_format += v:count1exe BufReadObject() + nnoremap i :let b:fugitive_display_format -= v:count1exe BufReadObject() + else + call s:JumpInit() + endif + endtry return '' catch /^fugitive:/ @@ -1820,31 +2615,61 @@ endfunction augroup fugitive_files autocmd! - autocmd BufReadCmd *.git/index exe s:BufReadIndex() - autocmd BufReadCmd *.git/*index*.lock exe s:BufReadIndex() + autocmd BufReadCmd index{,.lock} + \ if fugitive#is_git_dir(expand(':p:h')) | + \ exe s:BufReadIndex() | + \ elseif filereadable(expand('')) | + \ read | + \ 1delete | + \ endif autocmd FileReadCmd fugitive://**//[0-3]/** exe s:FileRead() autocmd BufReadCmd fugitive://**//[0-3]/** exe s:BufReadIndexFile() autocmd BufWriteCmd fugitive://**//[0-3]/** exe s:BufWriteIndexFile() autocmd BufReadCmd fugitive://**//[0-9a-f][0-9a-f]* exe s:BufReadObject() autocmd FileReadCmd fugitive://**//[0-9a-f][0-9a-f]* exe s:FileRead() - autocmd FileType git call s:JumpInit() + autocmd FileType git + \ if exists('b:git_dir') | + \ call s:JumpInit() | + \ endif augroup END -" }}}1 -" Go to file {{{1 +" Section: Temp files + +if !exists('s:temp_files') + let s:temp_files = {} +endif + +augroup fugitive_temp + autocmd! + autocmd BufNewFile,BufReadPost * + \ if has_key(s:temp_files,tolower(expand(':p'))) | + \ let b:git_dir = s:temp_files[tolower(expand(':p'))].dir | + \ let b:git_type = 'temp' | + \ let b:git_args = s:temp_files[tolower(expand(':p'))].args | + \ call fugitive#detect(expand(':p')) | + \ setlocal bufhidden=delete nobuflisted | + \ nnoremap q :bdelete| + \ endif +augroup END + +" Section: Go to file function! s:JumpInit() abort nnoremap :exe GF("edit") if !&modifiable nnoremap o :exe GF("split") + nnoremap S :exe GF("vsplit") nnoremap O :exe GF("tabedit") - nnoremap P :exe Edit('edit',buffer().commit().'^'.v:count1.buffer().path(':')) - nnoremap ~ :exe Edit('edit',buffer().commit().'~'.v:count1.buffer().path(':')) - nnoremap C :exe Edit('edit',buffer().containing_commit()) - nnoremap cc :exe Edit('edit',buffer().containing_commit()) - nnoremap co :exe Edit('split',buffer().containing_commit()) - nnoremap cO :exe Edit('tabedit',buffer().containing_commit()) - nnoremap cp :exe Edit('pedit',buffer().containing_commit()) + nnoremap - :exe Edit('edit',0,buffer().up(v:count1)) if fugitive#buffer().type('tree')call search('^'.escape(expand('#:t'),'.*[]~\').'/\=$','wc')endif + nnoremap P :exe Edit('edit',0,buffer().commit().'^'.v:count1.buffer().path(':')) + nnoremap ~ :exe Edit('edit',0,buffer().commit().'~'.v:count1.buffer().path(':')) + nnoremap C :exe Edit('edit',0,buffer().containing_commit()) + nnoremap cc :exe Edit('edit',0,buffer().containing_commit()) + nnoremap co :exe Edit('split',0,buffer().containing_commit()) + nnoremap cS :exe Edit('vsplit',0,buffer().containing_commit()) + nnoremap cO :exe Edit('tabedit',0,buffer().containing_commit()) + nnoremap cP :exe Edit('pedit',0,buffer().containing_commit()) + nnoremap . : =fnameescape(recall()) endif endfunction @@ -1852,15 +2677,18 @@ function! s:GF(mode) abort try let buffer = s:buffer() let myhash = buffer.sha1() + if myhash ==# '' && getline(1) =~# '^\%(commit\|tag\) \w' + let myhash = matchstr(getline(1),'^\w\+ \zs\S\+') + endif if buffer.type('tree') let showtree = (getline(1) =~# '^tree ' && getline(2) == "") if showtree && line('.') == 1 return "" elseif showtree && line('.') > 2 - return s:Edit(a:mode,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(getline('.'),'/$','')) + return s:Edit(a:mode,0,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(getline('.'),'/$','')) elseif getline('.') =~# '^\d\{6\} \l\{3,8\} \x\{40\}\t' - return s:Edit(a:mode,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(matchstr(getline('.'),'\t\zs.*'),'/$','')) + return s:Edit(a:mode,0,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(matchstr(getline('.'),'\t\zs.*'),'/$','')) endif elseif buffer.type('blob') @@ -1870,7 +2698,7 @@ function! s:GF(mode) abort catch /^fugitive:/ endtry if exists('sha1') - return s:Edit(a:mode,ref) + return s:Edit(a:mode,0,ref) endif else @@ -1879,29 +2707,29 @@ function! s:GF(mode) abort if getline('.') =~# '^\d\{6\} \x\{40\} \d\t' let ref = matchstr(getline('.'),'\x\{40\}') let file = ':'.s:sub(matchstr(getline('.'),'\d\t.*'),'\t',':') - return s:Edit(a:mode,file) + return s:Edit(a:mode,0,file) elseif getline('.') =~# '^#\trenamed:.* -> ' let file = '/'.matchstr(getline('.'),' -> \zs.*') - return s:Edit(a:mode,file) + return s:Edit(a:mode,0,file) elseif getline('.') =~# '^#\t[[:alpha:] ]\+: *.' - let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( (new commits)\)\=$') - return s:Edit(a:mode,file) + let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$') + return s:Edit(a:mode,0,file) elseif getline('.') =~# '^#\t.' let file = '/'.matchstr(getline('.'),'#\t\zs.*') - return s:Edit(a:mode,file) + return s:Edit(a:mode,0,file) elseif getline('.') =~# ': needs merge$' let file = '/'.matchstr(getline('.'),'.*\ze: needs merge$') - return s:Edit(a:mode,file).'|Gdiff' + return s:Edit(a:mode,0,file).'|Gdiff' elseif getline('.') ==# '# Not currently on any branch.' - return s:Edit(a:mode,'HEAD') + return s:Edit(a:mode,0,'HEAD') elseif getline('.') =~# '^# On branch ' let file = 'refs/heads/'.getline('.')[12:] - return s:Edit(a:mode,file) + return s:Edit(a:mode,0,file) elseif getline('.') =~# "^# Your branch .*'" let file = matchstr(getline('.'),"'\\zs\\S\\+\\ze'") - return s:Edit(a:mode,file) + return s:Edit(a:mode,0,file) endif let showtree = (getline(1) =~# '^tree ' && getline(2) == "") @@ -1909,6 +2737,10 @@ function! s:GF(mode) abort if getline('.') =~# '^ref: ' let ref = strpart(getline('.'),5) + elseif getline('.') =~# '^commit \x\{40\}\>' + let ref = matchstr(getline('.'),'\x\{40\}') + return s:Edit(a:mode,0,ref) + elseif getline('.') =~# '^parent \x\{40\}\>' let ref = matchstr(getline('.'),'\x\{40\}') let line = line('.') @@ -1917,14 +2749,14 @@ function! s:GF(mode) abort let parent += 1 let line -= 1 endwhile - return s:Edit(a:mode,ref) + return s:Edit(a:mode,0,ref) elseif getline('.') =~ '^tree \x\{40\}$' let ref = matchstr(getline('.'),'\x\{40\}') if s:repo().rev_parse(myhash.':') == ref let ref = myhash.':' endif - return s:Edit(a:mode,ref) + return s:Edit(a:mode,0,ref) elseif getline('.') =~# '^object \x\{40\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$' let ref = matchstr(getline('.'),'\x\{40\}') @@ -1940,6 +2772,21 @@ function! s:GF(mode) abort elseif getline('.') =~# '^[+-]\{3\} [ab/]' let ref = getline('.')[4:] + elseif getline('.') =~# '^[+-]' && search('^@@ -\d\+,\d\+ +\d\+,','bnW') + let type = getline('.')[0] + let lnum = line('.') - 1 + let offset = -1 + while getline(lnum) !~# '^@@ -\d\+,\d\+ +\d\+,' + if getline(lnum) =~# '^[ '.type.']' + let offset += 1 + endif + let lnum -= 1 + endwhile + let offset += matchstr(getline(lnum), type.'\zs\d\+') + let ref = getline(search('^'.type.'\{3\} [ab]/','bnW'))[4:-1] + let dcmd = '+'.offset.'|normal! zv' + let dref = '' + elseif getline('.') =~# '^rename from ' let ref = 'a/'.getline('.')[12:] elseif getline('.') =~# '^rename to ' @@ -1958,6 +2805,10 @@ function! s:GF(mode) abort elseif line('$') == 1 && getline('.') =~ '^\x\{40\}$' let ref = getline('.') + + elseif expand('') =~# '^\x\{7,40\}\>' + return s:Edit(a:mode,0,expand('')) + else let ref = '' endif @@ -1982,9 +2833,9 @@ function! s:GF(mode) abort endif if exists('dref') - return s:Edit(a:mode,ref) . '|'.dcmd.' '.s:fnameescape(dref) + return s:Edit(a:mode,0,ref) . '|'.dcmd.' '.s:fnameescape(dref) elseif ref != "" - return s:Edit(a:mode,ref) + return s:Edit(a:mode,0,ref) endif endif @@ -1994,16 +2845,18 @@ function! s:GF(mode) abort endtry endfunction -" }}}1 -" Statusline {{{1 +" Section: Statusline function! s:repo_head_ref() dict abort - return readfile(s:repo().dir('HEAD'))[0] + if !filereadable(self.dir('HEAD')) + return '' + endif + return readfile(self.dir('HEAD'))[0] endfunction call s:add_methods('repo',['head_ref']) -function! fugitive#statusline(...) +function! fugitive#statusline(...) abort if !exists('b:git_dir') return '' endif @@ -2011,12 +2864,7 @@ function! fugitive#statusline(...) if s:buffer().commit() != '' let status .= ':' . s:buffer().commit()[0:7] endif - let head = s:repo().head_ref() - if head =~# '^ref: ' - let status .= s:sub(head,'^ref: %(refs/%(heads/|remotes/|tags/)=)=','(').')' - elseif head =~# '^\x\{40\}$' - let status .= '('.head[0:7].')' - endif + let status .= '('.fugitive#head(7).')' if &statusline =~# '%[MRHWY]' && &statusline !~# '%[mrhwy]' return ',GIT'.status else @@ -2024,18 +2872,59 @@ function! fugitive#statusline(...) endif endfunction -function! s:repo_config(conf) dict abort - return matchstr(system(s:repo().git_command('config').' '.a:conf),"[^\r\n]*") -endfun +function! fugitive#head(...) abort + if !exists('b:git_dir') + return '' + endif -function! s:repo_user() dict abort - let username = s:repo().config('user.name') - let useremail = s:repo().config('user.email') - return username.' <'.useremail.'>' -endfun + return s:repo().head(a:0 ? a:1 : 0) +endfunction -call s:add_methods('repo',['config', 'user']) +" Section: Folding -" }}}1 +function! fugitive#foldtext() abort + if &foldmethod !=# 'syntax' + return foldtext() + elseif getline(v:foldstart) =~# '^diff ' + let [add, remove] = [-1, -1] + let filename = '' + for lnum in range(v:foldstart, v:foldend) + if filename ==# '' && getline(lnum) =~# '^[+-]\{3\} [abciow12]/' + let filename = getline(lnum)[6:-1] + endif + if getline(lnum) =~# '^+' + let add += 1 + elseif getline(lnum) =~# '^-' + let remove += 1 + elseif getline(lnum) =~# '^Binary ' + let binary = 1 + endif + endfor + if filename ==# '' + let filename = matchstr(getline(v:foldstart), '^diff .\{-\} a/\zs.*\ze b/') + endif + if filename ==# '' + let filename = getline(v:foldstart)[5:-1] + endif + if exists('binary') + return 'Binary: '.filename + else + return (add<10&&remove<100?' ':'') . add . '+ ' . (remove<10&&add<100?' ':'') . remove . '- ' . filename + endif + elseif getline(v:foldstart) =~# '^# .*:$' + let lines = getline(v:foldstart, v:foldend) + call filter(lines, 'v:val =~# "^#\t"') + cal map(lines,'s:sub(v:val, "^#\t%(modified: +|renamed: +)=", "")') + cal map(lines,'s:sub(v:val, "^([[:alpha:] ]+): +(.*)", "\\2 (\\1)")') + return getline(v:foldstart).' '.join(lines, ', ') + endif + return foldtext() +endfunction -" vim:set ft=vim ts=8 sw=2 sts=2: +augroup fugitive_foldtext + autocmd! + autocmd User Fugitive + \ if &filetype =~# '^git\%(commit\)\=$' && &foldtext ==# 'foldtext()' | + \ set foldtext=fugitive#foldtext() | + \ endif +augroup END diff --git a/vimfiles/plugin/linediff.vim b/vimfiles/plugin/linediff.vim index f154d6d..59d3437 100644 --- a/vimfiles/plugin/linediff.vim +++ b/vimfiles/plugin/linediff.vim @@ -1,15 +1,32 @@ -if exists("g:loaded_linediff") || &cp +if exists('g:loaded_linediff') || &cp finish endif -let g:loaded_linediff = '0.1.1' " version number +let g:loaded_linediff = '0.2.0' " version number let s:keepcpo = &cpo set cpo&vim +if !exists('g:linediff_indent') + let g:linediff_indent = 0 +endif + +if !exists('g:linediff_buffer_type') + " One of: 'tempfile', 'scratch' + let g:linediff_buffer_type = 'tempfile' +endif + +if !exists('g:linediff_first_buffer_command') + let g:linediff_first_buffer_command = 'tabnew' +endif + +if !exists('g:linediff_second_buffer_command') + let g:linediff_second_buffer_command = 'rightbelow vertical new' +endif + " Initialized lazily to avoid executing the autoload file before it's really " needed. function! s:Init() - if !exists('s:differ_one') + if !s:IsInitialized() let s:differ_one = linediff#differ#New('linediff_one', 1) let s:differ_two = linediff#differ#New('linediff_two', 2) endif @@ -24,25 +41,46 @@ function! s:Linediff(from, to) elseif s:differ_two.IsBlank() call s:differ_two.Init(a:from, a:to) - call s:PerformDiff(s:differ_one, s:differ_two) + call s:PerformDiff() else - call s:differ_one.Reset() - call s:differ_two.Reset() - + call s:LinediffReset('!') call s:Linediff(a:from, a:to) endif endfunction -command! LinediffReset call s:LinediffReset() -function! s:LinediffReset() - call s:differ_one.Reset() - call s:differ_two.Reset() +command! -bang LinediffReset call s:LinediffReset() +function! s:LinediffReset(bang) + if s:IsInitialized() + let force = a:bang == '!' + call s:differ_one.CloseAndReset(force) + call s:differ_two.CloseAndReset(force) + endif endfunction -function! s:PerformDiff(one, two) - call a:one.CreateDiffBuffer("tabedit") - call a:two.CreateDiffBuffer("rightbelow vsplit") - - let a:one.other_differ = a:two - let a:two.other_differ = a:one +" Checks whether plugin is initialized. +function! s:IsInitialized() + return exists('s:differ_one') endfunction + +" The closing logic is a bit roundabout, since changing a buffer in a +" BufUnload autocommand doesn't seem to work. +" +" The process is: if a window is entered after the other differ was destroyed, +" destroy this one as well and close the window. +" +function! s:PerformDiff() + call s:differ_one.CreateDiffBuffer(g:linediff_first_buffer_command) + autocmd BufUnload silent call s:differ_one.Reset() + autocmd WinEnter if s:differ_two.IsBlank() | silent call s:differ_one.CloseAndReset(0) | endif + + call s:differ_two.CreateDiffBuffer(g:linediff_second_buffer_command) + autocmd BufUnload silent call s:differ_two.Reset() + autocmd WinEnter if s:differ_one.IsBlank() | silent call s:differ_two.CloseAndReset(0) | endif + + wincmd t " move to the first diff buffer + + let s:differ_one.other_differ = s:differ_two + let s:differ_two.other_differ = s:differ_one +endfunction + +let &cpo = s:keepcpo diff --git a/vimfiles/plugin/tcomment.vim b/vimfiles/plugin/tcomment.vim index 02f58c7..4d095ad 100644 --- a/vimfiles/plugin/tcomment.vim +++ b/vimfiles/plugin/tcomment.vim @@ -2,14 +2,14 @@ " @Author: Tom Link (micathom AT gmail com) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Created: 27-Dez-2004. -" @Last Change: 2014-02-05. -" @Revision: 811 +" @Last Change: 2014-06-30. +" @Revision: 840 " GetLatestVimScripts: 1173 1 tcomment.vim if &cp || exists('loaded_tcomment') finish endif -let loaded_tcomment = 303 +let loaded_tcomment = 304 let s:save_cpo = &cpo set cpo&vim @@ -37,9 +37,14 @@ if !exists("g:tcommentMapLeaderOp1") let g:tcommentMapLeaderOp1 = 'gc' "{{{2 endif -if !exists("g:tcommentMapLeaderOp2") +if !exists("g:tcommentMapLeaderUncommentAnyway") " See |tcomment-operator|. - let g:tcommentMapLeaderOp2 = 'gC' "{{{2 + let g:tcommentMapLeaderUncommentAnyway = 'g<' "{{{2 +endif + +if !exists("g:tcommentMapLeaderCommentAnyway") + " See |tcomment-operator|. + let g:tcommentMapLeaderCommentAnyway = 'g>' "{{{2 endif if !exists('g:tcommentTextObjectInlineComment') @@ -56,7 +61,7 @@ endif " ARGS... are either (see also |tcomment#Comment()|): " 1. a list of key=value pairs " 2. 1-2 values for: ?commentBegin, ?commentEnd -command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TComment +command! -bar -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TComment \ keepjumps call tcomment#Comment(, , 'G', "", ) " :display: :[range]TCommentAs[!] commenttype ?ARGS... @@ -66,7 +71,7 @@ command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TComme " ARGS... are either (see also |tcomment#Comment()|): " 1. a list of key=value pairs " 2. 1-2 values for: ?commentBegin, ?commentEnd -command! -bang -complete=customlist,tcomment#Complete -range -nargs=+ TCommentAs +command! -bar -bang -complete=customlist,tcomment#Complete -range -nargs=+ TCommentAs \ call tcomment#CommentAs(, , "", ) " :display: :[range]TCommentRight[!] ?ARGS... @@ -78,7 +83,7 @@ command! -bang -complete=customlist,tcomment#Complete -range -nargs=+ TCommentAs " ARGS... are either (see also |tcomment#Comment()|): " 1. a list of key=value pairs " 2. 1-2 values for: ?commentBegin, ?commentEnd -command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TCommentRight +command! -bar -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TCommentRight \ keepjumps call tcomment#Comment(, , 'R', "", ) " :display: :[range]TCommentBlock[!] ?ARGS... @@ -89,7 +94,7 @@ command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TComme " ARGS... are either (see also |tcomment#Comment()|): " 1. a list of key=value pairs " 2. 1-2 values for: ?commentBegin, ?commentEnd -command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TCommentBlock +command! -bar -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TCommentBlock \ keepjumps call tcomment#Comment(, , 'B', "", ) " :display: :[range]TCommentInline[!] ?ARGS... @@ -99,7 +104,7 @@ command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TComme " ARGS... are either (see also |tcomment#Comment()|): " 1. a list of key=value pairs " 2. 1-2 values for: ?commentBegin, ?commentEnd -command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TCommentInline +command! -bar -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TCommentInline \ keepjumps call tcomment#Comment(, , 'I', "", ) " :display: :[range]TCommentMaybeInline[!] ?ARGS... @@ -108,7 +113,7 @@ command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TComme " ARGS... are either (see also |tcomment#Comment()|): " 1. a list of key=value pairs " 2. 1-2 values for: ?commentBegin, ?commentEnd -command! -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TCommentMaybeInline +command! -bar -bang -range -nargs=* -complete=customlist,tcomment#CompleteArgs TCommentMaybeInline \ keepjumps call tcomment#Comment(, , 'i', "", ) @@ -146,10 +151,15 @@ noremap TComment-_a :TCommentAs noremap TComment-_n :TCommentAs =&ft noremap TComment-_s :TCommentAs =&ft_ -nnoremap TComment-gC :let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ -nnoremap TComment-gCc :let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ -nnoremap TComment-gCb :let w:tcommentPos = getpos(".") \| call tcomment#SetOption("mode_extra", "B") \| set opfunc=tcomment#OperatorLineg@ -xnoremap TComment-gC :TCommentMaybeInline! +nnoremap TComment-Uncomment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ +nnoremap TComment-Uncommentc :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ +nnoremap TComment-Uncommentb :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "UB") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@ +xnoremap TComment-Uncomment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "U") \| '<,'>TCommentMaybeInline + +nnoremap TComment-Comment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorAnywayg@ +nnoremap TComment-Commentc :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineAnywayg@$ +nnoremap TComment-Commentb :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| call tcomment#SetOption("mode_extra", "B") \| let w:tcommentPos = getpos(".") \| set opfunc=tcomment#OperatorLineg@ +xnoremap TComment-Comment :if v:count > 0 \| call tcomment#SetOption("count", v:count) \| endif \| '<,'>TCommentMaybeInline! vnoremap TComment-ic :call tcomment#TextObjectInlineComment() noremap TComment-ic :call tcomment#TextObjectInlineComment() @@ -224,11 +234,17 @@ if g:tcommentMaps exec 'nmap '. g:tcommentMapLeaderOp1 .'b TComment-gcb' exec 'xmap '. g:tcommentMapLeaderOp1 .' TComment-gc' endif - if g:tcommentMapLeaderOp2 != '' - exec 'nmap '. g:tcommentMapLeaderOp2 .' TComment-gC' - exec 'nmap '. g:tcommentMapLeaderOp2 .'c TComment-gCc' - exec 'nmap '. g:tcommentMapLeaderOp2 .'b TComment-gCb' - exec 'xmap '. g:tcommentMapLeaderOp2 .' TComment-gC' + if g:tcommentMapLeaderUncommentAnyway != '' + exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .' TComment-Uncomment' + exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .'c TComment-Uncommentc' + exec 'nmap '. g:tcommentMapLeaderUncommentAnyway .'b TComment-Uncommentb' + exec 'xmap '. g:tcommentMapLeaderUncommentAnyway .' TComment-Uncomment' + endif + if g:tcommentMapLeaderCommentAnyway != '' + exec 'nmap '. g:tcommentMapLeaderCommentAnyway .' TComment-Comment' + exec 'nmap '. g:tcommentMapLeaderCommentAnyway .'c TComment-Commentc' + exec 'nmap '. g:tcommentMapLeaderCommentAnyway .'b TComment-Commentb' + exec 'xmap '. g:tcommentMapLeaderCommentAnyway .' TComment-Comment' endif if g:tcommentTextObjectInlineComment != '' exec 'vmap' g:tcommentTextObjectInlineComment ' TComment-ic'