Skip to content

Display A Help Screen

sshah254 edited this page Jan 17, 2018 · 35 revisions

IMPORTANT NOTE: This wiki refers to latest stables, if a beta version is available in github master branch please refer to Latest Version.

Mapping a method with HelpOptionAttribute will allow the parser to display a help screen when parsing rules are violated.

class Options
{
  [Option('p', "person-to-greet", Required=true, HelpText="The person to greet.")]
  public string PersonToGreet { get; set; }

  [HelpOption]
  public string GetUsage()
  {
    return "Please read user manual!" + Environment.NewLine;
  }
}

In this sample, the -p|--person-to-greet option is mandatory. Omitting it will cause the parser to display the string returned by Options::GetUsage().

When mapping a method with HelpOption there are only a few constraints to respect. The method must be an instance method, it has to return a string and accept no parameters. The name of the method is your choice.

Using HelpText Class

The CommandLine.Text namespace contains helper types to make it easy to render the help screen.

class Options
{
  [Option("p", "person-to-greet", Required=true, HelpText="The person to greet.")]
  public string PersonToGreet { get; set; }

  [HelpOption]
  public string GetUsage()
  {
    var help = new HelpText {
      Heading = new HeadingInfo("<<app title>>", "<<app version>>"),
      Copyright = new CopyrightInfo("<<app author>>", 2014),
      AdditionalNewLineAfterOption = true,
      AddDashesToOption = true
    };
    help.AddPreOptionsLine("<<license details here.>>");
    help.AddPreOptionsLine("Usage: app -p Someone");
    help.AddOptions(this);
    return help;
  }
}

In this example the method creates a HelpText instance, it uses secondary helper types to specify heading and copyright information and sets some preferences.

Then it simply adds text as a StringBuilder and with a single call (AddOptions) renders the options block. Every option attribute (except ValueList) inherits from BaseOptionAttribute and this type has a property named BaseOptionAttribute::HelpText and precisely the value of this property is used by AddOptions method.

Handling Parsing Errors

Parsing errors like badly formatted values or missing required options can be captured as generic list of ParsingError type. Access to this data requires that your target class contains a property of type IParserState decorated with ParserStateAttribute.

class Options
{
  [ParserState]
  public IParserState LastParserState { get; set; }
}

IParserState is simply defined as:

public interface IParserState
{
  IList<ParsingError> Errors { get; }
}

public class ParsingError
{
  public BadOptionInfo BadOption { get; }

  public bool ViolatesRequired { get; }

  public bool ViolatesFormat { get; }

  public bool ViolatesMutualExclusiveness { get; }
}

public sealed class BadOptionInfo
{
  public string ShortName { get; }

  public string LongName { get; }
}

Remarks: you're not entitled to provide your own implementation of IParserState. The library comes with a default implementation named ParserState with an internal constructor.

The following snippet of code demonstrates how to report errors using HelpText::RenderParsingErrorsText for rendering the text block automatically:

class Options
{
  [HelpOption]
  public string GetUsage()
  {
    var help = new HelpText();

    // ...
    if (this.LastParserState?.Errors.Any() == true)
    {
      var errors = help.RenderParsingErrorsText(this, 2); // indent with two spaces

      if (!string.IsNullOrEmpty(errors))
      {
        help.AddPreOptionsLine(string.Concat(Environment.NewLine, "ERROR(S):"));
        help.AddPreOptionsLine(errors);
      }
    }

    // ...
    return help;
  }
}

Automatic Building

By taking advantage of assembly attributes, you can build HelpText instance with one line of code.

Define the following attributes (usually in Properties/AssemblyInfo.cs):

// from .NET class library
[assembly: AssemblyTitle("yourapp")]
[assembly: AssemblyCopyright("Copyright (C) 2014 Your Name")]
[assembly: AssemblyInformationalVersionAttribute("1.0")]

// from CommandLineParser.Text
[assembly: AssemblyLicense(
    "This is free software. You may redistribute copies of it under the terms of",
    "the MIT License <http://www.opensource.org/licenses/mit-license.php>.")]
[assembly: AssemblyUsage(
    "Usage: YourApp -rMyData.in -wMyData.out --calculate",
    "       YourApp -rMyData.in -i -j9.7 file0.def file1.def")]

Remarks: if you don't define these attributes the library will provide reasonable defaults for you.

Now inside Options::GetUsage method just make a call to AutoBuild with a delegate, intended to format errors:

return HelpText.AutoBuild(this, (HelpText current) => HelpText.DefaultParsingErrorsHandler(this, current));

As previously stated, the parser knows when to call GetUsage and AutoBuild knows how to format the help screen for you.

If you want write a custom delegate the signature is Action<HelpText>. Please refer to the built-in for reference.

Localize Help Strings

There's quite a few (still) undocumented features that let you display words like Required in your national language.

There's a HelpText constructor overload that accepts a:

public abstract class BaseSentenceBuilder
{
  // Gets a string containing word 'option'.
  public abstract string OptionWord { get; }

  // Gets a string containing the word 'and'.
  public abstract string AndWord { get; }

  // Gets a string containing the sentence 'required option missing'.
  public abstract string RequiredOptionMissingText { get; }

  // Gets a string containing the sentence 'violates format'.
  public abstract string ViolatesFormatText { get; }

  // Gets a string containing the sentence 'violates mutual exclusiveness'.
  public abstract string ViolatesMutualExclusivenessText { get; }

  // Gets a string containing the error heading text.
  public abstract string ErrorsHeadingText { get; }

  // Don't care about this factory method.
  public static BaseSentenceBuilder CreateBuiltIn()
  {
    return new EnglishSentenceBuilder();
  }
}

See the built-in sentence builder, the English one, to know how to implement one.

Remarks: this was not documented because a replacement was scheduled but never done. It may be replaced using delegates (so I can worry of one hierarchy less.).