Merge pull request #6614

fb31167b1 Wallet, daemon: From 'help_advanced' back to 'help', and new 'apropos' command (rbrunner7)
This commit is contained in:
Alexander Blair 2020-08-16 12:44:03 -07:00
commit c6c4ead44e
No known key found for this signature in database
GPG Key ID: C64552D877C32479
7 changed files with 135 additions and 49 deletions

View File

@ -543,6 +543,31 @@ eof:
return it->second.second; return it->second.second;
} }
std::vector<std::string> get_command_list(const std::vector<std::string>& keywords = std::vector<std::string>())
{
std::vector<std::string> list;
list.reserve(m_command_handlers.size());
for(auto const& x:m_command_handlers)
{
bool take = true;
for(auto const& y:keywords)
{
bool in_usage = x.second.second.first.find(y) != std::string::npos;
bool in_description = x.second.second.second.find(y) != std::string::npos;
if (!(in_usage || in_description))
{
take = false;
break;
}
}
if (take)
{
list.push_back(x.first);
}
}
return list;
}
void set_handler(const std::string& cmd, const callback& hndlr, const std::string& usage = "", const std::string& description = "") void set_handler(const std::string& cmd, const callback& hndlr, const std::string& usage = "", const std::string& description = "")
{ {
lookup::mapped_type & vt = m_command_handlers[cmd]; lookup::mapped_type & vt = m_command_handlers[cmd];

View File

@ -1685,9 +1685,8 @@ namespace cryptonote
<< "You can set the level of process detailization through \"set_log <level|categories>\" command," << ENDL << "You can set the level of process detailization through \"set_log <level|categories>\" command," << ENDL
<< "where <level> is between 0 (no details) and 4 (very verbose), or custom category based levels (eg, *:WARNING)." << ENDL << "where <level> is between 0 (no details) and 4 (very verbose), or custom category based levels (eg, *:WARNING)." << ENDL
<< ENDL << ENDL
<< "Use the \"help\" command to see a simplified list of available commands." << ENDL << "Use the \"help\" command to see the list of available commands." << ENDL
<< "Use the \"help_advanced\" command to see an advanced list of available commands." << ENDL << "Use \"help <command>\" to see a command's documentation." << ENDL
<< "Use \"help_advanced <command>\" to see a command's documentation." << ENDL
<< "**********************************************************************" << ENDL); << "**********************************************************************" << ENDL);
m_starter_message_showed = true; m_starter_message_showed = true;
} }

View File

@ -2347,8 +2347,7 @@ skip:
MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
<< "You are now synchronized with the network. You may now start monero-wallet-cli." << ENDL << "You are now synchronized with the network. You may now start monero-wallet-cli." << ENDL
<< ENDL << ENDL
<< "Use the \"help\" command to see a simplified list of available commands." << ENDL << "Use the \"help\" command to see the list of available commands." << ENDL
<< "Use the \"help_advanced\" command to see an advanced list of available commands." << ENDL
<< "**********************************************************************"); << "**********************************************************************");
m_sync_timer.pause(); m_sync_timer.pause();
if (ELPP->vRegistry()->allowed(el::Level::Info, "sync-info")) if (ELPP->vRegistry()->allowed(el::Level::Info, "sync-info"))

View File

@ -57,6 +57,12 @@ t_command_server::t_command_server(
, "help [<command>]" , "help [<command>]"
, "Show the help section or the documentation about a <command>." , "Show the help section or the documentation about a <command>."
); );
m_command_lookup.set_handler(
"apropos"
, std::bind(&t_command_server::apropos, this, p::_1)
, "apropos <keyword> [<keyword> ...]"
, "Search all command descriptions for keyword(s)."
);
m_command_lookup.set_handler( m_command_lookup.set_handler(
"print_height" "print_height"
, std::bind(&t_command_parser_executor::print_height, &m_parser, p::_1) , std::bind(&t_command_parser_executor::print_height, &m_parser, p::_1)
@ -349,7 +355,7 @@ bool t_command_server::start_handling(std::function<void(void)> exit_handler)
{ {
if (m_is_rpc) return false; if (m_is_rpc) return false;
m_command_lookup.start_handling("", get_commands_str(), exit_handler); m_command_lookup.start_handling("", "Use \"help\" to list all commands and their usage\n", exit_handler);
return true; return true;
} }
@ -374,6 +380,33 @@ bool t_command_server::help(const std::vector<std::string>& args)
return true; return true;
} }
bool t_command_server::apropos(const std::vector<std::string>& args)
{
if (args.empty())
{
std::cout << "Missing keyword" << std::endl;
return true;
}
const std::vector<std::string>& command_list = m_command_lookup.get_command_list(args);
if (command_list.empty())
{
std::cout << "Nothing found" << std::endl;
return true;
}
std::cout << std::endl;
for(auto const& command:command_list)
{
std::vector<std::string> cmd;
cmd.push_back(command);
std::pair<std::string, std::string> documentation = m_command_lookup.get_documentation(cmd);
std::cout << " " << documentation.first << std::endl;
}
std::cout << std::endl;
return true;
}
std::string t_command_server::get_commands_str() std::string t_command_server::get_commands_str()
{ {
std::stringstream ss; std::stringstream ss;
@ -382,7 +415,7 @@ std::string t_command_server::get_commands_str()
std::string usage = m_command_lookup.get_usage(); std::string usage = m_command_lookup.get_usage();
boost::replace_all(usage, "\n", "\n "); boost::replace_all(usage, "\n", "\n ");
usage.insert(0, " "); usage.insert(0, " ");
ss << usage << std::endl; ss << usage;
return ss.str(); return ss.str();
} }

View File

@ -73,6 +73,7 @@ public:
private: private:
bool help(const std::vector<std::string>& args); bool help(const std::vector<std::string>& args);
bool apropos(const std::vector<std::string>& args);
std::string get_commands_str(); std::string get_commands_str();
std::string get_command_usage(const std::vector<std::string> &args); std::string get_command_usage(const std::vector<std::string> &args);

View File

@ -128,7 +128,7 @@ typedef cryptonote::simple_wallet sw;
#define SCOPED_WALLET_UNLOCK() SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return true;) #define SCOPED_WALLET_UNLOCK() SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return true;)
#define PRINT_USAGE(usage_help_advanced) fail_msg_writer() << boost::format(tr("usage: %s")) % usage_help_advanced; #define PRINT_USAGE(usage_help) fail_msg_writer() << boost::format(tr("usage: %s")) % usage_help;
#define LONG_PAYMENT_ID_SUPPORT_CHECK() \ #define LONG_PAYMENT_ID_SUPPORT_CHECK() \
do { \ do { \
@ -279,8 +279,8 @@ namespace
const char* USAGE_STOP_MINING_FOR_RPC("stop_mining_for_rpc"); const char* USAGE_STOP_MINING_FOR_RPC("stop_mining_for_rpc");
const char* USAGE_SHOW_QR_CODE("show_qr_code [<subaddress_index>]"); const char* USAGE_SHOW_QR_CODE("show_qr_code [<subaddress_index>]");
const char* USAGE_VERSION("version"); const char* USAGE_VERSION("version");
const char* USAGE_HELP_ADVANCED("help_advanced [<command>]"); const char* USAGE_HELP("help [<command> | all]");
const char* USAGE_HELP("help"); const char* USAGE_APROPOS("apropos <keyword> [<keyword> ...]");
std::string input_line(const std::string& prompt, bool yesno = false) std::string input_line(const std::string& prompt, bool yesno = false)
{ {
@ -2317,7 +2317,7 @@ bool simple_wallet::on_unknown_command(const std::vector<std::string> &args)
{ {
if (args[0] == "exit" || args[0] == "q") // backward compat if (args[0] == "exit" || args[0] == "q") // backward compat
return false; return false;
fail_msg_writer() << boost::format(tr("Unknown command '%s', try 'help_advanced'")) % args.front(); fail_msg_writer() << boost::format(tr("Unknown command '%s', try 'help'")) % args.front();
return true; return true;
} }
@ -3102,14 +3102,20 @@ bool simple_wallet::set_export_format(const std::vector<std::string> &args/* = s
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/) bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{ {
if(args.empty())
{
message_writer() << ""; message_writer() << "";
message_writer() << tr("Commands:"); message_writer() << tr("Important commands:");
message_writer() << ""; message_writer() << "";
message_writer() << tr("\"welcome\" - Read welcome message."); message_writer() << tr("\"welcome\" - Show welcome message.");
message_writer() << tr("\"donate <amount>\" - Donate XMR to the development team."); message_writer() << tr("\"help all\" - Show the list of all available commands.");
message_writer() << tr("\"help <command>\" - Show a command's documentation.");
message_writer() << tr("\"apropos <keyword>\" - Show commands related to a keyword.");
message_writer() << "";
message_writer() << tr("\"wallet_info\" - Show wallet main address and other info.");
message_writer() << tr("\"balance\" - Show balance."); message_writer() << tr("\"balance\" - Show balance.");
message_writer() << tr("\"address new\" - Create new subaddress.");
message_writer() << tr("\"address all\" - Show all addresses."); message_writer() << tr("\"address all\" - Show all addresses.");
message_writer() << tr("\"address new\" - Create new subaddress.");
message_writer() << tr("\"transfer <address> <amount>\" - Send XMR to an address."); message_writer() << tr("\"transfer <address> <amount>\" - Send XMR to an address.");
message_writer() << tr("\"show_transfers [in|out|pending|failed|pool]\" - Show transactions."); message_writer() << tr("\"show_transfers [in|out|pending|failed|pool]\" - Show transactions.");
message_writer() << tr("\"sweep_all <address>\" - Send whole balance to another wallet."); message_writer() << tr("\"sweep_all <address>\" - Send whole balance to another wallet.");
@ -3117,22 +3123,18 @@ bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<st
message_writer() << tr("\"refresh\" - Synchronize wallet with the Monero network."); message_writer() << tr("\"refresh\" - Synchronize wallet with the Monero network.");
message_writer() << tr("\"status\" - Check current status of wallet."); message_writer() << tr("\"status\" - Check current status of wallet.");
message_writer() << tr("\"version\" - Check software version."); message_writer() << tr("\"version\" - Check software version.");
message_writer() << tr("\"help_advanced\" - Show list with more available commands.");
message_writer() << tr("\"save\" - Save wallet.");
message_writer() << tr("\"exit\" - Exit wallet."); message_writer() << tr("\"exit\" - Exit wallet.");
message_writer() << ""; message_writer() << "";
return true; message_writer() << tr("\"donate <amount>\" - Donate XMR to the development team.");
} message_writer() << "";
}
bool simple_wallet::help_advanced(const std::vector<std::string> &args/* = std::vector<std::string>()*/) else if ((args.size() == 1) && (args.front() == "all"))
{
if(args.empty())
{ {
success_msg_writer() << get_commands_str(); success_msg_writer() << get_commands_str();
} }
else if ((args.size() == 2) && (args.front() == "mms")) else if ((args.size() == 2) && (args.front() == "mms"))
{ {
// Little hack to be able to do "help_advanced mms <subcommand>" // Little hack to be able to do "help mms <subcommand>"
std::vector<std::string> mms_args(1, args.front() + " " + args.back()); std::vector<std::string> mms_args(1, args.front() + " " + args.back());
success_msg_writer() << get_command_usage(mms_args); success_msg_writer() << get_command_usage(mms_args);
} }
@ -3143,6 +3145,33 @@ bool simple_wallet::help_advanced(const std::vector<std::string> &args/* = std::
return true; return true;
} }
bool simple_wallet::apropos(const std::vector<std::string> &args)
{
if (args.empty())
{
PRINT_USAGE(USAGE_APROPOS);
return true;
}
const std::vector<std::string>& command_list = m_cmd_binder.get_command_list(args);
if (command_list.empty())
{
fail_msg_writer() << tr("No commands found mentioning keyword(s)");
return true;
}
success_msg_writer() << "";
for(auto const& command:command_list)
{
std::vector<std::string> cmd;
cmd.push_back(command);
std::pair<std::string, std::string> documentation = m_cmd_binder.get_documentation(cmd);
success_msg_writer() << " " << documentation.first;
}
success_msg_writer() << "";
return true;
}
simple_wallet::simple_wallet() simple_wallet::simple_wallet()
: m_allow_mismatched_daemon_version(false) : m_allow_mismatched_daemon_version(false)
, m_refresh_progress_reporter(*this) , m_refresh_progress_reporter(*this)
@ -3526,7 +3555,7 @@ simple_wallet::simple_wallet()
"<subcommand> is one of:\n" "<subcommand> is one of:\n"
" init, info, signer, list, next, sync, transfer, delete, send, receive, export, note, show, set, help\n" " init, info, signer, list, next, sync, transfer, delete, send, receive, export, note, show, set, help\n"
" send_signer_config, start_auto_config, stop_auto_config, auto_config, config_checksum\n" " send_signer_config, start_auto_config, stop_auto_config, auto_config, config_checksum\n"
"Get help about a subcommand with: help_advanced mms <subcommand>")); "Get help about a subcommand with: help mms <subcommand>, or help mms <subcommand>"));
m_cmd_binder.set_handler("mms init", m_cmd_binder.set_handler("mms init",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1), boost::bind(&simple_wallet::on_command, this, &simple_wallet::mms, _1),
tr(USAGE_MMS_INIT), tr(USAGE_MMS_INIT),
@ -3684,14 +3713,14 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::on_command, this, &simple_wallet::show_qr_code, _1), boost::bind(&simple_wallet::on_command, this, &simple_wallet::show_qr_code, _1),
tr(USAGE_SHOW_QR_CODE), tr(USAGE_SHOW_QR_CODE),
tr("Show address as QR code")); tr("Show address as QR code"));
m_cmd_binder.set_handler("help_advanced",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::help_advanced, _1),
tr(USAGE_HELP_ADVANCED),
tr("Show the help section or the documentation about a <command>."));
m_cmd_binder.set_handler("help", m_cmd_binder.set_handler("help",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::help, _1), boost::bind(&simple_wallet::on_command, this, &simple_wallet::help, _1),
tr(USAGE_HELP), tr(USAGE_HELP),
tr("Show simplified list of available commands.")); tr("Show the help section or the documentation about a <command>."));
m_cmd_binder.set_handler("apropos",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::apropos, _1),
tr(USAGE_APROPOS),
tr("Search all command descriptions for keyword(s)"));
m_cmd_binder.set_unknown_command_handler(boost::bind(&simple_wallet::on_command, this, &simple_wallet::on_unknown_command, _1)); m_cmd_binder.set_unknown_command_handler(boost::bind(&simple_wallet::on_command, this, &simple_wallet::on_unknown_command, _1));
m_cmd_binder.set_empty_command_handler(boost::bind(&simple_wallet::on_empty_command, this)); m_cmd_binder.set_empty_command_handler(boost::bind(&simple_wallet::on_empty_command, this));
m_cmd_binder.set_cancel_handler(boost::bind(&simple_wallet::on_cancelled_command, this)); m_cmd_binder.set_cancel_handler(boost::bind(&simple_wallet::on_cancelled_command, this));
@ -4844,8 +4873,8 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
tr("Your wallet has been generated!\n" tr("Your wallet has been generated!\n"
"To start synchronizing with the daemon, use the \"refresh\" command.\n" "To start synchronizing with the daemon, use the \"refresh\" command.\n"
"Use the \"help\" command to see a simplified list of available commands.\n" "Use the \"help\" command to see a simplified list of available commands.\n"
"Use the \"help_advanced\" command to see an advanced list of available commands.\n" "Use \"help all\" command to see the list of all available commands.\n"
"Use \"help_advanced <command>\" to see a command's documentation.\n" "Use \"help <command>\" to see a command's documentation.\n"
"Always use the \"exit\" command when closing monero-wallet-cli to save \n" "Always use the \"exit\" command when closing monero-wallet-cli to save \n"
"your current session's state. Otherwise, you might need to synchronize \n" "your current session's state. Otherwise, you might need to synchronize \n"
"your wallet again (your wallet keys are NOT at risk in any case).\n") "your wallet again (your wallet keys are NOT at risk in any case).\n")
@ -5105,8 +5134,8 @@ boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::p
success_msg_writer() << success_msg_writer() <<
"**********************************************************************\n" << "**********************************************************************\n" <<
tr("Use the \"help\" command to see a simplified list of available commands.\n") << tr("Use the \"help\" command to see a simplified list of available commands.\n") <<
tr("Use the \"help_advanced\" command to see an advanced list of available commands.\n") << tr("Use \"help all\" to see the list of all available commands.\n") <<
tr("Use \"help_advanced <command>\" to see a command's documentation.\n") << tr("Use \"help <command>\" to see a command's documentation.\n") <<
"**********************************************************************"; "**********************************************************************";
return password; return password;
} }
@ -6321,7 +6350,7 @@ void simple_wallet::check_for_inactivity_lock(bool user)
m_in_command = true; m_in_command = true;
if (!user) if (!user)
{ {
const std::string speech = tr("I locked your Monero wallet to protect you while you were away\nsee \"help_advanced set\" to configure/disable"); const std::string speech = tr("I locked your Monero wallet to protect you while you were away\nsee \"help set\" to configure/disable");
std::vector<std::pair<std::string, size_t>> lines = tools::split_string_by_width(speech, 45); std::vector<std::pair<std::string, size_t>> lines = tools::split_string_by_width(speech, 45);
size_t max_len = 0; size_t max_len = 0;
@ -11206,7 +11235,7 @@ void simple_wallet::mms_help(const std::vector<std::string> &args)
{ {
if (args.size() > 1) if (args.size() > 1)
{ {
fail_msg_writer() << tr("Usage: help_advanced mms [<subcommand>]"); fail_msg_writer() << tr("Usage: help mms [<subcommand>]");
return; return;
} }
std::vector<std::string> help_args; std::vector<std::string> help_args;

View File

@ -154,8 +154,8 @@ namespace cryptonote
bool set_persistent_rpc_client_id(const std::vector<std::string> &args = std::vector<std::string>()); bool set_persistent_rpc_client_id(const std::vector<std::string> &args = std::vector<std::string>());
bool set_auto_mine_for_rpc_payment_threshold(const std::vector<std::string> &args = std::vector<std::string>()); bool set_auto_mine_for_rpc_payment_threshold(const std::vector<std::string> &args = std::vector<std::string>());
bool set_credits_target(const std::vector<std::string> &args = std::vector<std::string>()); bool set_credits_target(const std::vector<std::string> &args = std::vector<std::string>());
bool help_advanced(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>()); bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool apropos(const std::vector<std::string> &args);
bool start_mining(const std::vector<std::string> &args); bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args); bool stop_mining(const std::vector<std::string> &args);
bool set_daemon(const std::vector<std::string> &args); bool set_daemon(const std::vector<std::string> &args);