Skip to content

Commit

Permalink
HelpText fluent API, initial
Browse files Browse the repository at this point in the history
  • Loading branch information
b3b00 committed Jul 23, 2019
1 parent 9a9d27a commit 113a21c
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 36 deletions.
196 changes: 160 additions & 36 deletions src/CommandLine/Text/HelpText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ namespace CommandLine.Text
/// Provides means to format an help screen.
/// You can assign it in place of a <see cref="System.String"/> instance.
/// </summary>



public struct ComparableOption
{
public bool Required;
Expand All @@ -28,7 +28,125 @@ public struct ComparableOption
public string LongName;
public int Index;
}


public class HelpTextBuilder<T>
{

private Func<HelpText, HelpText> onError;
private ParserResult<T> parserResult;
private Func<Example, Example> onExample;

private bool verbsIndex = false;

private int maxDisplayWidth = HelpText.DefaultMaximumLength;

private Comparison<ComparableOption> optionComparison;

internal HelpTextBuilder(ParserResult<T> result)
{
parserResult = result;
}

public HelpTextBuilder<T> OnError(Func<HelpText, HelpText> error)
{
onError = error;
return this;
}
public HelpTextBuilder<T> OnExample(Func<Example, Example> example)
{
onExample = example;
return this;
}

public HelpTextBuilder<T> WithMaxDisplayWidth(int width) {
maxDisplayWidth = width;
return this;
}

public HelpTextBuilder<T> WithVerbsIndex(bool index) {
verbsIndex = index;
return this;
}

public HelpTextBuilder<T> WithComparison(Comparison<ComparableOption> comparison)
{
optionComparison = comparison;
return this;
}

public string Build()
{

//TODO : call HelpText.AutoBuild according to set parameters.

// if (onError)
// HelpText.AutoBuild(parserResult,onError,onExample,verbsIndex,maxDisplayWidth);
// HelpText.AutoBuild(parserResult,maxDisplayWidth);

var auto = new HelpText
{
Heading = HeadingInfo.Empty,
Copyright = CopyrightInfo.Empty,
AdditionalNewLineAfterOption = true,
AddDashesToOption = !verbsIndex,
MaximumDisplayWidth = maxDisplayWidth,
OptionComparison = optionComparison
};

try
{
auto.Heading = HeadingInfo.Default;
auto.Copyright = CopyrightInfo.Default;
}
catch (Exception)
{
auto = onError(auto);
}

var errors = Enumerable.Empty<Error>();

if (onError != null && parserResult.Tag == ParserResultType.NotParsed)
{
errors = ((NotParsed<T>)parserResult).Errors;

if (errors.OnlyMeaningfulOnes().Any())
auto = onError(auto);
}

ReflectionHelper.GetAttribute<AssemblyLicenseAttribute>()
.Do(license => license.AddToHelpText(auto, true));

var usageAttr = ReflectionHelper.GetAttribute<AssemblyUsageAttribute>();
var usageLines = HelpText.RenderUsageTextAsLines(parserResult, onExample).ToMaybe();

if (usageAttr.IsJust() || usageLines.IsJust())
{
var heading = auto.SentenceBuilder.UsageHeadingText();
if (heading.Length > 0)
auto.AddPreOptionsLine(heading);
}

usageAttr.Do(
usage => usage.AddToHelpText(auto, true));

usageLines.Do(
lines => auto.AddPreOptionsLines(lines));

if ((verbsIndex && parserResult.TypeInfo.Choices.Any())
|| errors.Any(e => e.Tag == ErrorType.NoVerbSelectedError))
{
auto.AddDashesToOption = false;
auto.AddVerbs(parserResult.TypeInfo.Choices.ToArray());
}
else
auto.AddOptions(parserResult);

return auto;
}
}



public class HelpText
{

Expand All @@ -48,46 +166,46 @@ ComparableOption ToComparableOption(Specification spec, int index)
LongName = name,
Index = index
};

}


public static Comparison<ComparableOption> OptionComparison = null;
public Comparison<ComparableOption> OptionComparison {get; set;} = null;

public static Comparison<ComparableOption> RequiredThenAlphaComparison = (ComparableOption attr1, ComparableOption attr2) =>
{
if (attr1.IsOption && attr2.IsOption)
{
if (attr1.Required && !attr2.Required)
{
return -1;
}
else if (!attr1.Required && attr2.Required)
{
return 1;
}
else
{
int t = String.Compare(attr1.LongName, attr2.LongName, StringComparison.CurrentCulture);
return t;
}
}
else if (attr1.IsOption && attr2.IsValue)
{
return -1;
}
else
{
return 1;
}
};

public static Comparison<ComparableOption> RequiredThenAlphaComparison = (ComparableOption attr1, ComparableOption attr2) =>
{
if (attr1.IsOption && attr2.IsOption)
{
if (attr1.Required && !attr2.Required)
{
return -1;
}
else if (!attr1.Required && attr2.Required)
{
return 1;
}
else
{
int t = String.Compare(attr1.LongName, attr2.LongName, StringComparison.CurrentCulture);
return t;
}
}
else if (attr1.IsOption && attr2.IsValue)
{
return -1;
}
else
{
return 1;
}
};

private const int BuilderCapacity = 128;
private const int DefaultMaximumLength = 80; // default console width
public const int DefaultMaximumLength = 80; // default console width
/// <summary>
/// The number of spaces between an option and its associated help text
/// </summary>
private const int OptionToHelpTextSeparatorWidth = 4;
private const int OptionToHelpTextSeparatorWidth = 4;
/// <summary>
/// The width of the option prefix (either "--" or " "
/// </summary>
Expand Down Expand Up @@ -304,6 +422,12 @@ public SentenceBuilder SentenceBuilder
/// <param name="verbsIndex">If true the output style is consistent with verb commands (no dashes), otherwise it outputs options.</param>
/// <param name="maxDisplayWidth">The maximum width of the display.</param>
/// <remarks>The parameter <paramref name="verbsIndex"/> is not ontly a metter of formatting, it controls whether to handle verbs or options.</remarks>

public static HelpTextBuilder<T> CreateWith<T>(ParserResult<T> parserResult)
{
return new HelpTextBuilder<T>(parserResult);
}

public static HelpText AutoBuild<T>(
ParserResult<T> parserResult,
Func<HelpText, HelpText> onError,
Expand Down
55 changes: 55 additions & 0 deletions tests/CommandLine.Tests/Unit/Issue482Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,61 @@ public void AutoBuild_with_ordering()

;
}

[Fact]
public void AutoBuild_with_ordering_fluent()
{
string expectedCompany = "Company";


var parser = Parser.Default;
var parseResult = parser.ParseArguments<Options_HelpText_Ordering_Verb1, Options_HelpText_Ordering_Verb2>(
new[] {"verb1", "--alpha", "alpaga", "--alpha2", "alala", "--charlie", "charlot"})
.WithNotParsed(errors => { throw new InvalidOperationException("Must be parsed."); })
.WithParsed(args => { ; });

Comparison<ComparableOption> comparison = HelpText.RequiredThenAlphaComparison;


var message = HelpText.CreateWith(parseResult)
.WithComparison(HelpText.RequiredThenAlphaComparison)
.OnError(error => {
throw new InvalidOperationException($"help text build failed. {error.ToString()}");
})
.OnExample(ex =>
{
return null;
})
.Build();





string helpMessage = message.ToString();
var helps = helpMessage.Split(new[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries).Skip(2).ToList<string>();
List<string> expected = new List<string>()
{
" -a, --alpha Required.",
" -b, --alpha2 Required.",
" -c, --bravo",
" -d, --charlie",
"-e, --echo",
"-f, --foxtrot",
"--help Display this help screen.",
"--version Display version information.",
"value pos. 0"
};
Assert.Equal(expected.Count,helps.Count);
int i = 0;
foreach (var expect in expected)
{
Assert.Equal(expect.Trim(),helps[i].Trim());
i++;
}

;
}


}
Expand Down

0 comments on commit 113a21c

Please sign in to comment.