Browse handler API

Taking experimental out of the name, but small tweaks may occur before
then next release.

For future compatibility, any third party handlers should bail and
return an empty string if any of the following are true:

* More than 2 arguments are given.
* The second argument isn't a dictionary.
* The dictionary doesn't contain a "remote" key.

Closes #445.
This commit is contained in:
Tim Pope 2014-07-22 00:17:43 -04:00
parent 5d1c219ee5
commit 5aaa65736d

View File

@ -2175,8 +2175,15 @@ function! s:Browse(bang,line1,count,...) abort
let raw = remote
endif
for Handler in g:fugitive_experimental_browse_handlers
let url = call(Handler, [s:repo(),raw,rev,commit,path,type,a:line1,a:count])
for Handler in g:fugitive_browse_handlers
let url = call(Handler, [s:repo(), {
\ 'remote': raw,
\ 'revision': rev,
\ 'commit': commit,
\ 'path': path,
\ 'type': type,
\ 'line1': a:line1,
\ 'line2': a:count}])
if !empty(url)
break
endif
@ -2199,17 +2206,20 @@ function! s:Browse(bang,line1,count,...) abort
endtry
endfunction
function! s:github_url(repo,url,rev,commit,path,type,line1,line2) abort
let path = a:path
function! s:github_url(repo, opts, ...) abort
if a:0 || type(a:opts) != type({})
return ''
endif
let domain_pattern = 'github\.com'
let domains = exists('g:fugitive_github_domains') ? g:fugitive_github_domains : []
for domain in domains
let domain_pattern .= '\|' . escape(split(domain, '://')[-1], '.')
endfor
let repo = matchstr(a:url,'^\%(https\=://\|git://\|git@\)\=\zs\('.domain_pattern.'\)[/:].\{-\}\ze\%(\.git\)\=$')
let repo = matchstr(get(a:opts, 'remote'), '^\%(https\=://\|git://\|git@\)\=\zs\('.domain_pattern.'\)[/:].\{-\}\ze\%(\.git\)\=$')
if repo ==# ''
return ''
endif
let path = a:opts.path
if index(domains, 'http://' . matchstr(repo, '^[^:/]*')) >= 0
let root = 'http://' . s:sub(repo,':','/')
else
@ -2229,27 +2239,27 @@ function! s:github_url(repo,url,rev,commit,path,type,line1,line2) abort
elseif path =~# '^\.git\>'
return root
endif
if a:rev =~# '^[[:alnum:]._-]\+:'
let commit = matchstr(a:rev,'^[^:]*')
elseif a:commit =~# '^\d\=$'
if a:opts.revision =~# '^[[:alnum:]._-]\+:'
let commit = matchstr(a:opts.revision,'^[^:]*')
elseif a:opts.commit =~# '^\d\=$'
let local = matchstr(a:repo.head_ref(),'\<refs/heads/\zs.*')
let commit = a:repo.git_chomp('config','branch.'.local.'.merge')[11:-1]
if commit ==# ''
let commit = local
endif
else
let commit = a:commit
let commit = a:opts.commit
endif
if a:type == 'tree'
if a:opts.type == 'tree'
let url = s:sub(root . '/tree/' . commit . '/' . path,'/$','')
elseif a:type == 'blob'
elseif a:opts.type == 'blob'
let url = root . '/blob/' . commit . '/' . path
if a:line2 > 0 && a:line1 == a:line2
let url .= '#L' . a:line1
elseif a:line2 > 0
let url .= '#L' . a:line1 . '-' . a:line2
if get(a:opts, 'line2') && a:opts.line1 == a:opts.line2
let url .= '#L' . a:opts.line1
elseif get(a:opts, 'line2')
let url .= '#L' . a:opts.line1 . '-' . a:opts.line2
endif
elseif a:type == 'tag'
elseif a:opts.type == 'tag'
let commit = matchstr(getline(3),'^tag \zs.*')
let url = root . '/tree/' . commit
else
@ -2258,52 +2268,52 @@ function! s:github_url(repo,url,rev,commit,path,type,line1,line2) abort
return url
endfunction
function! s:instaweb_url(repo,rev,commit,path,type,...) abort
function! s:instaweb_url(repo, opts) abort
let output = a:repo.git_chomp('instaweb','-b','unknown')
if output =~# 'http://'
let root = matchstr(output,'http://.*').'/?p='.fnamemodify(a:repo.dir(),':t')
else
return ''
endif
if a:path =~# '^\.git/refs/.'
return root . ';a=shortlog;h=' . matchstr(a:path,'^\.git/\zs.*')
elseif a:path =~# '^\.git\>'
if a:opts.path =~# '^\.git/refs/.'
return root . ';a=shortlog;h=' . matchstr(a:opts.path,'^\.git/\zs.*')
elseif a:opts.path =~# '^\.git\>'
return root
endif
let url = root
if a:commit =~# '^\x\{40\}$'
if a:type ==# 'commit'
if a:opts.commit =~# '^\x\{40\}$'
if a:opts.type ==# 'commit'
let url .= ';a=commit'
endif
let url .= ';h=' . a:repo.rev_parse(a:commit . (a:path == '' ? '' : ':' . a:path))
let url .= ';h=' . a:repo.rev_parse(a:opts.commit . (a:opts.path == '' ? '' : ':' . a:opts.path))
else
if a:type ==# 'blob'
if a:opts.type ==# 'blob'
let tmp = tempname()
silent execute 'write !'.a:repo.git_command('hash-object','-w','--stdin').' > '.tmp
let url .= ';h=' . readfile(tmp)[0]
else
try
let url .= ';h=' . a:repo.rev_parse((a:commit == '' ? 'HEAD' : ':' . a:commit) . ':' . a:path)
let url .= ';h=' . a:repo.rev_parse((a:opts.commit == '' ? 'HEAD' : ':' . a:opts.commit) . ':' . a:opts.path)
catch /^fugitive:/
call s:throw('fugitive: cannot browse uncommitted file')
endtry
endif
let root .= ';hb=' . matchstr(a:repo.head_ref(),'[^ ]\+$')
endif
if a:path !=# ''
let url .= ';f=' . a:path
if a:opts.path !=# ''
let url .= ';f=' . a:opts.path
endif
if a:0 && a:1
let url .= '#l' . a:1
if get(a:opts, 'line1')
let url .= '#l' . a:opts.line1
endif
return url
endfunction
if !exists('g:fugitive_experimental_browse_handlers')
let g:fugitive_experimental_browse_handlers = []
if !exists('g:fugitive_browse_handlers')
let g:fugitive_browse_handlers = []
endif
call extend(g:fugitive_experimental_browse_handlers,
call extend(g:fugitive_browse_handlers,
\ [s:function('s:github_url'), s:function('s:instaweb_url')])
" Section: File access