aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormitchell <70453897+667e-11@users.noreply.github.com>2014-07-12 15:01:30 -0400
committermitchell <70453897+667e-11@users.noreply.github.com>2014-07-12 15:01:30 -0400
commitd0796f1bdab199c4d1bdb9b2b133684192c7eff7 (patch)
treeac2393cc52934663b33db9c250dd3507b84a59c9
parent23617735d0b920bb5e995674a9143672932500d8 (diff)
downloadtextadept-d0796f1bdab199c4d1bdb9b2b133684192c7eff7.tar.gz
textadept-d0796f1bdab199c4d1bdb9b2b133684192c7eff7.zip
Implement spawn functionality for terminal version.
Requires lspawn r21. Thanks to Chris Emerson for proof-of-concept code. Spawning still does not work for Win32 terminal version, though.
-rw-r--r--core/init.lua49
-rw-r--r--src/Makefile46
-rw-r--r--src/textadept.c33
3 files changed, 78 insertions, 50 deletions
diff --git a/core/init.lua b/core/init.lua
index bdc9c21d..f20a6d08 100644
--- a/core/init.lua
+++ b/core/init.lua
@@ -16,27 +16,24 @@ keys = require('keys')
_M = {} -- language modules table
-- LuaJIT compatibility.
if jit then module, package.searchers, bit32 = nil, package.loaders, bit end
--- curses and OSX compatibility.
-if CURSES or OSX then
- local spawn_ = spawn
+-- OSX and pdcurses compatibility.
+if OSX or (CURSES and WIN32) then
+-- local spawn_ = spawn
function spawn(argv, working_dir, stdout_cb, stderr_cb, exit_cb)
--- if OSX then
--- -- Workaround for GLib abort caused by failed assertion.
--- local p, err = spawn_(argv, working_dir, stdout_cb, stderr_cb)
--- if not p then return p, err end
--- timeout(1, function()
--- if p:status() == 'running' then return true end
--- exit_cb('Process completed')
--- end)
--- else
- local current_dir = lfs.currentdir()
- lfs.chdir(working_dir)
- local p = io.popen(argv..' 2>&1')
- stdout_cb(p:read('*a'))
- exit_cb(select(3, p:close()))
- lfs.chdir(current_dir)
- return p
--- end
+-- -- Workaround for GLib abort caused by failed assertion.
+-- local p, err = spawn_(argv, working_dir, stdout_cb, stderr_cb)
+-- if not p then return p, err end
+-- timeout(1, function()
+-- if p:status() == 'running' then return true end
+-- exit_cb('Process completed')
+-- end)
+ local current_dir = lfs.currentdir()
+ lfs.chdir(working_dir)
+ local p = io.popen(argv..' 2>&1')
+ stdout_cb(p:read('*a'))
+ exit_cb(select(3, p:close()))
+ lfs.chdir(current_dir)
+ return p
end
end
@@ -151,7 +148,8 @@ local timeout
---
-- Spawns an interactive child process *argv* in a separate thread, returning
-- a handle to that process.
--- The terminal version spawns processes in the same thread.
+-- At the moment, the Mac OSX GUI version and Win32 terminal version spawn
+-- processes in the same thread.
-- @param argv A command line string containing the program's name followed by
-- arguments to pass to it. `PATH` is searched for program names.
-- @param working_dir Optional current working directory (cwd) for the child
@@ -160,8 +158,9 @@ local timeout
-- block of standard output read from the child. Stdout is read asynchronously
-- in 1KB or 0.5KB blocks (depending on the platform), or however much data is
-- available at the time.
--- The terminal version sends all output, whether it be stdout or stderr, to
--- this callback after the process finishes.
+-- At the moment, the Mac OSX GUI version and Win32 terminal version send all
+-- output, whether it be stdout or stderr, to this callback after the process
+-- finishes.
-- @param stderr_cb Optional Lua function that accepts a string parameter for a
-- block of standard error read from the child. Stderr is read asynchronously
-- in 1KB or 0.5kB blocks (depending on the platform), or however much data is
@@ -170,8 +169,8 @@ local timeout
-- finishes. The child's exit status is passed.
-- @return proc
-- @usage spawn('lua buffer.filename', nil, print)
--- @usage proc = spawn('lua -e "print(io.read())", nil, print)
--- proc:write('foo\\n')
+-- @usage proc = spawn('lua -e "print(io.read())"', nil, print)
+-- proc:write('foo\n')
-- @class function
-- @name spawn
local spawn
diff --git a/src/Makefile b/src/Makefile
index cf81d43a..8cf60e4b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -133,11 +133,6 @@ lua_lib_objs = lpeg.o lfs.o
luajit_lib_objs = lpegjit.o lfsjit.o
#luajit_lib_objs = lpcapjit.o lpcodejit.o lpprintjit.o lptreejit.o lpvmjit.o \
# lfsjit.o
-ifneq (curses, $(findstring curses, $(MAKECMDGOALS)))
- # Compile in lspawn module.
- lua_lib_objs += lspawn.o
- luajit_lib_objs += lspawnjit.o
-endif
termkey_objs = termkey.o driver-ti.o driver-csi.o
windowman_objs = windowman.o
cdk_objs = binding.o buttonbox.o button.o cdk.o cdk_display.o cdk_objs.o \
@@ -181,13 +176,13 @@ textadept.o: textadept.c
$(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(ta_flags) -Ilua/src $(GTK_CFLAGS) \
$< -o $@
textadeptjit.o: textadept.c
- $(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(ta_flags) -DLUAJIT -Iluajit/src \
+ $(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(ta_flags) -Iluajit/src \
$(GTK_CFLAGS) $< -o $@
textadept-curses.o: textadept.c
$(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(ta_flags) -Ilua/src \
-Iscintilla/term -Itermkey -Iwindowman -Icdk $(CURSES_CFLAGS) $< -o $@
textadeptjit-curses.o: textadept.c
- $(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(ta_flags) -DLUAJIT -Iluajit/src \
+ $(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(ta_flags) -Iluajit/src \
-Iscintilla/term -Itermkey -Iwindowman -Icdk $(CURSES_CFLAGS) $< -o $@
$(lua_objs): %.o: lua/src/%.c
$(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) -Ilua/src $< -o $@
@@ -197,6 +192,18 @@ $(lua_lib_objs): %.o: lua/src/lib/%.c
$(luajit_lib_objs): %jit.o: lua/src/lib/%.c
$(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(lua_api) -Iluajit/src \
$(GLIB_CFLAGS) $< -o $@
+spawn.o: lua/src/lib/lspawn.c
+ $(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(plat_flag) $(lua_api) -Ilua/src \
+ $(GLIB_CFLAGS) $< -o $@
+spawnjit.o: lua/src/lib/lspawn.c
+ $(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(plat_flag) $(lua_api) \
+ -Iluajit/src $(GLIB_CFLAGS) $< -o $@
+spawn-curses.o: lua/src/lib/lspawn.c
+ $(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(plat_flag) $(lua_api) -Ilua/src \
+ $< -o $@
+spawnjit-curses.o: lua/src/lib/lspawn.c
+ $(CROSS)$(CC) -c $(CFLAGS) $(LUA_CFLAGS) $(plat_flag) $(lua_api) \
+ -Iluajit/src $< -o $@
luajit/src/libluajit.a: ; $(MAKE) -C luajit CC="$(CC) $(CFLAGS)"
luajit/src/lua51.dll:
$(MAKE) -C luajit HOST_CC="$(CC) -m32" CROSS=$(CROSS) TARGET_SYS=Windows
@@ -219,39 +226,42 @@ textadept_rc.o: textadept.rc ; $(CROSS)$(WINDRES) $< $@
# Executables.
textadept: $(sci_objs) $(sci_lex_objs) $(sci_gtk_objs) scintilla-marshal.o \
- LexLPeg.o textadept.o $(lua_objs) $(lua_lib_objs) gtdialog.o
+ LexLPeg.o textadept.o $(lua_objs) $(lua_lib_objs) spawn.o gtdialog.o
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(GTK_LIBS) $(LDFLAGS)
textadeptjit: $(sci_objs) $(sci_lex_objs) $(sci_gtk_objs) scintilla-marshal.o \
LexLPegjit.o textadeptjit.o $(luajit_lib_objs) $(libluajit) \
- gtdialog.o
+ spawnjit.o gtdialog.o
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(GTK_LIBS) $(LDFLAGS)
textadept-curses: $(sci_objs) $(sci_lex_objs) ScintillaTerm.o LexLPeg-curses.o \
textadept-curses.o $(lua_objs) $(lua_lib_objs) \
- gtdialog-curses.o $(termkey_objs) $(windowman_objs) \
- $(cdk_objs)
+ spawn-curses.o gtdialog-curses.o $(termkey_objs) \
+ $(windowman_objs) $(cdk_objs)
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(CURSES_LIBS) $(LDFLAGS)
textadeptjit-curses: $(sci_objs) $(sci_lex_objs) ScintillaTerm.o \
LexLPegjit-curses.o textadeptjit-curses.o \
- $(luajit_lib_objs) $(libluajit) gtdialog-curses.o \
- $(termkey_objs) $(windowman_objs) $(cdk_objs)
+ $(luajit_lib_objs) $(libluajit) spawnjit-curses.o \
+ gtdialog-curses.o $(termkey_objs) $(windowman_objs) \
+ $(cdk_objs)
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(CURSES_LIBS) $(LDFLAGS)
textadept.exe: $(sci_objs) $(sci_lex_objs) $(sci_gtk_objs) scintilla-marshal.o \
LexLPeg.o textadept.o textadept_rc.o $(lua_objs) \
- $(lua_lib_objs) gtdialog.o
+ $(lua_lib_objs) spawn.o gtdialog.o
$(CROSS)$(CXX) $(CXXFLAGS) -o $@ $^ $(GTK_LIBS) $(LDFLAGS)
textadeptjit.exe: $(sci_objs) $(sci_lex_objs) $(sci_gtk_objs) \
scintilla-marshal.o LexLPegjit.o textadeptjit.o \
- textadept_rc.o $(luajit_lib_objs) $(libluajit) gtdialog.o
+ textadept_rc.o $(luajit_lib_objs) $(libluajit) spawnjit.o \
+ gtdialog.o
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(GTK_LIBS) $(LDFLAGS)
textadept-curses.exe: $(sci_objs) $(sci_lex_objs) ScintillaTerm.o \
LexLPeg-curses.o textadept-curses.o textadept_rc.o \
- $(lua_objs) $(lua_lib_objs) gtdialog-curses.o \
- $(windowman_objs) $(cdk_objs)
+ $(lua_objs) $(lua_lib_objs) spawn-curses.o \
+ gtdialog-curses.o $(windowman_objs) $(cdk_objs)
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(CURSES_LIBS) $(LDFLAGS)
textadeptjit-curses.exe: $(sci_objs) $(sci_lex_objs) ScintillaTerm.o \
LexLPegjit-curses.o textadeptjit-curses.o \
textadept_rc.o $(luajit_lib_objs) $(libluajit) \
- gtdialog-curses.o $(windowman_objs) $(cdk_objs)
+ spawnjit-curses.o gtdialog-curses.o $(windowman_objs) \
+ $(cdk_objs)
$(CROSS)$(CXX) $(CXXFLAGS) -o ../$@ $^ $(CURSES_LIBS) $(LDFLAGS)
# Install/uninstall.
diff --git a/src/textadept.c b/src/textadept.c
index ebc48bc2..1cc906b8 100644
--- a/src/textadept.c
+++ b/src/textadept.c
@@ -30,6 +30,7 @@
#if !_WIN32
#include <signal.h>
#include <sys/ioctl.h>
+#include <sys/select.h>
#include <termios.h>
#else
#undef main
@@ -89,7 +90,7 @@ typedef GtkWidget Scintilla;
lua_setmetatable(l, (n > 0) ? n : n - 1); \
}
// Translate Lua 5.2 API to LuaJIT API (Lua 5.1) for compatibility.
-#if LUAJIT
+#if LUA_VERSION_NUM == 501
#define LUA_OK 0
#define lua_rawlen lua_objlen
#define LUA_OPEQ 0
@@ -210,9 +211,8 @@ static void new_buffer(sptr_t);
static Scintilla *new_view(sptr_t);
static int lL_init(lua_State *, int, char **, int);
LUALIB_API int luaopen_lpeg(lua_State *), luaopen_lfs(lua_State *);
-#if !CURSES
LUALIB_API int luaopen_spawn(lua_State *);
-#endif
+LUALIB_API int lspawn_pushfds(lua_State *), lspawn_readfds(lua_State *);
/**
* Emits an event.
@@ -1593,7 +1593,7 @@ static int lL_init(lua_State *L, int argc, char **argv, int reinit) {
lua_getglobal(L, "package"), lua_getfield(L, -1, "loaded");
lL_cleartable(L, -1);
lua_pop(L, 2); // package.loaded and package
-#if !LUAJIT
+#if LUA_VERSION_NUM >= 502
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
lL_cleartable(L, -1);
lua_pop(L, 1); // _G
@@ -1605,9 +1605,7 @@ static int lL_init(lua_State *L, int argc, char **argv, int reinit) {
luaL_openlibs(L);
lL_openlib(L, "lpeg", luaopen_lpeg);
lL_openlib(L, "lfs", luaopen_lfs);
-#if !CURSES
lL_openlib(L, "spawn", luaopen_spawn);
-#endif
lua_newtable(L);
lua_newtable(L);
@@ -2363,6 +2361,27 @@ static void resize(int signal) {
lL_event(lua, "update_ui", -1);
refresh_all();
}
+
+/** Replacement for `termkey_waitkey()` that handles asynchronous I/O. */
+static TermKeyResult textadept_waitkey(TermKey *tk, TermKeyKey *key) {
+ int force = FALSE;
+ struct timeval timeout = {0, termkey_get_waittime(tk)};
+ while (1) {
+ TermKeyResult res = !force ? termkey_getkey(tk, key)
+ : termkey_getkey_force(tk, key);
+ if (res != TERMKEY_RES_AGAIN && res != TERMKEY_RES_NONE) return res;
+ if (res == TERMKEY_RES_AGAIN) force = TRUE;
+ // Wait for input.
+ int nfds = lspawn_pushfds(lua);
+ fd_set *fds = (fd_set *)lua_touserdata(lua, -1);
+ FD_SET(0, fds); // monitor stdin
+ if (select(nfds, fds, NULL, NULL, force ? &timeout : NULL) > 0) {
+ if (FD_ISSET(0, fds)) termkey_advisereadable(tk);
+ if (lspawn_readfds(lua) > 0) refresh_all();
+ }
+ lua_pop(lua, 1); // fd_set
+ }
+}
#endif
/**
@@ -2502,7 +2521,7 @@ int main(int argc, char **argv) {
TermKeyResult res;
TermKeyKey key;
int keysyms[] = {0,SCK_BACK,SCK_TAB,SCK_RETURN,SCK_ESCAPE,0,0,SCK_UP,SCK_DOWN,SCK_LEFT,SCK_RIGHT,0,0,SCK_INSERT,SCK_DELETE,0,SCK_PRIOR,SCK_NEXT,SCK_HOME,SCK_END};
- while ((res = termkey_waitkey(ta_tk, &key)) != TERMKEY_RES_EOF) {
+ while ((res = textadept_waitkey(ta_tk, &key)) != TERMKEY_RES_EOF) {
if (res == TERMKEY_RES_ERROR) continue;
if (key.type == TERMKEY_TYPE_UNICODE)
c = key.code.codepoint;