Skip to content

Commit

Permalink
Improve Lua REPL handling of statements (squashed PR #4026)
Browse files Browse the repository at this point in the history
* Improve Lua REPL handling of statements

Stop printing syntax error messages when executing variable assignments etc.

* Move doc comments to interface

* Simplify pattern matching expression

* Use reference equality to test for console output

* Revert "Use reference equality to test for console output"

This reverts commit 875bc3c.

* Use `_messageCount` to test for console output
  • Loading branch information
kalimag authored Nov 23, 2024
1 parent 7e9e2d5 commit 2bd2aed
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 15 deletions.
8 changes: 7 additions & 1 deletion src/BizHawk.Client.Common/lua/ILuaLibraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ INamedLuaFunction CreateAndRegisterNamedFunction(

void SpawnAndSetFileThread(string pathToLoad, LuaFile lf);

void ExecuteString(string command);
/// <summary>
/// Executes Lua code. Automatically prepends <see langword="return"/> statement if possible.
/// </summary>
/// <returns>
/// Values returned by the Lua script, if any.
/// </returns>
object[] ExecuteString(string command);

(bool WaitForFrame, bool Terminated) ResumeScript(LuaFile lf);
}
Expand Down
20 changes: 8 additions & 12 deletions src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,6 @@ private void InputBox_KeyDown(object sender, KeyEventArgs e)
{
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
Expand All @@ -1388,18 +1387,15 @@ private void InputBox_KeyDown(object sender, KeyEventArgs e)

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;
Expand Down
25 changes: 23 additions & 2 deletions src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,29 @@ public LuaThread SpawnCoroutine(string file)
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)
{
Expand Down

0 comments on commit 2bd2aed

Please sign in to comment.