Make '--help' do the same as 'help' (i.e. show a manpage)
This commit is contained in:
parent
488a826842
commit
b159d23800
7 changed files with 17 additions and 164 deletions
|
@ -96,41 +96,6 @@ void Args::parseCmdline(const Strings & _cmdline)
|
|||
processArgs(pendingArgs, true);
|
||||
}
|
||||
|
||||
void Args::printHelp(const string & programName, std::ostream & out)
|
||||
{
|
||||
std::cout << fmt(ANSI_BOLD "Usage:" ANSI_NORMAL " %s " ANSI_ITALIC "FLAGS..." ANSI_NORMAL, programName);
|
||||
for (auto & exp : expectedArgs) {
|
||||
std::cout << renderLabels({exp.label});
|
||||
// FIXME: handle arity > 1
|
||||
if (exp.handler.arity == ArityAny) std::cout << "...";
|
||||
if (exp.optional) std::cout << "?";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
auto s = description();
|
||||
if (s != "")
|
||||
std::cout << "\n" ANSI_BOLD "Summary:" ANSI_NORMAL " " << s << ".\n";
|
||||
|
||||
if (longFlags.size()) {
|
||||
std::cout << "\n";
|
||||
std::cout << ANSI_BOLD "Flags:" ANSI_NORMAL "\n";
|
||||
printFlags(out);
|
||||
}
|
||||
}
|
||||
|
||||
void Args::printFlags(std::ostream & out)
|
||||
{
|
||||
Table2 table;
|
||||
for (auto & flag : longFlags) {
|
||||
if (hiddenCategories.count(flag.second->category)) continue;
|
||||
table.push_back(std::make_pair(
|
||||
(flag.second->shortName ? std::string("-") + flag.second->shortName + ", " : " ")
|
||||
+ "--" + flag.first + renderLabels(flag.second->labels),
|
||||
flag.second->description));
|
||||
}
|
||||
printTable(out, table);
|
||||
}
|
||||
|
||||
bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||
{
|
||||
assert(pos != end);
|
||||
|
@ -331,28 +296,6 @@ Strings argvToStrings(int argc, char * * argv)
|
|||
return args;
|
||||
}
|
||||
|
||||
std::string renderLabels(const Strings & labels)
|
||||
{
|
||||
std::string res;
|
||||
for (auto label : labels) {
|
||||
for (auto & c : label) c = std::toupper(c);
|
||||
res += " " ANSI_ITALIC + label + ANSI_NORMAL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void printTable(std::ostream & out, const Table2 & table)
|
||||
{
|
||||
size_t max = 0;
|
||||
for (auto & row : table)
|
||||
max = std::max(max, filterANSIEscapes(row.first, true).size());
|
||||
for (auto & row : table) {
|
||||
out << " " << row.first
|
||||
<< std::string(max - filterANSIEscapes(row.first, true).size() + 2, ' ')
|
||||
<< row.second << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
MultiCommand::MultiCommand(const Commands & commands)
|
||||
: commands(commands)
|
||||
{
|
||||
|
@ -376,38 +319,6 @@ MultiCommand::MultiCommand(const Commands & commands)
|
|||
categories[Command::catDefault] = "Available commands";
|
||||
}
|
||||
|
||||
void MultiCommand::printHelp(const string & programName, std::ostream & out)
|
||||
{
|
||||
if (command) {
|
||||
command->second->printHelp(programName + " " + command->first, out);
|
||||
return;
|
||||
}
|
||||
|
||||
out << fmt(ANSI_BOLD "Usage:" ANSI_NORMAL " %s " ANSI_ITALIC "COMMAND FLAGS... ARGS..." ANSI_NORMAL "\n", programName);
|
||||
|
||||
out << "\n" ANSI_BOLD "Common flags:" ANSI_NORMAL "\n";
|
||||
printFlags(out);
|
||||
|
||||
std::map<Command::Category, std::map<std::string, ref<Command>>> commandsByCategory;
|
||||
|
||||
for (auto & [name, commandFun] : commands) {
|
||||
auto command = commandFun();
|
||||
commandsByCategory[command->category()].insert_or_assign(name, command);
|
||||
}
|
||||
|
||||
for (auto & [category, commands] : commandsByCategory) {
|
||||
out << fmt("\n" ANSI_BOLD "%s:" ANSI_NORMAL "\n", categories[category]);
|
||||
|
||||
Table2 table;
|
||||
for (auto & [name, command] : commands) {
|
||||
auto descr = command->description();
|
||||
if (!descr.empty())
|
||||
table.push_back(std::make_pair(name, descr));
|
||||
}
|
||||
printTable(out, table);
|
||||
}
|
||||
}
|
||||
|
||||
bool MultiCommand::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||
{
|
||||
if (Args::processFlag(pos, end)) return true;
|
||||
|
|
|
@ -20,8 +20,6 @@ public:
|
|||
wrong. */
|
||||
void parseCmdline(const Strings & cmdline);
|
||||
|
||||
virtual void printHelp(const string & programName, std::ostream & out);
|
||||
|
||||
/* Return a short one-line description of the command. */
|
||||
virtual std::string description() { return ""; }
|
||||
|
||||
|
@ -115,8 +113,6 @@ protected:
|
|||
|
||||
virtual bool processFlag(Strings::iterator & pos, Strings::iterator end);
|
||||
|
||||
virtual void printFlags(std::ostream & out);
|
||||
|
||||
/* Positional arguments. */
|
||||
struct ExpectedArg
|
||||
{
|
||||
|
@ -223,8 +219,6 @@ public:
|
|||
|
||||
MultiCommand(const Commands & commands);
|
||||
|
||||
void printHelp(const string & programName, std::ostream & out) override;
|
||||
|
||||
bool processFlag(Strings::iterator & pos, Strings::iterator end) override;
|
||||
|
||||
bool processArgs(const Strings & args, bool finish) override;
|
||||
|
@ -234,14 +228,6 @@ public:
|
|||
|
||||
Strings argvToStrings(int argc, char * * argv);
|
||||
|
||||
/* Helper function for rendering argument labels. */
|
||||
std::string renderLabels(const Strings & labels);
|
||||
|
||||
/* Helper function for printing 2-column tables. */
|
||||
typedef std::vector<std::pair<std::string, std::string>> Table2;
|
||||
|
||||
void printTable(std::ostream & out, const Table2 & table);
|
||||
|
||||
struct Completion {
|
||||
std::string completion;
|
||||
std::string description;
|
||||
|
|
|
@ -27,11 +27,6 @@ nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & p
|
|||
return res;
|
||||
}
|
||||
|
||||
void NixMultiCommand::printHelp(const string & programName, std::ostream & out)
|
||||
{
|
||||
MultiCommand::printHelp(programName, out);
|
||||
}
|
||||
|
||||
nlohmann::json NixMultiCommand::toJSON()
|
||||
{
|
||||
// FIXME: use Command::toJSON() as well.
|
||||
|
|
|
@ -25,8 +25,6 @@ static constexpr Command::Category catNixInstallation = 102;
|
|||
|
||||
struct NixMultiCommand : virtual MultiCommand, virtual Command
|
||||
{
|
||||
void printHelp(const string & programName, std::ostream & out) override;
|
||||
|
||||
nlohmann::json toJSON() override;
|
||||
};
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ static bool haveInternet()
|
|||
std::string programPath;
|
||||
char * * savedArgv;
|
||||
|
||||
struct HelpRequested { };
|
||||
|
||||
struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||
{
|
||||
bool printBuildLogs = false;
|
||||
|
@ -71,22 +73,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
|||
addFlag({
|
||||
.longName = "help",
|
||||
.description = "Show usage information.",
|
||||
.handler = {[&]() { if (!completions) showHelpAndExit(); }},
|
||||
});
|
||||
|
||||
addFlag({
|
||||
.longName = "help-config",
|
||||
.description = "Show configuration settings.",
|
||||
.handler = {[&]() {
|
||||
std::cout << "The following configuration settings are available:\n\n";
|
||||
Table2 tbl;
|
||||
std::map<std::string, Config::SettingInfo> settings;
|
||||
globalConfig.getSettings(settings);
|
||||
for (const auto & s : settings)
|
||||
tbl.emplace_back(s.first, s.second.description);
|
||||
printTable(std::cout, tbl);
|
||||
throw Exit();
|
||||
}},
|
||||
.handler = {[&]() { throw HelpRequested(); }},
|
||||
});
|
||||
|
||||
addFlag({
|
||||
|
@ -154,33 +141,6 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
|||
return pos;
|
||||
}
|
||||
|
||||
void printFlags(std::ostream & out) override
|
||||
{
|
||||
Args::printFlags(out);
|
||||
std::cout <<
|
||||
"\n"
|
||||
"In addition, most configuration settings can be overriden using '--" ANSI_ITALIC "name value" ANSI_NORMAL "'.\n"
|
||||
"Boolean settings can be overriden using '--" ANSI_ITALIC "name" ANSI_NORMAL "' or '--no-" ANSI_ITALIC "name" ANSI_NORMAL "'. See 'nix\n"
|
||||
"--help-config' for a list of configuration settings.\n";
|
||||
}
|
||||
|
||||
void printHelp(const string & programName, std::ostream & out) override
|
||||
{
|
||||
MultiCommand::printHelp(programName, out);
|
||||
|
||||
#if 0
|
||||
out << "\nFor full documentation, run 'man " << programName << "' or 'man " << programName << "-" ANSI_ITALIC "COMMAND" ANSI_NORMAL "'.\n";
|
||||
#endif
|
||||
|
||||
std::cout << "\nNote: this program is " ANSI_RED "EXPERIMENTAL" ANSI_NORMAL " and subject to change.\n";
|
||||
}
|
||||
|
||||
void showHelpAndExit()
|
||||
{
|
||||
printHelp(programName, std::cout);
|
||||
throw Exit();
|
||||
}
|
||||
|
||||
std::string description() override
|
||||
{
|
||||
return "a tool for reproducible and declarative configuration management";
|
||||
|
@ -298,6 +258,18 @@ void mainWrapped(int argc, char * * argv)
|
|||
|
||||
try {
|
||||
args.parseCmdline(argvToStrings(argc, argv));
|
||||
} catch (HelpRequested &) {
|
||||
std::vector<std::string> subcommand;
|
||||
MultiCommand * command = &args;
|
||||
while (command) {
|
||||
if (command && command->command) {
|
||||
subcommand.push_back(command->command->first);
|
||||
command = dynamic_cast<MultiCommand *>(&*command->command->second);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
showHelp(subcommand);
|
||||
return;
|
||||
} catch (UsageError &) {
|
||||
if (!completions) throw;
|
||||
}
|
||||
|
@ -306,7 +278,8 @@ void mainWrapped(int argc, char * * argv)
|
|||
|
||||
initPlugins();
|
||||
|
||||
if (!args.command) args.showHelpAndExit();
|
||||
if (!args.command)
|
||||
throw UsageError("no subcommand specified");
|
||||
|
||||
if (args.command->first != "repl"
|
||||
&& args.command->first != "doctor"
|
||||
|
|
|
@ -28,11 +28,6 @@ struct CmdNar : NixMultiCommand
|
|||
command->second->prepare();
|
||||
command->second->run();
|
||||
}
|
||||
|
||||
void printHelp(const string & programName, std::ostream & out) override
|
||||
{
|
||||
MultiCommand::printHelp(programName, out);
|
||||
}
|
||||
};
|
||||
|
||||
static auto rCmdNar = registerCommand<CmdNar>("nar");
|
||||
|
|
|
@ -21,11 +21,6 @@ struct CmdStore : virtual NixMultiCommand
|
|||
command->second->prepare();
|
||||
command->second->run();
|
||||
}
|
||||
|
||||
void printHelp(const string & programName, std::ostream & out) override
|
||||
{
|
||||
MultiCommand::printHelp(programName, out);
|
||||
}
|
||||
};
|
||||
|
||||
static auto rCmdStore = registerCommand<CmdStore>("store");
|
||||
|
|
Loading…
Reference in a new issue