// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using Microsoft.Extensions.Logging; namespace EpicGames.Core { /// /// Utility functions for showing help for objects /// public static class HelpUtils { /// /// Gets the width of the window for formatting purposes /// public static int WindowWidth => ConsoleUtils.WindowWidth; /// /// Prints help for the given object type /// /// /// Type to print help for public static void PrintHelp(string title, Type type) { PrintHelp(title, GetDescription(type), CommandLineArguments.GetParameters(type)); } /// /// Prints help for a command /// /// Title for the help text /// Description for the command /// List of parameters public static void PrintHelp(string? title, string? description, List> parameters) { bool bFirstLine = true; if (!String.IsNullOrEmpty(title)) { PrintParagraph(title); bFirstLine = false; } if (!String.IsNullOrEmpty(description)) { if (!bFirstLine) { Console.WriteLine(""); } PrintParagraph(description); bFirstLine = false; } if (parameters.Count > 0) { if (!bFirstLine) { Console.WriteLine(""); } Console.WriteLine("Parameters:"); PrintTable(parameters, 4, 24); } } /// /// Gets the description from a type /// /// The type to get a description for /// The description text public static string GetDescription(Type type) { StringBuilder descriptionText = new StringBuilder(); foreach (DescriptionAttribute attribute in type.GetCustomAttributes(typeof(DescriptionAttribute), false).OfType()) { if (descriptionText.Length > 0) { descriptionText.AppendLine(); } descriptionText.AppendLine(attribute.Description); } return descriptionText.ToString(); } /// /// Prints a paragraph of text using word wrapping /// /// Text to print public static void PrintParagraph(string text) { PrintParagraph(text, WindowWidth - 1); } /// /// Prints a paragraph of text using word wrapping /// /// Text to print /// Maximum width for each line public static void PrintParagraph(string text, int maxWidth) { IEnumerable lines = StringUtils.WordWrap(text, maxWidth); foreach (string line in lines) { Console.WriteLine(line); } } /// /// Prints an argument list to the console /// /// List of parameters arranged as "-ParamName Param Description" /// Indent from the left hand side /// The minimum padding from the start of the param name to the start of the description (resizes with larger param names) /// public static void PrintTable(List> items, int indent, int minFirstColumnWidth) { List lines = []; FormatTable(items, indent, minFirstColumnWidth, WindowWidth - 1, lines); foreach (string line in lines) { Console.WriteLine(line); } } /// /// Prints a table of items to a logging device /// /// /// /// /// /// public static void PrintTable(List> items, int indent, int minFirstColumnWidth, int maxWidth, ILogger logger) { List lines = []; FormatTable(items, indent, minFirstColumnWidth, maxWidth, lines); foreach (string line in lines) { logger.LogInformation("{Line}", line); } } /// /// Formats the given parameters as so: /// -Param1 Param1 Description /// /// -Param2 Param2 Description, this description is /// longer and splits onto a separate line. /// /// -Param3 Param3 Description continues as before. /// /// List of parameters arranged as "-ParamName Param Description" /// Indent from the left hand side /// The minimum padding from the start of the param name to the start of the description (resizes with larger param names) /// /// /// Sequence of formatted lines in the table public static void FormatTable(IReadOnlyList> items, int indent, int minFirstColumnWidth, int maxWidth, List lines) { if(items.Count > 0) { // string used to intent the param string indentString = new string(' ', indent); // default the padding value int rightPadding = Math.Max(minFirstColumnWidth, items.Max(x => x.Key.Length + 2)); // Build the formatted params foreach(KeyValuePair item in items) { // build the param first, including intend and padding on the rights size string paramString = indentString + item.Key.PadRight(rightPadding); // Build the description line by line, adding the same amount of intending each time. IEnumerable descriptionLines = StringUtils.WordWrap(item.Value, maxWidth - paramString.Length); foreach(string descriptionLine in descriptionLines) { // Formatting as following: // -paramDescription lines.Add(paramString + descriptionLine); // we replace the param string on subsequent lines with white space of the same length paramString = String.Empty.PadRight(indentString.Length + rightPadding); } } } } } }