1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 09:50:04 +08:00
SpaceVim/bundle/nerdtree-git-plugin/autoload/gitstatus/util.vim
2021-09-12 23:45:01 +08:00

233 lines
7.5 KiB
VimL
Vendored

" ============================================================================
" File: autoload/git_status/util.vim
" Description: utils
" Maintainer: Xuyuan Pang <xuyuanp at gmail dot com>
" License: This program is free software. It comes without any warranty,
" to the extent permitted by applicable law. You can redistribute
" it and/or modify it under the terms of the Do What The Fuck You
" Want To Public License, Version 2, as published by Sam Hocevar.
" See http://sam.zoy.org/wtfpl/COPYING for more details.
" ============================================================================
if exists('g:loaded_nerdtree_git_status_util')
finish
endif
let g:loaded_nerdtree_git_status_util = 1
" FUNCTION: gitstatus#utilFormatPath
" This function is used to format nerdtree.Path.
" For Windows, returns in format 'C:/path/to/file'
"
" ARGS:
" path: nerdtree.Path
"
" RETURNS:
" absolute path
if gitstatus#isWin()
if exists('+shellslash')
function! gitstatus#util#FormatPath(path) abort
let l:sslbak = &shellslash
try
set shellslash
return a:path.str()
finally
let &shellslash = l:sslbak
endtry
endfunction
else
function! gitstatus#util#FormatPath(path) abort
let l:pathStr = a:path.str()
let l:pathStr = a:path.WinToUnixPath(l:pathStr)
let l:pathStr = a:path.drive . l:pathStr
return l:pathStr
endfunction
endif
else
function! gitstatus#util#FormatPath(path) abort
return a:path.str()
endfunction
endif
function! gitstatus#util#BuildGitWorkdirCommand(root, opts) abort
return [
\ get(a:opts, 'NERDTreeGitStatusGitBinPath', 'git'),
\ '-C', a:root,
\ 'rev-parse',
\ '--show-toplevel',
\ ]
endfunction
function! gitstatus#util#BuildGitStatusCommand(root, opts) abort
let l:cmd = [
\ get(a:opts, 'NERDTreeGitStatusGitBinPath', 'git'),
\ '-C', a:root,
\ 'status',
\ '--porcelain' . (get(a:opts, 'NERDTreeGitStatusPorcelainVersion', 2) ==# 2 ? '=v2' : ''),
\ '-z'
\ ]
if has_key(a:opts, 'NERDTreeGitStatusUntrackedFilesMode')
let l:cmd += ['--untracked-files=' . a:opts['NERDTreeGitStatusUntrackedFilesMode']]
endif
if get(a:opts, 'NERDTreeGitStatusShowIgnored', 0)
let l:cmd += ['--ignored=traditional']
endif
if has_key(a:opts, 'NERDTreeGitStatusIgnoreSubmodules')
let l:cmd += ['--ignore-submodules=' . a:opts['NERDTreeGitStatusIgnoreSubmodules']]
endif
if has_key(a:opts, 'NERDTreeGitStatusCwdOnly')
let l:cmd += ['.']
endif
return l:cmd
endfunction
function! gitstatus#util#ParseGitStatusLines(root, statusLines, opts) abort
let l:result = {}
let l:is_rename = 0
for l:line in a:statusLines
if l:is_rename
call gitstatus#util#UpdateParentDirsStatus(l:result, a:root, a:root . '/' . l:line, 'Dirty', a:opts)
let l:is_rename = 0
continue
endif
let [l:pathStr, l:statusKey] = gitstatus#util#ParseGitStatusLine(l:line, a:opts)
let l:pathStr = a:root . '/' . l:pathStr
if l:pathStr[-1:-1] is# '/'
let l:pathStr = l:pathStr[:-2]
endif
let l:is_rename = l:statusKey is# 'Renamed'
let l:result[l:pathStr] = l:statusKey
call gitstatus#util#UpdateParentDirsStatus(l:result, a:root, l:pathStr, l:statusKey, a:opts)
endfor
return l:result
endfunction
let s:unmerged_status = {
\ 'DD': 1,
\ 'AU': 1,
\ 'UD': 1,
\ 'UA': 1,
\ 'DU': 1,
\ 'AA': 1,
\ 'UU': 1,
\ }
" Function: s:getStatusKey() function {{{2
" This function is used to get git status key
"
" Args:
" x: index tree
" y: work tree
"
"Returns:
" status key
"
" man git-status
" X Y Meaning
" -------------------------------------------------
" [MD] not updated
" M [ MD] updated in index
" A [ MD] added to index
" D [ M] deleted from index
" R [ MD] renamed in index
" C [ MD] copied in index
" [MARC] index and work tree matches
" [ MARC] M work tree changed since index
" [ MARC] D deleted in work tree
" -------------------------------------------------
" D D unmerged, both deleted
" A U unmerged, added by us
" U D unmerged, deleted by them
" U A unmerged, added by them
" D U unmerged, deleted by us
" A A unmerged, both added
" U U unmerged, both modified
" -------------------------------------------------
" ? ? untracked
" ! ! ignored
" -------------------------------------------------
function! s:getStatusKey(x, y) abort
let l:xy = a:x . a:y
if get(s:unmerged_status, l:xy, 0)
return 'Unmerged'
elseif l:xy ==# '??'
return 'Untracked'
elseif l:xy ==# '!!'
return 'Ignored'
elseif a:y ==# 'M'
return 'Modified'
elseif a:y ==# 'D'
return 'Deleted'
elseif a:y =~# '[RC]'
return 'Renamed'
elseif a:x ==# 'D'
return 'Deleted'
elseif a:x =~# '[MA]'
return 'Staged'
elseif a:x =~# '[RC]'
return 'Renamed'
else
return 'Unknown'
endif
endfunction
function! gitstatus#util#ParseGitStatusLine(statusLine, opts) abort
if get(a:opts, 'NERDTreeGitStatusPorcelainVersion', 2) ==# 2
if a:statusLine[0] ==# '1'
let l:statusKey = s:getStatusKey(a:statusLine[2], a:statusLine[3])
let l:pathStr = a:statusLine[113:]
elseif a:statusLine[0] ==# '2'
let l:statusKey = 'Renamed'
let l:pathStr = a:statusLine[113:]
let l:pathStr = l:pathStr[stridx(l:pathStr, ' ')+1:]
elseif a:statusLine[0] ==# 'u'
let l:statusKey = 'Unmerged'
let l:pathStr = a:statusLine[161:]
elseif a:statusLine[0] ==# '?'
let l:statusKey = 'Untracked'
let l:pathStr = a:statusLine[2:]
elseif a:statusLine[0] ==# '!'
let l:statusKey = 'Ignored'
let l:pathStr = a:statusLine[2:]
else
throw '[nerdtree_git_status] unknown status: ' . a:statusLine
endif
return [l:pathStr, l:statusKey]
else
let l:pathStr = a:statusLine[3:]
let l:statusKey = s:getStatusKey(a:statusLine[0], a:statusLine[1])
return [l:pathStr, l:statusKey]
endif
endfunction
function! gitstatus#util#UpdateParentDirsStatus(cache, root, pathStr, statusKey, opts) abort
if get(a:cache, a:pathStr, '') ==# 'Ignored'
return
endif
let l:dirtyPath = fnamemodify(a:pathStr, ':h')
let l:dir_dirty_only = get(a:opts, 'NERDTreeGitStatusDirDirtyOnly', 1)
while l:dirtyPath !=# a:root
let l:key = get(a:cache, l:dirtyPath, '')
if l:dir_dirty_only
if l:key ==# ''
let a:cache[l:dirtyPath] = 'Dirty'
else
return
endif
else
if l:key ==# ''
let a:cache[l:dirtyPath] = a:statusKey
elseif l:key ==# 'Dirty' || l:key ==# a:statusKey
return
else
let a:cache[l:dirtyPath] = 'Dirty'
endif
endif
let l:dirtyPath = fnamemodify(l:dirtyPath, ':h')
endwhile
endfunction