2010-02-14 14:16:30 -05:00
" fugitive.vim - A Git wrapper so awesome, it should be illegal
2011-08-06 16:55:57 -04:00
" Maintainer: Tim Pope <http://tpo.pe/>
2018-11-22 09:48:10 -05:00
" Version: 2.5
2010-02-15 14:03:22 -05:00
" GetLatestVimScripts: 2975 1 :AutoInstall: fugitive.vim
2009-10-10 19:47:14 -04:00
2018-06-01 13:38:22 -04:00
if exists ( 'g:loaded_fugitive' )
2009-10-10 19:47:14 -04:00
finish
endif
let g :loaded_fugitive = 1
2019-07-18 11:06:08 -04:00
if get ( g :, 'fugitive_git_executable' , '' ) = ~ # '^LANG='
echoerr 'Including "LANG=..." in g:fugitive_git_executable is no longer necessary or supported. Remove the "let g:fugitive_git_executable = ..." line from your vimrc.'
endif
2018-07-28 20:56:30 -04:00
function ! FugitiveGitDir ( ...) abort
if ! a :0 | | a :1 = = # -1
return get ( b :, 'git_dir' , '' )
elseif type ( a :1 ) = = type ( 0 )
return getbufvar ( a :1 , 'git_dir' )
elseif type ( a :1 ) = = type ( '' )
2018-07-30 01:35:11 -04:00
return substitute ( s :Slash ( a :1 ) , '/$' , '' , '' )
2018-07-28 20:56:30 -04:00
else
return ''
endif
endfunction
2018-07-28 21:08:56 -04:00
function ! FugitiveCommonDir ( ...) abort
let dir = FugitiveGitDir ( a :0 ? a :1 : -1 )
if empty ( dir )
return ''
endif
return fugitive #CommonDir ( dir )
2012-03-18 22:44:04 -04:00
endfunction
2018-07-27 00:56:21 -04:00
function ! FugitiveWorkTree ( ...) abort
2019-02-25 17:10:54 -05:00
return s :Tree ( FugitiveGitDir ( a :0 ? a :1 : -1 ) )
2018-05-30 00:19:38 -04:00
endfunction
2018-07-28 21:38:39 -04:00
function ! FugitiveReal ( ...) abort
let file = a :0 ? a :1 : @%
2018-08-06 01:21:19 -04:00
if file = ~ # '^\a\a\+:' | | a :0 > 1
2018-07-28 21:38:39 -04:00
return call ( 'fugitive#Real' , [file ] + a :000 [1 :-1 ])
2018-08-06 01:21:19 -04:00
elseif file = ~ # '^/\|^\a:\|^$'
2018-07-28 21:38:39 -04:00
return file
else
return fnamemodify ( file , ':p' . ( file = ~ # '[\/]$' ? '' : ':s?[\/]$??' ) )
endif
endfunction
2018-10-21 19:44:20 -04:00
function ! FugitiveFind ( ...) abort
return fugitive #Find ( a :0 ? a :1 : bufnr ( '' ) , FugitiveGitDir ( a :0 > 1 ? a :2 : -1 ) )
2018-08-02 20:53:15 -04:00
endfunction
2018-07-28 21:38:39 -04:00
function ! FugitivePath ( ...) abort
if a :0 > 1
return fugitive #Path ( a :1 , a :2 , FugitiveGitDir ( a :0 > 2 ? a :3 : -1 ) )
else
return FugitiveReal ( a :0 ? a :1 : @%)
endif
endfunction
function ! FugitiveParse ( ...) abort
2018-07-30 01:35:11 -04:00
let path = s :Slash ( a :0 ? a :1 : @%)
2018-09-19 17:17:17 -04:00
if path ! ~ # '^fugitive:'
return ['' , '' ]
endif
2018-07-28 21:38:39 -04:00
let vals = matchlist ( path , '\c^fugitive:\%(//\)\=\(.\{-\}\)\%(//\|::\)\(\x\{40\}\|[0-3]\)\(/.*\)\=$' )
if len ( vals )
return [( vals [2 ] = ~ # '^.$' ? ':' : '' ) . vals [2 ] . substitute ( vals [3 ], '^/' , ':' , '' ) , vals [1 ]]
endif
let v :errmsg = 'fugitive: invalid Fugitive URL ' . path
throw v :errmsg
endfunction
2018-11-22 09:36:28 -05:00
function ! FugitivePrepare ( ...) abort
return call ( 'fugitive#Prepare' , a :000 )
endfunction
2018-12-19 14:15:55 -05:00
function ! FugitiveConfig ( ...) abort
2018-12-21 13:23:30 -05:00
if a :0 = = 2 && type ( a :2 ) ! = type ( {})
return fugitive #Config ( a :1 , FugitiveGitDir ( a :2 ) )
elseif a :0 = = 1 && a :1 ! ~ # '^[[:alnum:]-]\+\.'
return fugitive #Config ( FugitiveGitDir ( a :1 ) )
2018-12-19 14:15:55 -05:00
else
return call ( 'fugitive#Config' , a :000 )
endif
2018-07-28 21:38:39 -04:00
endfunction
function ! FugitiveRemoteUrl ( ...) abort
return fugitive #RemoteUrl ( a :0 ? a :1 : '' , FugitiveGitDir ( a :0 > 1 ? a :2 : -1 ) )
endfunction
function ! FugitiveHead ( ...) abort
let dir = FugitiveGitDir ( a :0 > 1 ? a :2 : -1 )
if empty ( dir )
return ''
endif
2018-08-06 01:36:37 -04:00
return fugitive #Head ( a :0 ? a :1 : 0 , dir )
2018-07-28 21:38:39 -04:00
endfunction
function ! FugitiveStatusline ( ...) abort
if ! exists ( 'b:git_dir' )
return ''
endif
return fugitive #Statusline ( )
endfunction
2018-07-28 21:08:56 -04:00
function ! FugitiveIsGitDir ( path ) abort
let path = substitute ( a :path , '[\/]$' , '' , '' ) . '/'
2019-06-02 19:32:57 -04:00
return len ( a :path ) && getfsize ( path .'HEAD' ) > 10 && (
2018-07-28 21:08:56 -04:00
\ isdirectory ( path .'objects' ) && isdirectory ( path .'refs' ) | |
\ getftype ( path .'commondir' ) = = # 'file' )
endfunction
let s :worktree_for_dir = {}
let s :dir_for_worktree = {}
2019-02-25 17:10:54 -05:00
function ! s :Tree ( path ) abort
2018-07-28 21:08:56 -04:00
let dir = a :path
if dir = ~ # '/\.git$'
return len ( dir ) = = # 5 ? '/' : dir [0 :-6 ]
2018-10-17 23:20:11 -04:00
elseif dir = = # ''
return ''
2018-07-28 21:08:56 -04:00
endif
if ! has_key ( s :worktree_for_dir , dir )
let s :worktree_for_dir [dir ] = ''
let config_file = dir . '/config'
if filereadable ( config_file )
let config = readfile ( config_file , '' , 10 )
call filter ( config , 'v:val =~# "^\\s*worktree *="' )
if len ( config ) = = 1
let worktree = matchstr ( config [0 ], '= *\zs.*' )
endif
elseif filereadable ( dir . '/gitdir' )
let worktree = fnamemodify ( readfile ( dir . '/gitdir' ) [0 ], ':h' )
if worktree = = # '.'
unlet ! worktree
endif
endif
if exists ( 'worktree' )
let s :worktree_for_dir [dir ] = worktree
let s :dir_for_worktree [s :worktree_for_dir [dir ]] = dir
endif
endif
if s :worktree_for_dir [dir ] = ~ # '^\.'
return simplify ( dir . '/' . s :worktree_for_dir [dir ])
else
return s :worktree_for_dir [dir ]
endif
2018-07-27 00:56:21 -04:00
endfunction
2018-05-28 17:59:19 -04:00
function ! FugitiveExtractGitDir ( path ) abort
2018-07-30 01:35:11 -04:00
let path = s :Slash ( a :path )
2018-06-15 23:10:05 -04:00
if path = ~ # '^fugitive:'
return matchstr ( path , '\C^fugitive:\%(//\)\=\zs.\{-\}\ze\%(//\|::\|$\)' )
2018-05-30 00:30:46 -04:00
elseif isdirectory ( path )
let path = fnamemodify ( path , ':p:s?/$??' )
2017-04-29 19:15:00 -04:00
else
2018-05-30 00:30:46 -04:00
let path = fnamemodify ( path , ':p:h:s?/$??' )
endif
2018-07-28 19:41:00 -04:00
let pre = substitute ( matchstr ( path , '^\a\a\+\ze:' ) , '^.' , '\u&' , '' )
if len ( pre ) && exists ( '*' . pre . 'Real' )
2018-07-30 01:35:11 -04:00
let path = s :Slash ( {pre }Real ( path ) )
2018-07-28 19:41:00 -04:00
endif
2018-05-30 00:30:46 -04:00
let root = resolve ( path )
if root ! = # path
2019-06-30 21:11:31 -04:00
silent ! exe ( haslocaldir ( ) ? 'lcd' : exists ( ':tcd' ) && haslocaldir ( -1 ) ? 'tcd' : 'cd' ) '.'
2017-04-29 19:15:00 -04:00
endif
2012-03-18 22:44:04 -04:00
let previous = ""
2019-06-02 19:32:57 -04:00
let env_git_dir = len ( $GIT_DIR ) ? s :Slash ( simplify ( fnamemodify ( $GIT_DIR , ':p:s?[\/]$??' ) ) ) : ''
call s :Tree ( env_git_dir )
2012-03-18 22:44:04 -04:00
while root ! = # previous
2013-12-17 13:33:07 +01:00
if root = ~ # '\v^//%([^/]+/?)?$'
break
endif
2014-01-21 18:39:48 -05:00
if index ( split ( $GIT_CEILING_DIRECTORIES , ':' ) , root ) > = 0
break
endif
2019-06-02 19:32:57 -04:00
if root = = # $GIT_WORK_TREE && FugitiveIsGitDir ( env_git_dir )
return env_git_dir
elseif has_key ( s :dir_for_worktree , root )
return s :dir_for_worktree [root ]
2014-11-06 10:38:07 -08:00
endif
2018-05-29 23:27:53 -04:00
let dir = substitute ( root , '[\/]$' , '' , '' ) . '/.git'
2012-03-18 22:44:04 -04:00
let type = getftype ( dir )
2018-05-28 17:59:19 -04:00
if type = = # 'dir' && FugitiveIsGitDir ( dir )
2012-03-18 22:44:04 -04:00
return dir
2018-05-28 17:59:19 -04:00
elseif type = = # 'link' && FugitiveIsGitDir ( dir )
2012-03-18 22:44:04 -04:00
return resolve ( dir )
2012-03-20 08:10:46 -04:00
elseif type ! = # '' && filereadable ( dir )
2012-04-03 06:52:48 -04:00
let line = get ( readfile ( dir , '' , 1 ) , 0 , '' )
2018-05-28 17:59:19 -04:00
if line = ~ # '^gitdir: \.' && FugitiveIsGitDir ( root .'/' .line [8 :-1 ])
2012-05-15 21:50:13 -04:00
return simplify ( root .'/' .line [8 :-1 ])
2018-05-28 17:59:19 -04:00
elseif line = ~ # '^gitdir: ' && FugitiveIsGitDir ( line [8 :-1 ])
2012-03-14 22:02:20 -04:00
return line [8 :-1 ]
endif
2018-05-28 17:59:19 -04:00
elseif FugitiveIsGitDir ( root )
2012-03-18 22:44:04 -04:00
return root
2009-10-10 19:47:14 -04:00
endif
2012-03-18 22:44:04 -04:00
let previous = root
2012-04-10 22:49:31 -04:00
let root = fnamemodify ( root , ':h' )
2009-10-10 19:47:14 -04:00
endwhile
return ''
endfunction
2018-05-28 17:59:19 -04:00
function ! FugitiveDetect ( path ) abort
2018-07-17 01:42:37 -04:00
if exists ( 'b:git_dir' ) && b :git_dir = ~ # '^$\|/$\|^fugitive:'
2010-01-24 22:59:42 -05:00
unlet b :git_dir
endif
2009-10-10 19:47:14 -04:00
if ! exists ( 'b:git_dir' )
2018-05-28 17:59:19 -04:00
let dir = FugitiveExtractGitDir ( a :path )
2012-04-10 22:49:31 -04:00
if dir ! = # ''
2009-10-10 19:47:14 -04:00
let b :git_dir = dir
endif
endif
if exists ( 'b:git_dir' )
2018-05-29 23:27:53 -04:00
return fugitive #Init ( )
2009-10-10 19:47:14 -04:00
endif
endfunction
2018-07-30 01:35:11 -04:00
function ! s :Slash ( path ) abort
2018-08-19 05:12:04 -04:00
if exists ( '+shellslash' )
2018-07-30 01:35:11 -04:00
return tr ( a :path , '\' , '/' )
else
return a :path
endif
endfunction
2018-08-26 17:42:19 -04:00
function ! s :ProjectionistDetect ( ) abort
let file = s :Slash ( get ( g :, 'projectionist_file' , '' ) )
let dir = FugitiveExtractGitDir ( file )
let base = matchstr ( file , '^fugitive://.\{-\}//\x\+' )
if empty ( base )
2019-02-25 17:10:54 -05:00
let base = s :Tree ( dir )
2018-08-26 17:42:19 -04:00
endif
if len ( base )
2018-08-29 17:11:01 -04:00
if exists ( '+shellslash' ) && ! &shellslash
let base = tr ( base , '/' , '\' )
endif
2019-06-03 00:31:46 -04:00
let file = FugitiveCommonDir ( dir ) . '/info/projections.json'
if filereadable ( file )
call projectionist #append ( base , file )
endif
2018-08-26 17:42:19 -04:00
endif
endfunction
2009-10-10 19:47:14 -04:00
augroup fugitive
autocmd !
2018-05-30 01:33:57 -04:00
2018-07-28 19:41:00 -04:00
autocmd BufNewFile , BufReadPost * call FugitiveDetect ( expand ( '<amatch>:p' ) )
autocmd FileType netrw call FugitiveDetect ( fnamemodify ( get ( b :, 'netrw_curdir' , expand ( '<amatch>' ) ) , ':p' ) )
2018-07-02 15:12:09 -04:00
autocmd User NERDTreeInit , NERDTreeNewRoot
\ if exists ( 'b:NERDTree.root.path.str' ) |
\ call FugitiveDetect ( b :NERDTree .root .path .str ( ) ) |
\ endif
2018-07-17 00:11:07 -04:00
autocmd VimEnter * if empty ( expand ( '<amatch>' ) ) | call FugitiveDetect ( getcwd ( ) ) | endif
2018-05-28 17:59:19 -04:00
autocmd CmdWinEnter * call FugitiveDetect ( expand ( '#:p' ) )
2018-05-30 01:33:57 -04:00
2018-06-20 14:24:35 -04:00
autocmd FileType git
2019-02-25 17:10:54 -05:00
\ if len ( FugitiveGitDir ( ) ) |
2018-07-28 21:51:46 -04:00
\ call fugitive #MapJumps ( ) |
2018-07-26 21:53:43 -04:00
\ call fugitive #MapCfile ( ) |
2018-06-20 14:24:35 -04:00
\ endif
2018-07-26 21:53:43 -04:00
autocmd FileType gitcommit
2019-02-25 17:10:54 -05:00
\ if len ( FugitiveGitDir ( ) ) |
2018-12-25 14:07:17 -05:00
\ call fugitive #MapCfile ( 'fugitive#MessageCfile()' ) |
\ endif
autocmd FileType fugitive
2019-02-25 17:10:54 -05:00
\ if len ( FugitiveGitDir ( ) ) |
2018-07-26 21:53:43 -04:00
\ call fugitive #MapCfile ( 'fugitive#StatusCfile()' ) |
2018-06-20 14:24:35 -04:00
\ endif
2018-07-26 21:53:43 -04:00
autocmd FileType gitrebase
\ let &l :include = '^\%(pick\|squash\|edit\|reword\|fixup\|drop\|[pserfd]\)\>' |
2019-02-25 17:10:54 -05:00
\ if len ( FugitiveGitDir ( ) ) |
2018-10-21 19:44:20 -04:00
\ let &l :includeexpr = 'v:fname =~# ''^\x\{4,40\}$'' ? FugitiveFind(v:fname) : ' .
2018-07-26 21:53:43 -04:00
\ ( len ( &l :includeexpr ) ? &l :includeexpr : 'v:fname' ) |
\ endif |
\ let b :undo_ftplugin = get ( b :, 'undo_ftplugin' , 'exe' ) . '|setl inex= inc='
2018-06-20 14:24:35 -04:00
2018-07-17 00:11:07 -04:00
autocmd BufReadCmd index {, .lock }
2018-05-30 01:33:57 -04:00
\ if FugitiveIsGitDir ( expand ( '<amatch>:p:h' ) ) |
2018-07-30 01:35:11 -04:00
\ let b :git_dir = s :Slash ( expand ( '<amatch>:p:h' ) ) |
2018-05-30 01:33:57 -04:00
\ exe fugitive #BufReadStatus ( ) |
\ elseif filereadable ( expand ( '<amatch>' ) ) |
2019-02-10 20:02:27 -07:00
\ silent doautocmd BufReadPre |
\ keepalt read < amatch > |
2018-07-17 00:11:07 -04:00
\ 1 delete_ |
2019-02-10 20:02:27 -07:00
\ silent doautocmd BufReadPost |
\ else |
\ silent doautocmd BufNewFile |
2018-05-30 01:33:57 -04:00
\ endif
2019-02-10 20:02:27 -07:00
2018-07-17 00:11:07 -04:00
autocmd BufReadCmd fugitive :// *// * exe fugitive #BufReadCmd ( )
autocmd BufWriteCmd fugitive :// *// [0 -3 ]/* exe fugitive #BufWriteCmd ( )
autocmd FileReadCmd fugitive :// *// * exe fugitive #FileReadCmd ( )
2018-07-18 20:47:29 -04:00
autocmd FileWriteCmd fugitive :// *// [0 -3 ]/* exe fugitive #FileWriteCmd ( )
2018-07-26 20:54:10 -04:00
if exists ( '##SourceCmd' )
autocmd SourceCmd fugitive :// *// * nested exe fugitive #SourceCmd ( )
endif
2018-05-30 01:33:57 -04:00
autocmd User Flags call Hoist ( 'buffer' , function ( 'FugitiveStatusline' ) )
2018-08-26 17:42:19 -04:00
autocmd User ProjectionistDetect call s :ProjectionistDetect ( )
2009-10-10 19:47:14 -04:00
augroup END