[INIT]
This commit is contained in:
137
lua/repl_plugin/git.lua
Normal file
137
lua/repl_plugin/git.lua
Normal file
@@ -0,0 +1,137 @@
|
||||
local M = {}
|
||||
|
||||
local fn = vim.fn
|
||||
local api = vim.api
|
||||
|
||||
local function job_async(argv, opts)
|
||||
opts = opts or {}
|
||||
local on_stdout = opts.on_stdout
|
||||
local on_stderr = opts.on_stderr
|
||||
local on_exit = opts.on_exit
|
||||
|
||||
local id = fn.jobstart(argv, {
|
||||
stdout_buffered = true,
|
||||
stderr_buffered = true,
|
||||
on_stdout = vim.schedule_wrap(function(_, data, _)
|
||||
if on_stdout then on_stdout(data) end
|
||||
end),
|
||||
on_stderr = vim.schedule_wrap(function(_, data, _)
|
||||
if on_stderr then on_stderr(data) end
|
||||
end),
|
||||
on_exit = vim.schedule_wrap(function(_, code, _)
|
||||
if on_exit then on_exit(code) end
|
||||
end),
|
||||
})
|
||||
return id
|
||||
end
|
||||
|
||||
-- get current branch name of repo_path; cb(err, branch)
|
||||
function M.get_branch(repo_path, cb)
|
||||
cb = cb or function() end
|
||||
if not repo_path or repo_path == '' then
|
||||
return cb('no_repo')
|
||||
end
|
||||
job_async({'git','-C',repo_path,'rev-parse','--abbrev-ref','HEAD'}, {
|
||||
on_stdout = function(data)
|
||||
local out = table.concat(data, '\n'):gsub('\n+$','')
|
||||
cb(nil, out)
|
||||
end,
|
||||
on_stderr = function(data)
|
||||
-- ignore stderr unless needed
|
||||
end,
|
||||
on_exit = function(code)
|
||||
if code ~= 0 then cb('git_error') end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
-- status porcelain; cb(err, lines_table)
|
||||
function M.status_porcelain(repo_path, cb)
|
||||
cb = cb or function() end
|
||||
job_async({'git','-C',repo_path,'status','--porcelain'}, {
|
||||
on_stdout = function(data)
|
||||
-- data is table of lines
|
||||
cb(nil, data)
|
||||
end,
|
||||
on_exit = function(code)
|
||||
if code ~= 0 then cb('git_error') end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
-- commit_if_dirty: if dirty and auto_commit true, run add+commit
|
||||
-- opts = { auto_commit = true, message = 'msg' }
|
||||
-- cb(err, result)
|
||||
function M.commit_if_dirty(repo_path, opts, cb)
|
||||
cb = cb or function() end
|
||||
opts = opts or {}
|
||||
local auto_commit = opts.auto_commit
|
||||
local message = opts.message or ("Auto REPL state: " .. os.date("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
M.status_porcelain(repo_path, function(err, lines)
|
||||
if err then return cb('status_error') end
|
||||
-- lines may contain empty string elements
|
||||
local dirty = false
|
||||
for _, l in ipairs(lines) do
|
||||
if l and l:match('%S') then dirty = true; break end
|
||||
end
|
||||
if not dirty then
|
||||
return cb(nil, {committed = false, reason = 'no_changes'})
|
||||
end
|
||||
if not auto_commit then
|
||||
return cb(nil, {committed = false, reason = 'auto_commit_disabled'})
|
||||
end
|
||||
|
||||
-- run git add -A && git commit -m message
|
||||
-- We'll run as a shell command via sh -c to combine commands easily
|
||||
local cmd = {'sh','-c', "git -C " .. fn.shellescape(repo_path) .. " add -A && git -C " .. fn.shellescape(repo_path) .. " commit -m " .. fn.shellescape(message)}
|
||||
local stdout_acc = {}
|
||||
local stderr_acc = {}
|
||||
job_async(cmd, {
|
||||
on_stdout = function(data) for _, ln in ipairs(data) do table.insert(stdout_acc, ln) end end,
|
||||
on_stderr = function(data) for _, ln in ipairs(data) do table.insert(stderr_acc, ln) end end,
|
||||
on_exit = function(code)
|
||||
if code == 0 then
|
||||
cb(nil, {committed = true, success = true, stdout = stdout_acc, stderr = stderr_acc})
|
||||
else
|
||||
cb('commit_failed', {committed = true, success = false, stdout = stdout_acc, stderr = stderr_acc, code = code})
|
||||
end
|
||||
end,
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
function M.branch_exists(repo_path, branch, cb)
|
||||
cb = cb or function() end
|
||||
job_async({'git','-C',repo_path,'rev-parse','--verify','--quiet','refs/heads/' .. branch}, {
|
||||
on_exit = function(code)
|
||||
if code == 0 then cb(nil, true) else cb(nil, false) end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function M.checkout_branch(repo_path, branch, cb)
|
||||
cb = cb or function() end
|
||||
job_async({'git','-C',repo_path,'checkout',branch}, {
|
||||
on_stdout = function(_) end,
|
||||
on_stderr = function(_) end,
|
||||
on_exit = function(code)
|
||||
if code == 0 then cb(nil, true) else cb('checkout_failed', false) end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
-- create branch from 'from' (string), prefer using checkout then checkout -b
|
||||
function M.create_branch(repo_path, branch, from, cb)
|
||||
cb = cb or function() end
|
||||
from = from or 'HEAD'
|
||||
-- do two commands in shell: git -C repo checkout <from> && git -C repo checkout -b <branch>
|
||||
local cmd = {'sh','-c', "git -C " .. fn.shellescape(repo_path) .. " checkout " .. fn.shellescape(from) .. " && git -C " .. fn.shellescape(repo_path) .. " checkout -b " .. fn.shellescape(branch)}
|
||||
job_async(cmd, {
|
||||
on_exit = function(code)
|
||||
if code == 0 then cb(nil, true) else cb('create_failed', false) end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user