diff --git a/src/CommandLine/Core/InstanceBuilder.cs b/src/CommandLine/Core/InstanceBuilder.cs index 0c24fddd..78120d98 100644 --- a/src/CommandLine/Core/InstanceBuilder.cs +++ b/src/CommandLine/Core/InstanceBuilder.cs @@ -23,6 +23,8 @@ public static ParserResult Build( StringComparer nameComparer, bool ignoreValueCase, CultureInfo parsingCulture, + bool autoHelp, + bool autoVersion, IEnumerable nonFatalErrors) { var typeInfo = factory.MapValueOrDefault(f => f().GetType(), typeof(T)); @@ -129,7 +131,7 @@ join sp in specPropsWithValue on prms.Name.ToLower() equals sp.Property.Name.ToL }; var preprocessorErrors = arguments.Any() - ? arguments.Preprocess(PreprocessorGuards.Lookup(nameComparer)) + ? arguments.Preprocess(PreprocessorGuards.Lookup(nameComparer, autoHelp, autoVersion)) : Enumerable.Empty(); var result = arguments.Any() diff --git a/src/CommandLine/Core/InstanceChooser.cs b/src/CommandLine/Core/InstanceChooser.cs index f68216b1..bdd5eb51 100644 --- a/src/CommandLine/Core/InstanceChooser.cs +++ b/src/CommandLine/Core/InstanceChooser.cs @@ -18,6 +18,8 @@ public static ParserResult Choose( IEnumerable arguments, StringComparer nameComparer, CultureInfo parsingCulture, + bool autoHelp, + bool autoVersion, IEnumerable nonFatalErrors) { Func> choose = () => @@ -30,13 +32,13 @@ public static ParserResult Choose( var verbs = Verb.SelectFromTypes(types); - return preprocCompare("help") + return (autoHelp && preprocCompare("help")) ? MakeNotParsed(types, MakeHelpVerbRequestedError(verbs, arguments.Skip(1).FirstOrDefault() ?? string.Empty, nameComparer)) - : preprocCompare("version") + : (autoVersion && preprocCompare("version")) ? MakeNotParsed(types, new VersionRequestedError()) - : MatchVerb(tokenizer, verbs, arguments, nameComparer, parsingCulture, nonFatalErrors); + : MatchVerb(tokenizer, verbs, arguments, nameComparer, parsingCulture, autoHelp, autoVersion, nonFatalErrors); }; return arguments.Any() @@ -50,6 +52,8 @@ private static ParserResult MatchVerb( IEnumerable arguments, StringComparer nameComparer, CultureInfo parsingCulture, + bool autoHelp, + bool autoVersion, IEnumerable nonFatalErrors) { return verbs.Any(a => nameComparer.Equals(a.Item1.Name, arguments.First())) @@ -62,6 +66,8 @@ private static ParserResult MatchVerb( nameComparer, false, parsingCulture, + autoHelp, + autoVersion, nonFatalErrors) : MakeNotParsed(verbs.Select(v => v.Item2), new BadVerbSelectedError(arguments.First())); } diff --git a/src/CommandLine/Core/PreprocessorGuards.cs b/src/CommandLine/Core/PreprocessorGuards.cs index 30ffe4a0..8d6fb5be 100644 --- a/src/CommandLine/Core/PreprocessorGuards.cs +++ b/src/CommandLine/Core/PreprocessorGuards.cs @@ -9,13 +9,14 @@ namespace CommandLine.Core static class PreprocessorGuards { public static IEnumerable, IEnumerable>> - Lookup(StringComparer nameComparer) + Lookup(StringComparer nameComparer, bool autoHelp, bool autoVersion) { - return new List, IEnumerable>> - { - HelpCommand(nameComparer), - VersionCommand(nameComparer) - }; + var list = new List, IEnumerable>>(); + if (autoHelp) + list.Add(HelpCommand(nameComparer)); + if (autoVersion) + list.Add(VersionCommand(nameComparer)); + return list; } public static Func, IEnumerable> HelpCommand(StringComparer nameComparer) diff --git a/src/CommandLine/Parser.cs b/src/CommandLine/Parser.cs index a1c5cbdf..dda21a3b 100644 --- a/src/CommandLine/Parser.cs +++ b/src/CommandLine/Parser.cs @@ -99,6 +99,8 @@ public ParserResult ParseArguments(IEnumerable args) settings.NameComparer, settings.CaseInsensitiveEnumValues, settings.ParsingCulture, + settings.AutoHelp, + settings.AutoVersion, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } @@ -128,6 +130,8 @@ public ParserResult ParseArguments(Func factory, IEnumerable ar settings.NameComparer, settings.CaseInsensitiveEnumValues, settings.ParsingCulture, + settings.AutoHelp, + settings.AutoVersion, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } @@ -157,6 +161,8 @@ public ParserResult ParseArguments(IEnumerable args, params Type args, settings.NameComparer, settings.ParsingCulture, + settings.AutoHelp, + settings.AutoVersion, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } diff --git a/src/CommandLine/ParserSettings.cs b/src/CommandLine/ParserSettings.cs index 93962566..be62bff1 100644 --- a/src/CommandLine/ParserSettings.cs +++ b/src/CommandLine/ParserSettings.cs @@ -20,6 +20,8 @@ public class ParserSettings : IDisposable private bool caseInsensitiveEnumValues; private TextWriter helpWriter; private bool ignoreUnknownArguments; + private bool autoHelp; + private bool autoVersion; private CultureInfo parsingCulture; private bool enableDashDash; private int maximumDisplayWidth; @@ -31,6 +33,8 @@ public ParserSettings() { caseSensitive = true; caseInsensitiveEnumValues = false; + autoHelp = true; + autoVersion = true; parsingCulture = CultureInfo.InvariantCulture; try { @@ -118,6 +122,24 @@ public bool IgnoreUnknownArguments set { PopsicleSetter.Set(Consumed, ref ignoreUnknownArguments, value); } } + /// + /// Gets or sets a value indicating whether implicit option or verb 'help' should be supported. + /// + public bool AutoHelp + { + get { return autoHelp; } + set { PopsicleSetter.Set(Consumed, ref autoHelp, value); } + } + + /// + /// Gets or sets a value indicating whether implicit option or verb 'version' should be supported. + /// + public bool AutoVersion + { + get { return autoVersion; } + set { PopsicleSetter.Set(Consumed, ref autoVersion, value); } + } + /// /// Gets or sets a value indicating whether enable double dash '--' syntax, /// that forces parsing of all subsequent tokens as values. diff --git a/src/CommandLine/Text/HelpText.cs b/src/CommandLine/Text/HelpText.cs index eaa6ade5..c7118ee6 100644 --- a/src/CommandLine/Text/HelpText.cs +++ b/src/CommandLine/Text/HelpText.cs @@ -31,6 +31,8 @@ public class HelpText private StringBuilder optionsHelp; private bool addDashesToOption; private bool addEnumValuesToHelpText; + private bool autoHelp; + private bool autoVersion; /// /// Initializes a new instance of the class. @@ -113,6 +115,8 @@ public HelpText(SentenceBuilder sentenceBuilder, string heading, string copyrigh this.sentenceBuilder = sentenceBuilder; this.heading = heading; this.copyright = copyright; + this.autoHelp = true; + this.autoVersion = true; } /// @@ -183,6 +187,24 @@ public bool AddEnumValuesToHelpText set { addEnumValuesToHelpText = value; } } + /// + /// Gets or sets a value indicating whether implicit option or verb 'help' should be supported. + /// + public bool AutoHelp + { + get { return autoHelp; } + set { autoHelp = value; } + } + + /// + /// Gets or sets a value indicating whether implicit option or verb 'version' should be supported. + /// + public bool AutoVersion + { + get { return autoVersion; } + set { autoVersion = value; } + } + /// /// Gets the instance specified in constructor. /// @@ -676,8 +698,11 @@ private IEnumerable GetSpecificationsFromType(Type type) { var specs = type.GetSpecifications(Specification.FromProperty); var optionSpecs = specs - .OfType() - .Concat(new[] { MakeHelpEntry(), MakeVersionEntry() }); + .OfType(); + if (autoHelp) + optionSpecs = optionSpecs.Concat(new [] { MakeHelpEntry() }); + if (autoVersion) + optionSpecs = optionSpecs.Concat(new [] { MakeVersionEntry() }); var valueSpecs = specs .OfType() .OrderBy(v => v.Index); @@ -707,7 +732,7 @@ private static Maybe>> GetUsageFromTy private IEnumerable AdaptVerbsToSpecifications(IEnumerable types) { - return (from verbTuple in Verb.SelectFromTypes(types) + var optionSpecs = from verbTuple in Verb.SelectFromTypes(types) select OptionSpecification.NewSwitch( string.Empty, @@ -715,7 +740,12 @@ private IEnumerable AdaptVerbsToSpecifications(IEnumerable false, verbTuple.Item1.HelpText, string.Empty, - verbTuple.Item1.Hidden)).Concat(new[] { MakeHelpEntry(), MakeVersionEntry() }); + verbTuple.Item1.Hidden); + if (autoHelp) + optionSpecs = optionSpecs.Concat(new [] { MakeHelpEntry() }); + if (autoVersion) + optionSpecs = optionSpecs.Concat(new [] { MakeVersionEntry() }); + return optionSpecs; } private HelpText AddOptionsImpl( diff --git a/tests/CommandLine.Tests/CommandLine.Tests.csproj b/tests/CommandLine.Tests/CommandLine.Tests.csproj index 5914a3a9..3d0b7798 100644 --- a/tests/CommandLine.Tests/CommandLine.Tests.csproj +++ b/tests/CommandLine.Tests/CommandLine.Tests.csproj @@ -58,6 +58,8 @@ Properties\SharedAssemblyInfo.cs + + diff --git a/tests/CommandLine.Tests/Fakes/Options_With_Custom_Help_Option.cs b/tests/CommandLine.Tests/Fakes/Options_With_Custom_Help_Option.cs new file mode 100644 index 00000000..0215d392 --- /dev/null +++ b/tests/CommandLine.Tests/Fakes/Options_With_Custom_Help_Option.cs @@ -0,0 +1,8 @@ +namespace CommandLine.Tests.Fakes +{ + class Options_With_Custom_Help_Option : Simple_Options + { + [Option('h', "help")] + public bool Help { get; set; } + } +} diff --git a/tests/CommandLine.Tests/Fakes/Options_With_Custom_Version_Option.cs b/tests/CommandLine.Tests/Fakes/Options_With_Custom_Version_Option.cs new file mode 100644 index 00000000..df392ff5 --- /dev/null +++ b/tests/CommandLine.Tests/Fakes/Options_With_Custom_Version_Option.cs @@ -0,0 +1,8 @@ +namespace CommandLine.Tests.Fakes +{ + class Options_With_Custom_Version_Option : Simple_Options + { + [Option('v', "version")] + public bool MyVersion { get; set; } + } +} diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs index 7d7544e6..2c962d6d 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceBuilderTests.cs @@ -19,7 +19,7 @@ namespace CommandLine.Tests.Unit.Core { public class InstanceBuilderTests { - private static ParserResult InvokeBuild(string[] arguments) + private static ParserResult InvokeBuild(string[] arguments, bool autoHelp = true, bool autoVersion = true) where T : new() { return InstanceBuilder.Build( @@ -29,6 +29,8 @@ private static ParserResult InvokeBuild(string[] arguments) StringComparer.Ordinal, false, CultureInfo.InvariantCulture, + autoHelp, + autoVersion, Enumerable.Empty()); } @@ -42,6 +44,8 @@ private static ParserResult InvokeBuildEnumValuesCaseIgnore(string[] argum StringComparer.Ordinal, true, CultureInfo.InvariantCulture, + true, + true, Enumerable.Empty()); } @@ -54,6 +58,8 @@ private static ParserResult InvokeBuildImmutable(string[] arguments) StringComparer.Ordinal, false, CultureInfo.InvariantCulture, + true, + true, Enumerable.Empty()); } @@ -451,6 +457,8 @@ public void Double_dash_force_subsequent_arguments_as_values() StringComparer.Ordinal, false, CultureInfo.InvariantCulture, + true, + true, Enumerable.Empty()); // Verify outcome @@ -1007,6 +1015,76 @@ public void Parse_string_with_dashes_except_in_beginning(string[] arguments, str // Teardown } + [Theory] + [InlineData(new[] { "--help" }, ErrorType.UnknownOptionError)] + public void Parse_without_auto_help_should_not_recognize_help_option(string[] arguments, ErrorType errorType) + { + // Fixture setup in attributes + + // Exercize system + var result = InvokeBuild(arguments, autoHelp: false); + + // Verify outcome + result.Should().BeOfType>() + .Which.Errors.Should().ContainSingle() + .Which.Tag.Should().Be(errorType); + + // Teardown + } + + [Theory] + [InlineData(new[] { "--help" }, true)] + [InlineData(new[] { "-h" }, true)] + [InlineData(new[] { "-x" }, false)] + public void Parse_with_custom_help_option(string[] arguments, bool isHelp) + { + // Fixture setup in attributes + + // Exercize system + var result = InvokeBuild(arguments, autoHelp: false); + + // Verify outcome + result.Should().BeOfType>() + .Which.Value.Help.Should().Be(isHelp); + + // Teardown + } + + [Theory] + [InlineData(new[] { "--version" }, ErrorType.UnknownOptionError)] + public void Parse_without_auto_version_should_not_recognize_version_option(string[] arguments, ErrorType errorType) + { + // Fixture setup in attributes + + // Exercize system + var result = InvokeBuild(arguments, autoVersion: false); + + // Verify outcome + result.Should().BeOfType>() + .Which.Errors.Should().ContainSingle() + .Which.Tag.Should().Be(errorType); + + // Teardown + } + + [Theory] + [InlineData(new[] { "--version" }, true)] + [InlineData(new[] { "-v" }, true)] + [InlineData(new[] { "-s", "s" }, false)] + public void Parse_with_custom_version_option(string[] arguments, bool isVersion) + { + // Fixture setup in attributes + + // Exercize system + var result = InvokeBuild(arguments, autoVersion: false); + + // Verify outcome + result.Should().BeOfType>() + .Which.Value.MyVersion.Should().Be(isVersion); + + // Teardown + } + [Theory] [MemberData("GuidData")] public void Parse_Guid(string[] arguments, Options_With_Guid expected) diff --git a/tests/CommandLine.Tests/Unit/Core/InstanceChooserTests.cs b/tests/CommandLine.Tests/Unit/Core/InstanceChooserTests.cs index 96d175b1..616f4ba5 100644 --- a/tests/CommandLine.Tests/Unit/Core/InstanceChooserTests.cs +++ b/tests/CommandLine.Tests/Unit/Core/InstanceChooserTests.cs @@ -23,6 +23,8 @@ private static ParserResult InvokeChoose( arguments, StringComparer.Ordinal, CultureInfo.InvariantCulture, + true, + true, Enumerable.Empty()); }