diff --git a/src/BizHawk.Client.Common/lua/ILuaLibraries.cs b/src/BizHawk.Client.Common/lua/ILuaLibraries.cs
index c4e1ea1078..ca3f164c61 100644
--- a/src/BizHawk.Client.Common/lua/ILuaLibraries.cs
+++ b/src/BizHawk.Client.Common/lua/ILuaLibraries.cs
@@ -51,7 +51,13 @@ namespace BizHawk.Client.Common
void SpawnAndSetFileThread(string pathToLoad, LuaFile lf);
- void ExecuteString(string command);
+ ///
+ /// Executes Lua code. Automatically prepends statement if possible.
+ ///
+ ///
+ /// Values returned by the Lua script, if any.
+ ///
+ 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 f2b7fc07be..1e13fe4e10 100644
--- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs
+++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs
@@ -1373,7 +1373,6 @@ namespace BizHawk.Client.EmuHawk
{
if (e.KeyCode == Keys.Enter)
{
- string consoleBeforeCall = OutputBox.Text;
var rawCommand = InputBox.Text;
InputBox.Clear();
InputBox.Refresh(); // if the command is something like `client.seekframe`, the Lua Console (and MainForm) will freeze until it finishes, so at least make it obvious that the Enter press was received
@@ -1388,18 +1387,15 @@ namespace BizHawk.Client.EmuHawk
LuaSandbox.Sandbox(null, () =>
{
- LuaImp.ExecuteString($"console.log({rawCommand})");
- }, () =>
- {
- LuaSandbox.Sandbox(null, () =>
+ var prevMessageCount = _messageCount;
+ 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 ([ ] or [ null ]) || _messageCount == prevMessageCount)
{
- 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 8e0cb22239..5ac0a3922f 100644
--- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs
+++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs
@@ -323,8 +323,29 @@ namespace BizHawk.Client.EmuHawk
public void SpawnAndSetFileThread(string pathToLoad, LuaFile lf)
=> lf.Thread = SpawnCoroutine(pathToLoad);
- public void ExecuteString(string command)
- => _lua.DoString(command);
+ 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)
{