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 }); }
/// <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)); }
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();
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)); }
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()); }
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); }
/// <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; }
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); }