Overhaul of command parsing
This commit is contained in:
@@ -35,6 +35,12 @@ bool Gui::has_action(const std::string &action) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Gui::get_action(int index) {
|
||||
if ((index < 0) || (index >= elts_.size())) {
|
||||
return "";
|
||||
}
|
||||
return elts_[index].action();
|
||||
}
|
||||
|
||||
LuaDefine(gui_menu_item, "c") {
|
||||
Gui *gui = Gui::fetch_global_pointer(L);
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
void clear() { elts_.clear(); }
|
||||
bool has_action(const std::string &action) const;
|
||||
void menu_item(const std::string &action, const std::string &label);
|
||||
std::string get_action(int index);
|
||||
|
||||
// Put a pointer to a gui into the lua registry.
|
||||
//
|
||||
|
||||
@@ -36,6 +36,9 @@ Invocation::Invocation() : kind_(KIND_INVALID), actor_(0), place_(0) {}
|
||||
Invocation::Invocation(Kind kind, int64_t actor, int64_t place, const std::string &action, const InvocationData &data)
|
||||
: kind_(kind), actor_(actor), place_(place), action_(action), data_(data) {}
|
||||
|
||||
Invocation::Invocation(Kind kind, int64_t actor, int64_t place, const std::string &action)
|
||||
: kind_(kind), actor_(actor), place_(place), action_(action) {}
|
||||
|
||||
void Invocation::serialize(StreamBuffer *sb) const {
|
||||
sb->write_uint8(kind_);
|
||||
sb->write_int64(actor_);
|
||||
|
||||
@@ -33,7 +33,9 @@ private:
|
||||
public:
|
||||
Invocation();
|
||||
Invocation(Kind kind, int64_t actor, int64_t place, const std::string &action, const InvocationData &data);
|
||||
|
||||
Invocation(Kind kind, int64_t actor, int64_t place, const std::string &action);
|
||||
|
||||
bool valid() const { return kind_ != KIND_INVALID; }
|
||||
Kind kind() const { return kind_; }
|
||||
int64_t actor() const { return actor_; }
|
||||
int64_t place() const { return place_; }
|
||||
|
||||
@@ -96,29 +96,14 @@ public:
|
||||
}
|
||||
|
||||
void do_lua_command(const StringVec &words) {
|
||||
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);
|
||||
send_invocation(inv);
|
||||
send_invocation(Invocation(Invocation::KIND_LUA, actor_id_, actor_id_, words[1]));
|
||||
}
|
||||
|
||||
void do_syntax_command(const StringVec &words) {
|
||||
stdostream() << "Syntax Error: ";
|
||||
for (int i = 1; i < int(words.size()); i++) {
|
||||
stdostream() << words[i] << " ";
|
||||
}
|
||||
stdostream() << std::endl;
|
||||
stdostream() << "Syntax Error: " << words[1] << std::endl;
|
||||
}
|
||||
|
||||
void do_view_command(const StringVec &cmd) {
|
||||
if (cmd.size() != 1) {
|
||||
stdostream() << "view command takes no arguments" << std::endl;
|
||||
return;
|
||||
}
|
||||
for (int64_t id : world_->get_near(actor_id_, 100, true)) {
|
||||
const Tangible *tan = world_->tangible_get(id);
|
||||
const AnimStep &aqback = tan->anim_queue_.back();
|
||||
@@ -127,18 +112,9 @@ public:
|
||||
}
|
||||
|
||||
void do_menu_command(const StringVec &cmd) {
|
||||
int64_t id;
|
||||
if (cmd.size() == 1) {
|
||||
id = actor_id_;
|
||||
} else if (cmd.size() == 2) {
|
||||
id = util::strtoint(cmd[1], -1);
|
||||
} else {
|
||||
stdostream() << "menu command expects a tangible ID or defaults to actor_id" << std::endl;
|
||||
return;
|
||||
}
|
||||
world_to_asynchronous();
|
||||
gui_place_ = id;
|
||||
world_->update_gui(actor_id_, id, &gui_);
|
||||
gui_place_ = util::strtoint(cmd[1], actor_id_);
|
||||
world_->update_gui(actor_id_, gui_place_, &gui_);
|
||||
int index = 0;
|
||||
for (const GuiElt &elt : gui_.elts()) {
|
||||
stdostream() << index << " " << elt.label() << std::endl;
|
||||
@@ -147,32 +123,17 @@ public:
|
||||
}
|
||||
|
||||
void do_choose_command(const StringVec &cmd) {
|
||||
int64_t index;
|
||||
if (cmd.size() == 1) {
|
||||
index = util::strtoint(cmd[0], -1);
|
||||
} else {
|
||||
stdostream() << "choose command consists of a single menu line number" << std::endl;
|
||||
std::string action = gui_.get_action(util::strtoint(cmd[1], -1));
|
||||
if (action == "") {
|
||||
stdostream() << "Invalid menu item #" << std::endl;
|
||||
return;
|
||||
}
|
||||
const Gui::EltVec &elts = gui_.elts();
|
||||
if ((index < 0) || (index >= int(elts.size()))) {
|
||||
stdostream() << "No menu item #" << index << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string action = elts[index].action();
|
||||
stdostream() << "Invoking plan: " << action << std::endl;
|
||||
InvocationData dummyresult;
|
||||
dummyresult["flavor"] = "chocolate";
|
||||
dummyresult["color"] = "blue";
|
||||
Invocation inv(Invocation::KIND_PLAN, actor_id_, gui_place_, action, dummyresult);
|
||||
Invocation inv(Invocation::KIND_PLAN, actor_id_, gui_place_, action);
|
||||
send_invocation(inv);
|
||||
}
|
||||
|
||||
void do_quit_command(const util::StringVec &words) {
|
||||
if (words.size() != 1) {
|
||||
stdostream() << "quit command takes no arguments" << std::endl;
|
||||
return;
|
||||
}
|
||||
abandon_server();
|
||||
stop_driver();
|
||||
}
|
||||
@@ -184,9 +145,9 @@ public:
|
||||
else if (words[0] == "view") do_view_command(words);
|
||||
else if (words[0] == "menu") do_menu_command(words);
|
||||
else if (words[0] == "quit") do_quit_command(words);
|
||||
else if (util::validinteger(words[0])) do_choose_command(words);
|
||||
else if (words[0] == "choose") do_choose_command(words);
|
||||
else {
|
||||
stdostream() << "Unknown command: " << words[0] << std::endl;
|
||||
stdostream() << "Unsupported command: " << words[0] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,29 +43,14 @@ public:
|
||||
}
|
||||
|
||||
void do_lua_command(const util::StringVec &words) {
|
||||
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, admin_id_, admin_id_, exp, dummyresult);
|
||||
master_->invoke(inv);
|
||||
master_->invoke(Invocation(Invocation::KIND_LUA, admin_id_, admin_id_, words[1]));
|
||||
}
|
||||
|
||||
void do_syntax_command(const util::StringVec &words) {
|
||||
stdostream() << "Syntax Error: ";
|
||||
for (int i = 1; i < int(words.size()); i++) {
|
||||
stdostream() << words[i] << " ";
|
||||
}
|
||||
stdostream() << std::endl;
|
||||
stdostream() << "Syntax Error: " << words[1] << std::endl;
|
||||
}
|
||||
|
||||
void do_quit_command(const util::StringVec &words) {
|
||||
if (words.size() != 1) {
|
||||
stdostream() << "quit command takes no arguments" << std::endl;
|
||||
return;
|
||||
}
|
||||
stop_driver();
|
||||
}
|
||||
|
||||
@@ -75,7 +60,7 @@ public:
|
||||
else if (words[0] == "syntax") do_syntax_command(words);
|
||||
else if (words[0] == "quit") do_quit_command(words);
|
||||
else {
|
||||
stdostream() << "Unknown command: " << words[0] << std::endl;
|
||||
stdostream() << "Unsupported command: " << words[0] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,65 @@ LuaConsole::StringVec LuaConsole::get_command() {
|
||||
return result;
|
||||
}
|
||||
|
||||
void LuaConsole::synerr(const std::string &msg) {
|
||||
words_.clear();
|
||||
words_.push_back("syntax");
|
||||
words_.push_back(msg);
|
||||
}
|
||||
|
||||
void LuaConsole::simplify(const StringVec &words) {
|
||||
words_ = words;
|
||||
if (words.size() == 0) {
|
||||
return;
|
||||
} else if (util::validinteger(words[0])) {
|
||||
if (words.size() == 1) {
|
||||
words_.clear();
|
||||
words_.push_back("choose");
|
||||
words_.push_back(words[0]);
|
||||
} else {
|
||||
synerr("/choose command takes no arguments");
|
||||
}
|
||||
} else if (words[0] == "choose") {
|
||||
if ((words.size() == 2)&&(util::validinteger(words[1]))) {
|
||||
// OK
|
||||
} else {
|
||||
synerr("/choose [menu-line-number]");
|
||||
}
|
||||
} else if (words[0] == "view") {
|
||||
if (words.size() != 1) {
|
||||
synerr("/view takes no arguments");
|
||||
}
|
||||
} else if (words[0] == "menu") {
|
||||
if (words.size() == 1) {
|
||||
words_.push_back("-");
|
||||
} else if ((words.size() == 2)&&(util::validinteger(words[1]))) {
|
||||
// OK
|
||||
} else {
|
||||
synerr("/menu [optional-tangible-id]");
|
||||
}
|
||||
} else if (words[0] == "quit") {
|
||||
if (words.size() != 1) {
|
||||
synerr("/quit takes no arguments");
|
||||
}
|
||||
} else if (words[0] == "snap") {
|
||||
if (words.size() != 1) {
|
||||
synerr("/snap takes no arguments");
|
||||
}
|
||||
} else if (words[0] == "roll") {
|
||||
if (words.size() != 1) {
|
||||
synerr("/roll takes no arguments");
|
||||
}
|
||||
} else if (words[0] == "tick") {
|
||||
if ((words.size() == 2)&&(util::validinteger(words[1]))) {
|
||||
// OK
|
||||
} else {
|
||||
synerr("/tick [optional-timestamp]");
|
||||
}
|
||||
} else {
|
||||
synerr("unrecognized command");
|
||||
}
|
||||
}
|
||||
|
||||
void LuaConsole::clear_raw_input() {
|
||||
raw_input_ = "";
|
||||
lines_ = 0;
|
||||
@@ -52,10 +111,11 @@ void LuaConsole::add(std::string line) {
|
||||
raw_input_ += '\n';
|
||||
lines_ += 1;
|
||||
prompt_ = ">> ";
|
||||
words_.clear();
|
||||
|
||||
// Try to interpret it as a slash-command.
|
||||
if ((lines_ == 1)&&(raw_input_[0] == '/')) {
|
||||
words_ = split_words(raw_input_.substr(1));
|
||||
simplify(split_words(raw_input_.substr(1)));
|
||||
clear_raw_input();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,23 +8,28 @@
|
||||
// 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 'get_command'.
|
||||
// 4. Get the command word using get_command.
|
||||
// 5. If the command is empty, do nothing.
|
||||
// 6. If the command is nonempty, execute it.
|
||||
// 6. If the command is nonempty, get the args and execute it.
|
||||
//
|
||||
// The LuaConsole expects you to type one of three things:
|
||||
// The LuaConsole expects you to type a lua command, or one
|
||||
// of the following slash-commands:
|
||||
//
|
||||
// * Valid Lua Code.
|
||||
// * Valid Lua Code preceded by '=' as shorthand for 'return'
|
||||
// * A slash-command.
|
||||
// /quit - exit the program
|
||||
// /view - display the nearby tangibles
|
||||
// /menu [tanid] - display the menu for tangible
|
||||
// /snap - snapshot current state
|
||||
// /roll - rollback to previous state
|
||||
// /tick [timevalue] - advance the simulation clock
|
||||
// /1234 - choose menu item 1234
|
||||
//
|
||||
// The 'get_command' returned by the luaconsole can be one of
|
||||
// the following:
|
||||
// If you type anything else, the LuaConsole will generate a
|
||||
// syntax error. Note that not all of the commands above are
|
||||
// supported in all interpreters.
|
||||
//
|
||||
// empty vector - still collecting input: do nothing.
|
||||
// lua <expr> - found a lua command: execute it as lua.
|
||||
// syntax <words> - detected a syntax error: print the error.
|
||||
// word word ... - read a slash-command: execute the command.
|
||||
// Once a command has been typed (or a syntax error has been
|
||||
// typed), the LuaConsole will return the command. The command
|
||||
// can be fetched using command(), int_arg(), and str_arg()
|
||||
//
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
@@ -42,10 +47,12 @@ private:
|
||||
lua_State *lua_state_;
|
||||
std::string raw_input_;
|
||||
int lines_;
|
||||
StringVec words_;
|
||||
std::string prompt_;
|
||||
StringVec words_;
|
||||
|
||||
void clear_raw_input();
|
||||
void simplify(const StringVec &words);
|
||||
void synerr(const std::string &msg);
|
||||
|
||||
public:
|
||||
LuaConsole();
|
||||
@@ -57,15 +64,14 @@ public:
|
||||
//
|
||||
const std::string &get_prompt() { return prompt_; }
|
||||
|
||||
// Fetch the command to execute.
|
||||
// Get the command words.
|
||||
//
|
||||
// Note that the command words may not be exactly what
|
||||
// the user typed. Typically, the LuaConsole simplifies
|
||||
// the command before returning it to the caller.
|
||||
//
|
||||
// You should fetch the command after calling 'add'.
|
||||
// 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.
|
||||
//
|
||||
StringVec get_command();
|
||||
|
||||
|
||||
// Add a line of text that was just read from the console.
|
||||
//
|
||||
void add(std::string line);
|
||||
|
||||
@@ -29,32 +29,15 @@ private:
|
||||
int64_t gui_place_;
|
||||
int64_t actor_id_;
|
||||
|
||||
|
||||
void 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);
|
||||
world_->invoke(Invocation(Invocation::KIND_LUA, actor_id_, actor_id_, words[1]));
|
||||
}
|
||||
|
||||
void do_syntax_command(const StringVec &words) {
|
||||
stdostream() << "Syntax Error: ";
|
||||
for (int i = 1; i < int(words.size()); i++) {
|
||||
stdostream() << words[i] << " ";
|
||||
}
|
||||
stdostream() << std::endl;
|
||||
stdostream() << "Syntax Error: " << words[1] << std::endl;
|
||||
}
|
||||
|
||||
void do_view_command(const StringVec &cmd) {
|
||||
if (cmd.size() != 1) {
|
||||
stdostream() << "v command (view) takes no arguments" << std::endl;
|
||||
return;
|
||||
}
|
||||
for (int64_t id : world_->get_near(actor_id_, 100, true)) {
|
||||
const Tangible *tan = world_->tangible_get(id);
|
||||
const AnimStep &aqback = tan->anim_queue_.back();
|
||||
@@ -63,17 +46,8 @@ private:
|
||||
}
|
||||
|
||||
void do_menu_command(const StringVec &cmd) {
|
||||
int64_t id;
|
||||
if (cmd.size() == 1) {
|
||||
id = actor_id_;
|
||||
} else if (cmd.size() == 2) {
|
||||
id = util::strtoint(cmd[1], -1);
|
||||
} else {
|
||||
stdostream() << "m command (menu) expects a tangible ID or defaults to actor_id" << std::endl;
|
||||
return;
|
||||
}
|
||||
gui_place_ = id;
|
||||
world_->update_gui(actor_id_, id, &gui_);
|
||||
gui_place_ = util::strtoint(cmd[1], actor_id_);
|
||||
world_->update_gui(actor_id_, gui_place_, &gui_);
|
||||
int index = 0;
|
||||
for (const GuiElt &elt : gui_.elts()) {
|
||||
stdostream() << index << " " << elt.label() << std::endl;
|
||||
@@ -82,60 +56,29 @@ private:
|
||||
}
|
||||
|
||||
void do_choose_command(const StringVec &cmd) {
|
||||
int64_t index;
|
||||
if (cmd.size() == 1) {
|
||||
index = util::strtoint(cmd[0], -1);
|
||||
} else {
|
||||
stdostream() << "c command (choose) expects a menu line number" << std::endl;
|
||||
std::string action = gui_.get_action(util::strtoint(cmd[1], -1));
|
||||
if (action == "") {
|
||||
stdostream() << "Invalid menu item #" << std::endl;
|
||||
return;
|
||||
}
|
||||
const Gui::EltVec &elts = gui_.elts();
|
||||
if ((index < 0) || (index >= int(elts.size()))) {
|
||||
stdostream() << "No menu item #" << index << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string action = elts[index].action();
|
||||
stdostream() << "Invoking plan: " << action << std::endl;
|
||||
InvocationData dummyresult;
|
||||
dummyresult["flavor"] = "chocolate";
|
||||
dummyresult["color"] = "blue";
|
||||
Invocation inv(Invocation::KIND_PLAN, actor_id_, gui_place_, action, dummyresult);
|
||||
Invocation inv(Invocation::KIND_PLAN, actor_id_, gui_place_, action);
|
||||
stdostream() << "Invoking: " << inv.debug_string() << std::endl;
|
||||
world_->invoke(inv);
|
||||
}
|
||||
|
||||
|
||||
void do_snapshot_command(const StringVec &cmd) {
|
||||
if (cmd.size() != 1) {
|
||||
stdostream() << "s command (snapshot) takes no arguments" << std::endl;
|
||||
return;
|
||||
}
|
||||
world_->snapshot();
|
||||
}
|
||||
|
||||
void do_rollback_command(const StringVec &cmd) {
|
||||
if (cmd.size() != 1) {
|
||||
stdostream() << "r command (rollback) takes no arguments" << std::endl;
|
||||
return;
|
||||
}
|
||||
world_->rollback();
|
||||
}
|
||||
|
||||
void do_tick_command(const StringVec &cmd) {
|
||||
int64_t clock;
|
||||
if (cmd.size() == 2) {
|
||||
clock = util::strtoint(cmd[1], -1);
|
||||
} else {
|
||||
stdostream() << "t command (tick) expects a time value" << std::endl;
|
||||
return;
|
||||
}
|
||||
world_->run_scheduled_threads(clock);
|
||||
world_->run_scheduled_threads(util::strtoint(cmd[1], -1));
|
||||
}
|
||||
|
||||
void do_quit_command(const StringVec &cmd) {
|
||||
if (cmd.size() != 1) {
|
||||
stdostream() << "q command (quit) takes no arguments" << std::endl;
|
||||
return;
|
||||
}
|
||||
actor_id_ = 0;
|
||||
}
|
||||
|
||||
@@ -149,9 +92,9 @@ private:
|
||||
else if (words[0] == "snap") do_snapshot_command(words);
|
||||
else if (words[0] == "roll") do_rollback_command(words);
|
||||
else if (words[0] == "tick") do_tick_command(words);
|
||||
else if (util::validinteger(words[0])) do_choose_command(words);
|
||||
else if (words[0] == "choose") do_choose_command(words);
|
||||
else {
|
||||
stdostream() << "Unknown command: " << words[0] << std::endl;
|
||||
stdostream() << "Unsupported command: " << words[0] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,16 @@ StringVec split(const std::string &s, char sep) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string join(const StringVec &strs, const std::string &sep) {
|
||||
if (strs.empty()) return "";
|
||||
std::ostringstream oss;
|
||||
oss << strs[0];
|
||||
for (int i = 1; i < strs.size(); i++) {
|
||||
oss << sep << strs[i];
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string repeat_string(const std::string &a, int n) {
|
||||
int len = a.size();
|
||||
std::string result(len * n, ' ');
|
||||
|
||||
@@ -63,6 +63,9 @@ std::string hash_to_hex(const HashValue &hash);
|
||||
// Split a string into multiple strings
|
||||
StringVec split(const std::string &s, char sep);
|
||||
|
||||
// Join multiple strings into one string
|
||||
std::string join(const StringVec &strs, std::string sep);
|
||||
|
||||
// Return N repetitions of string A
|
||||
std::string repeat_string(const std::string &a, int n);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user