|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
There shouldn't be any issues enabling that. Cool. That was one of the things that would crash when I'd experiment. Now I just have to remember not to try to copy with CTRL+C in the mame console. kaboom! Old habits die hard. Interestingly, if I type CTRL+V (for paste) I see a ^V in the console, but it takes two deletes to remove it. If I only delete once after hitting CTRL+V I get this "unexpected symbol" and I could not figure out why my command didn't work. type print("hello") then CTRL+V and then delete once, the command line looks ok, but there's a bizarro character at the end. This is with Ubuntu terminal console. print("hello")
error: [string "print("hello")"]:1: unexpected symbol near '<\127>'
I can edit the plugins/console/init.lua and add this line:
local ln = require("linenoise")
ln_global = ln so I can access the linenoise as the global variable ln_global and then I can save the history as: ln_global.savehistory("mysavehistoryln.txt") and loading that into a text editor I can see that there's a strange 007F character at the end. Is there an easy way of accessing the actual linenoise history entries, like a "history" command in bash, for example? If I type ln_global. and then hit TAB to complete I get: ln_global.
addcompletion
clearscreen
sethistorymaxlen
linenoise
lines
historysave
line
preload
loadhistory
savehistory
setcompletion
addhistory
refresh
historyadd
historysetmaxlen
historyload
But none of those seem to give me access to the actual history. edit: Hmmm, why not savehistory to /dev/stdout, that seems to work. ln_global.savehistory("/dev/stdout")
Last edited by Golden Child; 11/22/17 03:55 PM.
|
|
|
|
Joined: Jan 2012
Posts: 891 Likes: 17
Senior Member
|
Senior Member
Joined: Jan 2012
Posts: 891 Likes: 17 |
The linenoise function char **linenoiseHistory(int *len) provides access to the history but it's not passed to lua in to lua-linenoise. If you can add it that'd be great, it shouldn't be hard to do.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
The linenoise function char **linenoiseHistory(int *len) provides access to the history but it's not passed to lua in to lua-linenoise. If you can add it that'd be great, it shouldn't be hard to do. sounds like an interesting idea, I'll give it a shot.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
I took a stab at adding it to linenoise.c, this seems to work. Cool! static int l_gethistorytable(lua_State *L)
{
int i,j;
char ** phist;
int lenhist = linenoiseHistoryGetMaxLen();
phist = linenoiseHistory(&lenhist);
lua_newtable(L);
i = 1;
for (j=0; j<lenhist; j++){
/* create result table */
lua_pushnumber(L, i++); /* push key */
lua_pushstring(L, (char *)*(phist+j)); /* push value */
lua_settable(L, -3); /* adds key and value to table on top of stack */
}
return 1; /* table is already on top */
}
luaL_Reg linenoise_funcs[] = {
{ "linenoise", l_linenoise },
{ "historyadd", l_historyadd },
{ "historysetmaxlen", l_historysetmaxlen },
{ "historysave", l_historysave },
{ "historyload", l_historyload },
{ "clearscreen", l_clearscreen },
{ "setcompletion", l_setcompletion},
{ "addcompletion", l_addcompletion },
{ "preload", l_preloadbuffer },
{ "refresh", l_refresh },
/* Aliases for more consistent function names */
{ "addhistory", l_historyadd },
{ "sethistorymaxlen", l_historysetmaxlen },
{ "savehistory", l_historysave },
{ "loadhistory", l_historyload },
{ "line", l_linenoise },
{ "lines", l_lines },
{ "gethistory", l_gethistorytable}, // added function to gethistory
{ NULL, NULL }
}; I think you don't see the current command in the history list because it gets added after it gets executed.
MAME debugger version 0.191 (mame0191-183-g346a935839-dirty)
Currently targeting a2600 (Atari 2600 (NTSC))
[MAME]> print(#ln_global.gethistory())
0
[MAME]> print(#ln_global.gethistory())
1
[MAME]> function printt(a) local i,j; for i,j in pairs(a) do print(i,j) end end
[MAME]> printt(ln_global.gethistory())
1 print(#ln_global.gethistory())
2 function printt(a) local i,j; for i,j in pairs(a) do print(i,j) end end
[MAME]> printt(ln_global.gethistory())
1 print(#ln_global.gethistory())
2 function printt(a) local i,j; for i,j in pairs(a) do print(i,j) end end
3 printt(ln_global.gethistory())
[MAME]>
|
|
|
|
Joined: Feb 2004
Posts: 2,608 Likes: 315
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,608 Likes: 315 |
Interestingly, if I type CTRL+V (for paste) I see a ^V in the console, but it takes two deletes to remove it. If I only delete once after hitting CTRL+V I get this "unexpected symbol" and I could not figure out why my command didn't work. type print("hello") then CTRL+V and then delete once, the command line looks ok, but there's a bizarro character at the end. This is with Ubuntu terminal console. print("hello")
error: [string "print("hello")"]:1: unexpected symbol near '<\127>'
Ctrl-V means "interpret the next character literally", so Ctrl-V Ctrl-C will type a literal ETX character rather than sending SIGINT, Ctrl-V Delete will type a literal DEL rather than deleting the previous character, etc.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Ctrl-V means "interpret the next character literally", so Ctrl-V Ctrl-C will type a literal ETX character rather than sending SIGINT, Ctrl-V Delete will type a literal DEL rather than deleting the previous character, etc. Ohhhh, now that makes perfect sense. That explains why if I'd type Ctrl+v Return that I'd get a ^M or Ctrl+v left arrow I'd get ESC [ D. So that's why I'd get an 007F character from Ctrl+V DEL. I guess that's a keystroke from VIM. And sure enough, the code in 3rdparty/linenoise/linenoise.c is pretty straightforward. case ctrl('V'): /* ctrl-v */
if (has_room(current, 3)) {
/* Insert the ^V first */
if (insert_char(current, current->pos, c)) {
refreshLine(current->prompt, current);
/* Now wait for the next char. Can insert anything except \0 */
c = fd_read(current);
/* Remove the ^V first */
remove_char(current, current->pos - 1);
if (c != -1) {
/* Insert the actual char */
insert_char(current, current->pos, c);
}
refreshLine(current->prompt, current);
}
}
Last edited by Golden Child; 11/23/17 08:33 AM.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
So while we're at it, why not do a historygetmaxlen too:
static int l_gethistorytable(lua_State *L)
{
int i,j;
char ** phist;
int lenhist = linenoiseHistoryGetMaxLen();
phist = linenoiseHistory(&lenhist);
lua_newtable(L); /* put a table on the stack */
i = 1;
for (j=0; j<lenhist; j++){
/* create result table */
lua_pushnumber(L, i++); /* push key */
lua_pushstring(L, phist[j]); /* push value */
lua_settable(L, -3); /* adds key and value to table at position 3 from top of stack */
}
return 1; /* table is already on top */
}
static int l_historygetmaxlen(lua_State *L)
{
lua_pushinteger(L, linenoiseHistoryGetMaxLen()); /* push max len on stack */
return 1; /* number of items on stack */
}
luaL_Reg linenoise_funcs[] = {
{ "linenoise", l_linenoise },
{ "historyadd", l_historyadd },
{ "historysetmaxlen", l_historysetmaxlen },
{ "historysave", l_historysave },
{ "historyload", l_historyload },
{ "clearscreen", l_clearscreen },
{ "setcompletion", l_setcompletion},
{ "addcompletion", l_addcompletion },
{ "preload", l_preloadbuffer },
{ "refresh", l_refresh },
/* Aliases for more consistent function names */
{ "addhistory", l_historyadd },
{ "sethistorymaxlen", l_historysetmaxlen },
{ "savehistory", l_historysave },
{ "loadhistory", l_historyload },
{ "line", l_linenoise },
{ "lines", l_lines },
{ "gethistory", l_gethistorytable},
{ "historygetmaxlen", l_historygetmaxlen},
{ NULL, NULL }
};
MAME debugger version 0.191 (mame0191-183-g346a935839-dirty)
Currently targeting a2600 (Atari 2600 (NTSC))
[MAME]> print(ln_global.historygetmaxlen())
100
[MAME]> print(ln_global.historysetmaxlen(250))
true
[MAME]> print(ln_global.historygetmaxlen())
250
[MAME]> function printt(a) local i,j; for i,j in pairs(a) do print(i,j) end end
[MAME]> printt(ln_global.gethistory())
1 print(ln_global.historygetmaxlen())
2 print(ln_global.historysetmaxlen(250))
3 print(ln_global.historygetmaxlen())
4 function printt(a) local i,j; for i,j in pairs(a) do print(i,j) end end
[MAME]>
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Ok, I thought I should clean the code up a little bit, and maybe add a couple of functions to return the history length ln.historylen() and to print the history ln.print() or ln.history(). 3rdparty/lua-linenoise/linenoise.c
static int l_gethistorytable(lua_State *L)
{
int history_len;
char ** history = linenoiseHistory(&history_len);
lua_newtable(L); /* put a table on the stack */
for (int i=0; i<history_len; i++){
/* create result table */
lua_pushnumber(L, i+1); /* push key */
lua_pushstring(L, history[i]); /* push value */
lua_settable(L, -3); /* adds key and value to table at position 3 from top of stack */
}
return 1; /* table is on top of stack */
}
static int l_historylen(lua_State *L)
{
int history_len;
char ** history = linenoiseHistory(&history_len);
history = history; // compiler warning about unused variable
lua_pushinteger(L, history_len);
return 1;
}
static int l_historygetmaxlen(lua_State *L)
{
lua_pushinteger(L, linenoiseHistoryGetMaxLen());
return 1;
}
static int l_historyprint(lua_State *L)
{
int history_len;
char ** history = linenoiseHistory(&history_len);
printf("print history: %d entries\n",history_len);
for (int i=0; i<history_len; i++){
printf("%d %s\n",i+1,history[i]);
}
return handle_ln_ok(L);
}
luaL_Reg linenoise_funcs[] = {
{ "linenoise", l_linenoise },
{ "historyadd", l_historyadd },
{ "historysetmaxlen", l_historysetmaxlen },
{ "historysave", l_historysave },
{ "historyload", l_historyload },
{ "clearscreen", l_clearscreen },
{ "setcompletion", l_setcompletion},
{ "addcompletion", l_addcompletion },
{ "preload", l_preloadbuffer },
{ "refresh", l_refresh },
/* Aliases for more consistent function names */
{ "addhistory", l_historyadd },
{ "sethistorymaxlen", l_historysetmaxlen },
{ "savehistory", l_historysave },
{ "loadhistory", l_historyload },
{ "line", l_linenoise },
{ "lines", l_lines },
{ "gethistorytable", l_gethistorytable},
{ "historygetmaxlen", l_historygetmaxlen},
{ "historylen", l_historylen},
{ "print", l_historyprint},
{ "history", l_historyprint},
{ NULL, NULL }
};
What's kind of interesting is that if you set the history to n, the maximum length is actually n-1. So for ln.historysetmaxlen(5), the length of the history is actually a maximum of 4 entries. And if you remove this line from plugins/console/init.lua it will default to a maximum length of 100. since 3rdparty/linenoise/linenoise.c has this: #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
And if you like to make ln a global variable ln for access you can do this in plugins/console/init.lua
local ln = require("linenoise")
_G.ln = ln -- make a global ln for console access
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
I was curious how the CTRL+C worked in linenoise and whether it could be "caught". One interesting side effect of enabling SOL_CHECK_ARGUMENTS in luaengine.h is in whether sol will throw an exception when it executes this in luaengine.cpp:
auto ret = func();
if (ret.valid()) {
const char *tmp = ret.get<const char *>();
if (tmp != nullptr)
ctx.result = tmp;
else
exit(0);
}
So when you type a CTRL+C on the console, it will return a nil from linenoise, tmp will be null so it calls exit(0); When you've got SOL_CHECK_ARGUMENTS enabled, it will throw a sol::error exception immediately when it executes the following line const char *tmp = ret.get<const char *>();
It drops out and never sees the following if (tmp != nullptr) statement. I had to put a bunch of printfs around to figure out exactly where it was blowing up. And you get this kind of exit. [MAME]>
terminate called after throwing an instance of 'sol::error'
what(): lua: error: stack index 2, expected string, received nil
Aborted (core dumped)
So if we insert a little try catch block, we can catch that sol::error on the get.
if (ret.valid()) {
printf("calling ret.get const char *\n");
try{
const char *tmp = ret.get<const char *>();
if (tmp != nullptr)
ctx.result = tmp;
else
exit(0);
catch (const std::exception& e) {
printf("Caught Exception:\n"); std::cout << e.what() << std::endl;
}
}
With the catch it will catch the sol::error and keep you in the console. Of course, it's so convenient to just hit CTRL+C to drop out of mame, but there are other ways, like manager:machine():exit() [MAME]>
calling ret.get const char *
Caught exception:
lua: error: stack index 2, expected string, received nil
[MAME]>
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Now that I've thought about for a bit, it's just getting a nil result from linenoise when you hit CTRL+C. The nil will cause the exception so why not look for that in plugins/console/init.lua: The linenoise reading code:
local scr = [[
local ln = require('linenoise')
ln.setcompletion(function(c, str, pos)
status = str .. "\x01" .. tostring(pos)
yield()
ln.addcompletion(c, status:match("([^\x01]*)\x01(.*)"))
end)
return ln.linenoise('\x1b[1;36m[MAME]\x1b[0m> ')
]]
so instead of just returning the value from ln.linenoise, we'll check it for NIL and if so, convert it to the empty string. local scr = [[
local ln = require('linenoise')
ln.setcompletion(function(c, str, pos)
status = str .. "\x01" .. tostring(pos)
yield()
ln.addcompletion(c, status:match("([^\x01]*)\x01(.*)"))
end)
local lnresult = ln.linenoise('\x1b[1;36m[MAME]\x1b[0m> ')
if lnresult == nil then print ("NIL result") lnresult = "" end
return lnresult
]]
|
|
|
0 members (),
54
guests, and
4
robots. |
Key:
Admin,
Global Mod,
Mod
|
|
Forums9
Topics9,331
Posts122,197
Members5,077
|
Most Online1,283 Dec 21st, 2022
|
|
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!
|
|
|
|