CommandLineUtils icon indicating copy to clipboard operation
CommandLineUtils copied to clipboard

Dynamic extended help

Open richardschneider opened this issue 5 years ago • 11 comments

I want to dynamically generate the ExtendedHelpText for a Subcommand. For example the command repo migrate <version>, I want to create the text that shows the allowable version numbers and their description.

Something like

string ExtendendHelp()
{
   var s = new StringBuilder("Versions:\r\n"));
   foreach (var v in Migration.Versions)
   {
      s.Append(v.Number);
      s.Append(' ');
      s.AppendLine(v.Description)
   }
   return s;
}

richardschneider avatar Aug 03 '19 01:08 richardschneider

Have you seen https://natemcmaster.github.io/CommandLineUtils/docs/help-text.html? You should be able to completely customize the help text by implementing IHelpTextGenerator. If you inherit from DefaultHelpTextGenerator, you don't have to write the whole help txt generation from scratch.

By the way, are you using the attribute or builder API?

natemcmaster avatar Aug 05 '19 06:08 natemcmaster

Thanks for the fast reply. So if I change my subcommand class to inherhit from DefaultHelpTextGenerator and change my ExtendendHelper method to override GenerateFooter then all will work. Thanks you.

I'm using the attributes.

richardschneider avatar Aug 05 '19 06:08 richardschneider

I tried overriding GenerateFooter to print the versions and it is never called. Obviously I'm missing something.

See what I did in https://github.com/richardschneider/net-ipfs-engine/pull/134

richardschneider avatar Aug 05 '19 07:08 richardschneider

Sorry my last comment was not clear enough. I would recommend reading the section in https://natemcmaster.github.io/CommandLineUtils/docs/help-text.html about "Custom help text". You will need to implement the IHelpTextGenerator on a separate class, not the command class. Super simplified example:

public class Program
{
   public static int Main(string[] args)
   {
 		var app = new CommandLineApplication<Program>();
		app.Conventions.UseDefaultConventions();
        app.HelpTextGenerator = new MyHelpTextGenerator();
        return app.Execute(args);
	}

	[Option]
	public string Name { get; set; }

	public void OnExecute() {  }
}

class MyHelpTextGenerator : DefaultHelpTextGenerator
{
	protected override void GenerateFooter(CommandLineApplication application, TextWriter output) { }
}

natemcmaster avatar Aug 07 '19 04:08 natemcmaster

Thanks again for you reply. My issue is that I want to only generate the extra help text when a specific subcommand is asking for help.

richardschneider avatar Aug 07 '19 06:08 richardschneider

You can do that using pattern matching.


class MyHelpTextGenerator : DefaultHelpTextGenerator
{
	protected override void GenerateFooter(CommandLineApplication application, TextWriter output)
	{
		if (application is TheSpecificCommandIWant cmd)
			output.Write(cmd.GetExtendedHelpText());
		else
			base.GenerateFooter(application, output);
	}
}

natemcmaster avatar Aug 08 '19 05:08 natemcmaster

I changed Main to set the app.HelpTextGenerator to my own class that derives from DefaultHelpTextGenerator. It is never being called.

Do you have a test/example that works with Subcommand(string, Type) and generates specific help text for the Subcommand?

richardschneider avatar Aug 08 '19 10:08 richardschneider

Ah, you probably hit one of those goofy bugs this library has in subcommand inheritance. Try changing the order in which HelpTextGenerator is assigned.

var app = new CommandLineApplication<Program>
{
    HelpTextGenerator = new MyHelpTextGenerator()
};
app.Conventions.UseDefaultConventions();

Also, I thought about it more and I think your pattern matching needs to look for CommandLineApplication<T>, instead of T.

class MyHelpTextGenerator : DefaultHelpTextGenerator
{
	protected override void GenerateFooter(CommandLineApplication application, TextWriter output)
	{
-              if (application is TheSpecificCommandIWant cmd)
-			output.Write(cmd.GetExtendedHelpText());
+              if (application is CommandLineApplication<TheSpecificCommandIWant> cmd)
+			output.Write(cmd.Model.GetExtendedHelpText());
		else
			base.GenerateFooter(application, output);
	}
}

natemcmaster avatar Aug 10 '19 18:08 natemcmaster

Thanks, setting the HelpTextGenerator before the UseDefaultConventions() works. My help generator is now working.

richardschneider avatar Aug 12 '19 02:08 richardschneider

I think I'm going to leave this open. There is probably a more intuitive way to extend the generated help text. I'm open to suggestions on this one...

natemcmaster avatar Aug 13 '19 03:08 natemcmaster

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Please comment if you believe this should remain open, otherwise it will be closed in 14 days. Thank you for your contributions to this project.

stale[bot] avatar Jul 21 '21 02:07 stale[bot]

This issue has been automatically marked as stale because it has no recent activity. It will be closed if no further activity occurs. Please comment if you believe this should remain open, otherwise it will be closed in 14 days. Thank you for your contributions to this project.

github-actions[bot] avatar Nov 14 '22 02:11 github-actions[bot]

Closing due to inactivity. If you are looking at this issue in the future and think it should be reopened, please make a commented here and mention natemcmaster so he sees the notification.

github-actions[bot] avatar Nov 30 '22 02:11 github-actions[bot]