using System; using System.Text; using System.Reflection; using System.Linq; namespace Antmicro.OptionsParser { public class HelpOption : CommandLineOptionDescriptor { public static HelpOption CreateInstance() { return new HelpOption(new ApplicationInfo()); } public void PrintHelp(OptionsParser parser) { if(!string.IsNullOrWhiteSpace(appInfo.ApplicationName)) { Console.Write(appInfo.ApplicationName); Console.WriteLine(string.IsNullOrWhiteSpace(appInfo.ApplicationVersion) ? string.Empty : " " + appInfo.ApplicationVersion); if(!string.IsNullOrWhiteSpace(appInfo.ApplicationCopyrights)) { Console.WriteLine(appInfo.ApplicationCopyrights); } Console.WriteLine(); } var valuesBuilder = new StringBuilder(); foreach(var value in parser.Values) { if(value.IsRequired) { valuesBuilder.Append(' ').Append(value.Name); } else { valuesBuilder.AppendFormat(" [{0}]", value.Name); } } var usageLine = string.Format(UsageLineFormat, appInfo.ApplicationBinaryName, valuesBuilder); Console.WriteLine(CustomUsageLineGenerator != null ? CustomUsageLineGenerator(usageLine) : usageLine); Console.WriteLine(); var interestingPositionalArguments = parser.Values.Where(x => !string.IsNullOrEmpty(x.Description) || x.ParameterType.IsEnum).ToList(); if(interestingPositionalArguments.Count > 0) { Console.WriteLine("Arguments:"); Console.WriteLine(); foreach(var value in interestingPositionalArguments) { Console.WriteLine(GeneratePositionalArgumentHelpEntry(value)); } } Console.WriteLine("Options:"); Console.WriteLine(); foreach(var option in parser.Options) { Console.WriteLine(GenerateOptionHelpEntry(option)); Console.WriteLine(); } if(CustomFooterGenerator != null) { Console.WriteLine(CustomFooterGenerator()); } } public Func CustomOptionEntryHelpGenerator { get; set; } public Func CustomUsageLineGenerator { get; set; } public Func CustomFooterGenerator { get; set; } public const string UsageLineFormat = "usage: {0} [options]{1}"; private static string GeneratePositionalArgumentHelpEntry(PositionalArgument argument) { var optionBuilder = new StringBuilder(); optionBuilder.AppendFormat(" '{0}' has possible values:\n\n", argument.Name); if(argument.ParameterType.IsEnum) { foreach(var e in GetEnumNames(argument.ParameterType)) { optionBuilder.AppendFormat(" {0,-26}", e.Item1); if(e.Item2 != null) { optionBuilder.Append(e.Item2); } optionBuilder.Append("\n\n"); } } return optionBuilder.ToString(); } private static string GenerateOptionHelpEntry(IFlag option) { var optionBuilder = new StringBuilder(" "); AppendSwitchName(optionBuilder, option); optionBuilder.Append(' ', Math.Max(0, DefaultIndent - optionBuilder.Length)); AppendTypeInformation(optionBuilder, option); if(option.IsRequired) { optionBuilder.Append(" (required)"); } if(!string.IsNullOrWhiteSpace(option.Description)) { optionBuilder.AppendLine(); optionBuilder.Append(' ', DefaultIndent); optionBuilder.Append(option.Description); } foreach(var alias in option.Aliases) { optionBuilder.AppendLine().AppendLine(); optionBuilder.AppendFormat(" --{0}", alias); optionBuilder.Append(' ', Math.Max(0, DefaultIndent - 4 - alias.Length)); // -4 to account for dashes and spaces AppendTypeInformation(optionBuilder, option); optionBuilder.AppendLine(); optionBuilder.Append(' ', DefaultIndent); optionBuilder.Append("Alias to "); AppendSwitchName(optionBuilder, option); optionBuilder.Append("."); } return optionBuilder.ToString(); } private static void AppendSwitchName(StringBuilder optionBuilder, IFlag option) { if(option.ShortName != Tokenizer.NullCharacter) { optionBuilder.AppendFormat("-{0}", option.ShortName); } if(option.LongName != null) { if(option.ShortName != Tokenizer.NullCharacter) { optionBuilder.Append(", "); } optionBuilder.AppendFormat("--{0}", option.LongName); } } private static void AppendTypeInformation(StringBuilder optionBuilder, IFlag option) { if(option.OptionType.IsArray) { optionBuilder.AppendFormat("{0}s separated by '{1}'", option.OptionType.GetElementType().Name.ToUpper(), option.Delimiter); } else if(option.OptionType.IsEnum) { optionBuilder.AppendLine("ENUM with possible values: "); foreach(var name in GetEnumNames(option.OptionType)) { optionBuilder.Append(' ', 32).Append(name.Item1).Append('\n'); } } else { optionBuilder.Append(option.OptionType.Name.ToUpper()); } } private static Tuple[] GetEnumNames(Type enumType) { DescriptionAttribute attr; return Enum.GetValues(enumType) .Cast() .Select(x => Enum.GetName(enumType, x)) .Where(x => enumType.GetMember(x)[0].GetCustomAttribute() == null) .Select(x => Tuple.Create(x, (attr = enumType.GetMember(x)[0].GetCustomAttribute()) != null ? attr.Value : null)) .ToArray(); } private HelpOption(ApplicationInfo info) : base('h', "help", typeof(bool)) { Description = "Display this help page."; appInfo = info; } private readonly ApplicationInfo appInfo; private const int DefaultIndent = 30; } }