feat(git): route commit through GIT_EDITOR proxy
This commit is contained in:
+57
-74
@@ -1,3 +1,5 @@
|
||||
local editor = require("git.editor")
|
||||
local git = require("git")
|
||||
local log = require("log")
|
||||
local repo = require("git.repo")
|
||||
|
||||
@@ -6,89 +8,70 @@ local M = {}
|
||||
---@param opts { amend: boolean? }?
|
||||
function M.commit(opts)
|
||||
local amend = opts and opts.amend or false
|
||||
local gitdir, worktree = repo.resolve_cwd()
|
||||
if not gitdir or not worktree then
|
||||
local _, worktree = repo.resolve_cwd()
|
||||
if not worktree then
|
||||
log.warning("not in a git repository")
|
||||
return
|
||||
end
|
||||
local msg_path = vim.fs.joinpath(gitdir, "COMMIT_EDITMSG")
|
||||
|
||||
local initial = ""
|
||||
local cmd = { "git", "commit" }
|
||||
if amend then
|
||||
local result = vim.system(
|
||||
{ "git", "log", "-1", "--pretty=%B" },
|
||||
{ cwd = worktree, text = true }
|
||||
):wait()
|
||||
if result.code == 0 then
|
||||
initial = (result.stdout or ""):gsub("\n+$", "")
|
||||
else
|
||||
log.warning("git log -1 failed: %s", vim.trim(result.stderr or ""))
|
||||
table.insert(cmd, "--amend")
|
||||
end
|
||||
|
||||
local proxy_buf
|
||||
editor.run(cmd, { cwd = worktree }, function(file_path, done)
|
||||
local lines = {}
|
||||
local f = io.open(file_path, "r")
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(lines, line)
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
local f, err = io.open(msg_path, "w")
|
||||
if not f then
|
||||
log.error("failed to open %s: %s", msg_path, err or "")
|
||||
return
|
||||
end
|
||||
f:write(initial)
|
||||
f:close()
|
||||
local buf = git.new_scratch({ name = file_path })
|
||||
proxy_buf = buf
|
||||
vim.bo[buf].buftype = "acwrite"
|
||||
vim.bo[buf].bufhidden = "wipe"
|
||||
vim.bo[buf].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
||||
vim.bo[buf].modified = false
|
||||
vim.bo[buf].filetype = "gitcommit"
|
||||
|
||||
local ok, err = pcall(vim.cmd.edit, vim.fn.fnameescape(msg_path))
|
||||
if not ok then
|
||||
log.error("failed to open %s: %s", msg_path, err or "")
|
||||
return
|
||||
end
|
||||
local buf = vim.api.nvim_get_current_buf()
|
||||
if vim.api.nvim_buf_get_name(buf) ~= msg_path then
|
||||
-- `:edit` returned without surfacing an error but didn't actually
|
||||
-- switch (defensive against an unusual ftplugin/autocmd path). Bail
|
||||
-- before attaching a BufWriteCmd that would overwrite the wrong
|
||||
-- file on the next `:w`.
|
||||
log.error("failed to switch to %s", msg_path)
|
||||
return
|
||||
end
|
||||
vim.bo[buf].filetype = "gitcommit"
|
||||
vim.api.nvim_create_autocmd("BufWriteCmd", {
|
||||
buffer = buf,
|
||||
callback = function()
|
||||
local out = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||
local fw, werr = io.open(file_path, "w")
|
||||
if not fw then
|
||||
log.error("failed to write %s: %s", file_path, werr or "")
|
||||
return
|
||||
end
|
||||
fw:write(table.concat(out, "\n"))
|
||||
fw:close()
|
||||
vim.bo[buf].modified = false
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("BufWriteCmd", {
|
||||
buffer = buf,
|
||||
callback = function()
|
||||
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||
local fw, werr = io.open(msg_path, "w")
|
||||
if not fw then
|
||||
log.error("failed to write %s: %s", msg_path, werr or "")
|
||||
return
|
||||
end
|
||||
fw:write(table.concat(lines, "\n"))
|
||||
fw:close()
|
||||
vim.bo[buf].modified = false
|
||||
|
||||
local cmd = { "git", "commit", "-F", msg_path }
|
||||
if amend then
|
||||
table.insert(cmd, "--amend")
|
||||
end
|
||||
vim.system(
|
||||
cmd,
|
||||
{ cwd = worktree, text = true },
|
||||
vim.schedule_wrap(function(result)
|
||||
if result.code ~= 0 then
|
||||
log.error(
|
||||
"git commit failed: %s",
|
||||
vim.trim(result.stderr or "")
|
||||
)
|
||||
return
|
||||
end
|
||||
local out = vim.trim(result.stdout or "")
|
||||
if out ~= "" then
|
||||
log.info("%s", out)
|
||||
end
|
||||
if vim.api.nvim_buf_is_valid(buf) then
|
||||
vim.api.nvim_buf_delete(buf, { force = true })
|
||||
end
|
||||
end)
|
||||
)
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("BufWipeout", {
|
||||
buffer = buf,
|
||||
once = true,
|
||||
callback = done,
|
||||
})
|
||||
end, function(result)
|
||||
if proxy_buf and vim.api.nvim_buf_is_valid(proxy_buf) then
|
||||
vim.api.nvim_buf_delete(proxy_buf, { force = true })
|
||||
end
|
||||
if result.code ~= 0 then
|
||||
log.error("git commit failed: %s", vim.trim(result.stderr or ""))
|
||||
return
|
||||
end
|
||||
local out = vim.trim(result.stdout or "")
|
||||
if out ~= "" then
|
||||
log.info("%s", out)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user