diff --git a/src/CommandLine/Text/HelpText.cs b/src/CommandLine/Text/HelpText.cs
index 1306e969..b287a6e8 100644
--- a/src/CommandLine/Text/HelpText.cs
+++ b/src/CommandLine/Text/HelpText.cs
@@ -17,8 +17,72 @@ namespace CommandLine.Text
/// Provides means to format an help screen.
/// You can assign it in place of a instance.
///
+
+
+
+ public struct ComparableOption
+ {
+ public bool Required;
+ public bool IsOption;
+ public bool IsValue;
+ public string LongName;
+ public string ShortName;
+ public int Index;
+ }
+
public class HelpText
{
+
+ #region ordering
+
+ ComparableOption ToComparableOption(Specification spec, int index)
+ {
+ OptionSpecification option = spec as OptionSpecification;
+ ValueSpecification value = spec as ValueSpecification;
+ bool required = option?.Required ?? false;
+
+ return new ComparableOption()
+ {
+ Required = required,
+ IsOption = option != null,
+ IsValue = value != null,
+ LongName = option?.LongName ?? value?.MetaName,
+ ShortName = option?.ShortName,
+ Index = index
+ };
+ }
+
+
+ public Comparison OptionComparison { get; set; } = null;
+
+ public static Comparison 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;
+ }
+
+ return String.Compare(attr1.LongName, attr2.LongName, StringComparison.Ordinal);
+
+ }
+ else if (attr1.IsOption && attr2.IsValue)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ };
+
+ #endregion
+
private const int BuilderCapacity = 128;
private const int DefaultMaximumLength = 80; // default console width
///
@@ -240,6 +304,7 @@ public SentenceBuilder SentenceBuilder
/// A delegate used to customize model used to render text block of usage examples.
/// If true the output style is consistent with verb commands (no dashes), otherwise it outputs options.
/// The maximum width of the display.
+ /// a comparison lambda to order options in help text
/// The parameter is not ontly a metter of formatting, it controls whether to handle verbs or options.
public static HelpText AutoBuild(
ParserResult parserResult,
@@ -736,14 +801,37 @@ private HelpText AddOptionsImpl(
int maximumLength)
{
var maxLength = GetMaxLength(specifications);
+
+
optionsHelp = new StringBuilder(BuilderCapacity);
var remainingSpace = maximumLength - (maxLength + TotalOptionPadding);
- specifications.ForEach(
- option =>
- AddOption(requiredWord, maxLength, option, remainingSpace));
+ if (OptionComparison != null)
+ {
+ int i = -1;
+ var comparables = specifications.ToList().Select(s =>
+ {
+ i++;
+ return ToComparableOption(s, i);
+ }).ToList();
+ comparables.Sort(OptionComparison);
+
+
+ foreach (var comparable in comparables)
+ {
+ Specification spec = specifications.ElementAt(comparable.Index);
+ AddOption(requiredWord, maxLength, spec, remainingSpace);
+ }
+ }
+ else
+ {
+ specifications.ForEach(
+ option =>
+ AddOption(requiredWord, maxLength, option, remainingSpace));
+
+ }
return this;
}
@@ -953,5 +1041,3 @@ private static string FormatDefaultValue(T value)
}
}
-
-
diff --git a/tests/CommandLine.Tests/Fakes/OPtions_HelpText_Ordering.cs b/tests/CommandLine.Tests/Fakes/OPtions_HelpText_Ordering.cs
new file mode 100644
index 00000000..3896ab67
--- /dev/null
+++ b/tests/CommandLine.Tests/Fakes/OPtions_HelpText_Ordering.cs
@@ -0,0 +1,48 @@
+// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
+
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+namespace CommandLine.Tests.Fakes
+{
+
+ [Verb("verb1")]
+ class Options_HelpText_Ordering_Verb1
+ {
+ [Option('a', "alpha", Required = true)]
+ public string alphaOption { get; set; }
+
+ [Option('b', "alpha2", Required = true)]
+ public string alphaTwoOption { get; set; }
+
+ [Option('d', "charlie", Required = false)]
+ public string deltaOption { get; set; }
+
+ [Option('c', "bravo", Required = false)]
+ public string charlieOption { get; set; }
+
+ [Option('f', "foxtrot", Required = false)]
+ public string foxOption { get; set; }
+
+ [Option('e', "echo", Required = false)]
+ public string echoOption { get; set; }
+
+ [Value(0)] public string someExtraOption { get; set; }
+ }
+
+ [Verb("verb2")]
+ class Options_HelpText_Ordering_Verb2
+ {
+ [Option('a', "alpha", Required = true)]
+ public string alphaOption { get; set; }
+
+ [Option('b', "alpha2", Required = true)]
+ public string alphaTwoOption { get; set; }
+
+ [Option('c', "bravo", Required = false)]
+ public string charlieOption { get; set; }
+
+ [Option('d', "charlie", Required = false)]
+ public string deltaOption { get; set; }
+ }
+}
diff --git a/tests/CommandLine.Tests/Unit/Issue482Tests.cs b/tests/CommandLine.Tests/Unit/Issue482Tests.cs
new file mode 100644
index 00000000..61bc1f25
--- /dev/null
+++ b/tests/CommandLine.Tests/Unit/Issue482Tests.cs
@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using CommandLine.Core;
+using System.Linq;
+using System.Reflection;
+using CommandLine.Infrastructure;
+using CommandLine.Tests.Fakes;
+using CommandLine.Text;
+using FluentAssertions;
+using Xunit;
+using System.Text;
+using Xunit.Sdk;
+
+namespace CommandLine.Tests.Unit
+{
+ public class Issue482Tests
+ {
+ [Fact]
+ public void AutoBuild_without_ordering()
+ {
+ string expectedCompany = "Company";
+
+
+ var parser = Parser.Default;
+ var parseResult = parser.ParseArguments(
+ new[] { "verb1", "--help" })
+ .WithNotParsed(errors => { ; })
+ .WithParsed(args => {; });
+
+ var message = HelpText.AutoBuild(parseResult,
+ error =>error,
+ ex => ex
+ );
+
+ string helpMessage = message.ToString();
+ var helps = helpMessage.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Skip(2).ToList();
+ List expected = new List()
+ {
+ " -a, --alpha Required.",
+ " -b, --alpha2 Required.",
+ " -d, --charlie",
+ " -c, --bravo",
+ "-f, --foxtrot",
+ "-e, --echo",
+ "--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++;
+ }
+
+ ;
+ }
+
+ [Fact]
+ public void AutoBuild_with_ordering()
+ {
+ string expectedCompany = "Company";
+
+
+ var parser = Parser.Default;
+ var parseResult = parser.ParseArguments(
+ new[] { "verb1", "--help" })
+ .WithNotParsed(errors => { ; })
+ .WithParsed(args => {; });
+
+ Comparison comparison = HelpText.RequiredThenAlphaComparison;
+
+ string message = HelpText.AutoBuild(parseResult,
+ error =>
+ {
+ error.OptionComparison = HelpText.RequiredThenAlphaComparison;
+ return error;
+ },
+ ex => ex);
+
+
+ string helpMessage = message.ToString();
+ var helps = helpMessage.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Skip(2).ToList();
+ List expected = new List()
+ {
+ " -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++;
+ }
+
+ ;
+ }
+
+ [Fact]
+ public void AutoBuild_with_ordering_on_shortName()
+ {
+ string expectedCompany = "Company";
+
+
+ var parser = Parser.Default;
+ var parseResult = parser.ParseArguments(
+ new[] { "verb1", "--help" })
+ .WithNotParsed(errors => { ; })
+ .WithParsed(args => {; });
+
+ Comparison orderOnShortName = (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
+ {
+ if (string.IsNullOrEmpty(attr1.ShortName) && !string.IsNullOrEmpty(attr2.ShortName))
+ {
+ return 1;
+ }
+ else if (!string.IsNullOrEmpty(attr1.ShortName) && string.IsNullOrEmpty(attr2.ShortName))
+ {
+ return -1;
+ }
+ return String.Compare(attr1.ShortName, attr2.ShortName, StringComparison.Ordinal);
+ }
+ }
+ else if (attr1.IsOption && attr2.IsValue)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ };
+
+ string message = HelpText.AutoBuild(parseResult,
+ error =>
+ {
+ error.OptionComparison = orderOnShortName;
+ return error;
+ },
+ ex => ex,
+ false,
+ 80
+ );
+
+
+ var helps = message.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Skip(2).ToList();
+ List expected = new List()
+ {
+ " -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++;
+ }
+ }
+
+
+ }
+}