From 5aaa65736d9cc99c3f8dbd0c24db9d8660b0c236 Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Tue, 22 Jul 2014 00:17:43 -0400 Subject: [PATCH] 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. --- plugin/fugitive.vim | 74 +++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/plugin/fugitive.vim b/plugin/fugitive.vim index 60e6c03..d451161 100644 --- a/plugin/fugitive.vim +++ b/plugin/fugitive.vim @@ -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(),'\ 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