예제 #1
0
        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);
            }
        }
예제 #2
0
        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));
        }
예제 #3
0
        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);
                }
            }
        }