diff options
author | 2023-03-08 03:18:21 +1100 | |
---|---|---|
committer | 2023-03-08 03:18:21 +1100 | |
commit | 6dea565343e81ab6b8c6da880ba166ba28235da8 (patch) | |
tree | 0b526ae232770a30a99ae6d1167388c0361307db | |
parent | 3f99355acc73398b663f33f50f47df65895fc9f9 (diff) |
plugins/console: Fixed tab completion after linenoise update.
* Can now cycle through candidates by repeatedly pushing Tab.
* Also cleaned up Lua thread context object a little, and made it
possible to pass any Lua object as a status value.
-rw-r--r-- | plugins/console/init.lua | 30 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.cpp | 157 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.h | 10 |
3 files changed, 109 insertions, 88 deletions
diff --git a/plugins/console/init.lua b/plugins/console/init.lua index 3e10e17bc14..33f698fc0cb 100644 --- a/plugins/console/init.lua +++ b/plugins/console/init.lua @@ -43,8 +43,11 @@ function console.startplugin() local ln = require('linenoise') ln.setcompletion( function(c, str) + status = str yield() - ln.addcompletion(c, str) + for k, v in pairs(status) do + ln.addcompletion(c, v) + end end) local ret = ln.linenoise('$PROMPT') if ret == nil then @@ -191,11 +194,8 @@ function console.startplugin() return curstring, strs, expr:match("([%.:%w%(%)%[%]_]-)([:%.%[%(])" .. word .. "$") end - local function get_completions(line, endpos) + local function get_completions(line) matches = {} - local endstr = line:sub(endpos + 1, -1) - line = line:sub(1, endpos) - endstr = endstr or "" local start, word = line:match("^(.*[ \t\n\"\\'><=;:%+%-%*/%%^~#{}%(%)%[%].,])(.-)$") if not start then start = "" @@ -206,16 +206,18 @@ function console.startplugin() local str, strs, expr, sep = simplify_expression(line, word) contextual_list(expr, sep, str, word, strs) - if #matches > 1 then - print("\n") - for k, v in pairs(matches) do - print(v) - end - return "\x01" .. "-1" + if #matches == 0 then + return { line } elseif #matches == 1 then - return start .. matches[1] .. endstr .. "\x01" .. (#start + #matches[1]) + return { start .. matches[1] } + end + print("") + result = { } + for k, v in pairs(matches) do + print(v) + table.insert(result, start .. v) end - return "\x01" .. "-1" + return result end emu.register_start(function() @@ -249,7 +251,7 @@ function console.startplugin() -- ln.refresh() FIXME: how to replicate this now that the API has been removed? end if conth.yield then - conth:continue(get_completions(conth.result:match("([^\x01]*)\x01(.*)"))) + conth:continue(get_completions(conth.result)) return elseif conth.busy then return diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index c8536bb044d..04b68b75e9a 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -31,7 +31,9 @@ #include "corestr.h" #include "notifier.h" +#include <condition_variable> #include <cstring> +#include <mutex> #include <thread> @@ -58,6 +60,91 @@ struct lua_engine::devenum namespace { +struct thread_context +{ +private: + sol::object m_result; + std::mutex m_guard; + std::condition_variable m_sync; + +public: + bool m_busy = false; + bool m_yield = false; + + bool start(char const *scr) + { + std::unique_lock<std::mutex> lock(m_guard); + if (m_busy) + return false; + + std::string script(scr); + std::thread th( + [this, script = std::string(scr)] () + { + sol::state thstate; + thstate.open_libraries(); + thstate["package"]["preload"]["zlib"] = &luaopen_zlib; + thstate["package"]["preload"]["lfs"] = &luaopen_lfs; + thstate["package"]["preload"]["linenoise"] = &luaopen_linenoise; + sol::load_result res = thstate.load(script); + if (res.valid()) + { + sol::protected_function func = res.get<sol::protected_function>(); + thstate.set_function( + "yield", + [this, &thstate]() + { + std::unique_lock<std::mutex> lock(m_guard); + m_result = thstate["status"]; + m_yield = true; + m_sync.wait(lock); + m_yield = false; + thstate["status"] = m_result; + }); + auto ret = func(); + if (ret.valid()) + { + m_result = ret.get<sol::object>(); + } + else + { + sol::error err = ret; + osd_printf_error("[LUA ERROR] in thread: %s\n", err.what()); + } + } + else + { + sol::error err = res; + osd_printf_error("[LUA ERROR] when loading script for thread: %s\n", err.what()); + } + m_busy = false; // FIXME: shouldn't do this when not holding the lock + }); + m_busy = true; + m_yield = false; + th.detach(); + return true; + } + + void resume(sol::object val) + { + std::unique_lock<std::mutex> lock(m_guard); + if (m_yield) + { + m_result = val; + m_sync.notify_all(); + } + } + + sol::object result() + { + std::unique_lock<std::mutex> lock(m_guard); + if (m_busy && !m_yield) + return sol::lua_nil; + else + return m_result; + } +}; + struct image_interface_formats { image_interface_formats(device_image_interface &i) : image(i) { } @@ -883,70 +970,12 @@ void lua_engine::initialize() * thread.yield - check if thread is yielded */ - auto thread_type = emu.new_usertype<context>("thread", sol::call_constructor, sol::constructors<sol::types<>>()); - thread_type.set("start", [](context &ctx, const char *scr) { - std::string script(scr); - if (ctx.busy) - return false; - std::thread th([&ctx, script]() { - sol::state thstate; - thstate.open_libraries(); - thstate["package"]["preload"]["zlib"] = &luaopen_zlib; - thstate["package"]["preload"]["lfs"] = &luaopen_lfs; - thstate["package"]["preload"]["linenoise"] = &luaopen_linenoise; - sol::load_result res = thstate.load(script); - if(res.valid()) - { - sol::protected_function func = res.get<sol::protected_function>(); - thstate["yield"] = [&ctx, &thstate]() { - std::mutex m; - std::unique_lock<std::mutex> lock(m); - ctx.result = thstate["status"]; - ctx.yield = true; - ctx.sync.wait(lock); - ctx.yield = false; - thstate["status"] = ctx.result; - }; - auto ret = func(); - if (ret.valid()) - { - const char *tmp = ret.get<const char *>(); - if (tmp != nullptr) - ctx.result = tmp; - else - osd_printf_error("[LUA ERROR] in thread: return value must be string\n"); - } - else - { - sol::error err = ret; - osd_printf_error("[LUA ERROR] in thread: %s\n", err.what()); - } - } - else - { - sol::error err = res; - osd_printf_error("[LUA ERROR] when loading script for thread: %s\n", err.what()); - } - ctx.busy = false; - }); - ctx.busy = true; - ctx.yield = false; - th.detach(); - return true; - }); - thread_type.set("continue", [](context &ctx, const char *val) { - if (!ctx.yield) - return; - ctx.result = val; - ctx.sync.notify_all(); - }); - thread_type.set("result", sol::property([](context &ctx) -> std::string { - if (ctx.busy && !ctx.yield) - return ""; - return ctx.result; - })); - thread_type.set("busy", sol::readonly(&context::busy)); - thread_type.set("yield", sol::readonly(&context::yield)); + auto thread_type = emu.new_usertype<thread_context>("thread", sol::call_constructor, sol::constructors<sol::types<>>()); + thread_type.set_function("start", &thread_context::start); + thread_type.set_function("continue", &thread_context::resume); + thread_type["result"] = sol::property(&thread_context::result); + thread_type["busy"] = sol::readonly(&thread_context::m_busy); + thread_type["yield"] = sol::readonly(&thread_context::m_yield); /* save_item library diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index c3c33e80b39..53795927a5c 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -12,7 +12,6 @@ #pragma once -#include <condition_variable> #include <functional> #include <map> #include <memory> @@ -161,15 +160,6 @@ private: unsigned int stride; }; - struct context - { - context() { busy = false; yield = false; } - std::string result; - std::condition_variable sync; - bool busy; - bool yield; - }; - // internal state lua_State *m_lua_state; std::unique_ptr<sol::state_view> m_sol_state; |