| 619 | } |
| 620 | |
| 621 | void LuaThreadedCall(lua_State *L, int nargs, int nresults, std::string const& title, wxWindow *parent, bool can_open_config) |
| 622 | { |
| 623 | bool failed = false; |
| 624 | BackgroundScriptRunner bsr(parent, title); |
| 625 | try { |
| 626 | bsr.Run([&](ProgressSink *ps) { |
| 627 | LuaProgressSink lps(L, ps, can_open_config); |
| 628 | |
| 629 | // Insert our error handler under the function to call |
| 630 | lua_pushcclosure(L, add_stack_trace, 0); |
| 631 | lua_insert(L, -nargs - 2); |
| 632 | |
| 633 | if (lua_pcall(L, nargs, nresults, -nargs - 2)) { |
| 634 | if (!lua_isnil(L, -1)) { |
| 635 | // if the call failed, log the error here |
| 636 | ps->Log("\n\nLua reported a runtime error:\n"); |
| 637 | ps->Log(get_string_or_default(L, -1)); |
| 638 | } |
| 639 | lua_pop(L, 2); |
| 640 | failed = true; |
| 641 | } |
| 642 | else |
| 643 | lua_remove(L, -nresults - 1); |
| 644 | |
| 645 | lua_gc(L, LUA_GCCOLLECT, 0); |
| 646 | }); |
| 647 | } catch (agi::UserCancelException const&) { |
| 648 | // A UserCancelException can be thrown by the background runner after |
| 649 | // the above closure ran through. |
| 650 | // Below, we want to throw our own UserCancelException when the script throws an error, |
| 651 | // in which case we leave the stack empty. Hence, if the script did not throw an error, |
| 652 | // we need to pop the return values here to also leave the stack empty. |
| 653 | if (!failed) |
| 654 | lua_pop(L, nresults); |
| 655 | throw; |
| 656 | } |
| 657 | if (failed) |
| 658 | throw agi::UserCancelException("Script threw an error"); |
| 659 | } |
| 660 | |
| 661 | // LuaFeature |
| 662 | void LuaFeature::RegisterFeature() |
no test coverage detected