chore: initial commit
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
local util = require("git.core.util")
|
||||
|
||||
local M = {}
|
||||
|
||||
local SENTINEL = "__NVIM_GIT_EDIT__"
|
||||
|
||||
local SCRIPT = string.format(
|
||||
[=[set -eu
|
||||
flag="${TMPDIR:-/tmp}/nvim-git-editor-$$.done"
|
||||
trap 'rm -f "$flag"' EXIT
|
||||
abs=$(realpath "$1")
|
||||
printf '%s\t%%s\t%%s\n' "$flag" "$abs" >&2
|
||||
while [ ! -e "$flag" ]; do
|
||||
sleep 0.05
|
||||
done
|
||||
]=],
|
||||
SENTINEL
|
||||
)
|
||||
|
||||
---@param s string
|
||||
---@return string
|
||||
local function shq(s)
|
||||
return "'" .. s:gsub("'", "'\\''") .. "'"
|
||||
end
|
||||
|
||||
local GIT_EDITOR = "sh -c " .. shq(SCRIPT) .. " --"
|
||||
|
||||
---@param on_open fun(file_path: string, done: fun())
|
||||
---@return fun(err: string?, data: string?), fun(result: vim.SystemCompleted)
|
||||
local function build_stderr_handler(on_open)
|
||||
local pending = ""
|
||||
local stderr_buf = {}
|
||||
|
||||
local function dispatch(flag_path, abs_path)
|
||||
vim.schedule(function()
|
||||
local fired = false
|
||||
local function done()
|
||||
if fired then
|
||||
return
|
||||
end
|
||||
fired = true
|
||||
local fw = io.open(flag_path, "w")
|
||||
if fw then
|
||||
fw:close()
|
||||
end
|
||||
end
|
||||
local ok, err = pcall(on_open, abs_path, done)
|
||||
if not ok then
|
||||
util.error("git.editor on_open failed: %s", tostring(err))
|
||||
done()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local pattern = "^" .. SENTINEL .. "\t(.-)\t(.+)$"
|
||||
|
||||
local function on_stderr(_, data)
|
||||
if not data or data == "" then
|
||||
return
|
||||
end
|
||||
pending = pending .. data
|
||||
while true do
|
||||
local nl = pending:find("\n", 1, true)
|
||||
if not nl then
|
||||
break
|
||||
end
|
||||
local line = pending:sub(1, nl - 1)
|
||||
pending = pending:sub(nl + 1)
|
||||
local flag, abs = line:match(pattern)
|
||||
if flag then
|
||||
dispatch(flag, abs)
|
||||
else
|
||||
table.insert(stderr_buf, line)
|
||||
table.insert(stderr_buf, "\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function finalize(result)
|
||||
if pending ~= "" then
|
||||
table.insert(stderr_buf, pending)
|
||||
end
|
||||
result.stderr = table.concat(stderr_buf)
|
||||
end
|
||||
|
||||
return on_stderr, finalize
|
||||
end
|
||||
|
||||
---@param cmd string[]
|
||||
---@param opts? { cwd?: string, env?: table<string,string> }
|
||||
---@param on_open fun(file_path: string, done: fun())
|
||||
---@param on_exit fun(result: vim.SystemCompleted)
|
||||
function M.run(cmd, opts, on_open, on_exit)
|
||||
opts = opts or {}
|
||||
local on_stderr, finalize = build_stderr_handler(on_open)
|
||||
|
||||
local env = vim.tbl_extend("force", opts.env or {}, {
|
||||
GIT_EDITOR = GIT_EDITOR,
|
||||
GIT_SEQUENCE_EDITOR = GIT_EDITOR,
|
||||
})
|
||||
|
||||
vim.system(
|
||||
cmd,
|
||||
{
|
||||
cwd = opts.cwd,
|
||||
text = true,
|
||||
env = env,
|
||||
stderr = on_stderr,
|
||||
},
|
||||
vim.schedule_wrap(function(result)
|
||||
finalize(result)
|
||||
on_exit(result)
|
||||
end)
|
||||
)
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user