summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2023-03-08 03:18:21 +1100
committer Vas Crabb <vas@vastheman.com>2023-03-08 03:18:21 +1100
commit6dea565343e81ab6b8c6da880ba166ba28235da8 (patch)
tree0b526ae232770a30a99ae6d1167388c0361307db
parent3f99355acc73398b663f33f50f47df65895fc9f9 (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.lua30
-rw-r--r--src/frontend/mame/luaengine.cpp157
-rw-r--r--src/frontend/mame/luaengine.h10
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;