Пример #1
0
        private ParameterEntry FormatParameterEntry(
            int currentMaxWidth,
            ArgumentUsageInfo info,
            ArgumentSetUsageInfo setInfo,
            List <IEnumArgumentType> inlineDocumentedEnums)
        {
            List <ColoredMultistring> enumValueEntries = null;

            if (inlineDocumentedEnums?.Count > 0)
            {
                enumValueEntries = inlineDocumentedEnums.SelectMany(
                    e => GetEnumValueEntries(currentMaxWidth - _options.SectionEntryHangingIndentWidth, e))
                                   .ToList();

                if (enumValueEntries.Count == 0)
                {
                    enumValueEntries = null;
                }
            }

            return(new ParameterEntry
            {
                Syntax = FormatParameterSyntax(info, setInfo, inlineDocumentedEnums?.Count > 0),
                Description = FormatParameterDescription(info, setInfo),
                // TODO: Let section hanging indent override.
                InlineEnumEntries = enumValueEntries
            });
        }
Пример #2
0
        /// <summary>
        /// Renders the given usage information.
        /// </summary>
        /// <param name="argSet">Argument set.</param>
        /// <param name="destination">Destination object.</param>
        /// <returns>Rendered string output, ready for display.</returns>
        public ColoredMultistring Format(ArgumentSetDefinition argSet, object destination)
        {
            var info = new ArgumentSetUsageInfo(argSet, destination);

            var unorderedSections = GenerateSections(info);

            var orderedSections = SortSections(unorderedSections, DefaultSectionOrdering);

            return(Format(orderedSections));
        }
Пример #3
0
        private IEnumerable <ParameterEntry> GetParameterEntries(
            int currentMaxWidth,
            IEnumerable <ArgumentUsageInfo> info,
            ArgumentSetUsageInfo setInfo,
            IReadOnlyDictionary <ArgumentUsageInfo, List <IEnumArgumentType> > inlineDocumentedEnums) =>
        info.Select(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(new None());
            }

            return(Some.Of(FormatParameterEntry(currentMaxWidth, i, setInfo, enumTypes)));
        }).WhereHasValue();
Пример #4
0
        private ColoredMultistring FormatParameterSyntax(ArgumentUsageInfo info, ArgumentSetUsageInfo setInfo, bool enumsDocumentedInline)
        {
            var longNameSyntax = info.GetSyntax(_options.Arguments, enumsDocumentedInline);

            var formattedSyntax = new List <ColoredString>();

            // First add parameter's short name (if it has one and if it's supposed to be here).
            if (_options.Arguments.ShortName == ArgumentShortNameHelpMode.IncludeWithLongName &&
                !string.IsNullOrEmpty(info.ShortName) &&
                !string.IsNullOrEmpty(setInfo.DefaultShortNamePrefix))
            {
                formattedSyntax.Add(new ColoredString(setInfo.DefaultShortNamePrefix + info.ShortName, _options.Arguments?.ArgumentNameColor));
                formattedSyntax.Add(", ");
            }

            formattedSyntax.Add(new ColoredString(longNameSyntax, _options.Arguments?.ArgumentNameColor));

            return(new ColoredMultistring(formattedSyntax));
        }
Пример #5
0
        private ColoredMultistring FormatParameterDescription(
            ArgumentUsageInfo info,
            ArgumentSetUsageInfo setInfo)
        {
            var builder = new ColoredMultistringBuilder();

            List <ColoredString> defaultValueContent = null;

            if (_options.Arguments.DefaultValue != ArgumentDefaultValueHelpMode.Omit &&
                !string.IsNullOrEmpty(info.DefaultValue))
            {
                defaultValueContent = new List <ColoredString>
                {
                    new ColoredString(Strings.UsageInfoDefaultValue, _options.Arguments.MetadataColor),
                    " ",
                    info.DefaultValue
                };
            }

            if (_options.Arguments.DefaultValue == ArgumentDefaultValueHelpMode.PrependToDescription &&
                defaultValueContent != null)
            {
                builder.Append("[");
                builder.Append(defaultValueContent);
                builder.Append("]");
            }

            if (_options.Arguments.IncludeDescription && !string.IsNullOrEmpty(info.Description))
            {
                if (builder.Length > 0)
                {
                    builder.Append(" ");
                }

                builder.Append(info.Description);
            }

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

            if (_options.Arguments.DefaultValue == ArgumentDefaultValueHelpMode.AppendToDescription &&
                defaultValueContent != null)
            {
                metadataItems.Add(defaultValueContent);
            }

            // Append parameter's short name (if it has one).
            if (_options.Arguments.ShortName == ArgumentShortNameHelpMode.AppendToDescription &&
                !string.IsNullOrEmpty(info.ShortName) &&
                !string.IsNullOrEmpty(setInfo.DefaultShortNamePrefix))
            {
                metadataItems.Add(new List <ColoredString>
                {
                    new ColoredString(Strings.UsageInfoShortForm, _options.Arguments.MetadataColor),
                    " ",
                    new ColoredString(setInfo.DefaultShortNamePrefix + info.ShortName, _options.Arguments?.ArgumentNameColor)
                });
            }

            if (metadataItems.Count > 0)
            {
                if (builder.Length > 0)
                {
                    builder.Append(" ");
                }

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

            return(builder.ToMultistring());
        }
Пример #6
0
        private static IReadOnlyDictionary <IArgumentType, List <ArgumentUsageInfo> > GetAllArgumentTypeMap(ArgumentSetUsageInfo setInfo, Func <IArgumentType, bool> 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);
        }
Пример #7
0
        /// <summary>
        /// Find all enum types that need to be documented, and sort out whether they
        /// should be documented inline in their usage sites or coalesced into a
        /// toplevel section.
        /// </summary>
        /// <param name="setInfo">Argument set usage info.</param>
        /// <param name="inlineDocumented">Receives a dictionary of inline-documented
        /// enum types.</param>
        /// <param name="separatelyDocumented">Receives an enumeration of enum types
        /// that should be separately documented.</param>
        private void GetEnumsToDocument(ArgumentSetUsageInfo setInfo,
                                        out IReadOnlyDictionary <ArgumentUsageInfo, List <IEnumArgumentType> > inlineDocumented,
                                        out IEnumerable <IEnumArgumentType> separatelyDocumented)
        {
            // Find all enum types in the full type graph of the argument set; this
            // "type map" will map each unique enum type to the one or more arguments that
            // reference it.
            var enumTypeMap = GetAllArgumentTypeMap(setInfo, t => t is IEnumArgumentType);

            // Construct a dictionary for us to register inline-documented types; it will
            // map from argument to the list of enum types that should be inline documented
            // with it.
            var id = new Dictionary <ArgumentUsageInfo, List <IEnumArgumentType> >();

            // Construct a list for us to register separately-documented types; it should
            // be a simple, unique list of enum types.
            var sd = new List <IEnumArgumentType>();

            // Look through all enum types.
            foreach (var pair in enumTypeMap)
            {
                var enumType = (IEnumArgumentType)pair.Key;

                // Figure out how many times it shows up.
                var instanceCount = pair.Value.Count;

                // Skip any types that somehow show up multiple times.
                if (instanceCount == 0)
                {
                    continue;
                }

                // Decide whether to separately document; we start with the assumption
                // that we *won't* separately document.
                bool shouldSeparatelyDocument = false;

                // If we've been asked to unify the summary of enums with multiple references,
                // then check the instance count.
                if (_options.EnumValues.Flags.HasFlag(ArgumentEnumValueHelpFlags.SingleSummaryOfEnumsWithMultipleUses) &&
                    instanceCount > 1)
                {
                    shouldSeparatelyDocument = true;
                }

                // If we've been asked to unify the summary of command enums, then check if this
                // enum is a command enum.
                if (_options.EnumValues.Flags.HasFlag(ArgumentEnumValueHelpFlags.SingleSummaryOfAllCommandEnums) &&
                    ArgumentUsageInfo.IsCommandEnum(enumType.Type))
                {
                    shouldSeparatelyDocument = true;
                }

                // If we're separately documenting, then add it into that list.
                if (shouldSeparatelyDocument)
                {
                    sd.Add(enumType);
                }

                // Otherwise, add it to the inline-documented map.
                else
                {
                    // Make sure to add it for each argument referencing it.
                    foreach (var arg in pair.Value)
                    {
                        if (!id.TryGetValue(arg, out List <IEnumArgumentType> types))
                        {
                            types   = new List <IEnumArgumentType>();
                            id[arg] = types;
                        }

                        types.Add(enumType);
                    }
                }
            }

            inlineDocumented     = id;
            separatelyDocumented = sd;
        }
Пример #8
0
        private IReadOnlyList <Section> GenerateSections(ArgumentSetUsageInfo info)
        {
            var sections = new List <Section>();

            if (_options.Logo?.Include ?? false &&
                info.Logo != null && !string.IsNullOrEmpty(info.Logo))
            {
                sections.Add(new Section(ArgumentSetHelpSectionType.Logo, _options, _options.Logo, info.Logo));
            }

            // Append basic usage info.
            if (_options.Syntax?.Include ?? false)
            {
                var basicSyntax = new List <ColoredString>();

                if (!string.IsNullOrEmpty(_options.Name))
                {
                    basicSyntax.Add(new ColoredString(_options.Name, _options.Syntax?.CommandNameColor));
                    basicSyntax.Add(" ");
                }

                basicSyntax.Add(info.GetBasicSyntax(_options.Syntax));

                sections.Add(new Section(ArgumentSetHelpSectionType.Syntax, _options, _options.Syntax, new[] { new ColoredMultistring(basicSyntax) }));
            }

            if ((_options.Description?.Include ?? false) && !string.IsNullOrEmpty(info.Description))
            {
                sections.Add(new Section(ArgumentSetHelpSectionType.ArgumentSetDescription, _options, _options.Description, info.Description));
            }

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

            if (_options.EnumValues?.Include ?? false)
            {
                GetEnumsToDocument(info, out inlineDocumented, out separatelyDocumented);
            }

            // Process parameters sections.
            var includeRequiredArgs = _options.Arguments?.RequiredArguments?.Include ?? false;
            var includeOptionalArgs = _options.Arguments?.OptionalArguments?.Include ?? false;

            if (includeRequiredArgs || includeOptionalArgs)
            {
                var argBlockIndentWidth = 0;
                if (includeRequiredArgs)
                {
                    argBlockIndentWidth = Math.Max(argBlockIndentWidth, _options.Arguments.RequiredArguments.BlockIndent.GetValueOrDefault(_options.SectionEntryBlockIndentWidth));
                }

                if (includeOptionalArgs)
                {
                    argBlockIndentWidth = Math.Max(argBlockIndentWidth, _options.Arguments.OptionalArguments.BlockIndent.GetValueOrDefault(_options.SectionEntryBlockIndentWidth));
                }

                var currentMaxWidth =
                    _options.MaxWidth.GetValueOrDefault(ArgumentSetHelpOptions.DefaultMaxWidth) - argBlockIndentWidth;

                var requiredEntries = includeRequiredArgs ?
                                      (IReadOnlyList <ParameterEntry>)GetParameterEntries(currentMaxWidth, info.RequiredParameters, info, inlineDocumented).ToList() :
                                      Array.Empty <ParameterEntry>();

                var optionalEntries = includeOptionalArgs ?
                                      (IReadOnlyList <ParameterEntry>)GetParameterEntries(currentMaxWidth, info.OptionalParameters, info, inlineDocumented).ToList() :
                                      Array.Empty <ParameterEntry>();

                if (requiredEntries.Count + optionalEntries.Count > 0)
                {
                    var maxLengthOfParameterSyntax = requiredEntries.Concat(optionalEntries).Max(e => e.Syntax.Length);

                    if (requiredEntries.Count > 0)
                    {
                        var formattedEntries = FormatParameterEntries(currentMaxWidth, requiredEntries, maxLengthOfParameterSyntax).ToList();
                        sections.Add(new Section(ArgumentSetHelpSectionType.RequiredParameters, _options, _options.Arguments.RequiredArguments, formattedEntries));
                    }

                    if (optionalEntries.Count > 0)
                    {
                        var formattedEntries = FormatParameterEntries(currentMaxWidth, optionalEntries, maxLengthOfParameterSyntax).ToList();
                        sections.Add(new Section(ArgumentSetHelpSectionType.OptionalParameters, _options, _options.Arguments.OptionalArguments, formattedEntries));
                    }
                }
            }

            // If needed, provide help for shared enum values.
            if (separatelyDocumented != null)
            {
                foreach (var enumType in separatelyDocumented)
                {
                    var maxWidth = _options.MaxWidth.GetValueOrDefault(ArgumentSetHelpOptions.DefaultMaxWidth);
                    maxWidth -= _options.EnumValues.BlockIndent.GetValueOrDefault(_options.SectionEntryBlockIndentWidth);

                    var enumValueEntries = GetEnumValueEntries(maxWidth, enumType).ToList();
                    if (enumValueEntries.Count > 0)
                    {
                        sections.Add(new Section(ArgumentSetHelpSectionType.EnumValues, _options,
                                                 _options.EnumValues,
                                                 enumValueEntries,
                                                 name: string.Format(Strings.UsageInfoEnumValueHeaderFormat, enumType.DisplayName)));
                    }
                }
            }

            // If present, append "EXAMPLES" section.
            if ((_options.Examples?.Include ?? false) && info.Examples.Any())
            {
                sections.Add(new Section(ArgumentSetHelpSectionType.Examples, _options, _options.Examples, info.Examples));
            }

            return(sections);
        }