A lua neovim plugin to generate shareable
file permalinks (with line ranges) for several git web frontend hosts. Inspired
by tpope/vim-fugitive's :GBrowse
Example of a permalink: https://github.com/neovim/neovim/blob/2e156a3b7d7e25e56b03683cc6228c531f4c91ef/src/nvim/main.c#L137-L156
Personally, I use this all the time to easily share code locations with my co-workers.
You can easily configure support for more hosts by defining your own host callbacks. It's even easier if your host is just an enterprise/self-hosted github/gitlab/gitea/gogs/cgit instance since you can just use the same callbacks that already exist in gitlinker! See callbacks
Install it like any other vim plugin, just make sure plenary.nvim is also installed.
use {
    'ruifm/gitlinker.nvim',
    requires = 'nvim-lua/plenary.nvim',
}
Plug 'nvim-lua/plenary.nvim'
Plug 'ruifm/gitlinker.nvim'
In your init.lua or in a lua-here-doc in your init.vim:
require"gitlinker".setup()
By default, the following mappings are defined:
<leader>gy for normal and visual modeWhen used, it will copy the generated url to your clipboard and print it in
:messages.
To disable the default mappings just set mappings = nil in the setup()
function (see Configuration)
If you want to disable mappings and set them on your own, the function you are
looking for is require"gitlinker".get_buf_range_url(mode, user_opts) where:
mode is the either "n" (normal) or "v" (visual)
user_opts is a table of options that override the ones set in setup() (see
Configuration). Because it just overrides, you do not need
to pass this parameter, only if you want to change something.
Example for setting extra mappings for an alternative action_callback (in
this case, open in browser):
vim.api.nvim_set_keymap('n', '<leader>gb', '<cmd>lua require"gitlinker".get_buf_range_url("n", {action_callback = require"gitlinker.actions".open_in_browser})<cr>', {silent = true})
vim.api.nvim_set_keymap('v', '<leader>gb', '<cmd>lua require"gitlinker".get_buf_range_url("v", {action_callback = require"gitlinker.actions".open_in_browser})<cr>', {})
For convenience, the function
require"gitlinker".get_buf_range_url(mode, user_opts) allows one to generate
the url for the repository homepage. You can map it like so:
vim.api.nvim_set_keymap('n', '<leader>gY', '<cmd>lua require"gitlinker".get_repo_url()<cr>', {silent = true})
vim.api.nvim_set_keymap('n', '<leader>gB', '<cmd>lua require"gitlinker".get_repo_url({action_callback = require"gitlinker.actions".open_in_browser})<cr>', {silent = true})
And use <leader>gY to copy the repo's homepage to your clipboard or
<leader>gB to open it in your browser.
To configure gitlinker.nvim, call require"gitlinker".setup(config) in your
init.lua or in a lua-here-doc in your init.vim.
Here's all the options with their defaults:
require"gitlinker".setup({
  opts = {
    remote = nil, -- force the use of a specific remote
    -- adds current line nr in the url for normal mode
    add_current_line_on_normal_mode = true,
    -- callback for what to do with the url
    action_callback = require"gitlinker.actions".copy_to_clipboard,
    -- print the url after performing the action
    print_url = true,
  },
  callbacks = {
        ["github.com"] = require"gitlinker.hosts".get_github_type_url,
        ["gitlab.com"] = require"gitlinker.hosts".get_gitlab_type_url,
        ["try.gitea.io"] = require"gitlinker.hosts".get_gitea_type_url,
        ["codeberg.org"] = require"gitlinker.hosts".get_gitea_type_url,
        ["bitbucket.org"] = require"gitlinker.hosts".get_bitbucket_type_url,
        ["try.gogs.io"] = require"gitlinker.hosts".get_gogs_type_url,
        ["git.sr.ht"] = require"gitlinker.hosts".get_srht_type_url,
        ["git.launchpad.net"] = require"gitlinker.hosts".get_launchpad_type_url,
        ["repo.or.cz"] = require"gitlinker.hosts".get_repoorcz_type_url,
        ["git.kernel.org"] = require"gitlinker.hosts".get_cgit_type_url,
        ["git.savannah.gnu.org"] = require"gitlinker.hosts".get_cgit_type_url
  },
-- default mapping to call url generation with action_callback
  mappings = "<leader>gy"
})
When configuring gitlinker.nvim, you don't need to copy-paste the above, you
just need to override/add what you want.
Besides the already configured hosts in the callbacks table, one can add
support for other git web hosts or self-hosted and enterprise instances.
In the key, place a string with the hostname and in value a callback function that constructs the url and receives:
url_data = {
  host = "<host.tld>",
  port = "3000" or nil,
  repo = "<user/repo>",
  rev = "<commit sha>",
  file = "<path/to/file/from/repo/root>",
  lstart = 42, -- the line start of the selected range / current line
  lend = 57, -- the line end of the selected range
}
port will always be nil except when the remote URI configured locally is
http(s) and specifies a port (e.g. http://localhost:3000/user/repo.git),
in which case the generated url permalink also needs the right port.
lstart and lend can be nil in case normal mode was used or
opts.add_current_line_on_normal_mode = false. Do not forget to check for that
in your callback.
As an example, here is the callback for github (you don't need this, it's already builtin, it's just an example):
callbacks = {
  ["github.com"] = function(url_data)
      local url = require"gitlinker.hosts".get_base_https_url(url_data) ..
        url_data.repo .. "/blob/" .. url_data.rev .. "/" .. url_data.file
      if url_data.lstart then
        url = url .. "#L" .. url_data.lstart
        if url_data.lend then url = url .. "-L" .. url_data.lend end
      end
      return url
    end
}
If you want to add support for your company's gitlab instance:
callbacks = {
  ["git.seriouscompany.com"] = require"gitlinker.hosts".get_gitlab_type_url
}
Here is my personal configuration for my personal self-hosted gitea instance for
which the host is a local one (since I can only access it from my LAN) and but
the web interface is public:
callbacks = {
  ["192.168.1.2"] = function(url_data)
      url_data.host = "git.ruimarques.xyz"
      return
          require"gitlinker.hosts".get_gitea_type_url(url_data)
    end
}
Warning: The keys in callbacks table are actually interpreted as lua
regexes. If your url contains magic lua character such as -, it needs to be
escaped as %-.
remoteIf remote = nil (default), the relevant remote will be auto-detected. If you
have multiple git remotes configured and want to use a specific one
(e.g. myfork), do remote = "myfork".
add_current_line_on_normal_modeIf true, when invoking the mapping/command in normal mode, it adds the current
line to the url.
action_callbackA function that receives a url string and decides which action to take. By
default set to require"gitlinker.actions".copy_to_clipboard which copies to
generated url to your system clipboard.
An alternative callback require"gitlinker.actions".open_in_browser is provided
which opens the url in your preferred browser using xdg-open (linux only).
You can define your own action callback.
For example, to copy the url over a remote SSH session with an
OSC52-compatible terminal, you can integrate gitlinker with
ojroques/vim-oscyank and use its OSCYankString function:
require'gitlinker'.setup{
  opts = {
    action_callback = function(url)
      -- yank to unnamed register
      vim.api.nvim_command('let @" = \'' .. url .. '\'')
      -- copy to the system clipboard using OSC52
      vim.fn.OSCYankString(url)
    end,
  },
}
For the above setup, make sure that ojroques/vim-oscyank is also installed.
print_urlIf true, then print the url before performing the configured action.
All contributions are welcome, feel free to open a pull request.
Please read CONTRIBUTING.md for general contributing guidelines for this project.