Skip to content

Make it easier to configure HelpText #458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,48 @@ let main args =
| :? CommandLine.NotParsed<obj> -> 1
```

# Configuring Help output

One of the most valuable aspects of the library is its ability to automatically generate help text for the user when parsing fails. The **HelpText** property of each **Option** is displayed when a command is not recognised or there is a mistake in the parameters. Multi-line 'Verbatim' strings are allowed and are correctly wrapped with sub-indentation honoured. For example:

```csharp
[Option(HelpText =
@"Length can take several types of values
-- a string such as 'ten days'
-- a number like 1000 - this is interpreted as a number of milliseconds"
)]
public string Length {get;set;}
```

In previous versions of the library, configuration of the help output was achieved through calling the AutoBuild method directly. This is now deprecated and a number of helper methods are supplied to simplify the process.


```csharp
var textwriter = ... my custom stream ....

Action<HelpText> configurer = h => {
h.AddEnumValuesToHelpText = true;
h.AdditionalNewLineAfterOption==true;
h.Copyright ="(C) Acme Solutions";
};

var parser = Parser.Default
.SetDisplayWidth(40,WidthPolicy.FitToScreen)
.SetTextWriter(textwriter)
.SetHelpTextConfiguration(configurer)
```


By default, the parser optionally automatically generates help and version commands. To disable these use:


```csharp

var parser = Parser.Default
.SetAutoHelp(false)
.SetAutoVersion(false)
```

# Contributors
First off, _Thank you!_ All contributions are welcome.

Expand Down
85 changes: 78 additions & 7 deletions src/CommandLine/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ public class Parser : IDisposable
private bool disposed;
private readonly ParserSettings settings;
private static readonly Lazy<Parser> DefaultParser = new Lazy<Parser>(
() => new Parser(new ParserSettings { HelpWriter = Console.Error }));
() => new Parser(new ParserSettings() ));

/// <summary>
/// Initializes a new instance of the <see cref="CommandLine.Parser"/> class.
/// </summary>
[Obsolete("Calling the constructor directly is deprecated - prefer Parser.Default")]
public Parser()
{
settings = new ParserSettings { Consumed = true };
Expand All @@ -35,6 +36,7 @@ public Parser()
/// </summary>
/// <param name="configuration">The <see cref="Action&lt;ParserSettings&gt;"/> delegate used to configure
/// aspects and behaviors of the parser.</param>
[Obsolete("Calling the constructor directly is deprecated - prefer Parser.Default.Set....")]
public Parser(Action<ParserSettings> configuration)
{
if (configuration == null) throw new ArgumentNullException("configuration");
Expand Down Expand Up @@ -194,16 +196,15 @@ private static ParserResult<T> MakeParserResult<T>(ParserResult<T> parserResult,
{
return DisplayHelp(
parserResult,
settings.HelpWriter,
settings.MaximumDisplayWidth);
settings.HelpTextConfiguration);
}

private static ParserResult<T> DisplayHelp<T>(ParserResult<T> parserResult, TextWriter helpWriter, int maxDisplayWidth)
private static ParserResult<T> DisplayHelp<T>(ParserResult<T> parserResult, HelpTextConfiguration helpTextConfig)
{
parserResult.WithNotParsed(
errors =>
Maybe.Merge(errors.ToMaybe(), helpWriter.ToMaybe())
.Do((_, writer) => writer.Write(HelpText.AutoBuild(parserResult, maxDisplayWidth)))
Maybe.Merge(errors.ToMaybe(), helpTextConfig.HelpWriter.ToMaybe())
.Do((_, writer) => writer.Write(HelpText.AutoBuild(parserResult,helpTextConfig)))
);

return parserResult;
Expand All @@ -228,5 +229,75 @@ private void Dispose(bool disposing)
disposed = true;
}
}
/// <summary>
/// Allows the client to use a stream other than Console.Error for ouput. NOTE - client should dispose the stream
/// </summary>
/// <param name="writer">The output stream to use </param>
/// <returns>The parser</returns>
public Parser SetTextWriter(TextWriter writer)
{
settings.Consumed = false;
settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithHelpWriter(writer);
settings.Consumed = true;
return this;
}

/// <summary>
/// Allows the client to select the display width
/// </summary>
/// <param name="width">The desired width</param>
/// <param name="policy">The policy to use when setting the width</param>
/// <returns>The parser</returns>
public Parser SetDisplayWidth(int width,WidthPolicy policy)
{
settings.Consumed = false;
//Note that the parser constructor has probably already worked out the console width
if (policy == WidthPolicy.FitToScreen)
width = Math.Min(settings.HelpTextConfiguration.DisplayWidth, width);
settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithDisplayWidth(width);
settings.Consumed = true;
return this;
}

/// <summary>
/// Allows the client to configure flags in the helpText class
/// </summary>
/// <param name="configurer">An action which can set flags in the HelpText class</param>
/// <returns>The parser</returns>
public Parser SetHelpTextConfiguration(Action<HelpText> configurer)
{
settings.Consumed = false;
settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithConfigurer(configurer);
settings.Consumed = true;
return this;
}


/// <summary>
/// Allows the client to turn the automatic help verb on and off
/// </summary>
/// <param name="enable">turn on/off</param>
/// <returns>The parser</returns>
public Parser SetAutoHelp(bool enable)
{
settings.Consumed = false;
settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithAutoHelp(enable);
settings.Consumed = true;
return this;
}

/// <summary>
/// Allows the client to turn the automatic version reporting on and off
/// </summary>
/// <param name="enable">turn on/off</param>
/// <returns>The parser</returns>
public Parser SetAutoVersion(bool enable)
{
settings.Consumed = false;
settings.HelpTextConfiguration = settings.HelpTextConfiguration.WithAutoVersion(enable);
settings.Consumed = true;
return this;
}

}
}
}
85 changes: 53 additions & 32 deletions src/CommandLine/ParserSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.IO;

using CommandLine.Infrastructure;
using CommandLine.Text;


namespace CommandLine
{
Expand All @@ -13,40 +15,31 @@ namespace CommandLine
/// </summary>
public class ParserSettings : IDisposable
{
private const int DefaultMaximumLength = 80; // default console width

private bool disposed;
private bool caseSensitive;
private bool caseInsensitiveEnumValues;
private TextWriter helpWriter;
private HelpTextConfiguration helpTextConfiguration = HelpTextConfiguration.Default;
private bool ignoreUnknownArguments;
private bool autoHelp;
private bool autoVersion;
private CultureInfo parsingCulture;
private bool enableDashDash;
private int maximumDisplayWidth;


/// <summary>
/// Initializes a new instance of the <see cref="ParserSettings"/> class.
/// </summary>
public ParserSettings()
{
caseSensitive = true;
caseInsensitiveEnumValues = false;
autoHelp = true;
autoVersion = true;
parsingCulture = CultureInfo.InvariantCulture;
try
{
maximumDisplayWidth = Console.WindowWidth;
if (maximumDisplayWidth < 1)
if (Console.WindowWidth >= 1)
{
maximumDisplayWidth = DefaultMaximumLength;
HelpTextConfiguration=HelpTextConfiguration.WithDisplayWidth(Console.WindowWidth);
}
}
catch (IOException)
{
maximumDisplayWidth = DefaultMaximumLength;
}
}

Expand All @@ -69,6 +62,7 @@ public bool CaseSensitive
set { PopsicleSetter.Set(Consumed, ref caseSensitive, value); }
}


/// <summary>
/// Gets or sets a value indicating whether perform case sensitive comparisons of <i>values</i>.
/// Note that case insensitivity only applies to <i>values</i>, not the parameters.
Expand Down Expand Up @@ -103,12 +97,27 @@ public CultureInfo ParsingCulture
/// <remarks>
/// It is the caller's responsibility to dispose or close the <see cref="TextWriter"/>.
/// </remarks>
[Obsolete("Internal use only - prefer Parser.Default.SetHelpWriter")]
public TextWriter HelpWriter
{
get { return helpWriter; }
set { PopsicleSetter.Set(Consumed, ref helpWriter, value); }
get { return HelpTextConfiguration.HelpWriter; }
set { HelpTextConfiguration = HelpTextConfiguration.WithHelpWriter(value); }
}

/// <summary>
/// Allows the HelpText to be configured
/// </summary>
/// <remarks>
/// It is intended that any future HelpText configuration should be encapsulated in this object.
/// </remarks>
[Obsolete("Internal use only - prefer Parser.Default.SetHelpTextConfiguration")]
public HelpTextConfiguration HelpTextConfiguration
{
get { return helpTextConfiguration; }
set { PopsicleSetter.Set(Consumed, ref helpTextConfiguration, value); }
}


/// <summary>
/// Gets or sets a value indicating whether the parser shall move on to the next argument and ignore the given argument if it
/// encounter an unknown arguments
Expand All @@ -125,43 +134,55 @@ public bool IgnoreUnknownArguments
get { return ignoreUnknownArguments; }
set { PopsicleSetter.Set(Consumed, ref ignoreUnknownArguments, value); }
}


/// <summary>
/// Gets or sets a value indicating whether implicit option or verb 'help' should be supported.
/// Gets or sets a value indicating whether enable double dash '--' syntax,
/// that forces parsing of all subsequent tokens as values.
/// </summary>
public bool AutoHelp
public bool EnableDashDash
{
get { return autoHelp; }
set { PopsicleSetter.Set(Consumed, ref autoHelp, value); }
get { return enableDashDash; }
set { PopsicleSetter.Set(Consumed, ref enableDashDash, value); }
}

/// <summary>
/// Gets or sets a value indicating whether implicit option or verb 'version' should be supported.
/// Gets or sets the maximum width of the display. This determines word wrap when displaying the text.
/// </summary>
public bool AutoVersion
/// <remarks>
/// </remarks>
[Obsolete("Prefer Parser.Default.SetDisplayWidth")]
public int MaximumDisplayWidth
{
get { return autoVersion; }
set { PopsicleSetter.Set(Consumed, ref autoVersion, value); }
get { return HelpTextConfiguration.DisplayWidth; }
set { HelpTextConfiguration = HelpTextConfiguration.WithDisplayWidth(value); }
}

/// <summary>
/// Gets or sets a value indicating whether enable double dash '--' syntax,
/// that forces parsing of all subsequent tokens as values.
/// Gets or sets a value indicating whether implicit option or verb 'version' should be supported.
/// </summary>
public bool EnableDashDash
/// <remarks>
/// Note that AutoVersion and AutoHelp straddle the line between being PARSER and HELP settings;
/// the are used buy the Help-text system to generate output but but the parser itself to decide
/// which verbs to accept. For simplicity, they are stored in HelpTextConfiguration and proxied here
/// </remarks>
[Obsolete("Internal use only - prefer Parser.Default.SetAutoVersion")]
public bool AutoVersion
{
get { return enableDashDash; }
set { PopsicleSetter.Set(Consumed, ref enableDashDash, value); }
get { return HelpTextConfiguration.AutoVersion; }
set { HelpTextConfiguration = HelpTextConfiguration.WithAutoVersion(value); }
}

/// <summary>
/// Gets or sets the maximum width of the display. This determines word wrap when displaying the text.
/// Gets or sets a value indicating whether implicit option or verb 'help' should be supported.
/// </summary>
public int MaximumDisplayWidth
[Obsolete("Internal use only - prefer Parser.Default.SetAutoHelp")]
public bool AutoHelp
{
get { return maximumDisplayWidth; }
set { maximumDisplayWidth = value; }
get { return HelpTextConfiguration.AutoHelp; }
set { HelpTextConfiguration = HelpTextConfiguration.WithAutoHelp(value); }
}


internal StringComparer NameComparer
{
Expand Down
Loading