Previous Thread
Next Thread
Print Thread
Page 13 of 78 1 2 11 12 13 14 15 77 78
Joined: Feb 2014
Posts: 853
Likes: 48
G
Senior Member
Offline
Senior Member
G
Joined: Feb 2014
Posts: 853
Likes: 48
Originally Posted by crazyc
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.

Code
print("hello")
error: 	[string "print("hello")"]:1: unexpected symbol near '<\127>'




I can edit the plugins/console/init.lua and add this line:

Code
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:

Code
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:

Code
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.

Code
ln_global.savehistory("/dev/stdout")


Last edited by Golden Child; 11/22/17 03:55 PM.
Joined: Jan 2012
Posts: 881
Likes: 10
C
Senior Member
Offline
Senior Member
C
Joined: Jan 2012
Posts: 881
Likes: 10
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: 853
Likes: 48
G
Senior Member
Offline
Senior Member
G
Joined: Feb 2014
Posts: 853
Likes: 48
Originally Posted by crazyc
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: 853
Likes: 48
G
Senior Member
Offline
Senior Member
G
Joined: Feb 2014
Posts: 853
Likes: 48

I took a stab at adding it to linenoise.c, this seems to work. Cool!

Code
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.

Code
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,383
Likes: 98
Very Senior Member
Offline
Very Senior Member
Joined: Feb 2004
Posts: 2,383
Likes: 98
Originally Posted by Golden Child
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.

Code
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: 853
Likes: 48
G
Senior Member
Offline
Senior Member
G
Joined: Feb 2014
Posts: 853
Likes: 48
Originally Posted by Vas Crabb

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.

Code
    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: 853
Likes: 48
G
Senior Member
Offline
Senior Member
G
Joined: Feb 2014
Posts: 853
Likes: 48
So while we're at it, why not do a historygetmaxlen too:

Code
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 }
};




Code
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: 853
Likes: 48
G
Senior Member
Offline
Senior Member
G
Joined: Feb 2014
Posts: 853
Likes: 48
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
Code

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.

Code
ln.historysetmaxlen(10)

since 3rdparty/linenoise/linenoise.c has this:
Code
#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

Code
  
local ln = require("linenoise")
_G.ln = ln  -- make a global ln for console access

Joined: Feb 2014
Posts: 853
Likes: 48
G
Senior Member
Offline
Senior Member
G
Joined: Feb 2014
Posts: 853
Likes: 48
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:

Code
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

Code
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.

Code
[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.
Code
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()


Code
[MAME]> 
calling ret.get const char *
Caught exception:
lua: error: stack index 2, expected string, received nil
[MAME]> 

Joined: Feb 2014
Posts: 853
Likes: 48
G
Senior Member
Offline
Senior Member
G
Joined: Feb 2014
Posts: 853
Likes: 48
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:

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.

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)
local lnresult = ln.linenoise('\x1b[1;36m[MAME]\x1b[0m> ')
if lnresult == nil then print ("NIL result") lnresult = "" end
return lnresult
]]


Page 13 of 78 1 2 11 12 13 14 15 77 78

Link Copied to Clipboard
Who's Online Now
3 members (Praxis, hap, yugffuts), 26 guests, and 3 robots.
Key: Admin, Global Mod, Mod
ShoutChat
Comment Guidelines: Do post respectful and insightful comments. Don't flame, hate, spam.
Forum Statistics
Forums9
Topics9,103
Posts119,284
Members5,019
Most Online890
Jan 17th, 2020
Our Sponsor
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!

Superior Solitaire
Forum hosted by www.retrogamesformac.com