diff --git a/src/System.CommandLine.Tests/HelpOptionTests.cs b/src/System.CommandLine.Tests/HelpOptionTests.cs index 922fc159e..98fff4cee 100644 --- a/src/System.CommandLine.Tests/HelpOptionTests.cs +++ b/src/System.CommandLine.Tests/HelpOptionTests.cs @@ -6,6 +6,7 @@ using System.CommandLine.Invocation; using System.CommandLine.Tests.Utility; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -239,9 +240,9 @@ public void The_users_can_set_max_width() RootCommand rootCommand = new(description); rootCommand.Options.Clear(); - rootCommand.Options.Add(new HelpOption() + rootCommand.Options.Add(new HelpOption { - Action = new HelpAction() + Action = new HelpAction { MaxWidth = 2 /* each line starts with two spaces */ + description.Length / 2 } @@ -286,6 +287,79 @@ public void DefaultValueFactory_does_not_throw_when_help_is_invoked() invocationConfiguration.Error.ToString().Should().Be(""); } + [Fact] // https://github.com/dotnet/command-line-api/issues/2589 + public void Help_and_version_options_are_displayed_after_other_options_on_root_command() + { + var command = new RootCommand + { + Subcommands = + { + new Command("subcommand") + { + Description = "The subcommand" + } + }, + Options = + { + new Option("-i") + { + Description = "The option" + } + } + }; + + var output = new StringWriter(); + + + command.Parse("-h").Invoke(new() { Output = output }); + + output.ToString() + .Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries) + .Select(line => line.Trim()) + .Should() + .ContainInOrder([ + "Options:", + "-i The option", + "-?, -h, --help Show help and usage information", + "--version Show version information", + "Commands:" + ]); + } + + [Fact] // https://github.com/dotnet/command-line-api/issues/2589 + public void Help_and_version_options_are_displayed_after_other_options_on_subcommand() + { + var command = new RootCommand + { + Subcommands = + { + new Command("subcommand") + { + Description = "The subcommand", Options = + { + new Option("-i") + { + Description = "The option" + } + } + } + } + }; + + var output = new StringWriter(); + + command.Parse("subcommand -h").Invoke(new() { Output = output }); + + output.ToString() + .Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries) + .Select(line => line.Trim()) + .Should() + .ContainInOrder([ + "Options:", + "-i The option", + "-?, -h, --help Show help and usage information", + ]); + } private sealed class CustomizedHelpAction : SynchronousCommandLineAction { diff --git a/src/System.CommandLine/Help/HelpBuilder.Default.cs b/src/System.CommandLine/Help/HelpBuilder.Default.cs index 33e53c0da..83e9150ae 100644 --- a/src/System.CommandLine/Help/HelpBuilder.Default.cs +++ b/src/System.CommandLine/Help/HelpBuilder.Default.cs @@ -215,15 +215,16 @@ public static Func OptionsSection() => { List optionRows = new(); bool addedHelpOption = false; - foreach (Option option in ctx.Command.Options) + foreach (Option option in ctx.Command.Options.OrderBy(o => o is HelpOption or VersionOption)) { if (!option.Hidden) { - optionRows.Add(ctx.HelpBuilder.GetTwoColumnRow(option, ctx)); if (option is HelpOption) { addedHelpOption = true; } + + optionRows.Add(ctx.HelpBuilder.GetTwoColumnRow(option, ctx)); } }