Example #1
0
        /// <summary>
        /// Retrieves the help text for the given options container type.
        /// </summary>
        /// <param name="containerType">
        /// The type of options container to retrieve the help text for.
        /// </param>
        /// <returns>
        /// A collection of text lines, the help text.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <para><paramref name="containerType"/> is <c>null</c>.</para>
        /// </exception>
        public static IEnumerable <string> GetHelp(Type containerType)
        {
            if (containerType == null)
            {
                throw new ArgumentNullException("containerType");
            }

            var map = new PropertyMap(containerType);

            // Command line help
            var parts         = new List <string>();
            int argumentIndex = 1;

            foreach (PropertyInfo prop in map.ArgumentProperties)
            {
                var    attr = (ArgumentAttribute)prop.GetCustomAttributes(typeof(ArgumentAttribute), true)[0];
                string name = attr.Name;
                if (StringEx.IsNullOrWhiteSpace(name))
                {
                    name = "ARG" + argumentIndex;
                }
                if (attr.Optional)
                {
                    parts.Add("[" + name + "]");
                }
                else
                {
                    parts.Add(name);
                }
                argumentIndex++;
            }

            if (map.ArgumentsProperty != null)
            {
                parts.Add("[ARG]...");
            }

            if (map.MappedProperties.Any())
            {
                parts.Add("[OPTIONS]...");
            }

            yield return(Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location).ToLower() + " " + string.Join(" ", parts.ToArray()));

            yield return(string.Empty);

            string[] containerHelp = GetHelpTextFor(containerType).ToArray();
            if (containerHelp.Length > 0)
            {
                foreach (string line in containerHelp)
                {
                    yield return(line);
                }
                yield return(string.Empty);
            }

            var argumentsWithDescription =
                (from entry in map.ArgumentProperties.Select((property, index) => new { property, index })
                 let descriptionAttr = entry.property.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault() as DescriptionAttribute
                                       where descriptionAttr != null
                                       let attr = (ArgumentAttribute)entry.property.GetCustomAttributes(typeof(ArgumentAttribute), true)[0]
                                                  let argName = !StringEx.IsNullOrWhiteSpace(attr.Name) ? attr.Name : ("ARG" + (entry.index + 1))
                                                                select new { argName, text = StringEx.SplitLines(descriptionAttr.Description).ToArray() }).ToArray();

            if (argumentsWithDescription.Length > 0)
            {
                yield return("arguments:");

                yield return(string.Empty);

                int maxLongLength = argumentsWithDescription.Max(p => p.argName.Length);

                foreach (var arg in argumentsWithDescription)
                {
                    int lines = arg.text.Length;
                    if (arg.argName.Length > 20)
                    {
                        yield return(" " + arg.argName);

                        var indent = new string(' ', maxLongLength + 3);
                        foreach (string line in arg.text)
                        {
                            yield return(indent + line);
                        }
                    }
                    else
                    {
                        yield return(" " + arg.argName.PadRight(maxLongLength, ' ') + "  " + arg.text[0]);

                        var indent = new string(' ', maxLongLength + 3);
                        foreach (string line in arg.text.Skip(1))
                        {
                            yield return(indent + line);
                        }
                    }
                }

                yield return(string.Empty);
            }

            var propertiesWithHelpText =
                (from propMap in map.MappedProperties
                 let text = GetHelpTextFor(propMap.Key).ToArray()
                            where text.Length > 0
                            select new
            {
                prop = propMap.Key, option = propMap.Value.Option, parameter = propMap.Value.ParameterName, text
            }
                 into entry
                 group entry by entry.prop
                 into g
                 select new
            {
                options = g.Select(e => e.option).OrderBy(o => o.Length).ToArray(), g.First().text, g.First().parameter
            }
                 into entry2
                 orderby(entry2.options.First() == "-h" || entry2.options.First() == "--help") ? 0 : 1, entry2.options.First()
                 let shortOption = entry2.options.Where(o => o.Length == 2).FirstOrDefault() ?? string.Empty
                                   let longOption = entry2.options.Where(o => o.Length > 2).FirstOrDefault() ?? string.Empty
                                                    select new
            {
                shortOption, longOption, entry2.options, entry2.parameter, entry2.text
            }).ToArray();

            if (propertiesWithHelpText.Length > 0)
            {
                yield return("options:");

                yield return(string.Empty);

                int maxLongLength = propertiesWithHelpText.Max(p => p.longOption.Length + p.parameter.Length);

                foreach (var prop in propertiesWithHelpText)
                {
                    int lines = prop.text.Length;
                    if (prop.longOption.Length > 20)
                    {
                        yield return(" " + (prop.shortOption.PadRight(2, ' ') + " " + prop.longOption + " " + prop.parameter).Trim());

                        var indent = new string(' ', 27);
                        foreach (string line in prop.text)
                        {
                            yield return(indent + line);
                        }
                    }
                    else
                    {
                        yield return(" " + prop.shortOption.PadRight(2, ' ') + " " + (prop.longOption + " " + prop.parameter).PadRight(20, ' ') + "  " + prop.text[0]);

                        var indent = new string(' ', 27);
                        foreach (string line in prop.text.Skip(1))
                        {
                            yield return(indent + line);
                        }
                    }
                }
            }
        }