diff --git a/src/BizHawk.Client.Common/lua/ILuaLibraries.cs b/src/BizHawk.Client.Common/lua/ILuaLibraries.cs index c4e1ea1078..dd66772f02 100644 --- a/src/BizHawk.Client.Common/lua/ILuaLibraries.cs +++ b/src/BizHawk.Client.Common/lua/ILuaLibraries.cs @@ -51,7 +51,7 @@ namespace BizHawk.Client.Common void SpawnAndSetFileThread(string pathToLoad, LuaFile lf); - void ExecuteString(string command); + object[] ExecuteString(string command); (bool WaitForFrame, bool Terminated) ResumeScript(LuaFile lf); } diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 5ed96ca666..8cda0fbaa5 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -1388,18 +1388,14 @@ namespace BizHawk.Client.EmuHawk LuaSandbox.Sandbox(null, () => { - LuaImp.ExecuteString($"console.log({rawCommand})"); - }, () => - { - LuaSandbox.Sandbox(null, () => + var results = LuaImp.ExecuteString(rawCommand); + // empty array if the command was e.g. a variable assignment or a loop without return statement + // "void" functions return a single null + // if output didn't change, Print will take care of writing out "(no return)" + if (results is not [ ] and not [ null ] || OutputBox.Text == consoleBeforeCall) { - LuaImp.ExecuteString(rawCommand); - - if (OutputBox.Text == consoleBeforeCall) - { - WriteLine("Command successfully executed"); - } - }); + LuaLibraries.Print(results); + } }); _messageCount = 0; diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs index 0490799b8f..002d04d9ca 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs @@ -323,8 +323,35 @@ namespace BizHawk.Client.EmuHawk public void SpawnAndSetFileThread(string pathToLoad, LuaFile lf) => lf.Thread = SpawnCoroutine(pathToLoad); - public void ExecuteString(string command) - => _lua.DoString(command); + /// <summary> + /// Executes Lua code. Automatically prepends <see langword="return"/> statement if possible. + /// </summary> + /// <returns> + /// Values returned by the Lua script, if any. + /// </returns> + public object[] ExecuteString(string command) + { + const string ChunkName = "input"; // shows up in error messages + + // Use LoadString to separate parsing and execution, to tell syntax errors and runtime errors apart + LuaFunction func; + try + { + // Adding a return is necessary to get out return values of functions and turn expressions ("1+1" etc.) into valid statements + func = _lua.LoadString($"return {command}", ChunkName); + } + catch (Exception) + { + // command may be a valid statement without the added "return" + // if previous attempt couldn't be parsed, run the raw command + return _lua.DoString(command, ChunkName); + } + + using (func) + { + return func.Call(); + } + } public (bool WaitForFrame, bool Terminated) ResumeScript(LuaFile lf) {