55 Commits

Author SHA1 Message Date
Tim Pope
16c2b7abb9 Support worktrees
Closes https://github.com/tpope/vim-fugitive/issues/655
2016-02-24 16:20:52 -05:00
Tim Pope
1e3f1103d9 DRY up refs/ paths 2016-02-24 15:53:51 -05:00
Tim Pope
9835920a3c Use includeexpr on default <cfile>
Closes https://github.com/tpope/vim-fugitive/issues/744
2016-01-22 20:03:58 -05:00
Tim Pope
fd36aa9c61 Fix issue extracting remote 2016-01-08 17:05:54 -05:00
Tim Pope
4dd41688cf Entertain P as a p alternative in :Gstatus
This could potentially free up `p` as "open in new tab", which would
correspond nicely with `vim -p`.
2016-01-01 16:55:17 -05:00
Tim Pope
18d6d1ab82 Overhaul :Gbrowse remote handling 2015-12-26 19:53:07 -05:00
Tim Pope
9ce67cdc93 Always pass commit SHA to :Gbrowse handlers 2015-12-26 15:09:08 -05:00
Tim Pope
bf04261080 Revert "Remove guard against index stage in :Gbrowse handler"
This reverts commit 14daf094d9.  My
assertion was wrong; commit will no longer be an index stage but it
still might be an empty string.
2015-12-26 14:54:35 -05:00
Tim Pope
52d180af0a Include trailing / in tree paths for :Gbrowse handlers 2015-12-26 14:37:45 -05:00
Tim Pope
14daf094d9 Remove guard against index stage in :Gbrowse handler
This parameter can now always be directly used within a URL, without any
sanity checking
2015-12-26 14:36:39 -05:00
Tim Pope
ac904e806d Don't pass stage number as commit to :Gbrowse handler 2015-12-26 14:18:00 -05:00
Tim Pope
9f768cd3bc Minimum viable URL escaping in :Gbrowse
Closes https://github.com/tpope/vim-fugitive/issues/703.
2015-12-26 14:11:54 -05:00
Tim Pope
09cdce7add Fix jump to file for tree at root of commit
Closes https://github.com/tpope/vim-fugitive/issues/735
2015-12-23 21:27:43 -05:00
Tim Pope
8851b8fe64 Fix jump from diff to file
This code hasn't been touched in 4 years; how did it break?!
2015-12-15 21:19:33 -05:00
Tim Pope
cfa485ede7 Better support for binary file grep results 2015-12-15 19:01:40 -05:00
Tim Pope
207c643ea4 Bring GitHub handler in line with rhubarb.vim
Closes https://github.com/tpope/vim-fugitive/issues/730
2015-12-11 16:38:05 -05:00
Tim Pope
cac2c8ef8e Fix instaweb current buffer assumption 2015-12-01 18:41:29 -05:00
Tim Pope
a9a22e0e4e Never :Gedit with a trailing slash 2015-12-01 18:35:25 -05:00
Tim Pope
c3e918072f Accommodate @ as alias for HEAD 2015-12-01 18:06:38 -05:00
Tim Pope
d854197c03 Open release page for tags on GitHub 2015-12-01 04:04:55 -05:00
Tim Pope
d8ce8d1d03 Document transition to rhubarb.vim 2015-11-30 22:25:50 -05:00
Tim Pope
23faeadc7c Revert "Show all untracked files in :Gstatus window"
This reverts commit 21b6dd7aee.

Closes https://github.com/tpope/vim-fugitive/issues/726
2015-11-30 19:38:48 -05:00
Andy Russell
1ecd12d523 Add support for fish shell syntax
Closes #626.
2015-11-06 15:54:34 -05:00
Jerome Reybert
f8aa87a4b5 Fix when $GIT_DIR is set and is not an absolute path 2015-11-03 09:52:22 -05:00
Jacob Niehus
dba8a0705d Fix diff sometimes opening in preview window
If the previous window no longer exists when Gedit is called, the
attempt to change windows with 'wincmd p' fails and 'wincmd w' should be
used instead.
2015-10-16 23:48:38 -04:00
Tim Pope
8cf3d94a3a Support gf in git filetypes
Closes https://github.com/tpope/vim-fugitive/issues/697
2015-10-07 00:21:49 -04:00
Tim Pope
28de2a1ddd Enable jumping on @@ hunk header 2015-10-07 00:21:49 -04:00
Tim Pope
01cda4d443 :Gdiff! keeps window focus 2015-10-07 00:21:35 -04:00
Tim Pope
b5188a1b4f Accept +cmd with :Gdiff 2015-10-07 00:05:07 -04:00
Tim Pope
8e63140181 Resplit when :Gstatus is final window 2015-10-07 00:05:07 -04:00
Tim Pope
cec56ef5ff Extract current file logic from s:GF 2015-10-06 21:45:40 -04:00
Tim Pope
1e755064e9 Better error on :Gwrite failure
References https://github.com/tpope/vim-fugitive/issues/696
2015-10-06 20:33:41 -04:00
Daniel Hahler
0b43b51d77 Expand % instead of <amatch> in the Buf* autocommands
This is relevant in case a previous BufReadPost autocmd changes the file
name using `:file` - fugitive should use the new/current name then.
2015-10-02 19:40:37 -04:00
Daniel Hahler
5dcf8a0175 ReplaceCmd: redirect stderr to tmp file / buffer
The option `status.showUntrackedFiles=all` used with `git status` for
`:Gstatus` might cause an error, which then causes fugitive to display an
empty status window / index file.

Redirecting the stderr output is useful in this case.

The generated command was:

    git --git-dir=/home/user/.dotfiles/.git -c 'status.displayCommentPrefix=true' -c 'color.status=false' -c 'status.short=false' -c 'status.showUntrackedFiles=all' status

The error from git is related to submodules being moved to another
subdirectory, where the relative "gitdir" now does not exist anymore:

    fatal: Not a git repository: vim/bundle.old.nobackup/CLEAN/colorscheme-base16/../../../.git/modules/vim/bundle/colorscheme-base16

While that's a Git / user error after all, fugitive should be more
helpful in that case by displaying the error.

It uses the 'shellpipe' setting to detect if '2>&1' is supported (Ref:
https://github.com/tpope/vim-fugitive/pull/661#issuecomment-120438667).

Closes #661.
2015-10-02 19:39:07 -04:00
Daniel Hahler
2509641eac Add "stash" and stash refs in repo.superglob
This looks for `refs/stash` and calls `git stash list` to get all of
them in case it exists.
2015-10-02 19:27:35 -04:00
Tim Pope
073f3a37b9 Short circuit when jumping too far in blame history
References https://github.com/tpope/vim-fugitive/issues/607
2015-09-30 18:49:56 -04:00
David Elentok
b7b23001de Allow using the "%" variable in git commands
Closes https://github.com/tpope/vim-fugitive/issues/686

For example, when running:

  :Git add %

neovim throws the following exception:

  E499: Empty file name for '%' or '#',
  only works with ":p:h": terminal git add %

It is a result of the tabnew command, it creates a new blank tab where
"%" is empty.

This commit changes "tabnew" to "tabedit %" so you're still working on
the same file.

Once the command is done running the tab closes.
2015-09-10 15:32:35 -04:00
Patrick Davey
b319b69453 Add the "L" prefix which github requires for highlighting ranges now
Fixes https://github.com/tpope/vim-fugitive/issues/669
2015-08-02 15:26:14 -04:00
Pieter-Jan Van de Maele
03cc95cc19 Support for Ggrep when only %f is available 2015-07-20 15:06:06 -04:00
Tim Pope
7c4a906147 Support Vim without 'wildignorecase'
Closes #659.
2015-07-01 10:55:35 -04:00
Tim Pope
b5b2548a87 Support older Vim without 'fileignorecase' 2015-06-30 20:39:54 -04:00
Tim Pope
ca727b07f1 Better support for case insensitive file systems
Closes #451.
2015-06-30 17:43:16 -04:00
Tim Pope
0fbbe0b3a4 Open :Gcommit tab before current
Pretty ridiculous, but this seems to be the only way to return to the
right tab after closing the commit message.
2015-06-29 17:52:39 -04:00
Tim Pope
1c844375fa Add support for flagship.vim 2015-06-14 20:06:38 -04:00
Daniel Hahler
e065e4f841 (Re)store the current window in s:diffoff_all
This is required to make Vim execute the "Enter" autocommands when
closing the fugitive window.

Fixes: https://github.com/tpope/vim-fugitive/issues/421
2015-05-31 12:14:23 -04:00
Eli Young
21b6dd7aee Show all untracked files in :Gstatus window
Previously, if there were untracked files inside an untracked folder,
:Gstatus would only show the new folder. Attempting to run a diff on the
folder would pass the directory name, which would result in Vim opening
a directory listing. This makes :Gstatus list all untracked files, even
if they're inside untracked folders. This requires Git >=1.4, and will
silently fall back to the old behavior on earlier versions.

Closes #605.
2015-05-22 17:50:42 -04:00
Tim Pope
935a2cccd3 Don't close window after :Gremove
This is nothing more than a change in personal preference on my part.
It's particularly annoying when :Gstatus or the quickfix window is the
only other window open.
2015-05-19 12:27:22 -04:00
Tim Pope
c2908b174d Support older Git in :Gpull
Closes #645.
2015-05-19 11:15:30 -04:00
Diego Vera
b0e38f08dc Make Ggrep to work properly on Mac
- Color were causing to appear strange characters in the result.
- These characters made impossible to navigate the results
- The solution was to disable colors while executing git grep
2015-05-16 10:12:41 -04:00
Ole Reifschneider
4cc201cbe3 Use the neovim terminal emulator for :Git 2015-03-31 13:40:01 -04:00
Tim Pope
baa05dcfda Pass correct files to git reset --patch 2015-03-29 16:29:18 -04:00
Fedor Gusev
0095769029 Provide g:fugitive_no_maps to disable key maps
Add variable g:fugitive_no_maps. If set y<C-G> and <C-R><C-G> are not
mapped.

Resolves tpope/vim-fugitive#394
2015-02-20 15:50:02 -05:00
Eli Young
e8b94098bb Support browsing with new netrw.vim
The previous fix for #594 didn't handle the case in which the net netrw
was installed on older versions of Vim.
2015-02-20 15:49:36 -05:00
Tim Pope
eb8eb1850a Support for browsing with recent Vim
Closes #594.
2015-02-08 22:31:37 -05:00
Daniel Hahler
933f6a1e1d s:Diff: use winnr with <C-W>w instead of <C-W>p
This is more reliable and fixes an issue where the syntastic location
list of the original file would be focused after `:Gdiff`.

Ref: c99f0ff06b (commitcomment-9434351)
2015-01-25 19:23:45 -05:00
2 changed files with 330 additions and 158 deletions

View File

@@ -220,32 +220,40 @@ that are part of Git repositories).
:[range]Gblame [flags] Run git-blame on the given range. :[range]Gblame [flags] Run git-blame on the given range.
*fugitive-:Gbrowse* *fugitive-:Gbrowse*
:[range]Gbrowse If the remote for the current branch is on GitHub, :Gbrowse Open the current file, blob, tree, commit, or tag
open the current file, blob, tree, commit, or tag in your browser at the upstream hosting provider.
(with git-web--browse) on GitHub. Otherwise, open the If a range is given, it is appropriately appended to
current file, blob, tree, commit, or tag in the URL as an anchor.
git-instaweb (if you have issues, verify you can run
"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 Upstream providers can be added by installing an
at a list of domains: appropriate Vim plugin. For example, GitHub can be
> supported by installing rhubarb.vim, available at
let g:fugitive_github_domains = ['https://example.com'] <https://github.com/tpope/vim-rhubarb>. (Native
~ support for GitHub is currently included, but that is
:[range]Gbrowse! Like :Gbrowse, but put the URL on the clipboard rather slated to be removed.)
than opening it.
:[range]Gbrowse {revision} The hosting provider is determined by looking at the
Like :Gbrowse, but for a given |fugitive-revision|. A remote for the current or specified branch and falls
back to "origin". In the special case of a "."
remote, a local instance of git-instaweb will be
started and used.
:Gbrowse {revision} Like :Gbrowse, but for a given |fugitive-revision|. A
useful value here is -, which ties the URL to the useful value here is -, which ties the URL to the
latest commit rather than a volatile branch. latest commit rather than a volatile branch.
:[range]Gbrowse [...]@{remote} :Gbrowse [...]@{remote} Force using the given remote rather than the remote
Force using the given remote rather than the remote
for the current branch. The remote is used to for the current branch. The remote is used to
determine which GitHub repository to link to. determine which GitHub repository to link to.
:{range}Gbrowse [args] Appends an anchor to the URL that emphasizes the
selected lines. You almost certainly want to give a
"-" argument in this case to force the URL to include
an exact revision.
:[range]Gbrowse! [args] Like :Gbrowse, but put the URL on the clipboard rather
than opening it.
MAPPINGS *fugitive-mappings* MAPPINGS *fugitive-mappings*
These maps are available everywhere. These maps are available everywhere.

View File

@@ -123,7 +123,9 @@ let s:abstract_prototype = {}
function! fugitive#is_git_dir(path) abort function! fugitive#is_git_dir(path) abort
let path = s:sub(a:path, '[\/]$', '') . '/' let path = s:sub(a:path, '[\/]$', '') . '/'
return isdirectory(path.'objects') && isdirectory(path.'refs') && getfsize(path.'HEAD') > 10 return getfsize(path.'HEAD') > 10 && (
\ isdirectory(path.'objects') && isdirectory(path.'refs') ||
\ getftype(path.'commondir') ==# 'file')
endfunction endfunction
function! fugitive#extract_git_dir(path) abort function! fugitive#extract_git_dir(path) abort
@@ -143,11 +145,11 @@ function! fugitive#extract_git_dir(path) abort
break break
endif endif
if root ==# $GIT_WORK_TREE && fugitive#is_git_dir($GIT_DIR) if root ==# $GIT_WORK_TREE && fugitive#is_git_dir($GIT_DIR)
return $GIT_DIR return simplify(fnamemodify(expand($GIT_DIR), ':p:s?[\/]$??'))
endif endif
if fugitive#is_git_dir($GIT_DIR) if fugitive#is_git_dir($GIT_DIR)
" Ensure that we've cached the worktree " Ensure that we've cached the worktree
call s:configured_tree($GIT_DIR) call s:configured_tree(simplify(fnamemodify(expand($GIT_DIR), ':p:s?[\/]$??')))
if has_key(s:dir_for_worktree, root) if has_key(s:dir_for_worktree, root)
return s:dir_for_worktree[root] return s:dir_for_worktree[root]
endif endif
@@ -193,8 +195,10 @@ function! fugitive#detect(path) abort
let &mls = save_mls let &mls = save_mls
endtry endtry
endif endif
cnoremap <buffer> <expr> <C-R><C-G> fnameescape(<SID>recall()) if !exists('g:fugitive_no_maps')
nnoremap <buffer> <silent> y<C-G> :call setreg(v:register, <SID>recall())<CR> cnoremap <buffer> <expr> <C-R><C-G> fnameescape(<SID>recall())
nnoremap <buffer> <silent> y<C-G> :call setreg(v:register, <SID>recall())<CR>
endif
let buffer = fugitive#buffer() let buffer = fugitive#buffer()
if expand('%:p') =~# '//' if expand('%:p') =~# '//'
call buffer.setvar('&path', s:sub(buffer.getvar('&path'), '^\.%(,|$)', '')) call buffer.setvar('&path', s:sub(buffer.getvar('&path'), '^\.%(,|$)', ''))
@@ -218,7 +222,7 @@ endfunction
augroup fugitive augroup fugitive
autocmd! autocmd!
autocmd BufNewFile,BufReadPost * call fugitive#detect(expand('<amatch>:p')) autocmd BufNewFile,BufReadPost * call fugitive#detect(expand('%:p'))
autocmd FileType netrw 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 User NERDTreeInit,NERDTreeNewRoot call fugitive#detect(b:NERDTreeRoot.path.str())
autocmd VimEnter * if expand('<amatch>')==''|call fugitive#detect(getcwd())|endif autocmd VimEnter * if expand('<amatch>')==''|call fugitive#detect(getcwd())|endif
@@ -263,9 +267,14 @@ function! s:configured_tree(git_dir) abort
let config = readfile(config_file,'',10) let config = readfile(config_file,'',10)
call filter(config,'v:val =~# "^\\s*worktree *="') call filter(config,'v:val =~# "^\\s*worktree *="')
if len(config) == 1 if len(config) == 1
let s:worktree_for_dir[a:git_dir] = matchstr(config[0], '= *\zs.*') let worktree = matchstr(config[0], '= *\zs.*')
let s:dir_for_worktree[s:worktree_for_dir[a:git_dir]] = a:git_dir
endif endif
elseif filereadable(a:git_dir . '/gitdir')
let worktree = fnamemodify(readfile(a:git_dir . '/gitdir')[0], ':h')
endif
if exists('worktree')
let s:worktree_for_dir[a:git_dir] = worktree
let s:dir_for_worktree[s:worktree_for_dir[a:git_dir]] = a:git_dir
endif endif
endif endif
if s:worktree_for_dir[a:git_dir] =~# '^\.' if s:worktree_for_dir[a:git_dir] =~# '^\.'
@@ -297,6 +306,10 @@ function! s:repo_bare() dict abort
endfunction endfunction
function! s:repo_translate(spec) dict abort function! s:repo_translate(spec) dict abort
let refs = self.dir('refs/')
if filereadable(self.dir('commondir'))
let refs = simplify(self.dir(get(readfile(self.dir('commondir'), 1), 0, ''))) . '/refs/'
endif
if a:spec ==# '.' || a:spec ==# '/.' if a:spec ==# '.' || a:spec ==# '/.'
return self.bare() ? self.dir() : self.tree() return self.bare() ? self.dir() : self.tree()
elseif a:spec =~# '^/\=\.git$' && self.bare() elseif a:spec =~# '^/\=\.git$' && self.bare()
@@ -318,18 +331,20 @@ function! s:repo_translate(spec) dict abort
return 'fugitive://'.self.dir().'//'.ref return 'fugitive://'.self.dir().'//'.ref
elseif a:spec =~# '^:' elseif a:spec =~# '^:'
return 'fugitive://'.self.dir().'//0/'.a:spec[1:-1] return 'fugitive://'.self.dir().'//0/'.a:spec[1:-1]
elseif a:spec =~# 'HEAD\|^refs/' && a:spec !~ ':' && filereadable(self.dir(a:spec)) elseif a:spec ==# '@'
return self.dir(a:spec) return self.dir('HEAD')
elseif filereadable(self.dir('refs/'.a:spec)) elseif a:spec =~# 'HEAD\|^refs/' && a:spec !~ ':' && filereadable(refs . '../' . a:spec)
return self.dir('refs/'.a:spec) return simplify(refs . '../' . a:spec)
elseif filereadable(self.dir('refs/tags/'.a:spec)) elseif filereadable(refs.a:spec)
return self.dir('refs/tags/'.a:spec) return refs.a:spec
elseif filereadable(self.dir('refs/heads/'.a:spec)) elseif filereadable(refs.'tags/'.a:spec)
return self.dir('refs/heads/'.a:spec) return refs.'tags/'.a:spec
elseif filereadable(self.dir('refs/remotes/'.a:spec)) elseif filereadable(refs.'heads/'.a:spec)
return self.dir('refs/remotes/'.a:spec) return refs.'heads/'.a:spec
elseif filereadable(self.dir('refs/remotes/'.a:spec.'/HEAD')) elseif filereadable(refs.'remotes/'.a:spec)
return self.dir('refs/remotes/'.a:spec,'/HEAD') return refs.'remotes/'.a:spec
elseif filereadable(refs.'remotes/'.a:spec.'/HEAD')
return refs.'remotes/'.a:spec,'/HEAD'
else else
try try
let ref = self.rev_parse(matchstr(a:spec,'[^:]*')) let ref = self.rev_parse(matchstr(a:spec,'[^:]*'))
@@ -402,6 +417,11 @@ function! s:repo_superglob(base) dict abort
if a:base !~# '^/' if a:base !~# '^/'
let heads = ["HEAD","ORIG_HEAD","FETCH_HEAD","MERGE_HEAD"] let heads = ["HEAD","ORIG_HEAD","FETCH_HEAD","MERGE_HEAD"]
let heads += sort(split(s:repo().git_chomp("rev-parse","--symbolic","--branches","--tags","--remotes"),"\n")) let heads += sort(split(s:repo().git_chomp("rev-parse","--symbolic","--branches","--tags","--remotes"),"\n"))
" Add any stashes.
if filereadable(s:repo().dir('refs/stash'))
let heads += ["stash"]
let heads += sort(split(s:repo().git_chomp("stash","list","--pretty=format:%gd"),"\n"))
endif
call filter(heads,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base') call filter(heads,'v:val[ 0 : strlen(a:base)-1 ] ==# a:base')
let results += heads let results += heads
endif endif
@@ -555,13 +575,24 @@ function! s:buffer_commit() dict abort
return matchstr(self.spec(),'^fugitive://.\{-\}//\zs\w*') return matchstr(self.spec(),'^fugitive://.\{-\}//\zs\w*')
endfunction endfunction
function! s:cpath(path) abort
if exists('+fileignorecase') && &fileignorecase
return tolower(a:path)
else
return a:path
endif
endfunction
function! s:buffer_path(...) dict abort function! s:buffer_path(...) dict abort
let rev = matchstr(self.spec(),'^fugitive://.\{-\}//\zs.*') let rev = matchstr(self.spec(),'^fugitive://.\{-\}//\zs.*')
if rev != '' if rev != ''
let rev = s:sub(rev,'\w*','') let rev = s:sub(rev,'\w*','')
elseif self.spec()[0 : len(self.repo().dir())] ==# self.repo().dir() . '/' elseif s:cpath(self.spec()[0 : len(self.repo().dir())]) ==#
\ s:cpath(self.repo().dir() . '/')
let rev = '/.git'.self.spec()[strlen(self.repo().dir()) : -1] let rev = '/.git'.self.spec()[strlen(self.repo().dir()) : -1]
elseif !self.repo().bare() && self.spec()[0 : len(self.repo().tree())] ==# self.repo().tree() . '/' elseif !self.repo().bare() &&
\ s:cpath(self.spec()[0 : len(self.repo().tree())]) ==#
\ s:cpath(self.repo().tree() . '/')
let rev = self.spec()[strlen(self.repo().tree()) : -1] let rev = self.spec()[strlen(self.repo().tree()) : -1]
endif endif
return s:sub(s:sub(rev,'.\zs/$',''),'^/',a:0 ? a:1 : '') return s:sub(s:sub(rev,'.\zs/$',''),'^/',a:0 ? a:1 : '')
@@ -668,8 +699,17 @@ function! s:Git(bang, args) abort
let git .= ' --no-pager' let git .= ' --no-pager'
endif endif
let args = matchstr(a:args,'\v\C.{-}%($|\\@<!%(\\\\)*\|)@=') let args = matchstr(a:args,'\v\C.{-}%($|\\@<!%(\\\\)*\|)@=')
call s:ExecuteInTree('!'.git.' '.args) if exists(':terminal')
call fugitive#reload_status() let dir = s:repo().tree()
tabedit %
execute 'lcd' fnameescape(dir)
execute 'terminal' git args
else
call s:ExecuteInTree('!'.git.' '.args)
if has('win32')
call fugitive#reload_status()
endif
endif
return matchstr(a:args, '\v\C\\@<!%(\\\\)*\|\zs.*') return matchstr(a:args, '\v\C\\@<!%(\\\\)*\|\zs.*')
endfunction endfunction
@@ -706,6 +746,7 @@ augroup fugitive_status
autocmd! autocmd!
if !has('win32') if !has('win32')
autocmd FocusGained,ShellCmdPost * call fugitive#reload_status() autocmd FocusGained,ShellCmdPost * call fugitive#reload_status()
autocmd BufDelete term://* call fugitive#reload_status()
endif endif
augroup END augroup END
@@ -971,7 +1012,7 @@ function! s:StagePatch(lnum1,lnum2) abort
execute "Git add --patch -- ".join(map(add,'s:shellesc(v:val)')) execute "Git add --patch -- ".join(map(add,'s:shellesc(v:val)'))
endif endif
if !empty(reset) if !empty(reset)
execute "Git reset --patch -- ".join(map(add,'s:shellesc(v:val)')) execute "Git reset --patch -- ".join(map(reset,'s:shellesc(v:val)'))
endif endif
if exists('first_filename') if exists('first_filename')
silent! edit! silent! edit!
@@ -1043,7 +1084,7 @@ function! s:Commit(args, ...) abort
if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod if bufname('%') == '' && line('$') == 1 && getline(1) == '' && !&mod
execute 'keepalt edit '.s:fnameescape(msgfile) execute 'keepalt edit '.s:fnameescape(msgfile)
elseif a:args =~# '\%(^\| \)-\%(-verbose\|\w*v\)\>' elseif a:args =~# '\%(^\| \)-\%(-verbose\|\w*v\)\>'
execute 'keepalt tabedit '.s:fnameescape(msgfile) execute 'keepalt '.(tabpagenr()-1).'tabedit '.s:fnameescape(msgfile)
elseif s:buffer().type() ==# 'index' elseif s:buffer().type() ==# 'index'
execute 'keepalt edit '.s:fnameescape(msgfile) execute 'keepalt edit '.s:fnameescape(msgfile)
execute (search('^#','n')+1).'wincmd+' execute (search('^#','n')+1).'wincmd+'
@@ -1164,13 +1205,15 @@ function! s:Merge(cmd, bang, args) abort
\ !empty(s:repo().git_chomp('diff-files', '--diff-filter=U'))) \ !empty(s:repo().git_chomp('diff-files', '--diff-filter=U')))
let &l:makeprg = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U' let &l:makeprg = g:fugitive_git_executable.' diff-files --name-status --diff-filter=U'
else else
let &l:makeprg = s:sub(g:fugitive_git_executable.' -c core.editor=false '. let &l:makeprg = s:sub(g:fugitive_git_executable . ' ' . a:cmd .
\ a:cmd . (a:args =~# ' \%(--no-edit\|--abort\|-m\)\>' ? '' : ' --edit') . ' ' . a:args, \ (a:args =~# ' \%(--no-edit\|--abort\|-m\)\>' ? '' : ' --edit') .
\ ' *$', '') \ ' ' . a:args, ' *$', '')
endif endif
if !empty($GIT_EDITOR) if !empty($GIT_EDITOR) || has('win32')
let old_editor = $GIT_EDITOR let old_editor = $GIT_EDITOR
let $GIT_EDITOR = 'false' let $GIT_EDITOR = 'false'
else
let &l:makeprg = 'env GIT_EDITOR=false ' . &l:makeprg
endif endif
execute cd fnameescape(s:repo().tree()) execute cd fnameescape(s:repo().tree())
silent noautocmd make! silent noautocmd make!
@@ -1227,8 +1270,8 @@ function! s:Grep(cmd,bang,arg) abort
let dir = getcwd() let dir = getcwd()
try try
execute cd.'`=s:repo().tree()`' execute cd.'`=s:repo().tree()`'
let &grepprg = s:repo().git_command('--no-pager', 'grep', '-n') let &grepprg = s:repo().git_command('--no-pager', 'grep', '-n', '--no-color')
let &grepformat = '%f:%l:%m' let &grepformat = '%f:%l:%m,%m %f match%ts,%f'
exe a:cmd.'! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|') exe a:cmd.'! '.escape(matchstr(a:arg,'\v\C.{-}%($|[''" ]\@=\|)@='),'|')
let list = a:cmd =~# '^l' ? getloclist(0) : getqflist() let list = a:cmd =~# '^l' ? getloclist(0) : getqflist()
for entry in list for entry in list
@@ -1303,7 +1346,14 @@ function! s:Edit(cmd,bang,...) abort
let buffer = s:buffer() let buffer = s:buffer()
if a:cmd !~# 'read' if a:cmd !~# 'read'
if &previewwindow && getbufvar('','fugitive_type') ==# 'index' if &previewwindow && getbufvar('','fugitive_type') ==# 'index'
wincmd p if winnr('$') == 1
let tabs = (&go =~# 'e' || !has('gui_running')) && &stal && (tabpagenr('$') >= &stal)
execute 'rightbelow' (&lines - &previewheight - &cmdheight - tabs - 1 - !!&laststatus).'new'
elseif winnr('#')
wincmd p
else
wincmd w
endif
if &diff if &diff
let mywinnr = winnr() let mywinnr = winnr()
for winnr in range(winnr('$'),1,-1) for winnr in range(winnr('$'),1,-1)
@@ -1334,7 +1384,7 @@ function! s:Edit(cmd,bang,...) abort
return 'redraw|echo '.string(':!'.git.' '.args) return 'redraw|echo '.string(':!'.git.' '.args)
else else
let temp = resolve(tempname()) let temp = resolve(tempname())
let s:temp_files[tolower(temp)] = { 'dir': buffer.repo().dir(), 'args': arglist } let s:temp_files[s:cpath(temp)] = { 'dir': buffer.repo().dir(), 'args': arglist }
silent execute a:cmd.' '.temp silent execute a:cmd.' '.temp
if a:cmd =~# 'pedit' if a:cmd =~# 'pedit'
wincmd P wincmd P
@@ -1369,6 +1419,9 @@ function! s:Edit(cmd,bang,...) abort
catch /^fugitive:/ catch /^fugitive:/
return 'echoerr v:errmsg' return 'echoerr v:errmsg'
endtry endtry
if file !~# '^fugitive:'
let file = s:sub(file, '/$', '')
endif
if a:cmd ==# 'read' if a:cmd ==# 'read'
return 'silent %delete_|read '.s:fnameescape(file).'|silent 1delete_|diffupdate|'.line('.') return 'silent %delete_|read '.s:fnameescape(file).'|silent 1delete_|diffupdate|'.line('.')
else else
@@ -1431,6 +1484,9 @@ function! s:Write(force,...) abort
let mytab = tabpagenr() let mytab = tabpagenr()
let mybufnr = bufnr('') let mybufnr = bufnr('')
let path = a:0 ? join(a:000, ' ') : s:buffer().path() let path = a:0 ? join(a:000, ' ') : s:buffer().path()
if empty(path)
return 'echoerr '.string('fugitive: cannot determine file path')
endif
if path =~# '^:\d\>' if path =~# '^:\d\>'
return 'write'.(a:force ? '! ' : ' ').s:fnameescape(s:repo().translate(s:buffer().expand(path))) return 'write'.(a:force ? '! ' : ' ').s:fnameescape(s:repo().translate(s:buffer().expand(path)))
endif endif
@@ -1588,9 +1644,9 @@ endfunction
" Section: Gdiff " Section: Gdiff
call s:command("-bang -bar -nargs=* -complete=customlist,s:EditComplete Gdiff :execute s:Diff('',<f-args>)") call s:command("-bang -bar -nargs=* -complete=customlist,s:EditComplete Gdiff :execute s:Diff('',<bang>0,<f-args>)")
call s:command("-bar -nargs=* -complete=customlist,s:EditComplete Gvdiff :execute s:Diff('keepalt vert ',<f-args>)") call s:command("-bang -bar -nargs=* -complete=customlist,s:EditComplete Gvdiff :execute s:Diff('keepalt vert ',<bang>0,<f-args>)")
call s:command("-bar -nargs=* -complete=customlist,s:EditComplete Gsdiff :execute s:Diff('keepalt ',<f-args>)") call s:command("-bang -bar -nargs=* -complete=customlist,s:EditComplete Gsdiff :execute s:Diff('keepalt ',<bang>0,<f-args>)")
augroup fugitive_diff augroup fugitive_diff
autocmd! autocmd!
@@ -1667,6 +1723,7 @@ function! s:diffoff() abort
endfunction endfunction
function! s:diffoff_all(dir) abort function! s:diffoff_all(dir) abort
let curwin = winnr()
for nr in range(1,winnr('$')) for nr in range(1,winnr('$'))
if getwinvar(nr,'&diff') if getwinvar(nr,'&diff')
if nr != winnr() if nr != winnr()
@@ -1678,6 +1735,7 @@ function! s:diffoff_all(dir) abort
endif endif
endif endif
endfor endfor
execute curwin.'wincmd w'
endfunction endfunction
function! s:buffer_compare_age(commit) dict abort function! s:buffer_compare_age(commit) dict abort
@@ -1702,11 +1760,16 @@ endfunction
call s:add_methods('buffer',['compare_age']) call s:add_methods('buffer',['compare_age'])
function! s:Diff(vert,...) abort function! s:Diff(vert,keepfocus,...) abort
let args = copy(a:000)
let post = ''
if get(args, 0) =~# '^+'
let post = remove(args, 0)[1:-1]
endif
let vert = empty(a:vert) ? s:diff_modifier(2) : a:vert let vert = empty(a:vert) ? s:diff_modifier(2) : a:vert
if exists(':DiffGitCached') if exists(':DiffGitCached')
return '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()) !=# '' elseif (empty(args) || args[0] == ':') && 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 vert = empty(a:vert) ? s:diff_modifier(3) : a:vert
let nr = bufnr('') let nr = bufnr('')
execute 'leftabove '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':2''))`' execute 'leftabove '.vert.'split `=fugitive#buffer().repo().translate(s:buffer().expand('':2''))`'
@@ -1718,11 +1781,11 @@ function! s:Diff(vert,...) abort
call s:diffthis() call s:diffthis()
wincmd p wincmd p
call s:diffthis() call s:diffthis()
return '' return post
elseif a:0 elseif len(args)
let arg = join(a:000, ' ') let arg = join(args, ' ')
if arg ==# '' if arg ==# ''
return '' return post
elseif arg ==# '/' elseif arg ==# '/'
let file = s:buffer().path('/') let file = s:buffer().path('/')
elseif arg ==# ':' elseif arg ==# ':'
@@ -1755,13 +1818,17 @@ function! s:Diff(vert,...) abort
else else
execute 'leftabove '.vert.'diffsplit '.s:fnameescape(spec) execute 'leftabove '.vert.'diffsplit '.s:fnameescape(spec)
endif endif
let &l:readonly = &l:readonly
redraw
let w:fugitive_diff_restore = restore let w:fugitive_diff_restore = restore
let winnr = winnr() let winnr = winnr()
if getwinvar('#', '&diff') if getwinvar('#', '&diff')
wincmd p wincmd p
call feedkeys("\<C-W>p", 'n') if !a:keepfocus
call feedkeys(winnr."\<C-W>w", 'n')
endif
endif endif
return '' return post
catch /^fugitive:/ catch /^fugitive:/
return 'echoerr v:errmsg' return 'echoerr v:errmsg'
endtry endtry
@@ -1831,7 +1898,7 @@ function! s:Remove(force) abort
return 'echoerr '.string(v:errmsg) return 'echoerr '.string(v:errmsg)
else else
call fugitive#reload_status() call fugitive#reload_status()
return 'bdelete'.(a:force ? '!' : '') return 'edit'.(a:force ? '!' : '')
endif endif
endfunction endfunction
@@ -1933,7 +2000,7 @@ function! s:Blame(bang,line1,line2,count,args) abort
endif endif
let top = line('w0') + &scrolloff let top = line('w0') + &scrolloff
let current = line('.') let current = line('.')
let s:temp_files[tolower(temp)] = { 'dir': s:repo().dir(), 'args': cmd } let s:temp_files[s:cpath(temp)] = { 'dir': s:repo().dir(), 'args': cmd }
exe 'keepalt leftabove vsplit '.temp exe 'keepalt leftabove vsplit '.temp
let b:fugitive_blamed_bufnr = bufnr let b:fugitive_blamed_bufnr = bufnr
let w:fugitive_leave = restore let w:fugitive_leave = restore
@@ -2043,15 +2110,17 @@ function! s:BlameJump(suffix) abort
if winnr > 0 if winnr > 0
exe bufnr.'bdelete' exe bufnr.'bdelete'
endif endif
execute 'Gblame '.args if exists(':Gblame')
execute lnum execute 'Gblame '.args
let delta = line('.') - line('w0') - offset execute lnum
if delta > 0 let delta = line('.') - line('w0') - offset
execute 'normal! '.delta."\<C-E>" if delta > 0
elseif delta < 0 execute 'normal! '.delta."\<C-E>"
execute 'normal! '.(-delta)."\<C-Y>" elseif delta < 0
execute 'normal! '.(-delta)."\<C-Y>"
endif
syncbind
endif endif
syncbind
return '' return ''
endfunction endfunction
@@ -2118,11 +2187,18 @@ endfunction
" Section: Gbrowse " Section: Gbrowse
call s:command("-bar -bang -range -nargs=* -complete=customlist,s:EditComplete Gbrowse :execute s:Browse(<bang>0,<line1>,<count>,<f-args>)") call s:command("-bar -bang -range=0 -nargs=* -complete=customlist,s:EditComplete Gbrowse :execute s:Browse(<bang>0,<line1>,<count>,<f-args>)")
function! s:Browse(bang,line1,count,...) abort function! s:Browse(bang,line1,count,...) abort
try try
let rev = a:0 ? substitute(join(a:000, ' '),'@[[:alnum:]_-]*\%(://.\{-\}\)\=$','','') : '' let validremote = '\.\|\.\=/.*\|[[:alnum:]_-]\+\%(://.\{-\}\)\='
if a:0
let remote = matchstr(join(a:000, ' '),'@\zs\%('.validremote.'\)$')
let rev = substitute(join(a:000, ' '),'@\%('.validremote.'\)$','','')
else
let remote = ''
let rev = ''
endif
if rev ==# '' if rev ==# ''
let expanded = s:buffer().rev() let expanded = s:buffer().rev()
elseif rev ==# ':' elseif rev ==# ':'
@@ -2133,10 +2209,11 @@ function! s:Browse(bang,line1,count,...) abort
let full = s:repo().translate(expanded) let full = s:repo().translate(expanded)
let commit = '' let commit = ''
if full =~# '^fugitive://' if full =~# '^fugitive://'
let commit = matchstr(full,'://.*//\zs\w\+') let commit = matchstr(full,'://.*//\zs\w\w\+')
let path = matchstr(full,'://.*//\w\+\zs/.*') let path = matchstr(full,'://.*//\w\+\zs/.*')
if commit =~ '..' if commit =~ '..'
let type = s:repo().git_chomp('cat-file','-t',commit.s:sub(path,'^/',':')) let type = s:repo().git_chomp('cat-file','-t',commit.s:sub(path,'^/',':'))
let branch = matchstr(expanded, '^[^:]*')
else else
let type = 'blob' let type = 'blob'
endif endif
@@ -2154,6 +2231,9 @@ function! s:Browse(bang,line1,count,...) abort
let type = 'blob' let type = 'blob'
endif endif
endif endif
if type ==# 'tree' && !empty(path)
let path = s:sub(path, '/\=$', '/')
endif
if path =~# '^\.git/.*HEAD' && filereadable(s:repo().dir(path[5:-1])) if path =~# '^\.git/.*HEAD' && filereadable(s:repo().dir(path[5:-1]))
let body = readfile(s:repo().dir(path[5:-1]))[0] let body = readfile(s:repo().dir(path[5:-1]))[0]
if body =~# '^\x\{40\}$' if body =~# '^\x\{40\}$'
@@ -2165,35 +2245,54 @@ function! s:Browse(bang,line1,count,...) abort
endif endif
endif endif
if a:0 && join(a:000, ' ') =~# '@[[:alnum:]_-]*\%(://.\{-\}\)\=$' let merge = ''
let remote = matchstr(join(a:000, ' '),'@\zs[[:alnum:]_-]\+\%(://.\{-\}\)\=$') if path =~# '^\.git/refs/remotes/.'
elseif path =~# '^\.git/refs/remotes/.' if empty(remote)
let remote = matchstr(path,'^\.git/refs/remotes/\zs[^/]\+') let remote = matchstr(path, '^\.git/refs/remotes/\zs[^/]\+')
else
let remote = 'origin'
let branch = matchstr(rev,'^[[:alnum:]/._-]\+\ze[:^~@]')
if branch ==# '' && path =~# '^\.git/refs/\w\+/'
let branch = s:sub(path,'^\.git/refs/\w+/','')
endif endif
if filereadable(s:repo().dir('refs/remotes/'.branch)) let merge = matchstr(path, '^\.git/refs/remotes/[^/]\+/\zs.\+')
let remote = matchstr(branch,'[^/]\+') let branch = ''
let rev = rev[strlen(remote)+1:-1] let path = '.git/refs/heads/'.merge
else elseif path =~# '^\.git/refs/heads/.'
if branch ==# '' let branch = path[16:-1]
let branch = matchstr(s:repo().head_ref(),'\<refs/heads/\zs.*') elseif !exists('branch')
let branch = s:repo().head()
endif
if !empty(branch)
let r = s:repo().git_chomp('config','branch.'.branch.'.remote')
let m = s:repo().git_chomp('config','branch.'.branch.'.merge')[11:-1]
if r ==# '.' && !empty(m)
let r2 = s:repo().git_chomp('config','branch.'.m.'.remote')
if r2 !~# '^\.\=$'
let r = r2
let m = s:repo().git_chomp('config','branch.'.m.'.merge')[11:-1]
endif endif
if branch != '' endif
let remote = s:repo().git_chomp('config','branch.'.branch.'.remote') if empty(remote)
if remote =~# '^\.\=$' let remote = r
let remote = 'origin' endif
elseif rev[0:strlen(branch)-1] ==# branch && rev[strlen(branch)] =~# '[:^~@]' if r ==# '.' || r ==# remote
let rev = s:repo().git_chomp('config','branch.'.branch.'.merge')[11:-1] . rev[strlen(branch):-1] let merge = m
endif if path =~# '^\.git/refs/heads/.'
let path = '.git/refs/heads/'.merge
endif endif
endif endif
endif endif
let raw = s:repo().git_chomp('config','remote.'.remote.'.url') if empty(commit) && path !~# '^\.git/'
if a:line1 && !a:count && !empty(merge)
let commit = merge
else
let commit = s:repo().rev_parse('HEAD')
endif
endif
if empty(remote)
let remote = '.'
let raw = s:repo().git_chomp('config','remote.origin.url')
else
let raw = s:repo().git_chomp('config','remote.'.remote.'.url')
endif
if raw ==# '' if raw ==# ''
let raw = remote let raw = remote
endif endif
@@ -2202,7 +2301,7 @@ function! s:Browse(bang,line1,count,...) abort
let url = call(Handler, [{ let url = call(Handler, [{
\ 'repo': s:repo(), \ 'repo': s:repo(),
\ 'remote': raw, \ 'remote': raw,
\ 'revision': rev, \ 'revision': 'No longer provided',
\ 'commit': commit, \ 'commit': commit,
\ 'path': path, \ 'path': path,
\ 'type': type, \ 'type': type,
@@ -2213,10 +2312,13 @@ function! s:Browse(bang,line1,count,...) abort
endif endif
endfor endfor
if empty(url) if empty(url) && raw ==# '.'
call s:throw("Instaweb failed to start and '".remote."' is not a supported remote") call s:throw("Instaweb failed to start")
elseif empty(url)
call s:throw('"'.remote."' is not a supported remote")
endif endif
let url = s:gsub(url, '[ <>]', '\="%".printf("%02X",char2nr(submatch(0)))')
if a:bang if a:bang
if has('clipboard') if has('clipboard')
let @* = url let @* = url
@@ -2225,7 +2327,14 @@ function! s:Browse(bang,line1,count,...) abort
elseif exists(':Browse') == 2 elseif exists(':Browse') == 2
return 'echomsg '.string(url).'|Browse '.url return 'echomsg '.string(url).'|Browse '.url
else else
return 'echomsg '.string(url).'|call netrw#NetrwBrowseX('.string(url).', 0)' if !exists('g:loaded_netrw')
runtime! autoload/netrw.vim
endif
if exists('*netrw#BrowseX')
return 'echomsg '.string(url).'|call netrw#BrowseX('.string(url).', 0)'
else
return 'echomsg '.string(url).'|call netrw#NetrwBrowseX('.string(url).', 0)'
endif
endif endif
catch /^fugitive:/ catch /^fugitive:/
return 'echoerr v:errmsg' return 'echoerr v:errmsg'
@@ -2245,7 +2354,7 @@ function! s:github_url(opts, ...) abort
if repo ==# '' if repo ==# ''
return '' return ''
endif endif
let path = a:opts.path let path = substitute(a:opts.path, '^/', '', '')
if index(domains, 'http://' . matchstr(repo, '^[^:/]*')) >= 0 if index(domains, 'http://' . matchstr(repo, '^[^:/]*')) >= 0
let root = 'http://' . s:sub(repo,':','/') let root = 'http://' . s:sub(repo,':','/')
else else
@@ -2258,36 +2367,29 @@ function! s:github_url(opts, ...) abort
else else
return root . '/commits/' . branch return root . '/commits/' . branch
endif endif
elseif path =~# '^\.git/refs/.' elseif path =~# '^\.git/refs/tags/'
return root . '/commits/' . matchstr(path,'[^/]\+$') return root . '/releases/tag/' . path[15:-1]
elseif path =~# '^\.git/refs/remotes/[^/]\+/.'
return root . '/commits/' . matchstr(path,'remotes/[^/]\+/\zs.*')
elseif path =~# '.git/\%(config$\|hooks\>\)' elseif path =~# '.git/\%(config$\|hooks\>\)'
return root . '/admin' return root . '/admin'
elseif path =~# '^\.git\>' elseif path =~# '^\.git\>'
return root return root
endif endif
if a:opts.revision =~# '^[[:alnum:]._-]\+:' if a:opts.commit =~# '^\d\=$'
let commit = matchstr(a:opts.revision,'^[^:]*') let commit = a:opts.repo.rev_parse('HEAD')
elseif a:opts.commit =~# '^\d\=$'
let local = matchstr(a:opts.repo.head_ref(),'\<refs/heads/\zs.*')
let commit = a:opts.repo.git_chomp('config','branch.'.local.'.merge')[11:-1]
if commit ==# ''
let commit = local
endif
else else
let commit = a:opts.commit let commit = a:opts.commit
endif endif
if a:opts.type == 'tree' if get(a:opts, 'type', '') ==# 'tree' || a:opts.path =~# '/$'
let url = s:sub(root . '/tree/' . commit . '/' . path,'/$','') let url = substitute(root . '/tree/' . commit . '/' . path, '/$', '', 'g')
elseif a:opts.type == 'blob' elseif get(a:opts, 'type', '') ==# 'blob' || a:opts.path =~# '[^/]$'
let url = root . '/blob/' . commit . '/' . path let url = root . '/blob/' . commit . '/' . path
if get(a:opts, 'line2') && a:opts.line1 == a:opts.line2 if get(a:opts, 'line2') && a:opts.line1 == a:opts.line2
let url .= '#L' . a:opts.line1 let url .= '#L' . a:opts.line1
elseif get(a:opts, 'line2') elseif get(a:opts, 'line2')
let url .= '#L' . a:opts.line1 . '-' . a:opts.line2 let url .= '#L' . a:opts.line1 . '-L' . a:opts.line2
endif endif
elseif a:opts.type == 'tag'
let commit = matchstr(getline(3),'^tag \zs.*')
let url = root . '/tree/' . commit
else else
let url = root . '/commit/' . commit let url = root . '/commit/' . commit
endif endif
@@ -2295,6 +2397,9 @@ function! s:github_url(opts, ...) abort
endfunction endfunction
function! s:instaweb_url(opts) abort function! s:instaweb_url(opts) abort
if a:opts.remote !=# '.'
return ''
endif
let output = a:opts.repo.git_chomp('instaweb','-b','unknown') let output = a:opts.repo.git_chomp('instaweb','-b','unknown')
if output =~# 'http://' if output =~# 'http://'
let root = matchstr(output,'http://.*').'/?p='.fnamemodify(a:opts.repo.dir(),':t') let root = matchstr(output,'http://.*').'/?p='.fnamemodify(a:opts.repo.dir(),':t')
@@ -2313,10 +2418,8 @@ function! s:instaweb_url(opts) abort
endif endif
let url .= ';h=' . a:opts.repo.rev_parse(a:opts.commit . (a:opts.path == '' ? '' : ':' . a:opts.path)) let url .= ';h=' . a:opts.repo.rev_parse(a:opts.commit . (a:opts.path == '' ? '' : ':' . a:opts.path))
else else
if a:opts.type ==# 'blob' if a:opts.type ==# 'blob' && empty(a:opts.commit)
let tmp = tempname() let url .= ';h='.a:opts.repo.git_chomp('hash-object', '-w', a:opts.path)
silent execute 'write !'.a:opts.repo.git_command('hash-object','-w','--stdin').' > '.tmp
let url .= ';h=' . readfile(tmp)[0]
else else
try try
let url .= ';h=' . a:opts.repo.rev_parse((a:opts.commit == '' ? 'HEAD' : ':' . a:opts.commit) . ':' . a:opts.path) let url .= ';h=' . a:opts.repo.rev_parse((a:opts.commit == '' ? 'HEAD' : ':' . a:opts.commit) . ':' . a:opts.path)
@@ -2357,11 +2460,17 @@ function! s:ReplaceCmd(cmd,...) abort
let prefix = 'env GIT_INDEX_FILE='.s:shellesc(a:1).' ' let prefix = 'env GIT_INDEX_FILE='.s:shellesc(a:1).' '
endif endif
endif endif
let redir = ' > '.tmp
if &shellpipe =~ '2>&1'
let redir .= ' 2>&1'
endif
if s:winshell() if s:winshell()
let cmd_escape_char = &shellxquote == '(' ? '^' : '^^^' let cmd_escape_char = &shellxquote == '(' ? '^' : '^^^'
call system('cmd /c "'.prefix.s:gsub(a:cmd,'[<>]', cmd_escape_char.'&').' > '.tmp.'"') call system('cmd /c "'.prefix.s:gsub(a:cmd,'[<>]', cmd_escape_char.'&').redir.'"')
elseif &shell =~# 'fish'
call system(' begin;'.prefix.a:cmd.redir.';end ')
else else
call system(' ('.prefix.a:cmd.' > '.tmp.') ') call system(' ('.prefix.a:cmd.redir.') ')
endif endif
finally finally
if exists('old_index') if exists('old_index')
@@ -2449,6 +2558,8 @@ function! s:BufReadIndex() abort
nnoremap <buffer> <silent> dv :<C-U>execute <SID>StageDiff('Gvdiff')<CR> nnoremap <buffer> <silent> dv :<C-U>execute <SID>StageDiff('Gvdiff')<CR>
nnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR> nnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>
xnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR> xnoremap <buffer> <silent> p :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR>
nnoremap <buffer> <silent> P :<C-U>execute <SID>StagePatch(line('.'),line('.')+v:count1-1)<CR>
xnoremap <buffer> <silent> P :<C-U>execute <SID>StagePatch(line("'<"),line("'>"))<CR>
nnoremap <buffer> <silent> q :<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<CR> nnoremap <buffer> <silent> q :<C-U>if bufnr('$') == 1<Bar>quit<Bar>else<Bar>bdelete<Bar>endif<CR>
nnoremap <buffer> <silent> r :<C-U>edit<CR> nnoremap <buffer> <silent> r :<C-U>edit<CR>
nnoremap <buffer> <silent> R :<C-U>edit<CR> nnoremap <buffer> <silent> R :<C-U>edit<CR>
@@ -2631,6 +2742,10 @@ augroup fugitive_files
\ if exists('b:git_dir') | \ if exists('b:git_dir') |
\ call s:JumpInit() | \ call s:JumpInit() |
\ endif \ endif
autocmd FileType git,gitcommit,gitrebase
\ if exists('b:git_dir') |
\ call s:GFInit() |
\ endif
augroup END augroup END
" Section: Temp files " Section: Temp files
@@ -2642,10 +2757,10 @@ endif
augroup fugitive_temp augroup fugitive_temp
autocmd! autocmd!
autocmd BufNewFile,BufReadPost * autocmd BufNewFile,BufReadPost *
\ if has_key(s:temp_files,tolower(expand('<afile>:p'))) | \ if has_key(s:temp_files,s:cpath(expand('<afile>:p'))) |
\ let b:git_dir = s:temp_files[tolower(expand('<afile>:p'))].dir | \ let b:git_dir = s:temp_files[s:cpath(expand('<afile>:p'))].dir |
\ let b:git_type = 'temp' | \ let b:git_type = 'temp' |
\ let b:git_args = s:temp_files[tolower(expand('<afile>:p'))].args | \ let b:git_args = s:temp_files[s:cpath(expand('<afile>:p'))].args |
\ call fugitive#detect(expand('<afile>:p')) | \ call fugitive#detect(expand('<afile>:p')) |
\ setlocal bufhidden=delete nobuflisted | \ setlocal bufhidden=delete nobuflisted |
\ nnoremap <buffer> <silent> q :<C-U>bdelete<CR>| \ nnoremap <buffer> <silent> q :<C-U>bdelete<CR>|
@@ -2654,7 +2769,18 @@ augroup END
" Section: Go to file " Section: Go to file
function! s:JumpInit() abort nnoremap <SID>: :<C-U><C-R>=v:count ? v:count : ''<CR>
function! s:GFInit(...) abort
cnoremap <buffer> <expr> <Plug><cfile> fugitive#cfile()
if !exists('g:fugitive_no_maps') && empty(mapcheck('gf', 'n'))
nmap <buffer> <silent> gf <SID>:find <Plug><cfile><CR>
nmap <buffer> <silent> <C-W>f <SID>:sfind <Plug><cfile><CR>
nmap <buffer> <silent> <C-W><C-F> <SID>:sfind <Plug><cfile><CR>
nmap <buffer> <silent> <C-W>gf <SID>:tabfind <Plug><cfile><CR>
endif
endfunction
function! s:JumpInit(...) abort
nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>GF("edit")<CR> nnoremap <buffer> <silent> <CR> :<C-U>exe <SID>GF("edit")<CR>
if !&modifiable if !&modifiable
nnoremap <buffer> <silent> o :<C-U>exe <SID>GF("split")<CR> nnoremap <buffer> <silent> o :<C-U>exe <SID>GF("split")<CR>
@@ -2673,7 +2799,7 @@ function! s:JumpInit() abort
endif endif
endfunction endfunction
function! s:GF(mode) abort function! s:cfile() abort
try try
let buffer = s:buffer() let buffer = s:buffer()
let myhash = buffer.sha1() let myhash = buffer.sha1()
@@ -2683,12 +2809,10 @@ function! s:GF(mode) abort
if buffer.type('tree') if buffer.type('tree')
let showtree = (getline(1) =~# '^tree ' && getline(2) == "") let showtree = (getline(1) =~# '^tree ' && getline(2) == "")
if showtree && line('.') == 1 if showtree && line('.') > 2
return "" return [buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(getline('.'),'/$','')]
elseif showtree && line('.') > 2
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' elseif getline('.') =~# '^\d\{6\} \l\{3,8\} \x\{40\}\t'
return s:Edit(a:mode,0,buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(matchstr(getline('.'),'\t\zs.*'),'/$','')) return [buffer.commit().':'.s:buffer().path().(buffer.path() =~# '^$\|/$' ? '' : '/').s:sub(matchstr(getline('.'),'\t\zs.*'),'/$','')]
endif endif
elseif buffer.type('blob') elseif buffer.type('blob')
@@ -2698,38 +2822,40 @@ function! s:GF(mode) abort
catch /^fugitive:/ catch /^fugitive:/
endtry endtry
if exists('sha1') if exists('sha1')
return s:Edit(a:mode,0,ref) return [ref]
endif endif
else else
let dcmds = []
" Index " Index
if getline('.') =~# '^\d\{6\} \x\{40\} \d\t' if getline('.') =~# '^\d\{6\} \x\{40\} \d\t'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
let file = ':'.s:sub(matchstr(getline('.'),'\d\t.*'),'\t',':') let file = ':'.s:sub(matchstr(getline('.'),'\d\t.*'),'\t',':')
return s:Edit(a:mode,0,file) return [file]
elseif getline('.') =~# '^#\trenamed:.* -> ' elseif getline('.') =~# '^#\trenamed:.* -> '
let file = '/'.matchstr(getline('.'),' -> \zs.*') let file = '/'.matchstr(getline('.'),' -> \zs.*')
return s:Edit(a:mode,0,file) return [file]
elseif getline('.') =~# '^#\t[[:alpha:] ]\+: *.' elseif getline('.') =~# '^#\t[[:alpha:] ]\+: *.'
let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$') let file = '/'.matchstr(getline('.'),': *\zs.\{-\}\ze\%( ([^()[:digit:]]\+)\)\=$')
return s:Edit(a:mode,0,file) return [file]
elseif getline('.') =~# '^#\t.' elseif getline('.') =~# '^#\t.'
let file = '/'.matchstr(getline('.'),'#\t\zs.*') let file = '/'.matchstr(getline('.'),'#\t\zs.*')
return s:Edit(a:mode,0,file) return [file]
elseif getline('.') =~# ': needs merge$' elseif getline('.') =~# ': needs merge$'
let file = '/'.matchstr(getline('.'),'.*\ze: needs merge$') let file = '/'.matchstr(getline('.'),'.*\ze: needs merge$')
return s:Edit(a:mode,0,file).'|Gdiff' return [file, 'Gdiff!']
elseif getline('.') ==# '# Not currently on any branch.' elseif getline('.') ==# '# Not currently on any branch.'
return s:Edit(a:mode,0,'HEAD') return ['HEAD']
elseif getline('.') =~# '^# On branch ' elseif getline('.') =~# '^# On branch '
let file = 'refs/heads/'.getline('.')[12:] let file = 'refs/heads/'.getline('.')[12:]
return s:Edit(a:mode,0,file) return [file]
elseif getline('.') =~# "^# Your branch .*'" elseif getline('.') =~# "^# Your branch .*'"
let file = matchstr(getline('.'),"'\\zs\\S\\+\\ze'") let file = matchstr(getline('.'),"'\\zs\\S\\+\\ze'")
return s:Edit(a:mode,0,file) return [file]
endif endif
let showtree = (getline(1) =~# '^tree ' && getline(2) == "") let showtree = (getline(1) =~# '^tree ' && getline(2) == "")
@@ -2739,7 +2865,7 @@ function! s:GF(mode) abort
elseif getline('.') =~# '^commit \x\{40\}\>' elseif getline('.') =~# '^commit \x\{40\}\>'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
return s:Edit(a:mode,0,ref) return [ref]
elseif getline('.') =~# '^parent \x\{40\}\>' elseif getline('.') =~# '^parent \x\{40\}\>'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
@@ -2749,21 +2875,21 @@ function! s:GF(mode) abort
let parent += 1 let parent += 1
let line -= 1 let line -= 1
endwhile endwhile
return s:Edit(a:mode,0,ref) return [ref]
elseif getline('.') =~ '^tree \x\{40\}$' elseif getline('.') =~ '^tree \x\{40\}$'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
if s:repo().rev_parse(myhash.':') == ref if s:repo().rev_parse(myhash.':') == ref
let ref = myhash.':' let ref = myhash.':'
endif endif
return s:Edit(a:mode,0,ref) return [ref]
elseif getline('.') =~# '^object \x\{40\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$' elseif getline('.') =~# '^object \x\{40\}$' && getline(line('.')+1) =~ '^type \%(commit\|tree\|blob\)$'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
let type = matchstr(getline(line('.')+1),'type \zs.*') let type = matchstr(getline(line('.')+1),'type \zs.*')
elseif getline('.') =~# '^\l\{3,8\} '.myhash.'$' elseif getline('.') =~# '^\l\{3,8\} '.myhash.'$'
return '' let ref = buffer.rev()
elseif getline('.') =~# '^\l\{3,8\} \x\{40\}\>' elseif getline('.') =~# '^\l\{3,8\} \x\{40\}\>'
let ref = matchstr(getline('.'),'\x\{40\}') let ref = matchstr(getline('.'),'\x\{40\}')
@@ -2775,7 +2901,7 @@ function! s:GF(mode) abort
elseif getline('.') =~# '^[+-]' && search('^@@ -\d\+,\d\+ +\d\+,','bnW') elseif getline('.') =~# '^[+-]' && search('^@@ -\d\+,\d\+ +\d\+,','bnW')
let type = getline('.')[0] let type = getline('.')[0]
let lnum = line('.') - 1 let lnum = line('.') - 1
let offset = -1 let offset = 0
while getline(lnum) !~# '^@@ -\d\+,\d\+ +\d\+,' while getline(lnum) !~# '^@@ -\d\+,\d\+ +\d\+,'
if getline(lnum) =~# '^[ '.type.']' if getline(lnum) =~# '^[ '.type.']'
let offset += 1 let offset += 1
@@ -2784,18 +2910,25 @@ function! s:GF(mode) abort
endwhile endwhile
let offset += matchstr(getline(lnum), type.'\zs\d\+') let offset += matchstr(getline(lnum), type.'\zs\d\+')
let ref = getline(search('^'.type.'\{3\} [ab]/','bnW'))[4:-1] let ref = getline(search('^'.type.'\{3\} [ab]/','bnW'))[4:-1]
let dcmd = '+'.offset.'|normal! zv' let dcmds = [offset, 'normal!zv']
let dref = ''
elseif getline('.') =~# '^rename from ' elseif getline('.') =~# '^rename from '
let ref = 'a/'.getline('.')[12:] let ref = 'a/'.getline('.')[12:]
elseif getline('.') =~# '^rename to ' elseif getline('.') =~# '^rename to '
let ref = 'b/'.getline('.')[10:] let ref = 'b/'.getline('.')[10:]
elseif getline('.') =~# '^@@ -\d\+,\d\+ +\d\+,'
let diff = getline(search('^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)', 'bcnW'))
let offset = matchstr(getline('.'), '+\zs\d\+')
let dref = matchstr(diff, '\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)')
let ref = matchstr(diff, '\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)')
let dcmd = 'Gdiff! +'.offset
elseif getline('.') =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)' elseif getline('.') =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)'
let dref = matchstr(getline('.'),'\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)') let dref = matchstr(getline('.'),'\Cdiff --git \zs\%(a/.*\|/dev/null\)\ze \%(b/.*\|/dev/null\)')
let ref = matchstr(getline('.'),'\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)') let ref = matchstr(getline('.'),'\Cdiff --git \%(a/.*\|/dev/null\) \zs\%(b/.*\|/dev/null\)')
let dcmd = 'Gdiff' let dcmd = 'Gdiff!'
elseif getline('.') =~# '^index ' && getline(line('.')-1) =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)' elseif getline('.') =~# '^index ' && getline(line('.')-1) =~# '^diff --git \%(a/.*\|/dev/null\) \%(b/.*\|/dev/null\)'
let line = getline(line('.')-1) let line = getline(line('.')-1)
@@ -2807,7 +2940,7 @@ function! s:GF(mode) abort
let ref = getline('.') let ref = getline('.')
elseif expand('<cword>') =~# '^\x\{7,40\}\>' elseif expand('<cword>') =~# '^\x\{7,40\}\>'
return s:Edit(a:mode,0,expand('<cword>')) return [expand('<cword>')]
else else
let ref = '' let ref = ''
@@ -2833,16 +2966,42 @@ function! s:GF(mode) abort
endif endif
if exists('dref') if exists('dref')
return s:Edit(a:mode,0,ref) . '|'.dcmd.' '.s:fnameescape(dref) return [ref, dcmd . ' ' . s:fnameescape(dref)] + dcmds
elseif ref != "" elseif ref != ""
return s:Edit(a:mode,0,ref) return [ref] + dcmds
endif endif
endif endif
return '' return []
endtry
endfunction
function! s:GF(mode) abort
try
let results = s:cfile()
catch /^fugitive:/ catch /^fugitive:/
return 'echoerr v:errmsg' return 'echoerr v:errmsg'
endtry endtry
if len(results)
return s:Edit(a:mode, 0, results[0]).join(map(results[1:-1], '"|".v:val'), '')
else
return ''
endif
endfunction
function! fugitive#cfile() abort
let pre = ''
let results = s:cfile()
if empty(results)
let cfile = expand('<cfile>')
if &includeexpr =~# '\<v:fname\>'
sandbox let cfile = eval(substitute(&includeexpr, '\C\<v:fname\>', '\=string(cfile)', 'g'))
endif
return cfile
elseif len(results) > 1
let pre = '+' . join(map(results[1:-1], 'escape(v:val, " ")'), '\|') . ' '
endif
return pre . s:fnameescape(fugitive#repo().translate(results[0]))
endfunction endfunction
" Section: Statusline " Section: Statusline
@@ -2880,6 +3039,11 @@ function! fugitive#head(...) abort
return s:repo().head(a:0 ? a:1 : 0) return s:repo().head(a:0 ? a:1 : 0)
endfunction endfunction
augroup fugitive_statusline
autocmd!
autocmd User Flags call Hoist('buffer', function('fugitive#statusline'))
augroup END
" Section: Folding " Section: Folding
function! fugitive#foldtext() abort function! fugitive#foldtext() abort