summaryrefslogtreecommitdiffstats
path: root/.config/nvim/plugin/50-git.lua
blob: 8bebef11d09ae24d625a1f9370f207bb00ca98bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
--
-- Git-related utilities
--

local function git_blame(file, line)
	local sys = vim.system({
		vim.fn.stdpath("config") .. "/scripts/git_blame.bash",
		tostring(line),
		file,
	}, { text = true }):wait()
	if sys.stdout then
		return vim.split(sys.stdout, "\n", { trimempty = true })
	end
	if sys.code ~= 0 then
		local err_msg = "git blame failed (" .. sys.code .. ")\n" .. sys.stderr
		vim.notify(err_msg, vim.log.levels.ERROR)
	end
end

local git_blame_toggle = (function()
	local win, auid, buf

	local function close()
		if win and vim.api.nvim_win_is_valid(win) then
			vim.api.nvim_win_close(win, true)
		end
		if buf and vim.api.nvim_buf_is_valid(buf) then
			vim.api.nvim_buf_delete(buf, { force = true })
		end
		win, auid, buf = nil, nil, nil
	end

	return function()
		if win and vim.api.nvim_win_is_valid(win) then
			if auid then
				vim.api.nvim_del_autocmd(auid)
			end
			vim.api.nvim_set_current_win(win)
			-- Transient, self-cleaning (once): not part of the global dotfiles augroup.
			vim.api.nvim_create_autocmd("BufLeave", {
				once = true,
				callback = close,
			})
			return
		end

		local text = git_blame(vim.api.nvim_buf_get_name(0), vim.api.nvim_win_get_cursor(0)[1])
		if not text then
			return
		end

		buf = vim.api.nvim_create_buf(false, true)
		vim.api.nvim_buf_set_lines(buf, 0, -1, false, text)
		win = vim.api.nvim_open_win(buf, false, {
			relative = "cursor",
			width = 50,
			height = #text,
			row = 0,
			col = 0,
			style = "minimal",
			border = "rounded",
			title = "git blame",
			noautocmd = true,
		})
		-- Transient, manually managed via auid/del_autocmd: not part of the global dotfiles augroup.
		auid = vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI", "BufLeave" }, {
			once = true,
			callback = close,
		})
	end
end)()

vim.api.nvim_create_user_command(
	"GitBlame",
	git_blame_toggle,
	{ desc = "Open/enter git blame window" }
)

-- The original mappings from the plugin are broken
vim.keymap.set("n", "]c", "<Cmd>GitGutterNextHunk<CR>", { desc = "Next git hunk" })
vim.keymap.set("n", "[c", "<Cmd>GitGutterPreviousHunk<CR>", { desc = "Next git hunk" })