From 5a56e021164c87d2112e1d99bce8088b7955b2e0 Mon Sep 17 00:00:00 2001 From: Adrian Aisemberg Date: Wed, 14 Mar 2012 00:16:09 +0200 Subject: [PATCH] better help --- CLAP/HelpGenerator.cs | 168 ++++++++++++++++++++++++++++++++----- CLAP/Method.cs | 3 +- CLAP/ParserRegistration.cs | 4 +- CLAP/ParserRunner.cs | 18 ++-- ConsoleTest/Program.cs | 33 +++++++- 5 files changed, 185 insertions(+), 41 deletions(-) diff --git a/CLAP/HelpGenerator.cs b/CLAP/HelpGenerator.cs index 3e8ca68..ff2f62c 100644 --- a/CLAP/HelpGenerator.cs +++ b/CLAP/HelpGenerator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text; #if !FW2 using System.Linq; @@ -33,7 +34,130 @@ internal static string GetHelp(IEnumerable parsers) private static string GetHelpString(HelpInfo helpInfo) { - return ""; + const string verbsLead = " "; + const string parametersLead = " "; + const string validationsLead = " "; + + var sb = new StringBuilder(); + + var count = helpInfo.Parsers.Count; + var multi = count > 1; + + for (int i = 0; i < count; i++) + { + var parser = helpInfo.Parsers[i]; + + foreach (var verb in parser.Verbs.OrderBy(v => v.Names.First())) + { + sb.AppendLine(); + sb.Append(verbsLead); + + if (multi) + { + sb.AppendFormat("{0}.", parser.Type.Name.ToLowerInvariant()); + } + + sb.AppendLine(verb.Names.StringJoin("|").ToLowerInvariant()); + + if (verb.Parameters.Any()) + { + var longestParameter = verb.Parameters.Max(p => p.Names.StringJoin("|").Length); + var longestType = verb.Parameters.Max(p => p.Type.GetGenericTypeName().Length); + + foreach (var p in verb.Parameters.OrderBy(p => p.Names.First())) + { + sb.Append(parametersLead); + sb.AppendFormat("/{0} : ", + p.Names.StringJoin("|").ToLowerInvariant().PadRight(longestParameter, ' ')); + + sb.AppendFormat("<{0}> ", p.Type.GetGenericTypeName()); + + if (!string.IsNullOrEmpty(p.Description)) + { + sb.AppendFormat("{0} ", p.Description); + } + + if (p.Required) + { + sb.Append("(Required) "); + } + + if (p.Default != null) + { + sb.AppendFormat("(Default = {0}) ", p.Default); + } + + if (p.Validations.Any()) + { + sb.AppendFormat("({0}) ", p.Validations.StringJoin(", ")); + } + + sb.AppendLine(); + } // foreach (var p in verb.Parameters + } + + if (verb.Validations.Any()) + { + sb.AppendLine(); + sb.Append(parametersLead); + sb.AppendLine("Validation:"); + + foreach (var v in verb.Validations) + { + sb.Append(validationsLead); + sb.AppendLine(v); + } + } + + } // foreach (var verb in parser.Verbs + + if (parser.Globals.Any()) + { + sb.AppendLine(); + + var longestGlobal = parser.Globals.Max(p => p.Names.StringJoin("|").Length); + + foreach (var g in parser.Globals.OrderBy(g => g.Names.First())) + { + sb.Append(verbsLead); + sb.AppendFormat("/{0} : ", + g.Names.StringJoin("|").ToLowerInvariant().PadRight(longestGlobal, ' ')); + + sb.AppendFormat("<{0}> ", g.Type.GetGenericTypeName()); + + if (!string.IsNullOrEmpty(g.Description)) + { + sb.AppendFormat("{0} ", g.Description); + } + + if (g.Required) + { + sb.Append("(Required) "); + } + + if (g.Default != null) + { + sb.AppendFormat("(Default = {0}) ", g.Default); + } + + if (g.Validations.Any()) + { + sb.AppendFormat("({0}) ", g.Validations.StringJoin(", ")); + } + + sb.AppendLine(); + } // foreach (var g in parser.Globals + } + + if (multi && i < count - 1) + { + sb.AppendLine(); + sb.Append(verbsLead); + sb.AppendLine(string.Empty.PadRight(80, '-')); + } + } + + return sb.ToString(); } private static ParserHelpInfo GetParserHelp(ParserRunner parser) @@ -43,7 +167,7 @@ private static ParserHelpInfo GetParserHelp(ParserRunner parser) Type = parser.Type, Verbs = parser.GetVerbs().Select(verb => new VerbHelpInfo { - Names = verb.Names.Union(new[] { verb.MethodInfo.Name }).ToList(), + Names = verb.Names.OrderBy(n => n.Length).ToList(), Description = verb.Description, IsDefault = verb.IsDefault, Validations = verb.MethodInfo.GetInterfaceAttributes().Select(v => v.Description).ToList(), @@ -51,34 +175,34 @@ private static ParserHelpInfo GetParserHelp(ParserRunner parser) Select(p => new ParameterHelpInfo { Required = p.Required, - Names = p.Names, + Names = p.Names.OrderBy(n => n.Length).ToList(), Type = p.ParameterInfo.ParameterType, Default = p.DefaultProvider != null ? p.DefaultProvider.Description : p.Default, Description = p.Description, Validations = p.ParameterInfo.GetAttributes().Select(v => v.Description).ToList(), }).ToList(), }).ToList(), - Globals = parser.GetDefinedGlobals(). - Select(g => - { - var att = g.GetAttribute(); - var parameter = ParserRunner.GetParameters(g).FirstOrDefault(); + Globals = parser.GetDefinedGlobals().Select(g => + { + var att = g.GetAttribute(); + var parameter = ParserRunner.GetParameters(g).FirstOrDefault(); - return new ParameterHelpInfo - { - IsGlobal = true, - Names = att.Aliases.CommaSplit().Union(new[] { att.Name ?? g.Name }).ToList(), - Type = parameter != null ? parameter.ParameterInfo.ParameterType : typeof(bool), - Description = att.Description, - Validations = g.GetInterfaceAttributes().Select(v => v.Description).ToList(), - }; - }) - .Union(parser.Register.RegisteredGlobalHandlers.Values.Select(handler => new ParameterHelpInfo + return new ParameterHelpInfo { - Names = handler.Names.ToList(), - Type = handler.Type, - Description = handler.Desription, - })).ToList(), + IsGlobal = true, + Names = att.Aliases.CommaSplit().Union(new[] { att.Name ?? g.Name }).OrderBy(n => n.Length).ToList(), + Type = parameter != null ? parameter.ParameterInfo.ParameterType : typeof(bool), + Description = att.Description, + Validations = g.GetInterfaceAttributes().Select(v => v.Description).ToList(), + }; + }).Union(parser.Register.RegisteredGlobalHandlers.Values.Select(handler => new ParameterHelpInfo + { + IsGlobal = true, + Names = handler.Names.OrderBy(n => n.Length).ToList(), + Type = handler.Type, + Description = handler.Desription, + Validations = new List(), + })).ToList(), }; } } diff --git a/CLAP/Method.cs b/CLAP/Method.cs index b81fadb..defdf57 100644 --- a/CLAP/Method.cs +++ b/CLAP/Method.cs @@ -56,8 +56,7 @@ internal Method(MethodInfo method) if (verbAttribute.Aliases != null) { - Names.AddRange( - verbAttribute.Aliases.ToLowerInvariant().CommaSplit()); + Names.AddRange(verbAttribute.Aliases.ToLowerInvariant().CommaSplit()); } } diff --git a/CLAP/ParserRegistration.cs b/CLAP/ParserRegistration.cs index 0026c1b..c1e5f3f 100644 --- a/CLAP/ParserRegistration.cs +++ b/CLAP/ParserRegistration.cs @@ -73,10 +73,10 @@ public void EmptyHelpHandler(Action handler) throw new ArgumentNullException("handler"); } - var help = HelpGetter(); - EmptyHandler(delegate { + var help = HelpGetter(); + handler(help); }); } diff --git a/CLAP/ParserRunner.cs b/CLAP/ParserRunner.cs index c83a3c5..9d5e656 100644 --- a/CLAP/ParserRunner.cs +++ b/CLAP/ParserRunner.cs @@ -382,8 +382,8 @@ private static void ValidateParameterDefaults(IEnumerable verbs) // make sure all default providers are DefaultProvider // - bad = dict.Where(kvp => - kvp.Key.DefaultProvider != null && + bad = dict.Where(kvp => + kvp.Key.DefaultProvider != null && !typeof(DefaultProvider).IsAssignableFrom(kvp.Key.DefaultProvider)); if (bad.Any()) @@ -676,15 +676,11 @@ private bool HandleHelp(string firstArg, object target) Action helpHandler = GetRegisteredHelpHandler(arg); - var help = HelpGenerator.GetHelp(this); - - var helpHandled = false; - if (helpHandler != null) { - helpHandler(help); + helpHandler(HelpGenerator.GetHelp(this)); - helpHandled = true; + return true; } var definedHelpMethods = Type.GetMethodsWith(); @@ -704,9 +700,9 @@ private bool HandleHelp(string firstArg, object target) var obj = method.IsStatic ? null : target; - MethodInvoker.Invoke(method, obj, new[] { help }); + MethodInvoker.Invoke(method, obj, new[] { HelpGenerator.GetHelp(this) }); - helpHandled = true; + return true; } catch (TargetParameterCountException ex) { @@ -719,7 +715,7 @@ private bool HandleHelp(string firstArg, object target) } } - return helpHandled; + return false; } internal void HandleEmptyArguments(object target) diff --git a/ConsoleTest/Program.cs b/ConsoleTest/Program.cs index 617d0ba..58c1f8d 100644 --- a/ConsoleTest/Program.cs +++ b/ConsoleTest/Program.cs @@ -13,7 +13,7 @@ class Program { static void Main(string[] args) { - Parser.RunConsole(args); + Parser.RunConsole(args); } } @@ -90,11 +90,36 @@ public static void Bar(int[] numbers, [Parameter(Aliases = "n,nms", Required = t [Parameter(Required = true)] bool rsw, - bool sw, + [Parameter(DefaultProvider = typeof(MyDefaultProvider1))] bool sw1, + [Parameter(DefaultProvider = typeof(MyDefaultProvider2))] bool sw2, ClapApp clap) { } + public class MyDefaultProvider1 : DefaultProvider + { + public override object GetDefault(VerbExecutionContext context) + { + return "foo"; + } + } + + public class MyDefaultProvider2 : DefaultProvider + { + public override object GetDefault(VerbExecutionContext context) + { + return "foo"; + } + + public override string Description + { + get + { + return "A Default Provider"; + } + } + } + [Help, Empty] public static void Help(string h) { @@ -132,10 +157,10 @@ public static void SavePersons(IEnumerable p) class BaseApp { [Error] - public static void Error(Exception ex) + public static void Error(ExceptionContext ex) { Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(ex.Message); + Console.WriteLine(ex.Exception.Message); Console.ResetColor(); }