diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index 69439c2..cabf629 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -1617,48 +1617,95 @@ function! fugitive#BufReadStatus() abort if s:cpath(fnamemodify($GIT_INDEX_FILE !=# '' ? $GIT_INDEX_FILE : fugitive#Find('.git/index'), ':p')) !=# s:cpath(amatch) let cmd += ['-c', 'GIT_INDEX_FILE=' . amatch] endif - let cmd += ['status', '--porcelain', '-bz'] - let [output, message, exec_error] = s:NullError(cmd) - if exec_error - throw 'fugitive: ' . message - endif - - let head = matchstr(output[0], '^## \zs\S\+\ze\%($\| \[\)') - let pull = '' - if head =~# '\.\.\.' - let [head, pull] = split(head, '\.\.\.') - let branch = head - elseif head ==# 'HEAD' || empty(head) - let head = FugitiveHead(11) - let branch = '' - else - let branch = head - endif let b:fugitive_files = {'Staged': {}, 'Unstaged': {}} let [staged, unstaged, untracked] = [[], [], []] - let i = 0 - while i < len(output) - let line = output[i] - let file = line[3:-1] - let files = file - let i += 1 - if line[2] !=# ' ' - continue + + if fugitive#GitVersion(2, 11) + let cmd += ['status', '--porcelain=v2', '-bz'] + let [output, message, exec_error] = s:NullError(cmd) + if exec_error + throw 'fugitive: ' . message endif - if line[0:1] =~# '[RC]' - let files = output[i] . ' -> ' . file + + let i = match(output, '^[^#]') + let head = matchlist(output[:i], '^# branch\.head \zs.*$')[0] + let pull = get(matchlist(output[:i], '^# branch\.upstream \zs.*$'), 0, '') + if len(pull) + let branch = head + elseif head ==# '(detached)' + let head = matchlist(output[:i], '^# branch\.oid \zs.*$')[0][:10] + let branch = '' + else + let branch = head + endif + + while i < len(output) + let line = output[i] + if line[0] ==# '?' + call add(untracked, {'type': 'File', 'status': line[0], 'filename': line[2:-1]}) + elseif line[0] !=# '#' + if line[0] ==# 'u' + let file = matchstr(line, '^.\{37\} \x\{40,\} \x\{40,\} \x\{40,\} \zs.*$') + else + let file = matchstr(line, '^.\{30\} \x\{40,\} \x\{40,\} \zs.*$') + endif + if line[0] ==# '2' + let i += 1 + let file = output[i] . ' -> ' . matchstr(file, ' \zs.*') + endif + if line[2] !=# '.' + call add(staged, {'type': 'File', 'status': line[2], 'filename': file}) + endif + if line[3] !=# '.' + let sub = matchstr(line, '^[12u] .. \zs....') + call add(unstaged, {'type': 'File', 'status': get({'C':'M','M':'?','U':'?'}, matchstr(sub, 'S\.*\zs[CMU]'), line[3]), 'filename': file}) + endif + endif let i += 1 + endwhile + else " git < 2.11 + let cmd += ['status', '--porcelain', '-bz'] + let [output, message, exec_error] = s:NullError(cmd) + if exec_error + throw 'fugitive: ' . message endif - if line[0] !~# '[ ?!#]' - call add(staged, {'type': 'File', 'status': line[0], 'filename': files}) + + let head = matchstr(output[0], '^## \zs\S\+\ze\%($\| \[\)') + let pull = '' + if head =~# '\.\.\.' + let [head, pull] = split(head, '\.\.\.') + let branch = head + elseif head ==# 'HEAD' || empty(head) + let head = FugitiveHead(11) + let branch = '' + else + let branch = head endif - if line[0:1] ==# '??' - call add(untracked, {'type': 'File', 'status': line[1], 'filename': files}) - elseif line[1] !~# '[ !#]' - call add(unstaged, {'type': 'File', 'status': line[1], 'filename': files}) - endif - endwhile + + let i = 0 + while i < len(output) + let line = output[i] + let file = line[3:-1] + let files = file + let i += 1 + if line[2] !=# ' ' + continue + endif + if line[0:1] =~# '[RC]' + let files = output[i] . ' -> ' . file + let i += 1 + endif + if line[0] !~# '[ ?!#]' + call add(staged, {'type': 'File', 'status': line[0], 'filename': files}) + endif + if line[0:1] ==# '??' + call add(untracked, {'type': 'File', 'status': line[1], 'filename': files}) + elseif line[1] !~# '[ !#]' + call add(unstaged, {'type': 'File', 'status': line[1], 'filename': files}) + endif + endwhile + endif for dict in staged let b:fugitive_files['Staged'][dict.filename] = dict