refactor(neovim): improve git-config.lua with helper functions and new feature
- Extract git_cmd and git_cmd_list for reusable git command execution - Add yank helper for consistent clipboard copying with notifications - Enhance get_git_info to include abs_path and file_dir - Add get_blame_info to retrieve detailed blame information with file hash - Implement copy_commit_url for copying direct commit URLs - Convert keymaps to use function references New: <Leader>gC copies GitHub commit URL with file hash fragment
This commit is contained in:
@@ -18,50 +18,107 @@ require("gitsigns").setup({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
local function git_cmd(dir, cmd)
|
||||||
|
return vim.fn.system("git -C " .. vim.fn.escape(dir, " ") .. " " .. cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function git_cmd_list(dir, cmd)
|
||||||
|
return vim.fn.systemlist("git -C " .. vim.fn.escape(dir, " ") .. " " .. cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function yank(message)
|
||||||
|
vim.fn.setreg("+", message)
|
||||||
|
vim.notify("Copied:\n\t" .. message, vim.log.levels.INFO)
|
||||||
|
end
|
||||||
|
|
||||||
local function get_git_info()
|
local function get_git_info()
|
||||||
local abs_path = vim.fn.expand("%:p")
|
local abs_path = vim.fn.expand("%:p")
|
||||||
local git_root = vim.fn.systemlist(
|
local file_dir = vim.fn.fnamemodify(abs_path, ":h")
|
||||||
"git -C " .. vim.fn.escape(vim.fn.fnamemodify(abs_path, ":h"), " ") .. " rev-parse --show-toplevel"
|
local git_root = git_cmd_list(file_dir, "rev-parse --show-toplevel")[1]
|
||||||
)[1]
|
|
||||||
|
|
||||||
if vim.v.shell_error ~= 0 then
|
if vim.v.shell_error ~= 0 then
|
||||||
|
vim.notify("Failed to get git info", vim.log.levels.ERROR)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local git_repo = vim.fn.system("git remote get-url origin"):match("([^/:]+/[^/.]+)%.?[^/]*$"):gsub("\n", "")
|
local git_repo = git_cmd(file_dir, "remote get-url origin"):match("([^/:]+/[^/.]+)%.?[^/]*$"):gsub("\n", "")
|
||||||
local git_branch = vim.fn.system("git rev-parse --abbrev-ref HEAD"):gsub("\n", "")
|
local git_branch = git_cmd(file_dir, "rev-parse --abbrev-ref HEAD"):gsub("\n", "")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
abs_path = abs_path,
|
||||||
|
file_dir = file_dir,
|
||||||
file = vim.fn.fnamemodify(abs_path, ":s?" .. git_root .. "/??"),
|
file = vim.fn.fnamemodify(abs_path, ":s?" .. git_root .. "/??"),
|
||||||
branch = git_branch,
|
branch = git_branch,
|
||||||
repo = git_repo,
|
repo = git_repo,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function copy_git_link()
|
local function get_blame_info(file_dir, abs_path, line_num)
|
||||||
local git_info = get_git_info()
|
local blame_output = git_cmd_list(
|
||||||
if git_info == nil then
|
file_dir,
|
||||||
vim.notify("Failed to get git info", vim.log.levels.ERROR)
|
"blame -L " .. line_num .. "," .. line_num .. " --porcelain " .. vim.fn.escape(abs_path, " ")
|
||||||
|
)
|
||||||
|
|
||||||
|
if vim.v.shell_error ~= 0 then
|
||||||
|
vim.notify("Failed to get git blame", vim.log.levels.ERROR)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local commit_hash = blame_output[1]:match("^(%S+)")
|
||||||
|
local original_line = blame_output[1]:match("^%S+ (%d+)")
|
||||||
|
local commit_file = nil
|
||||||
|
|
||||||
|
for _, line in ipairs(blame_output) do
|
||||||
|
local f = line:match("^filename (.+)$")
|
||||||
|
if f then
|
||||||
|
commit_file = f
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not commit_hash or not commit_file then
|
||||||
|
vim.notify("Failed to extract commit info", vim.log.levels.ERROR)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
hash = commit_hash,
|
||||||
|
line = tonumber(original_line),
|
||||||
|
file = commit_file,
|
||||||
|
file_hash = vim.fn.system("echo -n " .. vim.fn.shellescape(commit_file) .. " | sha256sum | cut -d' ' -f1"):gsub("\n",
|
||||||
|
""),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function copy_git_link()
|
||||||
|
local git_info = get_git_info()
|
||||||
|
if not git_info then return end
|
||||||
|
|
||||||
local start_line = vim.fn.line("v")
|
local start_line = vim.fn.line("v")
|
||||||
local end_line = vim.fn.line(".")
|
local end_line = vim.fn.line(".")
|
||||||
|
|
||||||
local message = string.format(
|
yank(string.format(
|
||||||
"https://github.com/%s/blob/%s/%s#L%d-L%d",
|
"https://github.com/%s/blob/%s/%s#L%d-L%d",
|
||||||
git_info.repo,
|
git_info.repo, git_info.branch, git_info.file, start_line, end_line
|
||||||
git_info.branch,
|
))
|
||||||
git_info.file,
|
|
||||||
start_line,
|
|
||||||
end_line
|
|
||||||
)
|
|
||||||
vim.fn.setreg("+", message)
|
|
||||||
vim.notify("Copied:\n\t" .. message, vim.log.levels.INFO)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create KeyMaps
|
local function copy_commit_url()
|
||||||
vim.keymap.set("v", "<Leader>gy", function() copy_git_link() end, { desc = "Copy GitHub Link" })
|
local git_info = get_git_info()
|
||||||
|
if not git_info then return end
|
||||||
|
|
||||||
|
local blame = get_blame_info(git_info.file_dir, git_info.abs_path, vim.fn.line("."))
|
||||||
|
if not blame then return end
|
||||||
|
|
||||||
|
yank(string.format(
|
||||||
|
"https://github.com/%s/commit/%s#diff-%sR%d",
|
||||||
|
git_info.repo, blame.hash, blame.file_hash, blame.line
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Keymaps
|
||||||
|
vim.keymap.set("v", "<Leader>gy", copy_git_link, { desc = "Copy GitHub Link" })
|
||||||
|
vim.keymap.set("n", "<Leader>gC", copy_commit_url, { desc = "Copy Commit URL" })
|
||||||
vim.keymap.set('n', '<leader>go', '<cmd>DiffviewOpen<CR>', { desc = "Open Diff - Current" })
|
vim.keymap.set('n', '<leader>go', '<cmd>DiffviewOpen<CR>', { desc = "Open Diff - Current" })
|
||||||
vim.keymap.set('n', '<leader>gO', '<cmd>DiffviewOpen origin/main...HEAD<CR>', { desc = "Open Diff - Main" })
|
vim.keymap.set('n', '<leader>gO', '<cmd>DiffviewOpen origin/main...HEAD<CR>', { desc = "Open Diff - Main" })
|
||||||
vim.keymap.set('n', '<leader>gh', '<cmd>DiffviewFileHistory<CR>', { desc = "Diff History" })
|
vim.keymap.set('n', '<leader>gh', '<cmd>DiffviewFileHistory<CR>', { desc = "Diff History" })
|
||||||
|
|||||||
Reference in New Issue
Block a user