From 879129388ab22b64c5a5cf0df83799084cab96fc Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 5 Jul 2023 22:58:01 +0800 Subject: [PATCH] feat(api): add lua job api close https://github.com/neovim/neovim/issues/20856 --- bundle/gtags.vim/autoload/ctags.vim | 3 +- lua/spacevim/api/job.lua | 159 ++++++++++++++++++++++++++++ test/lua/test_job.lua | 23 ++++ 3 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 lua/spacevim/api/job.lua create mode 100644 test/lua/test_job.lua diff --git a/bundle/gtags.vim/autoload/ctags.vim b/bundle/gtags.vim/autoload/ctags.vim index 673784f8c..d955d6dee 100644 --- a/bundle/gtags.vim/autoload/ctags.vim +++ b/bundle/gtags.vim/autoload/ctags.vim @@ -103,8 +103,7 @@ endfunction function! s:on_update_exit(id, data, event) abort " @bug on exit function is not called when failed - " C:\Users\wsdjeg\.SpaceVim>C:\Users\wsdjeg\.SpaceVim\bundle\phpcomplete.vim\bin\ctags.exe -R -o C:/Users/wsdjeg/.cache/SpaceVim/tags/C__Users_wsd - " jeg__SpaceVim_/tags C:\Users\wsdjeg\.SpaceVim + " C:\Users\wsdjeg\.SpaceVim>C:\Users\wsdjeg\.SpaceVim\bundle\phpcomplete.vim\bin\ctags.exe -R -o C:/Users/wsdjeg/.cache/SpaceVim/tags/C__Users_wsdjeg__SpaceVim_/tags C:\Users\wsdjeg\.SpaceVim " " C:\Users\wsdjeg\.SpaceVim>echo %ERRORLEVEL% " -1073741819 diff --git a/lua/spacevim/api/job.lua b/lua/spacevim/api/job.lua new file mode 100644 index 000000000..9338d8baf --- /dev/null +++ b/lua/spacevim/api/job.lua @@ -0,0 +1,159 @@ +--============================================================================= +-- 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 + command = 'cmd.exe' + argv = { '/c', 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 + opts.on_stdout(current_id, data, 'stdout') + end + end) + end + + if opts.on_stderr then + uv.read_start(stderr, function(err, data) + if data then + opts.on_stderr(current_id, data, '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 diff --git a/test/lua/test_job.lua b/test/lua/test_job.lua new file mode 100644 index 000000000..fcc91603a --- /dev/null +++ b/test/lua/test_job.lua @@ -0,0 +1,23 @@ +local job = require('spacevim.api.job') + +local jobid = job.start({ 'rg', 'wsdjeg', '.' }, { + on_stdout = function(id, data, event) + vim.print(id) + vim.print(data) + vim.print(event) + end, + on_stderr = function(id, data, event) + vim.print(id) + vim.print(data) + vim.print(event) + end, + on_exit = function(id, code, signal) + vim.print(id) + vim.print('exit code', code) + vim.print('exit signal', signal) + end, +}) + + +-- job.send(jobid, 'hello world') +-- job.stop(jobid)