neovim: add keybinding to open commit under cursor in floating window

This commit is contained in:
2025-05-24 17:49:03 +03:00
parent 22f9051633
commit 05b65038b8
3 changed files with 92 additions and 0 deletions

View File

@@ -16,3 +16,5 @@ vim.keymap.set("n", "tn", ":tabnew<CR>")
vim.keymap.set("n", "tN", ":-tabnew<CR>") vim.keymap.set("n", "tN", ":-tabnew<CR>")
vim.keymap.set("n", "H", ":tabprev<CR>") vim.keymap.set("n", "H", ":tabprev<CR>")
vim.keymap.set("n", "L", ":tabnext<CR>") vim.keymap.set("n", "L", ":tabnext<CR>")
vim.keymap.set("n", "<leader>gl", require("daniil.gitblame").open_blame_window)

View File

@@ -0,0 +1,47 @@
local u = require("daniil.utils")
local M = {}
---@param line number
---@param path string
---@return string
local function get_commit_hash_at_line(line, path)
local cmd = vim.system({ "git", "blame", "-L", line .. "," .. line, "-p", "--", path }, { text = true }):wait()
local lines = {}
for s in cmd.stdout:gmatch("[^\r\n]+") do
table.insert(lines, s)
end
local commit_hash = lines[1]:gmatch("[^%s]+")() -- why I need to call this here but not above. i don't understand
return commit_hash
end
---@param hash string
---@param dir string
---@return string
local function get_commit_info(hash, dir)
local cmd = vim.system({ "git", "-C", dir, "show", hash }, { text = true }):wait()
return cmd.stdout
end
function M.open_blame_window()
local cursor = vim.api.nvim_win_get_cursor(0)
local line = cursor[1]
local buf_name = vim.fn.expand("%:.")
local commit_hash = get_commit_hash_at_line(line, buf_name)
local commit_info = get_commit_info(commit_hash, vim.uv.cwd())
local bufnr, winnr = u.create_floating_window_in_center(0.75, 0.75)
u.set_buffer_text(bufnr, commit_info)
vim.bo[bufnr].filetype = "gitcommit"
vim.keymap.set("n", "<esc>", ":q<CR>", { buffer = bufnr })
vim.keymap.set("n", "q", ":q<CR>", { buffer = bufnr })
-- TODO: open not at the top of the buffer, but on line in OG file
end
return M

View File

@@ -0,0 +1,43 @@
local M = {}
---@return number width, number height
function M.get_terminal_size()
local width = vim.o.columns
local height = vim.o.lines
return width, height
end
---@param width number width in percentage of screen width (0.75, 0.5, etc)
---@param height number height in percentage of screen height (0.75, 0.5, etc)
---@return number buffer, number window
function M.create_floating_window_in_center(width, height)
local bufnr = vim.api.nvim_create_buf(false, true) -- not listed, scratch buffer
local max_width, max_height = M.get_terminal_size()
local win_width = math.floor(max_width * width)
local win_height = math.floor(max_height * height)
local winnr = vim.api.nvim_open_win(bufnr, true, {
relative = "editor",
width = win_width,
height = win_height,
row = (max_height - win_height) / 2,
col = (max_width - win_width) / 2,
focusable = true,
style = "minimal",
})
return bufnr, winnr
end
---@param bufnr number
---@param content string
function M.set_buffer_text(bufnr, content)
local lines = {}
for s in content:gmatch("[^\r\n]+") do
table.insert(lines, s)
end
vim.api.nvim_buf_set_lines(bufnr, 0, vim.tbl_count(lines), false, lines)
end
return M