diff --git a/modules/juce_core/misc/juce_ConsoleApplication.cpp b/modules/juce_core/misc/juce_ConsoleApplication.cpp index d3139925bb..0a1cfd0454 100644 --- a/modules/juce_core/misc/juce_ConsoleApplication.cpp +++ b/modules/juce_core/misc/juce_ConsoleApplication.cpp @@ -250,18 +250,26 @@ int ConsoleApplication::invokeCatchingFailures (std::function&& f) return returnCode; } -int ConsoleApplication::findAndRunCommand (const ArgumentList& args, bool commandFlagMustBeFirst) const +const ConsoleApplication::Command* ConsoleApplication::findCommand (const ArgumentList& args, bool optionMustBeFirstArg) const { for (auto& c : commands) { auto index = args.indexOfOption (c.commandOption); - if (commandFlagMustBeFirst ? (index == 0) : (index >= 0)) - return invokeCatchingFailures ([&] { c.command (args); return 0; }); + if (optionMustBeFirstArg ? (index == 0) : (index >= 0)) + return &c; } if (commandIfNoOthersRecognised >= 0) - return invokeCatchingFailures ([&] { commands[(size_t) commandIfNoOthersRecognised].command (args); return 0; }); + return &commands[(size_t) commandIfNoOthersRecognised]; + + return {}; +} + +int ConsoleApplication::findAndRunCommand (const ArgumentList& args, bool optionMustBeFirstArg) const +{ + if (auto c = findCommand (args, optionMustBeFirstArg)) + return invokeCatchingFailures ([=] { c->command (args); return 0; }); fail ("Unrecognised arguments"); return 0; @@ -277,28 +285,43 @@ void ConsoleApplication::addCommand (Command c) commands.emplace_back (std::move (c)); } -void ConsoleApplication::addHelpCommand (String arg, String helpMessage, bool invokeIfNoOtherCommandRecognised) +void ConsoleApplication::addDefaultCommand (Command c) { - if (invokeIfNoOtherCommandRecognised) - commandIfNoOthersRecognised = (int) commands.size(); + commandIfNoOthersRecognised = (int) commands.size(); + addCommand (std::move (c)); +} - addCommand ({ arg, arg, "Prints this message", - [this, helpMessage] (const ArgumentList& args) { printHelp (helpMessage, args); }}); +void ConsoleApplication::addHelpCommand (String arg, String helpMessage, bool makeDefaultCommand) +{ + Command c { arg, arg, "Prints the list of commands", {}, + [this, helpMessage] (const ArgumentList& args) + { + std::cout << helpMessage << std::endl; + printCommandList (args); + }}; + + if (makeDefaultCommand) + addDefaultCommand (std::move (c)); + else + addCommand (std::move (c)); } void ConsoleApplication::addVersionCommand (String arg, String versionText) { - addCommand ({ arg, arg, "Prints the current version number", + addCommand ({ arg, arg, "Prints the current version number", {}, [versionText] (const ArgumentList&) { std::cout << versionText << std::endl; }}); } -void ConsoleApplication::printHelp (const String& preamble, const ArgumentList& args) const +const std::vector& ConsoleApplication::getCommands() const { - std::cout << preamble << std::endl; + return commands; +} +void ConsoleApplication::printCommandList (const ArgumentList& args) const +{ auto exeName = args.executableName.fromLastOccurrenceOf ("/", false, false) .fromLastOccurrenceOf ("\\", false, false); @@ -324,7 +347,7 @@ void ConsoleApplication::printHelp (const String& preamble, const ArgumentList& else std::cout << nameAndArgs.paddedRight (' ', descriptionIndent); - std::cout << commands[i].commandDescription << std::endl; + std::cout << commands[i].shortDescription << std::endl; } std::cout << std::endl; diff --git a/modules/juce_core/misc/juce_ConsoleApplication.h b/modules/juce_core/misc/juce_ConsoleApplication.h index 99918485d1..336bb9d00f 100644 --- a/modules/juce_core/misc/juce_ConsoleApplication.h +++ b/modules/juce_core/misc/juce_ConsoleApplication.h @@ -213,8 +213,13 @@ struct ConsoleApplication */ String argumentDescription; - /** A description of the meaning of this command, for use in the help text. */ - String commandDescription; + /** A short (one line) description of this command, which can be printed by + ConsoleApplication::printCommandList(). + */ + String shortDescription; + + /** A longer description of this command, for use in extended help. */ + String longDescription; /** The actual command that should be invoked to perform this action. */ std::function command; @@ -224,15 +229,24 @@ struct ConsoleApplication /** Adds a command to the list. */ void addCommand (Command); + /** Adds a command to the list, and marks it as one which is invoked if no other + command matches. + */ + void addDefaultCommand (Command); + + /** Adds a command that will print the given text in response to the "--version" option. */ + void addVersionCommand (String versionArgument, String versionText); + /** Adds a help command to the list. This command will print the user-supplied message that's passed in here as an argument, followed by a list of all the registered commands. */ - void addHelpCommand (String helpArgument, String helpMessage, - bool invokeIfNoOtherCommandRecognised); + void addHelpCommand (String helpArgument, String helpMessage, bool makeDefaultCommand); - /** Adds a command that will print the given text in response to the "--version" option. */ - void addVersionCommand (String versionArgument, String versionText); + /** Prints out the list of commands and their short descriptions in a format that's + suitable for use as help. + */ + void printCommandList (const ArgumentList&) const; //============================================================================== /** Throws a failure exception to cause a command-line app to terminate. @@ -253,29 +267,40 @@ struct ConsoleApplication /** Looks for the first command in the list which matches the given arguments, and tries to invoke it. - If no command is found, it prints a help message listing the available commands. + If no command is found, and if there is no default command to run, it fails with + a suitable error message. If the command calls the fail() function, this will throw an exception that gets automatically caught and handled, and this method will return the error code that was passed into the fail() call. - If commandFlagMustBeFirst is true, then only the first argument will be looked at + If optionMustBeFirstArg is true, then only the first argument will be looked at when searching the available commands - this lets you do 'git' style commands where the executable name is followed by a verb. */ int findAndRunCommand (const ArgumentList&, - bool commandFlagMustBeFirst = false) const; + bool optionMustBeFirstArg = false) const; /** Creates an ArgumentList object from the argc and argv variablrs, and invokes findAndRunCommand() using it. */ int findAndRunCommand (int argc, char* argv[]) const; + /** Looks for the first command in the list which matches the given arguments. + If none is found, this returns either the default command (if one is set) + or nullptr. + If optionMustBeFirstArg is true, then only the first argument will be looked at + when searching the available commands - this lets you do 'git' style commands where + the executable name is followed by a verb. + */ + const Command* findCommand (const ArgumentList&, bool optionMustBeFirstArg) const; + + /** Gives read-only access to the list of registered commands. */ + const std::vector& getCommands() const; + private: //============================================================================== std::vector commands; int commandIfNoOthersRecognised = -1; - - void printHelp (const String& preamble, const ArgumentList&) const; }; } // namespace juce