Refactor luaconsole to make it easier to use

This commit is contained in:
2021-11-04 11:20:29 -04:00
parent 7cbf40e3d6
commit cf5a2d7462
4 changed files with 63 additions and 82 deletions

View File

@@ -34,10 +34,6 @@ public:
channel_ = new_outgoing_channel("localhost:8085");
}
void do_lua(const std::string &lua) {
stdostream() << "Lua: " << lua << std::endl;
}
void do_command(const util::StringVec &words) {
stdostream() << "Command: ";
for (const std::string &word : words) {
@@ -46,27 +42,17 @@ public:
stdostream() << std::endl;
}
void console_process(const std::string &line) {
console_.add(line);
int action = console_.action();
if (action == LuaConsole::DO_LUA) {
do_lua(console_.lua_expression());
console_.clear();
} else if (action == LuaConsole::DO_COMMAND) {
do_command(console_.words());
console_.clear();
} else if (action == LuaConsole::DO_SYNTAX) {
stdostream() << console_.syntax() << std::endl;
console_.clear();
}
}
virtual void event_update() {
// Check for keyboard input on stdin.
while (true) {
std::string line = get_stdio_channel()->in()->readline();
if (line == "") break;
console_process(line);
console_.add(line);
const util::StringVec &words = console_.words();
if (!words.empty()) {
do_command(words);
console_.clear();
}
get_stdio_channel()->out()->write_bytes(console_.get_prompt());
}

View File

@@ -20,13 +20,11 @@ LuaConsole::~LuaConsole() {
void LuaConsole::clear() {
raw_input_ = "";
lines_ = 0;
lua_expression_ = "";
words_.clear();
syntax_ = "";
action_ = DO_NOTHING;
prompt_ = "> ";
}
void LuaConsole::split_words() {
words_.clear();
std::string acc;
@@ -64,7 +62,7 @@ void LuaConsole::add(std::string line) {
split_words();
if (words_.size() >= 1) {
if (is_single_letter(words_[0]) || (util::validinteger(words_[0]))) {
action_ = DO_COMMAND;
// We have a valid parsed command. Return it.
return;
}
}
@@ -89,19 +87,16 @@ void LuaConsole::add(std::string line) {
size_t lmsg;
const char *msg = lua_tolstring(lua_state_, -1, &lmsg);
const char *tp = msg + lmsg - leof;
if (strstr(msg, eof) == tp) {
action_ = DO_NOTHING;
} else {
action_ = DO_SYNTAX;
syntax_ = msg;
if (strstr(msg, eof) != tp) {
words_.push_back("syntax");
words_.push_back(msg);
}
} else {
action_ = DO_LUA;
lua_expression_ = partial;
words_.push_back("lua");
words_.push_back(partial);
}
lua_settop(lua_state_, top);
if (action_ == DO_NOTHING) {
if (words_.empty()) {
prompt_ = ">> ";
}
}

View File

@@ -3,22 +3,26 @@
// LuaConsole:
//
// Used to parse commands that are being interactively typed
// in by a user.
// in by a user. The common usage pattern is:
//
// The command syntax is always a single character command,
// followed by arguments. Only two commands are hardwired:
// 1. Print the prompt suggested by 'get_prompt'.
// 2. Read a line of text from stdin.
// 3. Add the line to the LuaConsole using 'add'.
// 4. Get the command words using 'words'.
// 5. If the words are empty, do nothing.
// 6. If the words contain something, execute and call 'clear'.
//
// l - evaluate lua expression
// r - evaluate lua expression with 'return' prepended
// The 'words' returned by the luaconsole can be empty, meaning
// that there's no command to execute. If the words are nonempty,
// then the first word is the command. There are two hardwired
// commands:
//
// The console expects you to add lines of text one at a time.
// After adding a line, the console will recommend one of these
// actions:
// lua <expr> - execute a lua expression
// syntax <message> - print a syntax error message
//
// 1. DO_NOTHING: Add more lines of text.
// 2. DO_LUA: Evaluate a lua expression.
// 3. DO_OTHER: Execute a non-lua command.
// 4. DO_SYNTAX: Print a lua syntax error.
// If the first word is anything else, it means the user typed
// that word on the command line. It is up to you to interpret
// such commands.
//
//////////////////////////////////////////////////////
@@ -30,46 +34,34 @@
class LuaConsole {
public:
enum {
DO_NOTHING, // We need more input text.
DO_COMMAND, // We have a valid slash command.
DO_LUA, // We have a valid lua expression.
DO_SYNTAX, // We have a syntax error.
};
using StringVec = std::vector<std::string>;
private:
lua_State *lua_state_;
int action_;
std::string raw_input_;
int lines_;
std::string lua_expression_;
StringVec words_;
std::string syntax_;
std::string prompt_;
void split_words();
void clear_command();
public:
LuaConsole();
~LuaConsole();
// Get the recommended action.
int action() const { return action_; }
// Fetch the stored prompt. Also clears the stored prompt. You should fetch
// and print the prompt after 'add' or 'clear'.
std::string get_prompt();
// When action is DO_COMMAND, get the command words.
// Get the command words.
//
// Returns the empty vector if there is no command.
// If there is a command, the first word is the command word.
// See the file comment for certain built-in command words.
//
const StringVec &words() const { return words_; }
// When action is DO_LUA, get the valid lua expression.
std::string lua_expression() const { return lua_expression_; }
// When action is DO_SYNTAX, get the syntax error.
const std::string &syntax() const { return syntax_; }
// Add a line of text that was just read from the console.
// If more input is needed, stores the ">> " prompt.
void add(std::string line);

View File

@@ -28,6 +28,8 @@ private:
int64_t actor_id_;
int64_t printbuffer_line_;
void do_lua_command(const StringVec &cmd);
void do_syntax_command(const StringVec &cmd);
void do_view_command(const StringVec &cmd);
void do_menu_command(const StringVec &cmd);
void do_choose_command(const StringVec &cmd);
@@ -36,7 +38,6 @@ private:
void do_rollback_command(const StringVec &cmd);
void do_tick_command(const StringVec &cmd);
void do_lua(const std::string &exp);
void do_command(const StringVec &exp);
void check_redirects();
@@ -47,7 +48,25 @@ public:
virtual void event_update();
};
void TextGame::do_lua_command(const StringVec &words) {
assert(world_->stack_is_clear());
if (words.size() != 2) {
stdostream() << "lua command (lua) takes a single string" << std::endl;
return;
}
const std::string &exp = words[1];
InvocationData dummyresult;
Invocation inv(Invocation::KIND_LUA, actor_id_, actor_id_, exp, dummyresult);
world_->invoke(inv);
}
void TextGame::do_syntax_command(const StringVec &words) {
stdostream() << "Syntax Error: ";
for (int i = 1; i < int(words.size()); i++) {
stdostream() << words[i] << " ";
}
stdostream() << std::endl;
}
void TextGame::do_view_command(const StringVec &cmd) {
if (cmd.size() != 1) {
@@ -102,12 +121,6 @@ void TextGame::do_choose_command(const StringVec &cmd) {
world_->invoke(inv);
}
void TextGame::do_lua(const std::string &exp) {
assert(world_->stack_is_clear());
InvocationData dummyresult;
Invocation inv(Invocation::KIND_LUA, actor_id_, actor_id_, exp, dummyresult);
world_->invoke(inv);
}
void TextGame::do_snapshot_command(const StringVec &cmd) {
if (cmd.size() != 1) {
@@ -146,7 +159,9 @@ void TextGame::do_quit_command(const StringVec &cmd) {
}
void TextGame::do_command(const StringVec &words) {
if (words[0] == "v") do_view_command(words);
if (words[0] == "lua") do_lua_command(words);
else if (words[0] == "syntax") do_syntax_command(words);
else if (words[0] == "v") do_view_command(words);
else if (words[0] == "m") do_menu_command(words);
else if (words[0] == "q") do_quit_command(words);
else if (words[0] == "s") do_snapshot_command(words);
@@ -205,18 +220,11 @@ void TextGame::event_update()
std::string line = get_stdio_channel()->in()->readline();
if (line == "") break;
console_.add(line);
int action = console_.action();
if (action == LuaConsole::DO_LUA) {
do_lua(console_.lua_expression());
const StringVec &words = console_.words();
if (!words.empty()) {
do_command(words);
console_.clear();
channel_printbuffer();
} else if (action == LuaConsole::DO_COMMAND) {
do_command(console_.words());
console_.clear();
channel_printbuffer();
} else if (action == LuaConsole::DO_SYNTAX) {
stdostream() << console_.syntax() << std::endl;
console_.clear();
}
check_redirects();
if (actor_id_ == 0) {