Skip to content

Instantly share code, notes, and snippets.

@Vftdan
Last active February 9, 2021 22:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Vftdan/86c8b48320cf425e923552e4573d50c8 to your computer and use it in GitHub Desktop.
Save Vftdan/86c8b48320cf425e923552e4573d50c8 to your computer and use it in GitHub Desktop.
Vim gemini:// protocol plugin
function! s:read_gemini(url)
call s:init_go_url()
function! s:init_go_url()
endfunction
let l:svpos = winsaveview()
setlocal bl ro noswapfile
if &ft == ''
setlocal ft=gmi
else
let &ft=&ft
endif
exe "%read !gmni -j once " . shellescape(a:url) . ' 2>/dev/null'
keepjumps normal! ggJ
keepjumps call winrestview(l:svpos)
if len(join(getline(0, line('$')))) == 0 && match(a:url, '?') == -1
let l:url = a:url . '?' . input('query: ')
0file
exe 'file ' . fnameescape(l:url)
call s:read_gemini(l:url)
endif
endfunction
function! s:getsel()
let l:save = @a
norm! gv"ay
let l:res = @a
let @a = l:save
return l:res
endfunction
aug GeminiProtocol
au!
au BufReadCmd gemini://* exe "sil doau BufReadPre ".fnameescape(expand("<amatch>"))|call s:read_gemini(expand("<amatch>"))|exe "sil doau BufReadPost ".fnameescape(expand("<amatch>"))
au FileReadCmd gemini://* exe "sil doau FileReadPre ".fnameescape(expand("<amatch>"))|call s:read_gemini(expand("<amatch>"))|exe "sil doau FileReadPost ".fnameescape(expand("<amatch>"))
aug END
function! s:init_go_url()
" if has('python3')
" py3 from urllib.parse import urljoin, uses_relative, uses_netloc
" py3 uses_relative.append('gemini')
" py3 uses_netloc.append('gemini')
function! s:gemini_go_url(url)
" let l:path = py3eval('urljoin(vim.eval("@%"), vim.eval("a:url"))')
" exe "e " . fnameescape(l:path)
if match(@%, '\v^gemini\:\/\/') < 0
" Should be unreachable
exe 'edit ' . fnameescape(a:url)
endif
let l:base = substitute(@%, '\v[\?\#].*$', '', '')
" TODO properly handle paths starting from '?', '#' (are they supported in gemini?)
if match(a:url, '\v^[^\/]{-1,}($|[^\:\/]\/)') >= 0
" Relative
if match(l:base, '\v\c^gemini\:\/\/[^/]+\/.*[^\/]$') >= 0
let l:base = substitute(l:base, '\v\c^gemini\:\/\/[^/]+\/(.+\/)?\zs[^\/]+$', '', '')
endif
if split(l:base, '\zs')[-1] != '/'
let l:base .= '/'
endif
let [l:base, l:oldurl] = split(l:base, '\v\c^gemini\:\/\/[^/]+\zs', 1)
exe 'edit ' . fnameescape(l:base . simplify(l:oldurl . a:url))
elseif match(a:url, '\v^\/\/') >= 0
" Another domain
exe 'edit ' . fnameescape('gemini:' . simplify(a:url))
elseif match(a:url, '\v^\/') >= 0
" Root on the same domain
exe 'edit ' . fnameescape(substitute(l:base, '\v\c^(gemini\:\/\/[^/]+).*$', '\1', '') . simplify(a:url))
else
exe 'edit ' . fnameescape(a:url)
endif
return ''
endfunction
nnoremap <silent> <Plug>(gemini-protocol-go-url) <cmd>call <SID>gemini_go_url(expand('<cfile>'))<cr>
vnoremap <silent> <Plug>(gemini-protocol-go-url) <cmd>call <SID>gemini_go_url(<SID>getsel())<cr>
if !(has('g:gemini_protocol_no_gf') && g:gemini_protocol_no_gf)
aug GeminiProtocol
au BufReadPost gemini://* nmap <buffer> gf <Plug>(gemini-protocol-go-url)
au BufReadPost gemini://* vmap <buffer> gf <Plug>(gemini-protocol-go-url)
au FileReadPost gemini://* nmap <buffer> gf <Plug>(gemini-protocol-go-url)
au FileReadPost gemini://* vmap <buffer> gf <Plug>(gemini-protocol-go-url)
aug END
endif
" endif
endfunction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment