aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormitchell <70453897+667e-11@users.noreply.github.com>2020-07-15 00:38:05 -0400
committermitchell <70453897+667e-11@users.noreply.github.com>2020-07-15 00:38:05 -0400
commitb92eeb9d10b6f9cacb9a5e0a78e808d687b00a6f (patch)
treecc2d20118bb32bb940bffd5865a6d34115c4d672
parentec96c0bed0fdb3df98c88fc6d559fa4e483fb912 (diff)
downloadtextadept-b92eeb9d10b6f9cacb9a5e0a78e808d687b00a6f.tar.gz
textadept-b92eeb9d10b6f9cacb9a5e0a78e808d687b00a6f.zip
Call `os.spawn()` exit callback after `proc:wait()`.
Added tests for `os.spawn()`.
-rw-r--r--core/.os.luadoc3
-rw-r--r--src/lua.patch48
-rw-r--r--test/test.lua63
3 files changed, 80 insertions, 34 deletions
diff --git a/core/.os.luadoc b/core/.os.luadoc
index 1908c200..6c1b702b 100644
--- a/core/.os.luadoc
+++ b/core/.os.luadoc
@@ -31,7 +31,7 @@ module('os')
-- @param exit_cb Optional Lua function that is called when the child process
-- finishes. The child's exit status is passed.
-- @return proc or nil plus an error message on failure
--- @usage os.spawn('lua buffer.filename', print)
+-- @usage os.spawn('lua ' .. buffer.filename, print)
-- @usage proc = os.spawn('lua -e "print(io.read())"', print)
-- proc:write('foo\n')
-- @class function
@@ -84,4 +84,3 @@ function spawn_proc:close() end
-- @param signal Optional Unix signal to send to *spawn_proc*. The default value
-- is 9 (`SIGKILL`), which kills the process.
function spawn_proc:kill() end
-]]
diff --git a/src/lua.patch b/src/lua.patch
index c7b6fe91..4bf5fb3f 100644
--- a/src/lua.patch
+++ b/src/lua.patch
@@ -32,7 +32,7 @@ diff -r 8a23edc91533 src/luaconf.h
--- a/src/loslib.c 2017-04-19 13:29:57.000000000 -0400
-+++ b/src/loslib.c 2020-06-22 19:16:23.952024597 -0400
++++ b/src/loslib.c 2020-07-15 00:31:50.061476181 -0400
@@ -4,6 +4,15 @@
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,7 @@ diff -r 8a23edc91533 src/luaconf.h
{"time", os_time},
{"tmpname", os_tmpname},
{NULL, NULL}
-@@ -404,6 +419,643 @@
+@@ -404,6 +419,633 @@
LUAMOD_API int luaopen_os (lua_State *L) {
luaL_newlib(L, syslib);
@@ -139,12 +139,19 @@ diff -r 8a23edc91533 src/luaconf.h
+static int lp_status(lua_State *L) {
+ PStream *p = (PStream *)luaL_checkudata(L, 1, "ta_spawn");
+ lua_pushstring(L, p->pid ? "running" : "terminated");
- return 1;
- }
-
++ return 1;
++}
++
+/** Process exit cleanup function. */
+static void exited(PStream *p, int status) {
+ lua_State *L = p->L;
++ if (p->exit_cb != LUA_REFNIL) {
++ // Call exit callback function with exit status.
++ lua_rawgeti(L, LUA_REGISTRYINDEX, p->exit_cb);
++ lua_pushinteger(L, status);
++ if (lua_pcall(L, 1, 0, 0) != LUA_OK)
++ fprintf(stderr, "Lua: %s\n", lua_tostring(L, -1)), lua_pop(L, 1);
++ }
+#if _WIN32
+ close(p->pid);
+#elif (!GTK || __APPLE__)
@@ -296,9 +303,9 @@ diff -r 8a23edc91533 src/luaconf.h
+ lua_pushfstring(L, "process (pid=%d)", p->pid);
+ else
+ lua_pushstring(L, "process (terminated)");
-+ return 1;
-+}
-+
+ return 1;
+ }
+
+#if (GTK && !__APPLE__)
+/** __gc Lua metamethod. */
+static int lp_gc(lua_State *L) {
@@ -352,12 +359,7 @@ diff -r 8a23edc91533 src/luaconf.h
+
+/** Signal that the child process finished. */
+static void p_exit(GPid pid, int status, void *data) {
-+ PStream *p = (PStream *)data;
-+ lua_rawgeti(p->L, LUA_REGISTRYINDEX, p->exit_cb);
-+ lua_pushinteger(p->L, status);
-+ if (lua_pcall(p->L, 1, 0, 0) != LUA_OK)
-+ fprintf(stderr, "Lua: %s\n", lua_tostring(p->L, -1)), lua_pop(p->L, 1);
-+ exited(p, status);
++ exited((PStream *)data, status);
+}
+#elif !_WIN32
+/**
@@ -419,21 +421,9 @@ diff -r 8a23edc91533 src/luaconf.h
+ int status;
+ if (waitpid(p->pid, &status, WNOHANG) > 0) {
+ fd_read(p->fstdout, p), fd_read(p->fstderr, p); // read anything left
-+ if (p->exit_cb != LUA_REFNIL) {
-+ lua_rawgeti(L, LUA_REGISTRYINDEX, p->exit_cb);
-+ lua_pushinteger(L, status);
-+ if (lua_pcall(L, 1, 0, 0) != LUA_OK)
-+ fprintf(stderr, "Lua: %s\n", lua_tostring(L, -1)), lua_pop(L, 1);
-+ }
-+ close(p->fstdin), close(p->fstdout), close(p->fstderr);
-+ luaL_unref(L, LUA_REGISTRYINDEX, p->stdout_cb);
-+ luaL_unref(L, LUA_REGISTRYINDEX, p->stderr_cb);
-+ luaL_unref(L, LUA_REGISTRYINDEX, p->exit_cb);
-+ luaL_unref(L, LUA_REGISTRYINDEX, p->ref); // allow proc to be collected
-+ p->pid = 0;
-+ lua_pushnil(L), lua_replace(L, -2), lua_settable(L, -3); // t[proc] = nil
-+ lua_pushnil(L); // push nil for next call to lua_next()
-+ } else lua_pop(L, 1); // value
++ exited(p, status);
++ }
++ lua_pop(L, 1); // value
+ }
+ lua_pop(L, 1); // spawn_procs
+ return n;
diff --git a/test/test.lua b/test/test.lua
index e4e93604..5cf884cb 100644
--- a/test/test.lua
+++ b/test/test.lua
@@ -1041,6 +1041,59 @@ if CURSES then
-- TODO: clipboard, mouse events, etc.
end
+function test_spawn_cwd()
+ assert_equal(os.spawn('pwd'):read('a'), lfs.currentdir() .. '\n')
+ assert_equal(os.spawn('pwd', '/tmp'):read('a'), '/tmp\n')
+end
+
+function test_spawn_env()
+ assert(not os.spawn('env'):read('a'):find('^%s*$'), 'empty env')
+ assert(os.spawn('env', {'FOO=bar'}):read('a'):find('FOO=bar\n'), 'env not set')
+end
+
+function test_spawn_stdin()
+ local p = os.spawn('lua -e "print(io.read())"')
+ p:write('foo\n')
+ p:close()
+ assert_equal(p:read('l'), 'foo')
+ assert_equal(p:read('a'), '')
+end
+
+function test_spawn_callbacks()
+ local exit_status = -1
+ local p = os.spawn('echo foo', ui.print, nil, function(status) exit_status = status end)
+ os.execute('sleep 0.1')
+ ui.update()
+ assert_equal(buffer._type, _L['[Message Buffer]'])
+ assert(buffer:get_text():find('^foo'), 'no spawn stdout')
+ assert_equal(exit_status, 0)
+ buffer:close(true)
+ view:unsplit()
+ -- Verify stdout is not read as stderr.
+ p = os.spawn('echo foo', nil, ui.print)
+ os.execute('sleep 0.1')
+ ui.update()
+ assert_equal(#_BUFFERS, 1)
+end
+
+function test_spawn_wait()
+ local exit_status = -1
+ local p = os.spawn('sleep 0.1', nil, nil, function(status) exit_status = status end)
+ assert_equal(p:status(), "running")
+ assert_equal(p:wait(), 0)
+ assert_equal(exit_status, 0)
+ assert_equal(p:status(), "terminated")
+ -- Verify call to wait again returns previous exit status.
+ assert_equal(p:wait(), exit_status)
+end
+
+function test_spawn_kill()
+ local p = os.spawn('sleep 1')
+ p:kill()
+ assert(p:wait() ~= 0)
+ assert_equal(p:status(), "terminated")
+end
+
if WIN32 and CURSES then
function test_spawn()
-- TODO:
@@ -1754,6 +1807,8 @@ function test_editing_convert_indentation()
end
function test_ui_highlight_word()
+ local highlight = ui.highlight_words
+ ui.highlight_words = true
buffer.new()
buffer:append_text(table.concat({
'foo',
@@ -1796,6 +1851,7 @@ function test_ui_highlight_word()
pos = buffer:indicator_end(ui.INDIC_HIGHLIGHT, 2)
assert_equal(pos, 1) -- no highlights
buffer:close(true)
+ ui.highlight_words = highlight -- reset
end
function test_editing_filter_through()
@@ -3102,9 +3158,10 @@ function test_set_lexer_style()
assert(view.style_fore[style] ~= default_fore, 'function name style_fore same as default style_fore')
view.style_fore[style] = view.style_fore[view.STYLE_DEFAULT]
assert_equal(view.style_fore[style], default_fore)
- assert(lexer.colors.orange > 0 and lexer.colors.orange ~= default_fore)
- lexer.styles['function'] = {fore = lexer.colors.orange}
- assert_equal(view.style_fore[style], lexer.colors.orange)
+ local color = lexer.colors[not CURSES and 'orange' or 'blue']
+ assert(color > 0 and color ~= default_fore)
+ lexer.styles['function'] = {fore = color}
+ assert_equal(view.style_fore[style], color)
buffer:close(true)
-- Defined in Lua lexer, which is not currently loaded.
assert(buffer:style_of_name('library'), view.STYLE_DEFAULT)