diff --git a/src/CommandLine/Infrastructure/StringBuilderExtensions.cs b/src/CommandLine/Infrastructure/StringBuilderExtensions.cs
index 6519b66f..ae4ccbc4 100644
--- a/src/CommandLine/Infrastructure/StringBuilderExtensions.cs
+++ b/src/CommandLine/Infrastructure/StringBuilderExtensions.cs
@@ -113,5 +113,39 @@ public static int TrailingSpaces(this StringBuilder builder)
}
return c;
}
+
+ ///
+ /// Indicates whether the string value of a
+ /// starts with the input parameter. Returns false if either
+ /// the StringBuilder or input string is null or empty.
+ ///
+ /// The to test.
+ /// The to look for.
+ ///
+ 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;
+ }
+
+ ///
+ /// Indicates whether the string value of a
+ /// ends with the input parameter. Returns false if either
+ /// the StringBuilder or input string is null or empty.
+ ///
+ /// The to test.
+ /// The to look for.
+ ///
+ 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;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/CommandLine/Text/HelpText.cs b/src/CommandLine/Text/HelpText.cs
index b23bb804..2112a904 100644
--- a/src/CommandLine/Text/HelpText.cs
+++ b/src/CommandLine/Text/HelpText.cs
@@ -109,6 +109,7 @@ ComparableOption ToComparableOption(Specification spec, int index)
private bool addEnumValuesToHelpText;
private bool autoHelp;
private bool autoVersion;
+ private bool addNewLineBetweenHelpSections;
///
/// Initializes a new instance of the class.
@@ -258,6 +259,15 @@ public bool AdditionalNewLineAfterOption
set { additionalNewLineAfterOption = value; }
}
+ ///
+ /// Gets or sets a value indicating whether to add newlines between help sections.
+ ///
+ public bool AddNewLineBetweenHelpSections
+ {
+ get { return addNewLineBetweenHelpSections; }
+ set { addNewLineBetweenHelpSections = value; }
+ }
+
///
/// Gets or sets a value indicating whether to add the values of an enum after the description of the specification.
///
@@ -352,7 +362,11 @@ public static HelpText AutoBuild(
{
var heading = auto.SentenceBuilder.UsageHeadingText();
if (heading.Length > 0)
+ {
+ if (auto.AddNewLineBetweenHelpSections)
+ heading = Environment.NewLine + heading;
auto.AddPreOptionsLine(heading);
+ }
}
usageAttr.Do(
@@ -707,19 +721,40 @@ public static IEnumerable RenderUsageTextAsLines(ParserResult 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)
diff --git a/tests/CommandLine.Tests/Unit/StringBuilderExtensionsTests.cs b/tests/CommandLine.Tests/Unit/StringBuilderExtensionsTests.cs
new file mode 100644
index 00000000..8fe73a60
--- /dev/null
+++ b/tests/CommandLine.Tests/Unit/StringBuilderExtensionsTests.cs
@@ -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