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"); 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) { void do_command(const util::StringVec &words) {
stdostream() << "Command: "; stdostream() << "Command: ";
for (const std::string &word : words) { for (const std::string &word : words) {
@@ -46,27 +42,17 @@ public:
stdostream() << std::endl; 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() { virtual void event_update() {
// Check for keyboard input on stdin. // Check for keyboard input on stdin.
while (true) { while (true) {
std::string line = get_stdio_channel()->in()->readline(); std::string line = get_stdio_channel()->in()->readline();
if (line == "") break; 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()); get_stdio_channel()->out()->write_bytes(console_.get_prompt());
} }

View File

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

View File

@@ -3,22 +3,26 @@
// LuaConsole: // LuaConsole:
// //
// Used to parse commands that are being interactively typed // 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, // 1. Print the prompt suggested by 'get_prompt'.
// followed by arguments. Only two commands are hardwired: // 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 // The 'words' returned by the luaconsole can be empty, meaning
// r - evaluate lua expression with 'return' prepended // 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. // lua <expr> - execute a lua expression
// After adding a line, the console will recommend one of these // syntax <message> - print a syntax error message
// actions:
// //
// 1. DO_NOTHING: Add more lines of text. // If the first word is anything else, it means the user typed
// 2. DO_LUA: Evaluate a lua expression. // that word on the command line. It is up to you to interpret
// 3. DO_OTHER: Execute a non-lua command. // such commands.
// 4. DO_SYNTAX: Print a lua syntax error.
// //
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
@@ -30,46 +34,34 @@
class LuaConsole { class LuaConsole {
public: 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>; using StringVec = std::vector<std::string>;
private: private:
lua_State *lua_state_; lua_State *lua_state_;
int action_;
std::string raw_input_; std::string raw_input_;
int lines_; int lines_;
std::string lua_expression_;
StringVec words_; StringVec words_;
std::string syntax_;
std::string prompt_; std::string prompt_;
void split_words(); void split_words();
void clear_command();
public: public:
LuaConsole(); LuaConsole();
~LuaConsole(); ~LuaConsole();
// Get the recommended action.
int action() const { return action_; }
// Fetch the stored prompt. Also clears the stored prompt. You should fetch // Fetch the stored prompt. Also clears the stored prompt. You should fetch
// and print the prompt after 'add' or 'clear'. // and print the prompt after 'add' or 'clear'.
std::string get_prompt(); 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_; } 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. // Add a line of text that was just read from the console.
// If more input is needed, stores the ">> " prompt. // If more input is needed, stores the ">> " prompt.
void add(std::string line); void add(std::string line);

View File

@@ -28,6 +28,8 @@ private:
int64_t actor_id_; int64_t actor_id_;
int64_t printbuffer_line_; 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_view_command(const StringVec &cmd);
void do_menu_command(const StringVec &cmd); void do_menu_command(const StringVec &cmd);
void do_choose_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_rollback_command(const StringVec &cmd);
void do_tick_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 do_command(const StringVec &exp);
void check_redirects(); void check_redirects();
@@ -47,7 +48,25 @@ public:
virtual void event_update(); 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) { void TextGame::do_view_command(const StringVec &cmd) {
if (cmd.size() != 1) { if (cmd.size() != 1) {
@@ -102,12 +121,6 @@ void TextGame::do_choose_command(const StringVec &cmd) {
world_->invoke(inv); 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) { void TextGame::do_snapshot_command(const StringVec &cmd) {
if (cmd.size() != 1) { if (cmd.size() != 1) {
@@ -146,7 +159,9 @@ void TextGame::do_quit_command(const StringVec &cmd) {
} }
void TextGame::do_command(const StringVec &words) { 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] == "m") do_menu_command(words);
else if (words[0] == "q") do_quit_command(words); else if (words[0] == "q") do_quit_command(words);
else if (words[0] == "s") do_snapshot_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(); std::string line = get_stdio_channel()->in()->readline();
if (line == "") break; if (line == "") break;
console_.add(line); console_.add(line);
int action = console_.action(); const StringVec &words = console_.words();
if (action == LuaConsole::DO_LUA) { if (!words.empty()) {
do_lua(console_.lua_expression()); do_command(words);
console_.clear(); console_.clear();
channel_printbuffer(); 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(); check_redirects();
if (actor_id_ == 0) { if (actor_id_ == 0) {