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();
public abstract ColoredMultistring Format(ArgumentSetUsageInfo info);