diff --git a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt index 26cf6ad038..0269e4372d 100644 --- a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt +++ b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt @@ -54,7 +54,6 @@ System.CommandLine public System.Boolean TreatUnmatchedTokensAsErrors { get; set; } public System.Collections.Generic.List> Validators { get; } public System.Void Add(Symbol symbol) - public System.Void AddGlobalOption(Option option) public System.Collections.Generic.IEnumerable GetCompletions(System.CommandLine.Completions.CompletionContext context) public System.Collections.Generic.IEnumerator GetEnumerator() public static class CommandExtensions @@ -184,6 +183,7 @@ System.CommandLine public System.String VersionOptionDescription() public abstract class Option : IdentifierSymbol, System.CommandLine.Binding.IValueDescriptor public System.Boolean AllowMultipleArgumentsPerToken { get; set; } + public System.Boolean AppliesToSelfAndChildren { get; set; } public System.String ArgumentHelpName { get; set; } public ArgumentArity Arity { get; set; } public System.Collections.Generic.List>> CompletionSources { get; } diff --git a/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs b/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs index 70fbf85af0..1f992805f3 100644 --- a/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs +++ b/src/System.CommandLine.Tests/CommandLineConfigurationTests.cs @@ -170,13 +170,13 @@ public void ThrowIfInvalid_throws_if_sibling_command_and_option_aliases_collide_ [Fact] public void ThrowIfInvalid_throws_if_there_are_duplicate_sibling_global_option_aliases_on_the_root_command() { - var option1 = new Option("--dupe"); - var option2 = new Option("-y"); + var option1 = new Option("--dupe") { AppliesToSelfAndChildren = true }; + var option2 = new Option("-y") { AppliesToSelfAndChildren = true }; option2.AddAlias("--dupe"); var command = new RootCommand(); - command.AddGlobalOption(option1); - command.AddGlobalOption(option2); + command.Options.Add(option1); + command.Options.Add(option2); var config = new CommandLineConfiguration(command); @@ -200,7 +200,7 @@ public void ThrowIfInvalid_does_not_throw_if_global_option_alias_is_the_same_as_ new Option("--dupe") } }; - rootCommand.AddGlobalOption(new Option("--dupe")); + rootCommand.Options.Add(new Option("--dupe") { AppliesToSelfAndChildren = true }); var config = new CommandLineConfiguration(rootCommand); @@ -219,7 +219,7 @@ public void ThrowIfInvalid_does_not_throw_if_global_option_alias_is_the_same_as_ new Command("--dupe") } }; - rootCommand.AddGlobalOption(new Option("--dupe")); + rootCommand.Options.Add(new Option("--dupe") { AppliesToSelfAndChildren = true }); var config = new CommandLineConfiguration(rootCommand); diff --git a/src/System.CommandLine.Tests/CommandTests.cs b/src/System.CommandLine.Tests/CommandTests.cs index 9974354874..ff846e91ab 100644 --- a/src/System.CommandLine.Tests/CommandTests.cs +++ b/src/System.CommandLine.Tests/CommandTests.cs @@ -281,9 +281,9 @@ public void When_Name_is_set_to_its_current_value_then_it_is_not_removed_from_al [Fact] public void AddGlobalOption_updates_Options_property() { - var option = new Option("-x"); + var option = new Option("-x") { AppliesToSelfAndChildren = true }; var command = new Command("mycommand"); - command.AddGlobalOption(option); + command.Options.Add(option); command.Options .Should() @@ -303,7 +303,8 @@ public void When_Options_is_referenced_before_a_global_option_is_added_then_addi .Should() .BeEmpty(); - command.AddGlobalOption(option); + option.AppliesToSelfAndChildren = true; + command.Options.Add(option); command.Options .Should() diff --git a/src/System.CommandLine.Tests/CompletionTests.cs b/src/System.CommandLine.Tests/CompletionTests.cs index bb9691b151..29f9d2aaae 100644 --- a/src/System.CommandLine.Tests/CompletionTests.cs +++ b/src/System.CommandLine.Tests/CompletionTests.cs @@ -73,7 +73,7 @@ public void Command_GetCompletions_returns_available_option_aliases_for_global_o subcommand1 }; - rootCommand.AddGlobalOption(new Option("--three", "option three")); + rootCommand.Options.Add(new Option("--three", "option three") { AppliesToSelfAndChildren = true }); var completions = subcommand2.GetCompletions(CompletionContext.Empty); diff --git a/src/System.CommandLine.Tests/GlobalOptionTests.cs b/src/System.CommandLine.Tests/GlobalOptionTests.cs index 74a8c524d7..7de39fdd0a 100644 --- a/src/System.CommandLine.Tests/GlobalOptionTests.cs +++ b/src/System.CommandLine.Tests/GlobalOptionTests.cs @@ -13,9 +13,9 @@ public void Global_options_appear_in_options_list() { var root = new Command("parent"); - var option = new Option("--global"); + var option = new Option("--global") { AppliesToSelfAndChildren = true }; - root.AddGlobalOption(option); + root.Options.Add(option); var child = new Command("child"); @@ -32,9 +32,10 @@ public void When_a_required_global_option_is_omitted_it_results_in_an_error() command.SetHandler(() => { }); var requiredOption = new Option("--i-must-be-set") { - IsRequired = true + IsRequired = true, + AppliesToSelfAndChildren = true }; - rootCommand.AddGlobalOption(requiredOption); + rootCommand.Options.Add(requiredOption); var result = rootCommand.Parse("child"); @@ -50,9 +51,10 @@ public void When_a_required_global_option_has_multiple_aliases_the_error_message var rootCommand = new RootCommand(); var requiredOption = new Option(new[] { "-i", "--i-must-be-set" }) { - IsRequired = true + IsRequired = true, + AppliesToSelfAndChildren = true }; - rootCommand.AddGlobalOption(requiredOption); + rootCommand.Options.Add(requiredOption); var result = rootCommand.Parse(""); @@ -70,9 +72,10 @@ public void When_a_required_global_option_is_present_on_child_of_command_it_was_ command.SetHandler(() => { }); var requiredOption = new Option("--i-must-be-set") { - IsRequired = true + IsRequired = true, + AppliesToSelfAndChildren = true }; - rootCommand.AddGlobalOption(requiredOption); + rootCommand.Options.Add(requiredOption); var result = rootCommand.Parse("child --i-must-be-set"); @@ -84,9 +87,9 @@ public void Subcommands_added_after_a_global_option_is_added_to_parent_will_reco { var root = new Command("parent"); - var option = new Option("--global"); + var option = new Option("--global") { AppliesToSelfAndChildren = true }; - root.AddGlobalOption(option); + root.Options.Add(option); var child = new Command("child"); @@ -106,9 +109,9 @@ public void Subcommands_with_global_option_should_propagate_option_to_children() root.Subcommands.Add(firstChild); - var option = new Option("--global"); + var option = new Option("--global") { AppliesToSelfAndChildren = true }; - firstChild.AddGlobalOption(option); + firstChild.Options.Add(option); var secondChild = new Command("second"); diff --git a/src/System.CommandLine.Tests/ParseResultTests.cs b/src/System.CommandLine.Tests/ParseResultTests.cs index d0f22af927..d7ed496943 100644 --- a/src/System.CommandLine.Tests/ParseResultTests.cs +++ b/src/System.CommandLine.Tests/ParseResultTests.cs @@ -98,13 +98,13 @@ public void ParseResult_GetCompletions_returns_global_options_of_given_command_o { leafCommand }; - midCommand1.AddGlobalOption(new Option("--three1", "option three 1")); + midCommand1.Options.Add(new Option("--three1", "option three 1") { AppliesToSelfAndChildren = true }); var midCommand2 = new Command("midCommand2") { leafCommand }; - midCommand2.AddGlobalOption(new Option("--three2", "option three 2")); + midCommand2.Options.Add(new Option("--three2", "option three 2") { AppliesToSelfAndChildren = true }); var rootCommand = new Command("root") { diff --git a/src/System.CommandLine.Tests/ParsingValidationTests.cs b/src/System.CommandLine.Tests/ParsingValidationTests.cs index 66ce605324..85710b9395 100644 --- a/src/System.CommandLine.Tests/ParsingValidationTests.cs +++ b/src/System.CommandLine.Tests/ParsingValidationTests.cs @@ -458,7 +458,7 @@ public void All_custom_validators_are_called(string commandLine) [InlineData("subcommand --file \"Foo\"")] public void Validators_on_global_options_are_executed_when_invoking_a_subcommand(string commandLine) { - var option = new Option("--file"); + var option = new Option("--file") { AppliesToSelfAndChildren = true }; option.Validators.Add(r => { r.AddError("Invoked validator"); @@ -469,7 +469,7 @@ public void Validators_on_global_options_are_executed_when_invoking_a_subcommand { subCommand }; - rootCommand.AddGlobalOption(option); + rootCommand.Options.Add(option); var result = rootCommand.Parse(commandLine); @@ -495,7 +495,11 @@ public async Task A_custom_validator_added_to_a_global_option_is_checked(string { var handlerWasCalled = false; - var globalOption = new Option("--value"); + var globalOption = new Option("--value") + { + AppliesToSelfAndChildren = true + }; + globalOption.Validators.Add(r => r.AddError("oops!")); var grandchildCommand = new Command("grandchild"); @@ -509,7 +513,7 @@ public async Task A_custom_validator_added_to_a_global_option_is_checked(string childCommand }; - rootCommand.AddGlobalOption(globalOption); + rootCommand.Options.Add(globalOption); rootCommand.SetHandler((int i) => handlerWasCalled = true, globalOption); childCommand.SetHandler((int i) => handlerWasCalled = true, globalOption); diff --git a/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs b/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs index 3ee71b811d..048dbf4637 100644 --- a/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs +++ b/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs @@ -364,7 +364,7 @@ internal static CommandLineBuilder UseHelp( if (builder.HelpOption is null) { builder.HelpOption = helpOption; - builder.Command.AddGlobalOption(helpOption); + builder.Command.Options.Add(helpOption); builder.MaxHelpWidth = maxWidth; } return builder; diff --git a/src/System.CommandLine/Command.cs b/src/System.CommandLine/Command.cs index 1bf406913a..7bd9f12a43 100644 --- a/src/System.CommandLine/Command.cs +++ b/src/System.CommandLine/Command.cs @@ -81,18 +81,6 @@ public IEnumerable Children internal bool HasValidators => _validators is not null && _validators.Count > 0; - /// - /// Adds a global to the command. - /// - /// The global option to add to the command. - /// Global options are applied to the command and recursively to subcommands. They do not apply to - /// parent commands. - public void AddGlobalOption(Option option) - { - option.IsGlobal = true; - Options.Add(option); - } - /// /// Adds a to the command. /// @@ -202,7 +190,7 @@ public override IEnumerable GetCompletions(CompletionContext con { var option = parentCommand.Options[i]; - if (option.IsGlobal) + if (option.AppliesToSelfAndChildren) { AddCompletionsFor(option); } diff --git a/src/System.CommandLine/Help/HelpBuilder.Default.cs b/src/System.CommandLine/Help/HelpBuilder.Default.cs index 1681fb2583..77d5fe9912 100644 --- a/src/System.CommandLine/Help/HelpBuilder.Default.cs +++ b/src/System.CommandLine/Help/HelpBuilder.Default.cs @@ -226,7 +226,7 @@ public static Action OptionsSection() => foreach (var option in parentCommand.Options) { // global help aliases may be duplicated, we just ignore them - if (option.IsGlobal && !option.IsHidden && uniqueOptions.Add(option)) + if (option.AppliesToSelfAndChildren && !option.IsHidden && uniqueOptions.Add(option)) { options.Add(ctx.HelpBuilder.GetTwoColumnRow(option, ctx)); } diff --git a/src/System.CommandLine/Help/HelpBuilder.cs b/src/System.CommandLine/Help/HelpBuilder.cs index 0519020d4a..44a6d3280d 100644 --- a/src/System.CommandLine/Help/HelpBuilder.cs +++ b/src/System.CommandLine/Help/HelpBuilder.cs @@ -125,7 +125,7 @@ IEnumerable GetUsageParts() { if (!displayOptionTitle) { - displayOptionTitle = parentCommand.HasOptions && parentCommand.Options.Any(x => x.IsGlobal && !x.IsHidden); + displayOptionTitle = parentCommand.HasOptions && parentCommand.Options.Any(x => x.AppliesToSelfAndChildren && !x.IsHidden); } yield return parentCommand.Name; diff --git a/src/System.CommandLine/Help/HelpOption.cs b/src/System.CommandLine/Help/HelpOption.cs index 654afd5647..ab3726cdf3 100644 --- a/src/System.CommandLine/Help/HelpOption.cs +++ b/src/System.CommandLine/Help/HelpOption.cs @@ -15,6 +15,7 @@ public HelpOption(string[] aliases, Func getLocalizationR : base(aliases, null, new Argument { Arity = ArgumentArity.Zero }) { _localizationResources = getLocalizationResources; + AppliesToSelfAndChildren = true; } public HelpOption(Func getLocalizationResources) : this(new[] diff --git a/src/System.CommandLine/Option.cs b/src/System.CommandLine/Option.cs index 45f3ebae59..f1a473de42 100644 --- a/src/System.CommandLine/Option.cs +++ b/src/System.CommandLine/Option.cs @@ -72,10 +72,10 @@ public ArgumentArity Arity } /// - /// Global options are applied to the command and recursively to subcommands. - /// They do not apply to parent commands. + /// When set to true, this option will be applied to the command and recursively to subcommands. + /// It will not apply to parent commands. /// - internal bool IsGlobal { get; set; } + public bool AppliesToSelfAndChildren { get; set; } /// /// Validators that will be called when the option is matched by the parser. diff --git a/src/System.CommandLine/Parsing/CommandResult.cs b/src/System.CommandLine/Parsing/CommandResult.cs index 3b868952a2..6eb8f7b935 100644 --- a/src/System.CommandLine/Parsing/CommandResult.cs +++ b/src/System.CommandLine/Parsing/CommandResult.cs @@ -84,7 +84,7 @@ private void ValidateOptions(bool completeValidation) { var option = options[i]; - if (!completeValidation && !(option.IsGlobal || option.Argument.HasDefaultValue || (option is HelpOption or VersionOption))) + if (!completeValidation && !(option.AppliesToSelfAndChildren || option.Argument.HasDefaultValue || (option is HelpOption or VersionOption))) { continue; } diff --git a/src/System.CommandLine/Parsing/StringExtensions.cs b/src/System.CommandLine/Parsing/StringExtensions.cs index ee7010b933..78d3e85f95 100644 --- a/src/System.CommandLine/Parsing/StringExtensions.cs +++ b/src/System.CommandLine/Parsing/StringExtensions.cs @@ -454,7 +454,7 @@ private static Dictionary ValidTokens(this Command command) Option option = options[childIndex]; foreach (string childAlias in option.Aliases) { - if (!option.IsGlobal || !tokens.ContainsKey(childAlias)) + if (!option.AppliesToSelfAndChildren || !tokens.ContainsKey(childAlias)) { tokens.Add(childAlias, new Token(childAlias, TokenType.Option, option, Token.ImplicitPosition)); } @@ -476,7 +476,7 @@ private static Dictionary ValidTokens(this Command command) for (var i = 0; i < parentCommand.Options.Count; i++) { Option option = parentCommand.Options[i]; - if (option.IsGlobal) + if (option.AppliesToSelfAndChildren) { foreach (var childAlias in option.Aliases) {