Enhance the interactive interpreter mode of dfusion.

1. Reimplement Console.print* to behave exactly as the standard print
   function, and apply print = Console.println from c++ init code.
2. Add a couple of convenience shortcuts to save some manual typing
   when poking around data structures using the interactive prompt.
3. Change the prompt string to a more distinguished shape.
develop
Alexander Gavrilov 2012-03-30 11:57:27 +04:00
parent 81bc73f435
commit e989ca58db
3 changed files with 105 additions and 21 deletions

@ -64,6 +64,11 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
st.setglobal("WINDOWS"); st.setglobal("WINDOWS");
#endif #endif
st.getglobal("Console");
st.getfield("println");
st.setglobal("print");
st.pop();
commands.push_back(PluginCommand("dfusion","Run dfusion system (interactive i.e. can input further commands).",dfusion,true)); commands.push_back(PluginCommand("dfusion","Run dfusion system (interactive i.e. can input further commands).",dfusion,true));
commands.push_back(PluginCommand("dfuse","Init dfusion system (not interactive).",dfuse,false)); commands.push_back(PluginCommand("dfuse","Init dfusion system (not interactive).",dfuse,false));
commands.push_back(PluginCommand("lua", "Run interactive interpreter. Use 'lua <filename>' to run <filename> instead.",lua_run,true)); commands.push_back(PluginCommand("lua", "Run interactive interpreter. Use 'lua <filename>' to run <filename> instead.",lua_run,true));
@ -115,28 +120,75 @@ void InterpreterLoop(color_ostream &out)
DFHack::CommandHistory hist; DFHack::CommandHistory hist;
lua::state s=lua::glua::Get(); lua::state s=lua::glua::Get();
string curline; string curline;
out.print("Type quit to exit interactive mode\n"); out.print("Type quit to exit interactive mode.\n"
"Shortcuts:\n"
" '= foo' => '_1,_2,... = foo'\n"
" '! foo' => 'print(foo)'\n");
assert(out.is_console()); assert(out.is_console());
Console &con = static_cast<Console&>(out); Console &con = static_cast<Console&>(out);
con.lineedit(">>",curline,hist); int vcnt = 1;
s.settop(0);
for (;;) {
con.lineedit("[lua]# ",curline,hist);
if (curline.empty())
continue;
if (curline == "quit")
break;
while (curline!="quit") {
hist.add(curline); hist.add(curline);
try try
{
if (curline[0] == '=')
{
curline = "return " + curline.substr(1);
s.loadstring(curline);
s.pcall(0, LUA_MULTRET);
int numret = s.gettop();
for (int i = 1; i <= numret; i++)
{
if (i == 1)
{
s.pushvalue(i);
s.setglobal("_");
}
std::string name = stl_sprintf("_%d", vcnt++);
s.pushvalue(i);
s.setglobal(name);
con.print("%s = ", name.c_str());
s.getglobal("print");
s.pushvalue(i);
s.pcall(1,0);
}
}
else if (curline[0] == '!')
{
curline = "print(" + curline.substr(1) + ")";
s.loadstring(curline);
s.pcall();
}
else
{ {
s.loadstring(curline); s.loadstring(curline);
s.pcall(); s.pcall();
}
} }
catch(lua::exception &e) catch(lua::exception &e)
{ {
con.printerr("Error:%s\n",e.what()); con.printerr("Error:%s\n",e.what());
con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str()); con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
s.settop(0);
}
con.lineedit(">>",curline,hist);
} }
s.settop(0); s.settop(0);
} }
}
command_result lua_run_file (color_ostream &out, std::vector <std::string> &parameters) command_result lua_run_file (color_ostream &out, std::vector <std::string> &parameters)
{ {
if(parameters.size()==0) if(parameters.size()==0)

@ -1,6 +1,3 @@
function print(msg)
Console.print(msg.."\n")
end
function err(msg) --make local maybe... function err(msg) --make local maybe...
print(msg) print(msg)
print(debug.traceback()) print(debug.traceback())

@ -1,4 +1,7 @@
#include "lua_Console.h" #include "lua_Console.h"
#include <sstream>
//TODO error management. Using lua error? or something other? //TODO error management. Using lua error? or something other?
static DFHack::color_ostream* GetConsolePtr(lua::state &st) static DFHack::color_ostream* GetConsolePtr(lua::state &st)
{ {
@ -9,21 +12,52 @@ static DFHack::color_ostream* GetConsolePtr(lua::state &st)
st.settop(t); st.settop(t);
return c; return c;
} }
static std::string lua_print_fmt(lua_State *L)
{
/* Copied from lua source to fully replicate builtin print */
int n = lua_gettop(L); /* number of arguments */
lua_getglobal(L, "tostring");
std::stringstream ss;
for (int i=1; i<=n; i++) {
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
const char *s = lua_tostring(L, -1); /* get result */
if (s == NULL)
luaL_error(L, "tostring must return a string to print");
if (i>1)
ss << '\t';
ss << s;
lua_pop(L, 1); /* pop result */
}
return ss.str();
}
static int lua_Console_print(lua_State *S) static int lua_Console_print(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
int t=st.gettop();
DFHack::color_ostream* c=GetConsolePtr(st); DFHack::color_ostream* c=GetConsolePtr(st);
c->print("%s",st.as<string>(t).c_str()); c->print("%s", lua_print_fmt(S).c_str());
return 0;
}
static int lua_Console_println(lua_State *S)
{
lua::state st(S);
DFHack::color_ostream* c=GetConsolePtr(st);
c->print("%s\n", lua_print_fmt(S).c_str());
return 0; return 0;
} }
static int lua_Console_printerr(lua_State *S) static int lua_Console_printerr(lua_State *S)
{ {
lua::state st(S); lua::state st(S);
int t=st.gettop();
DFHack::color_ostream* c=GetConsolePtr(st); DFHack::color_ostream* c=GetConsolePtr(st);
c->printerr("%s",st.as<string>(t).c_str()); c->printerr("%s", lua_print_fmt(S).c_str());
return 0; return 0;
} }
@ -123,6 +157,7 @@ static int lua_Console_lineedit(lua_State *S)
const luaL_Reg lua_console_func[]= const luaL_Reg lua_console_func[]=
{ {
{"print",lua_Console_print}, {"print",lua_Console_print},
{"println",lua_Console_println},
{"printerr",lua_Console_printerr}, {"printerr",lua_Console_printerr},
{"clear",lua_Console_clear}, {"clear",lua_Console_clear},
{"gotoxy",lua_Console_gotoxy}, {"gotoxy",lua_Console_gotoxy},