You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Right now, when the specifies no command line arguments at all, I output "type -? for help". I'd like it to actually show the help. How can you invoke the help programmatically?
usingSystem.CommandLine;usingSystem.CommandLine.Help;staticvoidMain(string[]args){//// Set up your commands, options, and command handlers as usual...//varyourRootCommand=newRootCommand() ...
...if(args.Length==0){//// No commandline arguments given, output help text//varhelpBld=newHelpBuilder(Resources.Instance,Console.WindowWidth);helpBld.Write(yourRootCommand,Console.Out);return;}yourRootCommand.Invoke(args);}
Thank you for this. Now on to an even more important question: How did you know this? There's nothing about this class in the docs, or am I looking in the wrong place?
There's other things I'm curious about such as -- for instance, what if I want to group the output of commands under headings like "Common" vs "Advanced" commands.
Also, what if I have 20 commands, and now I want to add a new global option, like "--settings-file", right now I'm having to update all 20 commands and passing new parameter "settingsFile", which works, but I would prefer handling that once and place the settings data in a global application context that each command can have access to.
How did you know this? There's nothing about this class in the docs, or am I looking in the wrong place?
As the saying goes, the documentation comments in the source code are the documentation ;-)
Some time ago already, when i was dealing with a similar desire to get the actual help text on demand regardless of the --help option, i roughly perused the documentation comments and the library source code, looking for methods / classes in the library which deal with help output. Once i noticed the HelpBuilder class, it was a very short way to get an understanding of how it can be used.
The nuget package for the library should also contain an (Intellisense) XML file containing the content of these documentation comments, which makes searching/perusing much easier than crawling just the source code. (The XML file is part of the unpacked nuget package that you should find in nuget's global-packages folder.)
As a side note, once the public API has stabilized with the non-beta 2.0 release someday in the not so far future (you can see the tracking for the 2.0 release milestone here: https://github.com/dotnet/command-line-api/milestone/1), i hope some love will be given to some proper API documentation :-)
Also, what if I have 20 commands, and now I want to add a new global option [...]
Look at the public methods offered by the Command class. It has the void AddGlobalOption(Option option) method for exactly that purpose. Also take a look at the documentation comments for this method:
/// Adds a global <see cref="Option"/> to the command.
/// </summary>
/// <param name="option">The global option to add to the command.</param>
/// <remarks>Global options are applied to the command and recursively to subcommands. They do not apply to
/// parent commands.</remarks>
publicvoidAddGlobalOption(Optionoption)
Keep in mind that you will have to have a matching argument in each of your command handlers that will receive the value of such a global option. On the other hand, if you use complex model bindings, you could put the properties for the global options in an abstract base class, and let your CLI model classes for each command inherit from this base class.
I am already using AddGlobalOption for this. I add that to the root command, but then I have to pass the parameter in for each command.
But back to the HelpBuilder. What is Resources.Instance? The source says something about localization. I need to create a resource for localization to invoke the "/?" help? It already works if the user types "/?".. I just want to call the same thing programmatically (when the user enters no parameters)
And finally, when I do "F12" to view the source for the HelpBuilder constructor, I don't get a resource -- I get this:
public HelpBuilder(IConsole console, int maxWidth = int.MaxValue)
{
Console = (console ?? throw new ArgumentNullException("console"));
if (maxWidth <= 0)
{
maxWidth = int.MaxValue;
}
MaxWidth = maxWidth;
}
So the version I have requires an IConsole.
Do I need to build everything from source to see where everything is at?
Ah, i forgot one of your questions. Sorry about that, here it is...
There's other things I'm curious about such as -- for instance, what if I want to group the output of commands under headings like "Common" vs "Advanced" commands.
Look at the public and protected methods offered by HelpBuilder, and you will notice this:
So my suggestion would be to subclass HelpBuilder and override the AddSubCommands method. Your override would be mostly like the original AddSubCommands method, but with one distinction: it has to partion/split the gathered subcommands according to your grouping requirements, and call the RenderAsColumns method for each of those subcommand groups plus some additional output for whatever group headings you want/need...
Basically, unless you want customize/localize the pre-defined text strings in the help text, use LocalizationResources.Instance. If you want/need to customize/localize (some of) the pre-defined text strings but do not want to do it by providing and/or altering the resource files themselves, create your own subclass derived from LocalizationResources and override the respective virtual methods as you see fit.
And finally, when I do "F12" to view the source for the HelpBuilder constructor, I don't get a resource -- I get this
So the version I have requires an IConsole.
Do I need to build everything from source to see where everything is at?
I would suggest to use one of the recent daily builds, and not rely on old library version. You don't need to build from souce yourself. There are nuget packages for the daily builds available. Further details about how to get these are in the readme.md of the project here: https://github.com/dotnet/command-line-api#packages
since this seems to have changed, this is how it looks to work with the latest daily builds.
var helpBld = new HelpBuilder(LocalizationResources.Instance, Console.WindowWidth);
var hc = new HelpContext(helpBld,rootCommand,Console.Out);
helpBld.Write(hc);
Activity
elgonzo commentedon Oct 26, 2021
Something along the lines of this?
kasajian commentedon Nov 4, 2021
Thank you for this. Now on to an even more important question: How did you know this? There's nothing about this class in the docs, or am I looking in the wrong place?
There's other things I'm curious about such as -- for instance, what if I want to group the output of commands under headings like "Common" vs "Advanced" commands.
Also, what if I have 20 commands, and now I want to add a new global option, like "--settings-file", right now I'm having to update all 20 commands and passing new parameter "settingsFile", which works, but I would prefer handling that once and place the settings data in a global application context that each command can have access to.
elgonzo commentedon Nov 4, 2021
As the saying goes, the documentation comments in the source code are the documentation ;-)
Some time ago already, when i was dealing with a similar desire to get the actual help text on demand regardless of the --help option, i roughly perused the documentation comments and the library source code, looking for methods / classes in the library which deal with help output. Once i noticed the HelpBuilder class, it was a very short way to get an understanding of how it can be used.
The nuget package for the library should also contain an (Intellisense) XML file containing the content of these documentation comments, which makes searching/perusing much easier than crawling just the source code. (The XML file is part of the unpacked nuget package that you should find in nuget's global-packages folder.)
As a side note, once the public API has stabilized with the non-beta 2.0 release someday in the not so far future (you can see the tracking for the 2.0 release milestone here: https://github.com/dotnet/command-line-api/milestone/1), i hope some love will be given to some proper API documentation :-)
Look at the public methods offered by the
Command
class. It has thevoid AddGlobalOption(Option option)
method for exactly that purpose. Also take a look at the documentation comments for this method:command-line-api/src/System.CommandLine/Command.cs
Lines 71 to 77 in 8a0f746
Keep in mind that you will have to have a matching argument in each of your command handlers that will receive the value of such a global option. On the other hand, if you use complex model bindings, you could put the properties for the global options in an abstract base class, and let your CLI model classes for each command inherit from this base class.
kasajian commentedon Nov 4, 2021
I am already using AddGlobalOption for this. I add that to the root command, but then I have to pass the parameter in for each command.
But back to the HelpBuilder. What is Resources.Instance? The source says something about localization. I need to create a resource for localization to invoke the "/?" help? It already works if the user types "/?".. I just want to call the same thing programmatically (when the user enters no parameters)
And finally, when I do "F12" to view the source for the HelpBuilder constructor, I don't get a resource -- I get this:
So the version I have requires an IConsole.
Do I need to build everything from source to see where everything is at?
elgonzo commentedon Nov 4, 2021
Ah, i forgot one of your questions. Sorry about that, here it is...
Look at the public and protected methods offered by HelpBuilder, and you will notice this:
command-line-api/src/System.CommandLine/Help/HelpBuilder.cs
Lines 244 to 260 in 8a0f746
So my suggestion would be to subclass HelpBuilder and override the AddSubCommands method. Your override would be mostly like the original AddSubCommands method, but with one distinction: it has to partion/split the gathered subcommands according to your grouping requirements, and call the RenderAsColumns method for each of those subcommand groups plus some additional output for whatever group headings you want/need...
elgonzo commentedon Nov 4, 2021
I noticed that recently (end of September) the name of this type has been changed from Resources to LocalizationResources. I didn't catch that when i wrote my first response to you. The source code of this type is here: https://github.com/dotnet/command-line-api/blob/8a0f746b0d9f2afba278349482cd7c2137de473d/src/System.CommandLine/LocalizationResources.cs
Basically, unless you want customize/localize the pre-defined text strings in the help text, use LocalizationResources.Instance. If you want/need to customize/localize (some of) the pre-defined text strings but do not want to do it by providing and/or altering the resource files themselves, create your own subclass derived from LocalizationResources and override the respective virtual methods as you see fit.
I would suggest to use one of the recent daily builds, and not rely on old library version. You don't need to build from souce yourself. There are nuget packages for the daily builds available. Further details about how to get these are in the readme.md of the project here: https://github.com/dotnet/command-line-api#packages
EricZimmerman commentedon Dec 8, 2021
since this seems to have changed, this is how it looks to work with the latest daily builds.
skibitsky commentedon Dec 17, 2021
Please consider adding an answer to the How To document.