mirror of
https://github.com/holub/mame
synced 2025-07-04 17:38:08 +03:00
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.
This commit is contained in:
parent
3f99355acc
commit
6dea565343
@ -43,8 +43,11 @@ function console.startplugin()
|
|||||||
local ln = require('linenoise')
|
local ln = require('linenoise')
|
||||||
ln.setcompletion(
|
ln.setcompletion(
|
||||||
function(c, str)
|
function(c, str)
|
||||||
|
status = str
|
||||||
yield()
|
yield()
|
||||||
ln.addcompletion(c, str)
|
for k, v in pairs(status) do
|
||||||
|
ln.addcompletion(c, v)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
local ret = ln.linenoise('$PROMPT')
|
local ret = ln.linenoise('$PROMPT')
|
||||||
if ret == nil then
|
if ret == nil then
|
||||||
@ -191,11 +194,8 @@ function console.startplugin()
|
|||||||
return curstring, strs, expr:match("([%.:%w%(%)%[%]_]-)([:%.%[%(])" .. word .. "$")
|
return curstring, strs, expr:match("([%.:%w%(%)%[%]_]-)([:%.%[%(])" .. word .. "$")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_completions(line, endpos)
|
local function get_completions(line)
|
||||||
matches = {}
|
matches = {}
|
||||||
local endstr = line:sub(endpos + 1, -1)
|
|
||||||
line = line:sub(1, endpos)
|
|
||||||
endstr = endstr or ""
|
|
||||||
local start, word = line:match("^(.*[ \t\n\"\\'><=;:%+%-%*/%%^~#{}%(%)%[%].,])(.-)$")
|
local start, word = line:match("^(.*[ \t\n\"\\'><=;:%+%-%*/%%^~#{}%(%)%[%].,])(.-)$")
|
||||||
if not start then
|
if not start then
|
||||||
start = ""
|
start = ""
|
||||||
@ -206,16 +206,18 @@ function console.startplugin()
|
|||||||
|
|
||||||
local str, strs, expr, sep = simplify_expression(line, word)
|
local str, strs, expr, sep = simplify_expression(line, word)
|
||||||
contextual_list(expr, sep, str, word, strs)
|
contextual_list(expr, sep, str, word, strs)
|
||||||
if #matches > 1 then
|
if #matches == 0 then
|
||||||
print("\n")
|
return { line }
|
||||||
for k, v in pairs(matches) do
|
|
||||||
print(v)
|
|
||||||
end
|
|
||||||
return "\x01" .. "-1"
|
|
||||||
elseif #matches == 1 then
|
elseif #matches == 1 then
|
||||||
return start .. matches[1] .. endstr .. "\x01" .. (#start + #matches[1])
|
return { start .. matches[1] }
|
||||||
end
|
end
|
||||||
return "\x01" .. "-1"
|
print("")
|
||||||
|
result = { }
|
||||||
|
for k, v in pairs(matches) do
|
||||||
|
print(v)
|
||||||
|
table.insert(result, start .. v)
|
||||||
|
end
|
||||||
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
emu.register_start(function()
|
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?
|
-- ln.refresh() FIXME: how to replicate this now that the API has been removed?
|
||||||
end
|
end
|
||||||
if conth.yield then
|
if conth.yield then
|
||||||
conth:continue(get_completions(conth.result:match("([^\x01]*)\x01(.*)")))
|
conth:continue(get_completions(conth.result))
|
||||||
return
|
return
|
||||||
elseif conth.busy then
|
elseif conth.busy then
|
||||||
return
|
return
|
||||||
|
@ -31,7 +31,9 @@
|
|||||||
#include "corestr.h"
|
#include "corestr.h"
|
||||||
#include "notifier.h"
|
#include "notifier.h"
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
@ -58,6 +60,91 @@ struct lua_engine::devenum
|
|||||||
|
|
||||||
namespace {
|
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
|
struct image_interface_formats
|
||||||
{
|
{
|
||||||
image_interface_formats(device_image_interface &i) : image(i) { }
|
image_interface_formats(device_image_interface &i) : image(i) { }
|
||||||
@ -883,70 +970,12 @@ void lua_engine::initialize()
|
|||||||
* thread.yield - check if thread is yielded
|
* thread.yield - check if thread is yielded
|
||||||
*/
|
*/
|
||||||
|
|
||||||
auto thread_type = emu.new_usertype<context>("thread", sol::call_constructor, sol::constructors<sol::types<>>());
|
auto thread_type = emu.new_usertype<thread_context>("thread", sol::call_constructor, sol::constructors<sol::types<>>());
|
||||||
thread_type.set("start", [](context &ctx, const char *scr) {
|
thread_type.set_function("start", &thread_context::start);
|
||||||
std::string script(scr);
|
thread_type.set_function("continue", &thread_context::resume);
|
||||||
if (ctx.busy)
|
thread_type["result"] = sol::property(&thread_context::result);
|
||||||
return false;
|
thread_type["busy"] = sol::readonly(&thread_context::m_busy);
|
||||||
std::thread th([&ctx, script]() {
|
thread_type["yield"] = sol::readonly(&thread_context::m_yield);
|
||||||
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));
|
|
||||||
|
|
||||||
|
|
||||||
/* save_item library
|
/* save_item library
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -161,15 +160,6 @@ private:
|
|||||||
unsigned int stride;
|
unsigned int stride;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct context
|
|
||||||
{
|
|
||||||
context() { busy = false; yield = false; }
|
|
||||||
std::string result;
|
|
||||||
std::condition_variable sync;
|
|
||||||
bool busy;
|
|
||||||
bool yield;
|
|
||||||
};
|
|
||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
lua_State *m_lua_state;
|
lua_State *m_lua_state;
|
||||||
std::unique_ptr<sol::state_view> m_sol_state;
|
std::unique_ptr<sol::state_view> m_sol_state;
|
||||||
|
Loading…
Reference in New Issue
Block a user