From a9bb11c145928d5ce9d0301842b889d18509afd4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 20 Nov 2020 17:57:54 -0500 Subject: [PATCH 1/6] Optimize Lua's internal.runCommand() when printing directly to the console This also makes commands run with `run_command()` detect the console properly (notably used by `df2console()`) --- library/LuaApi.cpp | 46 +++++++++++++++++++++++++++++------------- library/lua/dfhack.lua | 16 ++++----------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 431ab3ae5..ed214397d 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2822,13 +2822,25 @@ static int internal_diffscan(lua_State *L) static int internal_runCommand(lua_State *L) { - buffered_color_ostream out; + color_ostream *out = NULL; + std::unique_ptr out_buffer; command_result res; if (lua_gettop(L) == 0) { lua_pushstring(L, ""); } int type_1 = lua_type(L, 1); + bool use_console = lua_toboolean(L, 2); + if (use_console) + { + out = &Core::getInstance().getConsole(); + } + else + { + out_buffer.reset(new buffered_color_ostream()); + out = out_buffer.get(); + } + if (type_1 == LUA_TTABLE) { std::string command = ""; @@ -2843,13 +2855,13 @@ static int internal_runCommand(lua_State *L) lua_pop(L, 1); // remove value, leave key } CoreSuspender suspend; - res = Core::getInstance().runCommand(out, command, args); + res = Core::getInstance().runCommand(*out, command, args); } else if (type_1 == LUA_TSTRING) { std::string command = lua_tostring(L, 1); CoreSuspender suspend; - res = Core::getInstance().runCommand(out, command); + res = Core::getInstance().runCommand(*out, command); } else { @@ -2857,22 +2869,28 @@ static int internal_runCommand(lua_State *L) lua_pushfstring(L, "Expected table, got %s", lua_typename(L, type_1)); return 2; } - auto fragments = out.fragments(); + lua_newtable(L); lua_pushinteger(L, (int)res); lua_setfield(L, -2, "status"); - int i = 1; - for (auto iter = fragments.begin(); iter != fragments.end(); iter++, i++) + + if (out_buffer) { - int color = iter->first; - std::string output = iter->second; - lua_createtable(L, 2, 0); - lua_pushinteger(L, color); - lua_rawseti(L, -2, 1); - lua_pushstring(L, output.c_str()); - lua_rawseti(L, -2, 2); - lua_rawseti(L, -2, i); + auto fragments = out_buffer->fragments(); + int i = 1; + for (auto iter = fragments.begin(); iter != fragments.end(); iter++, i++) + { + int color = iter->first; + std::string output = iter->second; + lua_createtable(L, 2, 0); + lua_pushinteger(L, color); + lua_rawseti(L, -2, 1); + lua_pushstring(L, output.c_str()); + lua_rawseti(L, -2, 2); + lua_rawseti(L, -2, i); + } } + lua_pushvalue(L, -1); return 1; } diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 73fd651e2..26a23db55 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -735,8 +735,7 @@ function dfhack.script_help(script_name, extension) return help end -local function _run_command(...) - args = {...} +local function _run_command(args, use_console) if type(args[1]) == 'table' then command = args[1] elseif #args > 1 and type(args[2]) == 'table' then @@ -750,11 +749,11 @@ local function _run_command(...) else error('Invalid arguments') end - return internal.runCommand(command) + return internal.runCommand(command, use_console) end function dfhack.run_command_silent(...) - local result = _run_command(...) + local result = _run_command({...}) local output = "" for i, f in pairs(result) do if type(f) == 'table' then @@ -765,14 +764,7 @@ function dfhack.run_command_silent(...) end function dfhack.run_command(...) - local result = _run_command(...) - for i, f in pairs(result) do - if type(f) == 'table' then - dfhack.color(f[1]) - dfhack.print(f[2]) - end - end - dfhack.color(COLOR_RESET) + local result = _run_command({...}, true) return result.status end From b4c040291f117d6f6fabd3cd84260b42bbc88b7d Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 20 Nov 2020 22:23:29 -0500 Subject: [PATCH 2/6] Document dfhack.run_command() and related functions/constants --- docs/Lua API.rst | 51 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index ffce7fd4e..02b8a324f 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -833,6 +833,9 @@ can be omitted. * ``dfhack.getCompiledDFVersion()`` * ``dfhack.getGitDescription()`` * ``dfhack.getGitCommit()`` +* ``dfhack.getGitXmlCommit()`` +* ``dfhack.getGitXmlExpectedCommit()`` +* ``dfhack.gitXmlMatch()`` * ``dfhack.isRelease()`` Return information about the DFHack build in use. @@ -899,6 +902,28 @@ can be omitted. Note that the returned string may be longer than the input string. For example, ``ä`` is replaced with ``a``, and ``æ`` is replaced with ``ae``. +* ``dfhack.run_command(command[, ...])`` + + Run an arbitrary DFHack command, with the core suspended, and send output to + the DFHack console. The command can be passed as a table, multiple string + arguments, or a single string argument (not recommended - in this case, the + usual DFHack console tokenization is used). + + A ``command_result`` constant starting with ``CR_`` is returned, where ``CR_OK`` + indicates success. + + The following examples are equivalent:: + + dfhack.run_command({'ls', '-a'}) + dfhack.run_command('ls', '-a') + dfhack.run_command('ls -a') -- not recommended + +* ``dfhack.run_command_silent(command[, ...])`` + + Similar to ``run_command()``, but instead of printing to the console, + returns an ``output, command_result`` pair. ``output`` is a single string - + see ``dfhack.internal.runCommand()`` to obtain colors as well. + Gui module ---------- @@ -2229,11 +2254,6 @@ Internal API These functions are intended for the use by dfhack developers, and are only documented here for completeness: -* ``dfhack.internal.scripts`` - - The table used by ``dfhack.run_script()`` to give every script its own - global environment, persistent between calls to the script. - * ``dfhack.internal.getPE()`` Returns the PE timestamp of the DF executable (only on Windows) @@ -2348,6 +2368,21 @@ and are only documented here for completeness: This requires an extension to be specified (``.lua`` or ``.rb``) - use ``dfhack.findScript()`` to include the ``.lua`` extension automatically. +* ``dfhack.internal.runCommand(command[, use_console])`` + + Runs a DFHack command with the core suspended. Used internally by the + ``dfhack.run_command()`` family of functions. + + - ``command``: either a table of strings or a single string which is parsed by + the default console tokenization strategy (not recommended) + - ``use_console``: if true, output is sent directly to the DFHack console + + Returns a table with a ``status`` key set to a ``command_result`` constant + (``status = CR_OK`` indicates success). Additionally, if ``use_console`` is + not true, enumerated table entries of the form ``{color, text}`` are included, + e.g. ``result[1][0]`` is the color of the first piece of text printed (a + ``COLOR_`` constant). These entries can be iterated over with ``ipairs()``. + * ``dfhack.internal.md5(string)`` Returns the MD5 hash of the given string. @@ -2507,6 +2542,12 @@ environment by the mandatory init file dfhack.lua: SC_WORLD_LOADED, SC_WORLD_UNLOADED, SC_MAP_LOADED, SC_MAP_UNLOADED, SC_VIEWSCREEN_CHANGED, SC_CORE_INITIALIZED +* Command result constants (equivalent to ``command_result`` in C++), used by + ``dfhack.run_command()`` and related functions: + + CR_OK, CR_LINK_FAILURE, CR_NEEDS_CONSOLE, CR_NOT_IMPLEMENTED, CR_FAILURE, + CR_WRONG_USAGE, CR_NOT_FOUND + * Functions already described above safecall, qerror, mkmodule, reload From 867d7ebfc953254e227aa4083ab0cff77e49786a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 21 Nov 2020 10:10:32 -0500 Subject: [PATCH 3/6] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 4ac39084f..381c9f871 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4ac39084f7e6fde5ec08c5c5691422859a212460 +Subproject commit 381c9f87160e4d836faab8678ebdfbb219d23ebe From 6ceaf77b38863b1d5cb42ba6cc0824f1e98e4708 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 21 Nov 2020 10:10:47 -0500 Subject: [PATCH 4/6] Update authors (dfhack/scripts#217) --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index e3478e486..83ce58ef0 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -159,6 +159,7 @@ stolencatkarma Stoyan Gaydarov sgayda2 suokko suokko shrieker sv-esk sv-esk +Tachytaenius wolfboyft Tacomagic thefriendlyhacker thefriendlyhacker TheHologram TheHologram From fe0cd9a939385fa987e6ffc7960fe3a21a696491 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 3 Dec 2020 22:04:00 -0500 Subject: [PATCH 5/6] Make lineedit() fail sooner when another lineedit() call is active Before, calling `dfhack.run_command('tiletypes')` from a `dfhack.timeout` callback would leave the console in a broken state, since raw mode was enabled but never disabled. Only tested on Linux with a supported terminal. --- library/Console-posix.cpp | 6 ++++-- library/Console-windows.cpp | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/library/Console-posix.cpp b/library/Console-posix.cpp index 595f50e97..3c8645ebf 100644 --- a/library/Console-posix.cpp +++ b/library/Console-posix.cpp @@ -405,6 +405,8 @@ namespace DFHack /// A simple line edit (raw mode) int lineedit(const std::string& prompt, std::string& output, recursive_mutex * lock, CommandHistory & ch) { + if(state == con_lineedit) + return Console::FAILURE; output.clear(); reset_color(); this->prompt = prompt; @@ -414,7 +416,9 @@ namespace DFHack fflush(dfout_C); // FIXME: what do we do here??? //SDL_recursive_mutexV(lock); + state = con_lineedit; std::getline(std::cin, output); + state = con_unclaimed; //SDL_recursive_mutexP(lock); return output.size(); } @@ -422,8 +426,6 @@ namespace DFHack { int count; if (enable_raw() == -1) return 0; - if(state == con_lineedit) - return Console::FAILURE; state = con_lineedit; count = prompt_loop(lock,ch); state = con_unclaimed; diff --git a/library/Console-windows.cpp b/library/Console-windows.cpp index d339e53a0..515d89911 100644 --- a/library/Console-windows.cpp +++ b/library/Console-windows.cpp @@ -376,6 +376,8 @@ namespace DFHack } int lineedit(const std::string & prompt, std::string & output, recursive_mutex * lock, CommandHistory & ch) { + if(state == con_lineedit) + return Console::FAILURE; output.clear(); reset_color(); int count; From 69ce5d9e3faed4b147ae46a3e6910f2d208dff33 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 8 Jan 2021 21:06:42 -0500 Subject: [PATCH 6/6] Send runCommand output to correct output stream e.g. when run with dfhack-run --- library/LuaApi.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index ed214397d..d7f3b269f 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2833,7 +2833,11 @@ static int internal_runCommand(lua_State *L) bool use_console = lua_toboolean(L, 2); if (use_console) { - out = &Core::getInstance().getConsole(); + out = Lua::GetOutput(L); + if (!out) + { + out = &Core::getInstance().getConsole(); + } } else {