One of my favorite Vim mappings is gx. When hovering over a URL with the cursor in normal mode and using this mapping, Vim will open the URL under the cursor with your default browser.
To learn more about this mapping, which is part of the built-in NETRW plugin, type :h gx
inside Vim.
What if we could take this a step further?
When you're in a package.json
file or mix.exs
, what if you could press gx
and have Vim open the npmjs.org or hexdocs.pm page for the package under the cursor? Turns out it's not that hard to do!
JavaScript: package.json + gx
For package.json
we will need to parse the package name, then construct the npm url and pass it to netrw#BrowseX
function, which in turn will open it in the default browser. First let's create a function to do just that:
function! PackageJsonGx() abort
let l:line = getline('.')
let l:package = matchlist(l:line, '\v"(.*)": "(.*)"')
if len(l:package) > 0
let l:package_name = l:package[1]
let l:url = 'https://www.npmjs.com/package/' . l:package_name
call netrw#BrowseX(l:url, 0)
endif
endfunction
Then we need to override the gx mappings to call our function whenever we are inside of a package.json
file:
augroup PackageJsonGx
autocmd!
autocmd BufRead,BufNewFile package.json nnoremap <buffer> <silent> gx :call PackageJsonGx()<cr>
augroup END
Elixir: mix.exs + gx
Thankfully there is an Elixir plugin that will allow us to open the hexdocs.pm page or Github page for the package under the cursor. All we have to do is set the mappings to activate whenever we are in a mix.exs
file.
First, make sure you install the plugin:
Plug 'lucidstack/hex.vim'
Then add the following to your vimrc to have gx open the Hex Docs page, and gh to open the Github page:
" Elixir mix.exs
augroup MixExsGx
autocmd!
autocmd BufRead,BufNewFile mix.exs nnoremap <buffer> <silent> gx :HexOpenHexDocs<cr>
autocmd BufRead,BufNewFile mix.exs nnoremap <buffer> <silent> gh :HexOpenGithub<cr>
augroup END
" }}}
Bonus: VimPlug
If you're using VimPlug as your Vim plugin manager, you can also get the gx mapping to work inside Plug windows (like the one that opens when you update your plugins with :PlugUpdate
). This code was originally posted in VimPlug's wiki (and was my inspiration for customizing gx for other scenarios), but I modified it so it also works inside my plugin definition file (~/.vimrc.bundles
):
" For VimPlug
function! PlugGx()
let l:line = getline('.')
let l:sha = matchstr(l:line, '^ \X*\zs\x\{7,9}\ze ')
if (&filetype ==# 'vim-plug')
" inside vim plug splits such as :PlugStatus
let l:name = empty(l:sha)
\ ? matchstr(l:line, '^[-x+] \zs[^:]\+\ze:')
\ : getline(search('^- .*:$', 'bn'))[2:-2]
else
" in .vimrc.bundles
let l:name = matchlist(l:line, '\v/([A-Za-z0-9\-_\.]+)')[1]
endif
let l:uri = get(get(g:plugs, l:name, {}), 'uri', '')
if l:uri !~? 'github.com'
return
endif
let l:repo = matchstr(l:uri, '[^:/]*/'.l:name)
let l:url = empty(l:sha)
\ ? 'https://github.com/'.l:repo
\ : printf('https://github.com/%s/commit/%s', l:repo, l:sha)
call netrw#BrowseX(l:url, 0)
endfunction
augroup PlugGxGroup
autocmd!
autocmd BufRead,BufNewFile .vimrc.bundles nnoremap <buffer> <silent> gx :call PlugGx()<cr>
autocmd FileType vim-plug nnoremap <buffer> <silent> gx :call PlugGx()<cr>
augroup END
Hope you find it this post useful and that it inspires you to customize gx to support your favorite package manager / programming language. If you do write your own customization please @/DM me on Twitter - I'm interested in hearing what you come up with!