public static ParserResult <object> ParseVerbs(this Parser parser, IEnumerable <string> args, IDynamicVerbFactory dynamicVerbFactory, params Type[] types) { string[] argsArray = ModifyArgs(); return(ParseVerbs(parser, argsArray, dynamicVerbFactory, types.Concat(dynamicVerbFactory.GetDynamicVerbs(Array.Empty <string>())).ToArray(), new List <string>())); string[] ModifyArgs() { string[] result = args.ToArray(); if (result.Length > 1) { for (int i = 0; i < result.Length; i++) { if (result[i] == "--version") { result[i] = "-v"; } } } return(result); } }
private static ParserResult <object> ParseVerbs(Parser parser, string[] argsArray, IDynamicVerbFactory dynamicVerbFactory, Type[] types, List <string> path) { if (parser == null) { throw new ArgumentNullException(nameof(parser)); } if (argsArray.Length == 0 || argsArray[0].StartsWith("-", StringComparison.Ordinal)) { return(parser.ParseArguments(argsArray, types)); } var verb = argsArray[0]; foreach (var type in types) { var verbAttribute = type.GetCustomAttribute <VerbAttribute>(); if (verbAttribute == null || verbAttribute.Name != verb) { continue; } path.Add(verb); var subVerbsAttribute = type.GetCustomAttribute <ChildVerbsAttribute>(); Type[] subTypes = subVerbsAttribute?.Types ?? Array.Empty <Type>(); subTypes = subTypes.Concat(dynamicVerbFactory.GetDynamicVerbs(path)).ToArray(); if (subTypes.Any() && type.GetCustomAttribute <UseChildVerbsAsCategoryAttribute>() == null) { return(ParseVerbs(parser, argsArray.Skip(1).ToArray(), dynamicVerbFactory, subTypes, path)); } break; } return(parser.ParseArguments(argsArray, types)); }
private string ConstructHelp(ParserResult <object> result, ParserTypeInfo typeInfo) { List <string> helpText = new List <string>(); IEnumerable <Error> errors = ((NotParsed <object>)result).Errors.ToArray(); CopyrightInfo CreateCopyrightInfo() { try { return(CopyrightInfo.Default); } catch (Exception e) { executionContext.WriteError($"Exception while creating the copyright:{Environment.NewLine}{e}", false); } return(CopyrightInfo.Empty); } bool helpVerbRequested = errors.Any(e => e.Tag == ErrorType.HelpVerbRequestedError); Assembly assembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly(); GenerateHelpTextHeader(); GenerateHelpTextBody(); GenerateHelpTextFooter(); string help = string.Join(Environment.NewLine, helpText); return(help); void GenerateHelpTextHeader() { HelpText helpTextHeader = new HelpText { Heading = CreateHeadingInfo(), Copyright = CreateCopyrightInfo(), AdditionalNewLineAfterOption = true, AddDashesToOption = true, MaximumDisplayWidth = DisplayWidth }; helpTextHeader = HelpText.DefaultParsingErrorsHandler(result, helpTextHeader); AssemblyLicenseAttribute licenseAttribute = assembly.GetCustomAttribute <AssemblyLicenseAttribute>(); licenseAttribute?.AddToHelpText(helpTextHeader); helpText.AddRange(helpTextHeader.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None)); } void GenerateHelpTextBody() { if ((helpVerbRequested && typeInfo.Choices.Any()) || errors.Any(e => e.Tag == ErrorType.NoVerbSelectedError) || errors.Any(e => e.Tag == ErrorType.BadVerbSelectedError)) { HelpText helpTextBody = new HelpText { AdditionalNewLineAfterOption = true, AddDashesToOption = true, MaximumDisplayWidth = DisplayWidth }; helpTextBody.AddDashesToOption = false; helpTextBody.AddVerbs(typeInfo.Choices.ToArray()); List <string> helpLines = new List <string>(helpTextBody.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None)); //direct base type == VerbBase means first level - show version option if (typeInfo.Choices.Any() && typeInfo.Choices.First().BaseType != typeof(VerbBase)) { RemoveVersion(helpLines); } else { AddDashesToVersion(helpLines); } AddDashesToHelp(helpLines); helpText.AddRange(helpLines); } else { if (typeInfo.Current.GetCustomAttribute <UseChildVerbsAsCategoryAttribute>() != null) { ChildVerbsAttribute childVerbs = typeInfo.Current.GetCustomAttribute <ChildVerbsAttribute>(); IEnumerable <Type> childVerbTypes = (childVerbs?.Types ?? Enumerable.Empty <Type>()) .Concat(dynamicVerbFactory.GetDynamicVerbs(typeInfo.Current)); foreach (Type childVerbType in childVerbTypes) { HelpText helpTextBody = new HelpText { AdditionalNewLineAfterOption = true, AddDashesToOption = true, MaximumDisplayWidth = DisplayWidth }; helpTextBody.AddPreOptionsLine(childVerbType.GetCustomAttribute <VerbAttribute>().HelpText); if (typeof(TypeInfo).GetMethod("Create", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(Type) }, null) ?.Invoke(null, new object[] { childVerbType }) is TypeInfo childTypeInfo && typeof(Parsed <object>).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object), typeof(TypeInfo) }, null)?.Invoke(new[] { null, childTypeInfo }) is ParserResult <object> childResult) { helpTextBody.AddOptions(childResult); } List <string> helpLines = new List <string>(helpTextBody.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None)); RemoveVersion(helpLines); AddDashesToHelp(helpLines); helpText.AddRange(helpLines); } } else { HelpText helpTextBody = new HelpText { AdditionalNewLineAfterOption = true, AddDashesToOption = true, MaximumDisplayWidth = DisplayWidth }; helpTextBody.AddOptions(result); List <string> helpLines = new List <string>(helpTextBody.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None)); RemoveVersion(helpLines); AddDashesToHelp(helpLines); helpText.AddRange(helpLines); } } } void RemoveVersion(List <string> list) { string versionLine = list.FirstOrDefault(l => l.Trim().StartsWith("version ", StringComparison.Ordinal) || l.Trim().StartsWith("--version ", StringComparison.Ordinal)); if (!string.IsNullOrEmpty(versionLine)) { int index = list.IndexOf(versionLine); do { list.RemoveAt(index - 1); } while (!string.IsNullOrEmpty(list[index - 1])); } } void AddDashesToHelp(List <string> list) { string helpLine = list.FirstOrDefault(l => l.Trim().StartsWith("help ", StringComparison.Ordinal)); if (!string.IsNullOrEmpty(helpLine)) { int index = helpLine.IndexOf("help ", StringComparison.Ordinal); list[list.IndexOf(helpLine)] = helpLine.Substring(0, index) + "--help " + helpLine.Substring(index + "help ".Length + 2); } } void AddDashesToVersion(List <string> list) { string versionLine = list.FirstOrDefault(l => l.Trim().StartsWith("version ", StringComparison.Ordinal) && string.IsNullOrWhiteSpace(list[list.IndexOf(l) - 1])); if (!string.IsNullOrEmpty(versionLine)) { int index = versionLine.IndexOf("version ", StringComparison.Ordinal); list[list.IndexOf(versionLine)] = versionLine.Substring(0, index) + "--version " + versionLine.Substring(index + "version ".Length + 2); } } void GenerateHelpTextFooter() { UsageExample[] examples = GetExamplesFromVerb(typeInfo.Current); if (examples.Any()) { HelpText helpTextFooter = new HelpText { AdditionalNewLineAfterOption = true, AddDashesToOption = true, MaximumDisplayWidth = DisplayWidth }; helpTextFooter.AddPostOptionsLine("Examples:"); helpTextFooter.AddPostOptionsLine(string.Empty); string commandName = assembly.GetName().Name.ToLowerInvariant(); foreach (UsageExample usageExample in examples) { PrintExample(helpTextFooter, usageExample, commandName); } if (typeInfo.Current.GetCustomAttribute <UseChildVerbsAsCategoryAttribute>() != null) { ChildVerbsAttribute childVerbs = typeInfo.Current.GetCustomAttribute <ChildVerbsAttribute>(); IEnumerable <Type> childVerbTypes = (childVerbs?.Types ?? Enumerable.Empty <Type>()) .Concat(dynamicVerbFactory.GetDynamicVerbs(typeInfo.Current)); IEnumerable <(string verbName, UsageExample[] examples)> childExamples = childVerbTypes.Select(t => (t.GetCustomAttribute <VerbAttribute>().Name, GetExamplesFromVerb(t))) .Where(e => e.Item2.Any()); foreach ((string verbName, UsageExample[] usageExamples) in childExamples) { helpTextFooter.AddPostOptionsLine(string.Empty); helpTextFooter.AddPostOptionsLine($"For {verbName}s:"); helpTextFooter.AddPostOptionsLine(string.Empty); foreach (UsageExample usageExample in usageExamples) { PrintExample(helpTextFooter, usageExample, commandName); } } } helpText.AddRange(helpTextFooter.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None)); } void PrintExample(HelpText helpTextFooter, UsageExample usageExample, string commandName) { helpTextFooter.AddPostOptionsLine(usageExample.HelpText.EndsWith(":", StringComparison.Ordinal) ? usageExample.HelpText : $"{usageExample.HelpText}:"); helpTextFooter.AddPostOptionsLine($@"{commandName} {usageExample.Command}"); helpTextFooter.AddPostOptionsLine(string.Empty); } UsageExample[] GetExamplesFromVerb(Type verbType) { PropertyInfo property = verbType.GetProperties(BindingFlags.Public | BindingFlags.Static) .FirstOrDefault(p => p.GetCustomAttribute <UsageAttribute>() != null && p.PropertyType == typeof(IEnumerable <UsageExample>)); UsageExample[] verbExamples = ((IEnumerable <UsageExample>)property?.GetValue(null) ?? Enumerable.Empty <UsageExample>()) .ToArray(); return(verbExamples); } } }