private static void GetEnumsToDocument(ArgumentSetUsageInfo setInfo,
                                               out IReadOnlyDictionary <ArgumentUsageInfo, List <IEnumArgumentType> > inlineDocumented,
                                               out IEnumerable <IEnumArgumentType> separatelyDocumented)
        {
            var enumTypeMap = GetAllArgumentTypeMap(setInfo, t => t is IEnumArgumentType);

            var id = new Dictionary <ArgumentUsageInfo, List <IEnumArgumentType> >();

            inlineDocumented = id;

            foreach (var pair in enumTypeMap.Where(e => e.Value.Count == 1))
            {
                var newKey = pair.Value.Single();
                if (!id.TryGetValue(newKey, out List <IEnumArgumentType> types))
                {
                    types      = new List <IEnumArgumentType>();
                    id[newKey] = types;
                }

                types.Add((IEnumArgumentType)pair.Key);
            }

            separatelyDocumented = enumTypeMap
                                   .Where(e => e.Value.Count > 1)
                                   .Select(e => (IEnumArgumentType)e.Key);
        }
        private IReadOnlyList <Section> GenerateSections(ArgumentSetUsageInfo info)
        {
            var sections = new List <Section>();

            // If requested, add a "logo" for the program.
            if (Options.HasFlag(UsageInfoOptions.IncludeLogo) &&
                info.Logo != null && !info.Logo.IsEmpty())
            {
                sections.Add(new Section(null, info.Logo));
            }

            // Append the "NAME" section: lists the program name.
            if (Options.HasFlag(UsageInfoOptions.IncludeName))
            {
                sections.Add(new Section(Strings.UsageInfoNameHeader.ToUpper(), info.Name));
            }

            // Append the "SYNTAX" section: describes the basic syntax.
            if (Options.HasFlag(UsageInfoOptions.IncludeBasicSyntax))
            {
                sections.Add(new Section(Strings.UsageInfoSyntaxHeader.ToUpper(), info.Name + " " + info.GetBasicSyntax()));
            }

            // If present (and if requested), display the "DESCRIPTION" for the
            // program here.
            if (Options.HasFlag(UsageInfoOptions.IncludeDescription) && !string.IsNullOrEmpty(info.Description))
            {
                sections.Add(new Section(Strings.UsageInfoDescriptionHeader.ToUpper(), info.Description));
            }

            // If desired (and present), append "REQUIRED PARAMETERS" section.
            if (Options.HasFlag(UsageInfoOptions.IncludeRequiredParameterDescriptions) &&
                info.RequiredParameters.Any())
            {
                var entries = GetParameterEntries(info.RequiredParameters, info);
                sections.Add(new Section(Strings.UsageInfoRequiredParametersHeader.ToUpper(), entries));
            }

            // If desired (and present), append "OPTIONAL PARAMETERS" section.
            if (Options.HasFlag(UsageInfoOptions.IncludeOptionalParameterDescriptions) &&
                info.OptionalParameters.Any())
            {
                var entries = GetParameterEntries(info.OptionalParameters, info);
                sections.Add(new Section(Strings.UsageInfoOptionalParametersHeader.ToUpper(), entries));
            }

            // If present, append "EXAMPLES" section.
            if (Options.HasFlag(UsageInfoOptions.IncludeExamples) && info.Examples.Any())
            {
                sections.Add(new Section(Strings.UsageInfoExamplesHeader.ToUpper(), info.Examples));
            }

            // If requested, display remarks
            if (Options.HasFlag(UsageInfoOptions.IncludeRemarks) && !string.IsNullOrEmpty(info.Remarks))
            {
                sections.Add(new Section(Strings.UsageInfoRemarksHeader.ToUpper(), info.Remarks));
            }

            return(sections);
        }
        /// <summary>
        /// Constructs a user-friendly usage string describing the command-line
        /// argument syntax.
        /// </summary>
        /// <param name="maxUsageWidth">Maximum width in characters for the
        /// usage text; used to wrap it.</param>
        /// <param name="commandName">Command name to display in the usage
        /// information.</param>
        /// <param name="options">Options for generating info.</param>
        /// <param name="destination">Destination object, optionally.</param>
        /// <returns>The constructed usage information string.</returns>
        public ColoredMultistring GetUsageInfo(int maxUsageWidth, string commandName, UsageInfoOptions options, object destination = null)
        {
            // Construct info for argument set.
            var info = new ArgumentSetUsageInfo
            {
                Name                   = commandName ?? AssemblyUtilities.GetAssemblyFileName(),
                Description            = _argumentSet.Attribute.AdditionalHelp,
                DefaultShortNamePrefix = _argumentSet.Attribute.ShortNameArgumentPrefixes.FirstOrDefault()
            };

            // Add parameters and examples.
            info.AddParameters(GetArgumentUsageInfo(destination));
            if (_argumentSet.Attribute.Examples != null)
            {
                info.AddExamples(_argumentSet.Attribute.Examples);
            }

            // Update logo, if one was provided.
            if (_argumentSet.Attribute.LogoString != null)
            {
                info.Logo = _argumentSet.Attribute.LogoString;
            }

            // Compose remarks, if any.
            const string defaultHelpArgumentName = "?";
            var          namedArgPrefix          = _argumentSet.Attribute.ShortNameArgumentPrefixes.FirstOrDefault();

            if (_argumentSet.TryGetNamedArgument(defaultHelpArgumentName, out ArgumentDefinition ignored) && namedArgPrefix != null)
            {
                info.Remarks = string.Format(Strings.UsageInfoHelpAdvertisement, $"{info.Name} {namedArgPrefix}{defaultHelpArgumentName}");
            }

            // Construct formatter and use it.
            HelpFormatter formatter;

            if (options.HasFlag(UsageInfoOptions.VerticallyExpandedOutput))
            {
                formatter = new PowershellStyleHelpFormatter();
            }
            else
            {
                formatter = new CondensedHelpFormatter();
            }

            formatter.MaxWidth = maxUsageWidth;
            formatter.Options  = options;

            return(formatter.Format(info));
        }
        private IEnumerable <ColoredMultistring> GetParameterEntries(
            IEnumerable <ArgumentUsageInfo> info,
            ArgumentSetUsageInfo setInfo,
            IReadOnlyDictionary <ArgumentUsageInfo, List <IEnumArgumentType> > inlineDocumentedEnums)
        {
            var entries = info.SelectMany(i =>
            {
                List <IEnumArgumentType> enumTypes = null;
                inlineDocumentedEnums?.TryGetValue(i, out enumTypes);

                // N.B. Special-case parent command groups that are already selected (i.e. skip them).
                if (i.IsSelectedCommand())
                {
                    return(Enumerable.Empty <ColoredMultistring>());
                }

                return(FormatParameterInfo(i, setInfo, enumTypes));
            });

            return(entries);
        }
        private IEnumerable <ColoredMultistring> FormatParameterInfo(
            ArgumentUsageInfo info,
            ArgumentSetUsageInfo setInfo,
            List <IEnumArgumentType> inlineDocumentedEnums)
        {
            var builder = new ColoredMultistringBuilder();

            var syntax = SimplifyParameterSyntax(info.DetailedSyntax);

            builder.Append(new ColoredString(syntax, ParameterNameForegroundColor));

            if (!string.IsNullOrEmpty(info.Description))
            {
                builder.Append(" - ");
                builder.Append(info.Description);
            }

            var metadataItems = new List <List <ColoredString> >();

            if (Options.HasFlag(UsageInfoOptions.IncludeParameterDefaultValues) &&
                !string.IsNullOrEmpty(info.DefaultValue))
            {
                metadataItems.Add(new List <ColoredString>
                {
                    new ColoredString(Strings.UsageInfoDefaultValue, ParameterMetadataForegroundColor),
                    " ",
                    info.DefaultValue
                });
            }

            // Append parameter's short name (if it has one).
            if (Options.HasFlag(UsageInfoOptions.IncludeParameterShortNameAliases) &&
                !string.IsNullOrEmpty(info.ShortName) &&
                !string.IsNullOrEmpty(setInfo.DefaultShortNamePrefix))
            {
                metadataItems.Add(new List <ColoredString>
                {
                    new ColoredString(Strings.UsageInfoShortForm, ParameterMetadataForegroundColor),
                    " ",
                    new ColoredString(setInfo.DefaultShortNamePrefix + info.ShortName, NameForegroundColor)
                });
            }

            if (metadataItems.Count > 0)
            {
                builder.Append(" [");
                builder.Append(metadataItems.InsertBetween(new List <ColoredString> {
                    ", "
                }).Flatten());
                builder.Append("]");
            }

            var formattedInfo = new List <ColoredMultistring> {
                builder.ToMultistring()
            };

            if (inlineDocumentedEnums?.Count > 0)
            {
                foreach (var entry in inlineDocumentedEnums.SelectMany(GetEnumValueEntries))
                {
                    var indentedEntry = new ColoredMultistring(new ColoredString[]
                    {
                        new string(' ', Section.DefaultIndent)
                    }.Concat(entry.Content));
                    formattedInfo.Add(indentedEntry);
                }
            }

            return(formattedInfo);
        }
        private IReadOnlyList <Section> GenerateSections(ArgumentSetUsageInfo info)
        {
            var sections = new List <Section>();

            if (Options.HasFlag(UsageInfoOptions.IncludeLogo) &&
                info.Logo != null && !info.Logo.IsEmpty())
            {
                sections.Add(new Section(null, info.Logo)
                {
                    BodyIndentWidth = 0
                });
            }

            // Append basic usage info.
            if (Options.HasFlag(UsageInfoOptions.IncludeBasicSyntax))
            {
                var basicSyntax = new ColoredString[]
                {
                    new ColoredString(info.Name, NameForegroundColor),
                    " ",
                    info.GetBasicSyntax(includeOptionalParameters: true)
                };

                sections.Add(new Section(Strings.UsageInfoUsageHeader + ":", new[] { new ColoredMultistring(basicSyntax) })
                {
                    BodyIndentWidth    = Section.DefaultIndent * 3 / 2,
                    HangingIndentWidth = Section.DefaultIndent / 2
                });
            }

            if (Options.HasFlag(UsageInfoOptions.IncludeDescription) && !string.IsNullOrEmpty(info.Description))
            {
                sections.Add(new Section(null, info.Description));
            }

            // If needed, get help info for enum values.
            IReadOnlyDictionary <ArgumentUsageInfo, List <IEnumArgumentType> > inlineDocumented = null;
            IEnumerable <IEnumArgumentType> separatelyDocumented = null;

            if (Options.HasFlag(UsageInfoOptions.IncludeEnumValues))
            {
                GetEnumsToDocument(info, out inlineDocumented, out separatelyDocumented);
            }

            // If desired (and present), append "REQUIRED PARAMETERS" section.
            if (Options.HasFlag(UsageInfoOptions.IncludeRequiredParameterDescriptions) &&
                info.RequiredParameters.Any())
            {
                var entries = GetParameterEntries(info.RequiredParameters, info, inlineDocumented).ToList();
                if (entries.Count > 0)
                {
                    sections.Add(new Section(Strings.UsageInfoRequiredParametersHeader + ":", entries)
                    {
                        BodyIndentWidth    = Section.DefaultIndent * 3 / 2,
                        HangingIndentWidth = Section.DefaultIndent / 2
                    });
                }
            }

            // If desired (and present), append "OPTIONAL PARAMETERS" section.
            if (Options.HasFlag(UsageInfoOptions.IncludeOptionalParameterDescriptions) &&
                info.OptionalParameters.Any())
            {
                var entries = GetParameterEntries(info.OptionalParameters, info, inlineDocumented).ToList();
                if (entries.Count > 0)
                {
                    sections.Add(new Section(Strings.UsageInfoOptionalParametersHeader + ":", entries)
                    {
                        BodyIndentWidth    = Section.DefaultIndent * 3 / 2,
                        HangingIndentWidth = Section.DefaultIndent / 2
                    });
                }
            }

            // If needed, provide help for shared enum values.
            if (separatelyDocumented != null)
            {
                foreach (var enumType in separatelyDocumented)
                {
                    sections.Add(new Section(
                                     string.Format(Strings.UsageInfoEnumValueHeaderFormat, enumType.DisplayName),
                                     GetEnumValueEntries(enumType))
                    {
                        BodyIndentWidth    = Section.DefaultIndent * 3 / 2,
                        HangingIndentWidth = Section.DefaultIndent / 2
                    });
                }
            }

            // If present, append "EXAMPLES" section.
            if (Options.HasFlag(UsageInfoOptions.IncludeExamples) && info.Examples.Any())
            {
                sections.Add(new Section(Strings.UsageInfoExamplesHeader + ":", info.Examples));
            }

            // If requested, display remarks
            if (Options.HasFlag(UsageInfoOptions.IncludeRemarks) && !string.IsNullOrEmpty(info.Remarks))
            {
                sections.Add(new Section(Strings.UsageInfoRemarksHeader + ":", info.Remarks));
            }

            return(sections);
        }
        private static IReadOnlyDictionary <IArgumentType, List <ArgumentUsageInfo> > GetAllArgumentTypeMap(ArgumentSetUsageInfo setInfo, Func <IArgumentType, bool> typeFilterFunc)
        {
            if (typeFilterFunc == null)
            {
                throw new ArgumentNullException(nameof(typeFilterFunc));
            }

            var map = new Dictionary <IArgumentType, List <ArgumentUsageInfo> >(new ArgumentTypeComparer());

            foreach (var parameter in setInfo.AllParameters.Where(p => p.ArgumentType != null))
            {
                foreach (var type in GetDependencyTransitiveClosure(parameter.ArgumentType).Where(typeFilterFunc))
                {
                    if (!map.TryGetValue(type, out List <ArgumentUsageInfo> infoList))
                    {
                        infoList  = new List <ArgumentUsageInfo>();
                        map[type] = infoList;
                    }

                    infoList.Add(parameter);
                }
            }

            return(map);
        }
 public override ColoredMultistring Format(ArgumentSetUsageInfo info) => Format(GenerateSections(info));
        private IReadOnlyList <ColoredString> FormatParameterInfo(ArgumentUsageInfo info, ArgumentSetUsageInfo setInfo)
        {
            // Select the colors we'll use.
            var          paramMetadataFgColor = UseColor ? new ConsoleColor?(ParameterMetadataForegroundColor) : null;
            ConsoleColor?paramSyntaxFgColor   = null;

            var entries = new List <ColoredString>
            {
                // Append parameter syntax info.
                new ColoredString(SimplifyParameterSyntax(info.DetailedSyntax), paramSyntaxFgColor)
            };

            // If both are present (and requested to be displayed), we combine the short name and
            // default value onto the same line.
            var parameterMetadata = new List <string>();

            // Append parameter's short name (if it has one).
            if (Options.HasFlag(UsageInfoOptions.IncludeParameterShortNameAliases) &&
                !string.IsNullOrEmpty(info.ShortName) &&
                !string.IsNullOrEmpty(setInfo.DefaultShortNamePrefix))
            {
                parameterMetadata.Add($"{Strings.UsageInfoShortForm} {setInfo.DefaultShortNamePrefix + info.ShortName}");
            }

            // Append the parameter's default value (if it has one, and if requested).
            if (Options.HasFlag(UsageInfoOptions.IncludeParameterDefaultValues) &&
                !string.IsNullOrEmpty(info.DefaultValue))
            {
                parameterMetadata.Add($"{Strings.UsageInfoDefaultValue} {info.DefaultValue}");
            }

            // Now append the short name and/or default value, if either
            // were present and accounted for.
            if (parameterMetadata.Count > 0)
            {
                entries.Add(new ColoredString(
                                string.Join(", ", parameterMetadata),
                                paramMetadataFgColor));
            }

            // Append the parameter's description (if it has one).
            if (!string.IsNullOrEmpty(info.Description))
            {
                entries.Add(info.Description);
            }

            return(entries);
        }
 private IEnumerable <ColoredString> GetParameterEntries(IEnumerable <ArgumentUsageInfo> info, ArgumentSetUsageInfo setInfo) =>
 info.Select(i => FormatParameterInfo(i, setInfo))
 .InsertBetween(new ColoredString[] { string.Empty })
 .Flatten();
Esempio n. 11
0
 public abstract ColoredMultistring Format(ArgumentSetUsageInfo info);