mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-27 12:40:06 +08:00
169 lines
3.6 KiB
Lua
169 lines
3.6 KiB
Lua
--=============================================================================
|
|
-- job.lua ---
|
|
-- Copyright (c) 2016-2022 Wang Shidong & Contributors
|
|
-- Author: Wang Shidong < wsdjeg@outlook.com >
|
|
-- URL: https://spacevim.org
|
|
-- License: GPLv3
|
|
--=============================================================================
|
|
|
|
local M = {}
|
|
|
|
local uv = vim.loop
|
|
|
|
local _jobs = {}
|
|
local _jobid = 0
|
|
|
|
local function new_job_obj(id, handle, opt, state)
|
|
local jobobj = {
|
|
id = id,
|
|
handle = handle,
|
|
opt = opt,
|
|
state = state,
|
|
}
|
|
return jobobj
|
|
end
|
|
|
|
function M.start(cmd, opts)
|
|
local stdin = uv.new_pipe()
|
|
local stdout = uv.new_pipe()
|
|
local stderr = uv.new_pipe()
|
|
local command = ''
|
|
local argv = {}
|
|
if type(cmd) == 'string' then
|
|
local shell = vim.fn.split(vim.o.shell)
|
|
local shellcmdflag = vim.fn.split(vim.o.shellcmdflag)
|
|
-- :call jobstart(split(&shell) + split(&shellcmdflag) + ['{cmd}'])
|
|
command = shell[1]
|
|
argv = vim.list_slice(shell, 2)
|
|
for _, v in ipairs(shellcmdflag) do
|
|
table.insert(argv, v)
|
|
end
|
|
table.insert(argv, cmd)
|
|
elseif type(cmd) == 'table' then
|
|
command = cmd[1]
|
|
argv = vim.list_slice(cmd, 2)
|
|
end
|
|
|
|
local opt = {
|
|
stdio = { stdin, stdout, stderr },
|
|
args = argv,
|
|
}
|
|
_jobid = _jobid + 1
|
|
local current_id = _jobid
|
|
local exit_cb
|
|
if opts.on_exit then
|
|
exit_cb = function(code, singin)
|
|
opts.on_exit(current_id, code, singin)
|
|
end
|
|
end
|
|
|
|
local handle, pid = uv.spawn(command, opt, exit_cb)
|
|
|
|
_jobs['jobid_' .. _jobid] = new_job_obj(_jobid, handle, opts, {
|
|
stdout = stdout,
|
|
stderr = stderr,
|
|
stdin = stdin,
|
|
pid = pid,
|
|
})
|
|
if opts.on_stdout then
|
|
uv.read_start(stdout, function(err, data)
|
|
if data then
|
|
data = data:gsub('\r', '')
|
|
opts.on_stdout(current_id, vim.split(data, '\n'), 'stdout')
|
|
end
|
|
end)
|
|
end
|
|
|
|
if opts.on_stderr then
|
|
uv.read_start(stderr, function(err, data)
|
|
if data then
|
|
data = data:gsub('\r', '')
|
|
opts.on_stderr(current_id, vim.split(data, '\n'), 'stderr')
|
|
end
|
|
end)
|
|
end
|
|
return current_id
|
|
end
|
|
|
|
function M.send(id, data) -- {{{
|
|
local jobobj = _jobs['jobid_' .. id]
|
|
|
|
if not jobobj then
|
|
error('can not find job:' .. id)
|
|
end
|
|
|
|
local stdin = jobobj.state.stdin
|
|
|
|
if not stdin then
|
|
error('no stdin stream for jobid:' .. id)
|
|
end
|
|
|
|
if type(data) == 'table' then
|
|
for _, v in ipairs(data) do
|
|
stdin:write(v)
|
|
stdin:write('\n')
|
|
end
|
|
elseif type(data) == 'string' then
|
|
stdin:write(data)
|
|
elseif data == nil then
|
|
stdin:write('', function()
|
|
stdin:shutdown(function()
|
|
if stdin then
|
|
stdin:close()
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
end
|
|
|
|
function M.chanclose(id, t)
|
|
local jobobj = _jobs['jobid_' .. id]
|
|
|
|
if not jobobj then
|
|
error('can not find job:' .. id)
|
|
end
|
|
if t == 'stdin' then
|
|
local stdin = jobobj.state.stdin
|
|
if not stdin then
|
|
stdin:shutdown(function()
|
|
if stdin then
|
|
stdin:close()
|
|
end
|
|
end)
|
|
end
|
|
elseif t == 'stdout' then
|
|
elseif t == 'stderr' then
|
|
else
|
|
error('the type only can be:stdout, stdin or stderr')
|
|
end
|
|
end
|
|
|
|
function M.stop(id)
|
|
local jobobj = _jobs['jobid_' .. id]
|
|
|
|
if not jobobj then
|
|
error('can not find job:' .. id)
|
|
end
|
|
|
|
-- close stdio
|
|
local stdin = jobobj.state.stdin
|
|
if stdin and stdin:is_active() then
|
|
stdin:close()
|
|
end
|
|
-- close stdio
|
|
local stdout = jobobj.state.stout
|
|
if stdout and stdout:is_active() then
|
|
stdout:close()
|
|
end
|
|
-- close stdio
|
|
local stderr = jobobj.state.stderr
|
|
if stderr and stderr:is_active() then
|
|
stderr:close()
|
|
end
|
|
|
|
local handle = jobobj.handle
|
|
handle:kill(6)
|
|
end
|
|
|
|
return M
|