nix/config/nvim/lua/plugins/git.lua
2026-03-05 13:42:50 -05:00

248 lines
7 KiB
Lua

vim.pack.add({
'https://github.com/tpope/vim-fugitive',
})
-- selene: allow(global_usage)
function _G._fugitive_stl()
local s = vim.fn.FugitiveStatusline()
return s ~= '' and s .. ' ' or ''
end
vim.api.nvim_create_autocmd('VimEnter', {
once = true,
callback = function()
vim.o.statusline = ' %{v:lua._fugitive_stl()}'
.. vim.o.statusline:sub(2)
end,
})
vim.pack.add({
'https://github.com/lewis6991/gitsigns.nvim',
}, { load = function() end })
---@return string
local function file_loc()
local root = vim.trim(vim.fn.system('git rev-parse --show-toplevel'))
local file = vim.api.nvim_buf_get_name(0):sub(#root + 2)
local mode = vim.fn.mode()
if mode:match('[vV]') or mode == '\22' then
local s = vim.fn.line('v')
local e = vim.fn.line('.')
if s > e then
s, e = e, s
end
if s == e then
return ('%s:%d'):format(file, s)
end
return ('%s:%d-%d'):format(file, s, e)
end
return ('%s:%d'):format(file, vim.fn.line('.'))
end
---@param args string[]
local function yank_url(args)
vim.system(args, { text = true }, function(result)
if result.code == 0 then
local url = vim.trim(result.stdout or '')
if url ~= '' then
vim.schedule(function()
vim.fn.setreg('+', url)
end)
end
end
end)
end
local function remote_web_url()
local url = vim.trim(vim.fn.system('git remote get-url origin'))
url = url:gsub('%.git$', '')
url = url:gsub('^ssh://git@', 'https://')
url = url:gsub('^git@([^:]+):', 'https://%1/')
return url
end
local function gitlab_file_url(loc, ref)
local base = remote_web_url()
local file, lines = loc:match('^(.+):(.+)$')
return ('%s/-/blob/%s/%s#L%s'):format(base, ref, file, lines)
end
local function detect_forge()
local url = vim.trim(vim.fn.system('git remote get-url origin'))
if vim.v.shell_error ~= 0 then
return nil
end
if url:find('github') and vim.fn.executable('gh') == 1 then
return 'github'
end
if url:find('gitlab') and vim.fn.executable('glab') == 1 then
return 'gitlab'
end
return nil
end
local forges = {
github = {
kinds = { issue = 'issue', pr = 'pr' },
labels = { issue = 'Issues', pr = 'PRs' },
list_cmd = function(kind, state)
return ('gh %s list --limit 100 --state %s'):format(kind, state)
end,
view_cmd = function(kind, num)
return { 'gh', kind, 'view', num, '--web' }
end,
browse = function(loc, branch)
vim.system({ 'gh', 'browse', loc, '--branch', branch })
end,
browse_root = function()
vim.system({ 'gh', 'browse' })
end,
yank_branch = function(loc)
yank_url({ 'gh', 'browse', loc, '-n' })
end,
yank_commit = function(loc)
yank_url({ 'gh', 'browse', loc, '--commit=last', '-n' })
end,
},
gitlab = {
kinds = { issue = 'issue', pr = 'mr' },
labels = { issue = 'Issues', pr = 'MRs' },
list_cmd = function(kind, state)
local cmd = ('glab %s list --per-page 100'):format(kind)
if state == 'closed' then
cmd = cmd .. ' --closed'
elseif state == 'all' then
cmd = cmd .. ' --all'
end
return cmd
end,
view_cmd = function(kind, num)
return { 'glab', kind, 'view', num, '--web' }
end,
browse = function(loc, branch)
vim.ui.open(gitlab_file_url(loc, branch))
end,
browse_root = function()
vim.system({ 'glab', 'repo', 'view', '--web' })
end,
yank_branch = function(loc)
local branch = vim.trim(vim.fn.system('git branch --show-current'))
vim.fn.setreg('+', gitlab_file_url(loc, branch))
end,
yank_commit = function(loc)
local commit = vim.trim(vim.fn.system('git rev-parse HEAD'))
vim.fn.setreg('+', gitlab_file_url(loc, commit))
end,
},
}
---@param kind 'issue'|'pr'
---@param state 'all'|'open'|'closed'
local function forge_picker(kind, state)
local forge_name = detect_forge()
if not forge_name then
vim.notify('No supported forge detected', vim.log.levels.WARN)
return
end
local forge = forges[forge_name]
local cli_kind = forge.kinds[kind]
local next_state = ({ all = 'open', open = 'closed', closed = 'all' })[state]
pcall(vim.cmd.packadd, 'fzf-lua')
require('fzf-lua').fzf_exec(forge.list_cmd(cli_kind, state), {
prompt = ('%s (%s)> '):format(forge.labels[kind], state),
header = ':: <c-o> to toggle all/open/closed',
actions = {
['default'] = function(selected)
local num = selected[1]:match('^[#!]?(%d+)')
if num then
vim.system(forge.view_cmd(cli_kind, num))
end
end,
['ctrl-o'] = function()
forge_picker(kind, next_state)
end,
},
})
end
local function with_forge(fn)
return function()
local forge_name = detect_forge()
if not forge_name then
vim.notify('No supported forge detected', vim.log.levels.WARN)
return
end
fn(forges[forge_name])
end
end
vim.keymap.set(
{ 'n', 'v' },
'<leader>go',
with_forge(function(forge)
local branch = vim.trim(vim.fn.system('git branch --show-current'))
forge.browse(file_loc(), branch)
end)
)
vim.keymap.set(
{ 'n', 'v' },
'<leader>gy',
with_forge(function(forge)
forge.yank_commit(file_loc())
end)
)
vim.keymap.set(
{ 'n', 'v' },
'<leader>gl',
with_forge(function(forge)
forge.yank_branch(file_loc())
end)
)
vim.keymap.set(
'n',
'<leader>gx',
with_forge(function(forge)
forge.browse_root()
end)
)
vim.keymap.set('n', '<leader>gd', function()
pcall(vim.cmd.packadd, 'fzf-lua')
require('fzf-lua').fzf_exec('git branch -a --format="%(refname:short)"', {
prompt = 'Git diff> ',
actions = {
['default'] = function(selected)
vim.cmd('Git diff ' .. selected[1])
end,
},
})
end)
vim.keymap.set('n', '<leader>gi', function()
forge_picker('issue', 'all')
end)
vim.keymap.set('n', '<leader>gp', function()
forge_picker('pr', 'all')
end)
return {
{
'barrettruth/diffs.nvim',
enabled = true,
before = function()
vim.g.diffs = {
debug = '/tmp/diffs.log',
fugitive = true,
extra_filetypes = { 'diff' },
hide_prefix = false,
highlights = {
vim = {
enabled = true,
},
intra = {
enabled = true,
max_lines = 500,
},
},
}
end,
},
}