Skip to content

Commit

Permalink
Improve spacing in HelpText (#494)
Browse files Browse the repository at this point in the history
* Improve spacing in HelpText

* Make new spacing an option

* Refactor

* Extend logic to PostOptions

* Add XML docs
  • Loading branch information
asherber authored and moh-hassan committed Dec 7, 2019
1 parent ce3011c commit 0148bda
Show file tree
Hide file tree
Showing 4 changed files with 378 additions and 96 deletions.
36 changes: 35 additions & 1 deletion src/CommandLine/Infrastructure/StringBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,39 @@ public static int TrailingSpaces(this StringBuilder builder)
}
return c;
}

/// <summary>
/// Indicates whether the string value of a <see cref="System.Text.StringBuilder"/>
/// starts with the input <see cref="System.String"/> parameter. Returns false if either
/// the StringBuilder or input string is null or empty.
/// </summary>
/// <param name="builder">The <see cref="System.Text.StringBuilder"/> to test.</param>
/// <param name="s">The <see cref="System.String"/> to look for.</param>
/// <returns></returns>
public static bool SafeStartsWith(this StringBuilder builder, string s)
{
if (string.IsNullOrEmpty(s))
return false;

return builder?.Length >= s.Length
&& builder.ToString(0, s.Length) == s;
}

/// <summary>
/// Indicates whether the string value of a <see cref="System.Text.StringBuilder"/>
/// ends with the input <see cref="System.String"/> parameter. Returns false if either
/// the StringBuilder or input string is null or empty.
/// </summary>
/// <param name="builder">The <see cref="System.Text.StringBuilder"/> to test.</param>
/// <param name="s">The <see cref="System.String"/> to look for.</param>
/// <returns></returns>
public static bool SafeEndsWith(this StringBuilder builder, string s)
{
if (string.IsNullOrEmpty(s))
return false;

return builder?.Length >= s.Length
&& builder.ToString(builder.Length - s.Length, s.Length) == s;
}
}
}
}
55 changes: 45 additions & 10 deletions src/CommandLine/Text/HelpText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ ComparableOption ToComparableOption(Specification spec, int index)
private bool addEnumValuesToHelpText;
private bool autoHelp;
private bool autoVersion;
private bool addNewLineBetweenHelpSections;

/// <summary>
/// Initializes a new instance of the <see cref="CommandLine.Text.HelpText"/> class.
Expand Down Expand Up @@ -258,6 +259,15 @@ public bool AdditionalNewLineAfterOption
set { additionalNewLineAfterOption = value; }
}

/// <summary>
/// Gets or sets a value indicating whether to add newlines between help sections.
/// </summary>
public bool AddNewLineBetweenHelpSections
{
get { return addNewLineBetweenHelpSections; }
set { addNewLineBetweenHelpSections = value; }
}

/// <summary>
/// Gets or sets a value indicating whether to add the values of an enum after the description of the specification.
/// </summary>
Expand Down Expand Up @@ -352,7 +362,11 @@ public static HelpText AutoBuild<T>(
{
var heading = auto.SentenceBuilder.UsageHeadingText();
if (heading.Length > 0)
{
if (auto.AddNewLineBetweenHelpSections)
heading = Environment.NewLine + heading;
auto.AddPreOptionsLine(heading);
}
}

usageAttr.Do(
Expand Down Expand Up @@ -707,19 +721,40 @@ public static IEnumerable<string> RenderUsageTextAsLines<T>(ParserResult<T> pars
public override string ToString()
{
const int ExtraLength = 10;
return
new StringBuilder(
heading.SafeLength() + copyright.SafeLength() + preOptionsHelp.SafeLength() +
optionsHelp.SafeLength() + ExtraLength).Append(heading)
.AppendWhen(!string.IsNullOrEmpty(copyright), Environment.NewLine, copyright)
.AppendWhen(preOptionsHelp.Length > 0, Environment.NewLine, preOptionsHelp.ToString())
.AppendWhen(
optionsHelp != null && optionsHelp.Length > 0,

var sbLength = heading.SafeLength() + copyright.SafeLength() + preOptionsHelp.SafeLength()
+ optionsHelp.SafeLength() + postOptionsHelp.SafeLength() + ExtraLength;
var result = new StringBuilder(sbLength);

result.Append(heading)
.AppendWhen(!string.IsNullOrEmpty(copyright),
Environment.NewLine,
copyright)
.AppendWhen(preOptionsHelp.SafeLength() > 0,
NewLineIfNeededBefore(preOptionsHelp),
Environment.NewLine,
preOptionsHelp.ToString())
.AppendWhen(optionsHelp.SafeLength() > 0,
Environment.NewLine,
Environment.NewLine,
optionsHelp.SafeToString())
.AppendWhen(postOptionsHelp.Length > 0, Environment.NewLine, postOptionsHelp.ToString())
.ToString();
.AppendWhen(postOptionsHelp.SafeLength() > 0,
NewLineIfNeededBefore(postOptionsHelp),
Environment.NewLine,
postOptionsHelp.ToString());

string NewLineIfNeededBefore(StringBuilder sb)
{
if (AddNewLineBetweenHelpSections
&& result.Length > 0
&& !result.SafeEndsWith(Environment.NewLine)
&& !sb.SafeStartsWith(Environment.NewLine))
return Environment.NewLine;
else
return null;
}

return result.ToString();
}

internal static void AddLine(StringBuilder builder, string value, int maximumLength)
Expand Down
104 changes: 104 additions & 0 deletions tests/CommandLine.Tests/Unit/StringBuilderExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using FluentAssertions;
using CommandLine.Infrastructure;

namespace CommandLine.Tests.Unit
{
public class StringBuilderExtensionsTests
{
private static StringBuilder _sb = new StringBuilder("test string");
private static StringBuilder _emptySb = new StringBuilder();
private static StringBuilder _nullSb = null;

public static IEnumerable<object[]> GoodStartsWithData => new []
{
new object[] { "t" },
new object[] { "te" },
new object[] { "test " },
new object[] { "test string" }
};

public static IEnumerable<object[]> BadTestData => new []
{
new object[] { null },
new object[] { "" },
new object[] { "xyz" },
new object[] { "some long test string" }
};

public static IEnumerable<object[]> GoodEndsWithData => new[]
{
new object[] { "g" },
new object[] { "ng" },
new object[] { " string" },
new object[] { "test string" }
};



[Theory]
[MemberData(nameof(GoodStartsWithData))]
[MemberData(nameof(BadTestData))]
public void StartsWith_null_builder_returns_false(string input)
{
_nullSb.SafeStartsWith(input).Should().BeFalse();
}

[Theory]
[MemberData(nameof(GoodStartsWithData))]
[MemberData(nameof(BadTestData))]
public void StartsWith_empty_builder_returns_false(string input)
{
_emptySb.SafeStartsWith(input).Should().BeFalse();
}

[Theory]
[MemberData(nameof(GoodStartsWithData))]
public void StartsWith_good_data_returns_true(string input)
{
_sb.SafeStartsWith(input).Should().BeTrue();
}

[Theory]
[MemberData(nameof(BadTestData))]
public void StartsWith_bad_data_returns_false(string input)
{
_sb.SafeStartsWith(input).Should().BeFalse();
}

[Theory]
[MemberData(nameof(GoodEndsWithData))]
[MemberData(nameof(BadTestData))]
public void EndsWith_null_builder_returns_false(string input)
{
_nullSb.SafeEndsWith(input).Should().BeFalse();
}

[Theory]
[MemberData(nameof(GoodEndsWithData))]
[MemberData(nameof(BadTestData))]
public void EndsWith_empty_builder_returns_false(string input)
{
_emptySb.SafeEndsWith(input).Should().BeFalse();
}

[Theory]
[MemberData(nameof(GoodEndsWithData))]
public void EndsWith_good_data_returns_true(string input)
{
_sb.SafeEndsWith(input).Should().BeTrue();
}

[Theory]
[MemberData(nameof(BadTestData))]
public void EndsWith_bad_data_returns_false(string input)
{
_sb.SafeEndsWith(input).Should().BeFalse();
}
}
}
Loading

0 comments on commit 0148bda

Please sign in to comment.