23 #include <boost/algorithm/string.hpp> 49 void parse(
const std::string& str)
64 if (n <
args.size()) {
74 if (n <
args.size()) {
93 std::size_t first_space =
str_.find_first_of(
' ',
args.back());
94 std::size_t next_arg_begin =
str_.find_first_not_of(
' ', first_space);
95 if (next_arg_begin != std::string::npos) {
96 args.push_back(next_arg_begin);
104 mutable std::vector<std::size_t>
args;
121 template <
class Worker>
125 typedef void (Worker::*command_handler)();
132 explicit command(command_handler
h,
const std::string& help =
"",
133 const std::string& usage =
"",
const std::string& flags =
"")
134 : handler(h), help(help), usage(usage), flags(flags)
139 return flags.find(f) != flags.npos;
158 return command_map_.empty();
169 for (
int i = 0;
i < 100; ++
i) {
171 std::string actual_cmd = get_actual_cmd(
get_cmd());
176 cmd = actual_cmd + (data.empty() ?
"" :
" ") + data;
183 if (
const command*
c = get_command(
get_cmd())) {
184 if (is_enabled(*
c)) {
185 (
static_cast<Worker*
>(
this)->*(
c->handler))();
188 print(
get_cmd(),
_(
"This command is currently unavailable."));
191 else if (help_on_unknown_) {
194 symbols[
"help_command"] = cmd_prefix_ +
"help";
195 symbols[
"command"] = cmd_prefix_ +
get_cmd();
198 symbols[
"help_command"] =
"help";
199 symbols[
"command"] =
get_cmd();
201 std::string string_user =
get_cmd();
205 bool has_command_proposal =
false;
207 for(
const auto& [key,
index] : command_map_) {
209 if(is_enabled(
index)) {
211 len_min = std::min(string_user.length(), key.length());
215 if(distance * 100 / len_min < 34) {
216 symbols[
"command_proposal"] = key;
217 has_command_proposal =
true;
224 if(has_command_proposal) {
225 print(
"help",
VGETTEXT(
"Unknown command '$command', did you mean '$command_proposal'? try $help_command " 226 "for a list of available commands.", symbols));
229 print(
"help",
VGETTEXT(
"Unknown command '$command', try $help_command " 230 "for a list of available commands.", symbols));
237 std::vector<std::string> res;
238 for (
typename command_map::value_type
i : command_map_) {
239 res.push_back(
i.first);
252 _(
"Available commands list and command-specific help. " 253 "Use \"help all\" to include currently unavailable commands."),
257 _(
"[all|<command>]\n“all” = overview of all commands, <command> = name of a specific command (provides more detail)"));
260 virtual void init_map() = 0;
262 virtual void print(
const std::string& title,
const std::string& message) = 0;
282 cap_.parse(cmd_string);
285 virtual std::string
get_arg(
unsigned argn)
const 287 return cap_.get_arg(argn);
290 virtual std::string
get_data(
unsigned argn = 1)
const 292 return cap_.get_data(argn);
296 return cap_.get_cmd();
301 symbols[
"arg_id"] = std::to_string(argn);
302 command_failed(
VGETTEXT(
"Missing argument $arg_id", symbols));
311 command_alias_map::const_iterator
i = command_alias_map_.find(cmd);
312 return i != command_alias_map_.end() ? i->second : cmd;
316 typename command_map::const_iterator
i = command_map_.find(cmd);
317 return i != command_map_.end() ? &i->second : 0;
322 return i != command_map_.end() ? &i->second : 0;
327 if (help_command(
get_arg(1))) {
330 std::stringstream ss;
331 bool show_unavail = show_unavailable_ ||
get_arg(1) ==
"all";
332 for (
typename command_map::value_type
i : command_map_) {
333 if (show_unavail || is_enabled(
i.second)) {
340 if (!
i.second.flags.empty()) {
341 ss <<
" (" <<
i.second.flags <<
") ";
347 symbols[
"flags_description"] = get_flags_description();
348 symbols[
"list_of_commands"] = ss.str();
350 symbols[
"help_command"] = cmd_prefix_ +
"help";
353 symbols[
"help_command"] =
"help";
355 print(
_(
"help"),
VGETTEXT(
"Available commands $flags_description:\n$list_of_commands", symbols));
356 print(
_(
"help"),
VGETTEXT(
"Type $help_command <command> for more info.", symbols));
361 std::string cmd = get_actual_cmd(acmd);
362 const command*
c = get_command(cmd);
364 std::stringstream ss;
366 ss << cmd_prefix_ << cmd;
371 if (c->help.empty() && c->usage.empty()) {
372 ss <<
_(
" No help available.");
375 ss <<
" - " << c->help <<
"\n";
377 if (!c->usage.empty()) {
379 ss <<
_(
"Usage:") <<
" " << cmd_prefix_ << cmd <<
" " << c->usage <<
"\n";
382 ss <<
_(
"Usage:") <<
" " << cmd <<
" " << c->usage <<
"\n";
385 const auto flags_description = get_command_flags_description(*c);
386 if (!flags_description.empty()) {
388 ss <<
_(
"Notes:") <<
" " << get_command_flags_description(*c) <<
"\n";
390 const std::vector<std::string> l = get_aliases(cmd);
394 ss <<
_n(
"command^Alias:",
"Aliases:", l.size()) <<
" " <<
utils::join(l,
" ") <<
"\n";
396 print(
_(
"help"), ss.str());
405 help_on_unknown_ = value;
420 command_handler
h,
const std::string&
help =
"",
421 const std::string& usage =
"",
const std::string& flags =
"")
423 command
c = command(h,
help, usage, flags);
424 std::pair<typename command_map::iterator, bool> r;
425 r = command_map_.insert(
typename command_map::value_type(cmd, c));
432 const std::string& cmd)
434 command_alias_map_[cmd] = to_cmd;
438 static const std::vector<std::string>
get_aliases(
const std::string& cmd)
440 std::vector<std::string> aliases;
441 typedef command_alias_map::value_type
p;
442 for (p
i : command_alias_map_) {
443 if (
i.second == cmd) {
444 aliases.push_back(
i.first);
450 static inline command_map command_map_ {};
451 static inline command_alias_map command_alias_map_ {};
452 static inline bool help_on_unknown_ =
true;
453 static inline bool show_unavailable_ =
false;
454 static inline std::string cmd_prefix_ {};
455 static inline bool cmd_flag_ =
false;
void command_failed(const std::string &message, bool=false)
std::string get_arg(unsigned n) const
void parse(const std::string &str)
static std::string _n(const char *str1, const char *str2, int n)
std::map< std::string, t_string > string_map
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
virtual std::string get_data(unsigned argn=1) const
std::vector< std::string > get_commands_list() const
cmd_arg_parser & operator=(const cmd_arg_parser &)
static void set_cmd_prefix(const std::string &value)
std::string get_data(unsigned n) const
virtual std::string get_cmd() const
virtual std::string get_arg(unsigned argn) const
static std::string _(const char *str)
Definitions for the interface to Wesnoth Markup Language (WML).
const std::string & get_str() const
cmd_arg_parser(const std::string &str)
void dispatch(std::string cmd)
void advance_to_arg(unsigned n) const
virtual void register_alias(const std::string &to_cmd, const std::string &cmd)
virtual bool is_enabled(const command &) const
const command * get_command(const std::string &cmd) const
virtual std::string get_flags_description() const
std::vector< std::size_t > args
virtual std::string get_command_flags_description(const command &) const
command & add_flag(const char f)
std::map< std::string, std::string > command_alias_map
static void print(std::stringstream &sstr, const std::string &queue, const std::string &id)
std::map< std::string, command > command_map
command * get_command(const std::string &cmd)
static const std::vector< std::string > get_aliases(const std::string &cmd)
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Handling of system events.
static void set_help_on_unknown(bool value)
bool has_flag(const char f) const
void trim(std::string_view &s)
bool help_command(const std::string &acmd)
virtual void parse_cmd(const std::string &cmd_string)
virtual void register_command(const std::string &cmd, command_handler h, const std::string &help="", const std::string &usage="", const std::string &flags="")
std::string get_cmd() const
static void set_cmd_flag(bool value)
static map_location::DIRECTION n
std::string::const_iterator iterator
virtual ~map_command_handler()
std::string get_actual_cmd(const std::string &cmd) const
command(command_handler h, const std::string &help="", const std::string &usage="", const std::string &flags="")
void command_failed_need_arg(int argn)