From 383b2a43df5b5170ce1f57f864d88715edcefd3e Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Sat, 26 Feb 2011 15:40:59 -0500 Subject: [PATCH] Handle arbitrary :Gbrowse revision --- doc/fugitive.txt | 15 ++--- plugin/fugitive.vim | 151 +++++++++++++++++++++++++++++--------------- 2 files changed, 106 insertions(+), 60 deletions(-) diff --git a/doc/fugitive.txt b/doc/fugitive.txt index f7edb11..2c4ee12 100644 --- a/doc/fugitive.txt +++ b/doc/fugitive.txt @@ -166,17 +166,12 @@ that are part of Git repositories). :[range]Gbrowse! Like :Gbrowse, but put the URL on the clipboard rather than opening it. -:[range]Gbrowse - Like :Gbrowse, but tie the URL to the current HEAD. - This is useful in a work tree file to ensure the link - always goes to the file as it currently stands, rather - than whatever the latest on master is. Note that - when editing a historical file, said link is tied by - default to the commit you're currently browsing. (The - intent is that ultimately, one will be able to specify - any |fugitive-revision| here, but the current - implementation is limited to this one special case.) +:[range]Gbrowse {revision} + Like :Gbrowse, but for a given |fugitive-revision|. A + useful value here is -, which ties the URL to the + latest commit rather than a volatile branch. -[range]Gbrowse [...]@{remote} +:[range]Gbrowse [...]@{remote} Force using the given remote rather than the remote for the current branch. The remote is used to determine which GitHub repository to link to. diff --git a/plugin/fugitive.vim b/plugin/fugitive.vim index b052220..b285e6c 100644 --- a/plugin/fugitive.vim +++ b/plugin/fugitive.vim @@ -1372,36 +1372,87 @@ endfunction " }}}1 " Gbrowse {{{1 -call s:command("-bar -bang -count=0 -nargs=? Gbrowse :execute s:Browse(0,,,)") +call s:command("-bar -bang -count=0 -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:]_-]\+\%(://.\{-\}\)\=$','','') : '' - if a:0 && a:1 =~# '@[[:alnum:]_-]\+\%(://.\{-\}\)\=$' + let rev = a:0 ? substitute(a:1,'@[[:alnum:]_-]*\%(://.\{-\}\)\=$','','') : '' + if rev ==# '' + let expanded = s:buffer().rev() + elseif rev ==# ':' + let expanded = s:buffer().path('/') + else + let expanded = s:buffer().expand(rev) + endif + let full = s:repo().translate(expanded) + let commit = '' + if full =~# '^fugitive://' + let commit = matchstr(full,'://.*//\zs\w\+') + let path = matchstr(full,'://.*//\w\+\zs/.*') + if commit =~ '..' + let type = s:repo().git_chomp('cat-file','-t',commit.s:sub(path,'^/',':')) + else + let type = 'blob' + endif + let path = path[1:-1] + elseif s:repo().bare() + let path = '.git/' . full[strlen(s:repo().dir())+1:-1] + let type = '' + else + let path = full[strlen(s:repo().tree())+1:-1] + if path =~# '^\.git/' + let type = '' + elseif isdirectory(full) + let type = 'tree' + else + let type = 'blob' + endif + endif + + if a:0 && a:1 =~# '@[[:alnum:]_-]*\%(://.\{-\}\)\=$' let remote = matchstr(a:1,'@\zs[[:alnum:]_-]\+\%(://.\{-\}\)\=$') - elseif s:buffer().path() =~# '^\.git/refs/remotes/.' - let remote = matchstr(s:buffer().path(),'^\.git/refs/remotes/\zs[^/]\+') + elseif path =~# '^\.git/refs/remotes/.' + let remote = matchstr(path,'^\.git/refs/remotes/\zs[^/]\+') else let remote = 'origin' - let branch = matchstr(s:repo().head_ref(),'\\)' return root . '/admin' elseif path =~# '^\.git\>' return root endif - if a:rev ==# '-' - let commit = self.repo().rev_parse('HEAD') - elseif self.commit() =~# '^\x\{40\}$' - let commit = self.commit() - else - let local = matchstr(self.repo().head_ref(),'\' + if a:path =~# '^\.git/refs/.' + return root . ';a=shortlog;h=' . matchstr(a:path,'^\.git/\zs.*') + elseif a:path =~# '^\.git\>' return root endif let url = root - if self.commit() =~# '^\x\{40\}$' || a:rev ==# '-' - let ref = a:rev ==# '-' ? 'HEAD' : self.commit() - let url .= ';h=' . self.repo().rev_parse(ref . path) + if a:commit =~# '^\x\{40\}$' + if a:type ==# 'commit' + let url .= ';a=commit' + endif + let url .= ';h=' . a:repo.rev_parse(a:commit . (a:path == '' ? '' : ':' . a:path)) else - if self.type() ==# 'file' || self.type() ==# 'blob' + if a:type ==# 'blob' let tmp = tempname() - silent execute 'write !'.self.repo().git_command('hash-object','-w','--stdin').' > '.tmp + silent execute 'write !'.a:repo.git_command('hash-object','-w','--stdin').' > '.tmp let url .= ';h=' . readfile(tmp)[0] else try - let url .= ';h=' . self.repo().rev_parse(self.path((self.commit() == '' ? 'HEAD' : ':'.self.commit()).':')) + let url .= ';h=' . a:repo.rev_parse((a:commit == '' ? 'HEAD' : ':' . a:commit) . ':' . a:path) catch /^fugitive:/ + throw 'fugitive: cannot browse uncommitted file' endtry endif - let root .= ';hb=' . matchstr(self.repo().head_ref(),'[^ ]\+$') + let root .= ';hb=' . matchstr(a:repo.head_ref(),'[^ ]\+$') endif - if path !=# '' - let url .= ';f=' . path + if a:path !=# '' + let url .= ';f=' . a:path endif if a:0 && a:1 let url .= '#l' . a:1