BadScript 2
Loading...
Searching...
No Matches
HelpText.cs
Go to the documentation of this file.
1// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
2
3using System;
4using System.Collections;
5using System.Collections.Generic;
6using System.IO;
7using System.Linq;
8using System.Reflection;
9using System.Text;
10
13
14using CSharpx;
15
16namespace CommandLine.Text
17{
22 public struct ComparableOption
23 {
24 public bool Required;
25 public bool IsOption;
26 public bool IsValue;
27 public string LongName;
28 public string ShortName;
29 public int Index;
30 }
31
32 public class HelpText
33 {
34 private const int BuilderCapacity = 128;
35 private const int DefaultMaximumLength = 80; // default console width
36
40 private const int OptionToHelpTextSeparatorWidth = 4;
41
45 private const int OptionPrefixWidth = 2;
46
51
52 private readonly StringBuilder postOptionsHelp;
53 private readonly StringBuilder preOptionsHelp;
54 private string copyright;
55 private string heading;
56 private StringBuilder optionsHelp;
57
61 public HelpText()
62 : this(SentenceBuilder.Create(), string.Empty, string.Empty) { }
63
71 public HelpText(SentenceBuilder sentenceBuilder)
72 : this(sentenceBuilder, string.Empty, string.Empty) { }
73
80 public HelpText(string heading)
81 : this(SentenceBuilder.Create(), heading, string.Empty) { }
82
89 public HelpText(SentenceBuilder sentenceBuilder, string heading)
90 : this(sentenceBuilder, heading, string.Empty) { }
91
99 public HelpText(string heading, string copyright)
100 : this(SentenceBuilder.Create(), heading, copyright) { }
101
110 public HelpText(SentenceBuilder sentenceBuilder, string heading, string copyright)
111 {
112 if (sentenceBuilder == null)
113 {
114 throw new ArgumentNullException("sentenceBuilder");
115 }
116
117 if (heading == null)
118 {
119 throw new ArgumentNullException("heading");
120 }
121
122 if (copyright == null)
123 {
124 throw new ArgumentNullException("copyright");
125 }
126
127 preOptionsHelp = new StringBuilder(BuilderCapacity);
128 postOptionsHelp = new StringBuilder(BuilderCapacity);
129
130 try
131 {
132 MaximumDisplayWidth = Console.WindowWidth;
133
134 if (MaximumDisplayWidth < 1)
135 {
137 }
138 }
139 catch (IOException)
140 {
142 }
143
144 SentenceBuilder = sentenceBuilder;
145 this.heading = heading;
146 this.copyright = copyright;
147 AutoHelp = true;
148 AutoVersion = true;
149 }
150
155 public string Heading
156 {
157 get => heading;
158 set
159 {
160 if (value == null)
161 {
162 throw new ArgumentNullException("value");
163 }
164
165 heading = value;
166 }
167 }
168
173 public string Copyright
174 {
175 get => copyright;
176 set
177 {
178 if (value == null)
179 {
180 throw new ArgumentNullException("value");
181 }
182
183 copyright = value;
184 }
185 }
186
191 public int MaximumDisplayWidth { get; set; }
192
197 public bool AddDashesToOption { get; set; }
198
202 public bool AdditionalNewLineAfterOption { get; set; }
203
207 public bool AddNewLineBetweenHelpSections { get; set; }
208
212 public bool AddEnumValuesToHelpText { get; set; }
213
217 public bool AutoHelp { get; set; }
218
222 public bool AutoVersion { get; set; }
223
228
253 public static HelpText AutoBuild<T>(ParserResult<T> parserResult,
254 Func<HelpText, HelpText> onError,
255 Func<Example, Example> onExample,
256 bool verbsIndex = false,
257 int maxDisplayWidth = DefaultMaximumLength)
258 {
259 HelpText auto = new HelpText
260 {
264 AddDashesToOption = !verbsIndex,
265 MaximumDisplayWidth = maxDisplayWidth,
266 };
267
268 try
269 {
270 auto.Heading = HeadingInfo.Default;
271 auto.Copyright = CopyrightInfo.Default;
272 }
273 catch (Exception)
274 {
275 auto = onError(auto);
276 }
277
278 IEnumerable<Error> errors = Enumerable.Empty<Error>();
279
280 if (onError != null && parserResult.Tag == ParserResultType.NotParsed)
281 {
282 errors = ((NotParsed<T>)parserResult).Errors;
283
284 if (errors.IsHelp() ||
285 errors.OnlyMeaningfulOnes()
286 .Any())
287 {
288 auto = onError(auto);
289 }
290 }
291
293 .Do(license => license.AddToHelpText(auto, true));
294
296
297 Maybe<IEnumerable<string>> usageLines = RenderUsageTextAsLines(parserResult, onExample)
298 .ToMaybe();
299
300 if (usageAttr.IsJust() || usageLines.IsJust())
301 {
302 string heading = auto.SentenceBuilder.UsageHeadingText();
303
304 if (heading.Length > 0)
305 {
307 {
308 heading = Environment.NewLine + heading;
309 }
310
311 auto.AddPreOptionsLine(heading);
312 }
313 }
314
315 usageAttr.Do(usage => usage.AddToHelpText(auto, true));
316
317 usageLines.Do(lines => auto.AddPreOptionsLines(lines));
318
319 if ((verbsIndex && parserResult.TypeInfo.Choices.Any()) ||
320 errors.Any(e => e.Tag == ErrorType.NoVerbSelectedError))
321 {
322 auto.AddDashesToOption = false;
323 auto.AddVerbs(parserResult.TypeInfo.Choices.ToArray());
324 }
325 else
326 {
327 auto.AddOptions(parserResult);
328 }
329
330 return auto;
331 }
332
349 public static HelpText AutoBuild<T>(ParserResult<T> parserResult, int maxDisplayWidth = DefaultMaximumLength)
350 {
351 return AutoBuild(parserResult, h => h, maxDisplayWidth);
352 }
353
371 public static HelpText AutoBuild<T>(ParserResult<T> parserResult,
372 Func<HelpText, HelpText> onError,
373 int maxDisplayWidth = DefaultMaximumLength)
374 {
375 if (parserResult.Tag != ParserResultType.NotParsed)
376 {
377 throw new ArgumentException("Excepting NotParsed<T> type.", "parserResult");
378 }
379
380 IEnumerable<Error> errors = ((NotParsed<T>)parserResult).Errors;
381
382 if (errors.Any(e => e.Tag == ErrorType.VersionRequestedError))
383 {
384 return new HelpText($"{HeadingInfo.Default}{Environment.NewLine}")
385 {
386 MaximumDisplayWidth = maxDisplayWidth,
387 }.AddPreOptionsLine(Environment.NewLine);
388 }
389
390 if (!errors.Any(e => e.Tag == ErrorType.HelpVerbRequestedError))
391 {
392 return AutoBuild(parserResult,
393 current =>
394 {
395 onError?.Invoke(current);
396
397 return DefaultParsingErrorsHandler(parserResult, current);
398 },
399 e => e,
400 maxDisplayWidth: maxDisplayWidth
401 );
402 }
403
405 .Single();
406
408 new Error[] { err }
409 );
410
411 return err.Matched
412 ? AutoBuild(pr,
413 current =>
414 {
415 onError?.Invoke(current);
416
417 return DefaultParsingErrorsHandler(pr, current);
418 },
419 e => e,
420 maxDisplayWidth: maxDisplayWidth
421 )
422 : AutoBuild(parserResult,
423 current =>
424 {
425 onError?.Invoke(current);
426
427 return DefaultParsingErrorsHandler(parserResult, current);
428 },
429 e => e,
430 true,
431 maxDisplayWidth
432 );
433 }
434
444 {
445 if (parserResult == null)
446 {
447 throw new ArgumentNullException("parserResult");
448 }
449
450 if (current == null)
451 {
452 throw new ArgumentNullException("current");
453 }
454
455 if (((NotParsed<T>)parserResult).Errors.OnlyMeaningfulOnes()
456 .Empty())
457 {
458 return current;
459 }
460
461 IEnumerable<string> errors = RenderParsingErrorsTextAsLines(parserResult,
463 current.SentenceBuilder
465 2
466 ); // indent with two spaces
467
468 if (errors.Empty())
469 {
470 return current;
471 }
472
473 return current
474 .AddPreOptionsLine(string.Concat(Environment.NewLine, current.SentenceBuilder.ErrorsHeadingText()))
475 .AddPreOptionsLines(errors);
476 }
477
483 public static implicit operator string(HelpText info)
484 {
485 return info.ToString();
486 }
487
494 public HelpText AddPreOptionsLine(string value)
495 {
497 }
498
505 public HelpText AddPostOptionsLine(string value)
506 {
507 return AddLine(postOptionsHelp, value);
508 }
509
515 public HelpText AddPreOptionsLines(IEnumerable<string> lines)
516 {
517 lines.ForEach(line => AddPreOptionsLine(line));
518
519 return this;
520 }
521
527 public HelpText AddPostOptionsLines(IEnumerable<string> lines)
528 {
529 lines.ForEach(line => AddPostOptionsLine(line));
530
531 return this;
532 }
533
539 public HelpText AddPreOptionsText(string text)
540 {
541 string[] lines = text.Split(new[] { Environment.NewLine },
542 StringSplitOptions.None
543 );
544 lines.ForEach(line => AddPreOptionsLine(line));
545
546 return this;
547 }
548
554 public HelpText AddPostOptionsText(string text)
555 {
556 string[] lines = text.Split(new[] { Environment.NewLine },
557 StringSplitOptions.None
558 );
559 lines.ForEach(line => AddPostOptionsLine(line));
560
561 return this;
562 }
563
570 {
571 if (result == null)
572 {
573 throw new ArgumentNullException("result");
574 }
575
580 );
581 }
582
589 public HelpText AddVerbs(params Type[] types)
590 {
591 if (types == null)
592 {
593 throw new ArgumentNullException("types");
594 }
595
596 if (types.Length == 0)
597 {
598 throw new ArgumentOutOfRangeException("types");
599 }
600
605 );
606 }
607
614 public HelpText AddOptions<T>(int maximumLength, ParserResult<T> result)
615 {
616 if (result == null)
617 {
618 throw new ArgumentNullException("result");
619 }
620
624 maximumLength
625 );
626 }
627
635 public HelpText AddVerbs(int maximumLength, params Type[] types)
636 {
637 if (types == null)
638 {
639 throw new ArgumentNullException("types");
640 }
641
642 if (types.Length == 0)
643 {
644 throw new ArgumentOutOfRangeException("types");
645 }
646
650 maximumLength
651 );
652 }
653
668 public static string RenderParsingErrorsText<T>(ParserResult<T> parserResult,
669 Func<Error, string> formatError,
670 Func<IEnumerable<MutuallyExclusiveSetError>, string>
671 formatMutuallyExclusiveSetErrors,
672 int indent)
673 {
674 return string.Join(Environment.NewLine,
675 RenderParsingErrorsTextAsLines(parserResult,
676 formatError,
677 formatMutuallyExclusiveSetErrors,
678 indent
679 )
680 );
681 }
682
697 public static IEnumerable<string> RenderParsingErrorsTextAsLines<T>(ParserResult<T> parserResult,
698 Func<Error, string> formatError,
699 Func<IEnumerable<MutuallyExclusiveSetError>,
700 string>
701 formatMutuallyExclusiveSetErrors,
702 int indent)
703 {
704 if (parserResult == null)
705 {
706 throw new ArgumentNullException("parserResult");
707 }
708
709 IEnumerable<Error> meaningfulErrors =
710 ((NotParsed<T>)parserResult).Errors.OnlyMeaningfulOnes();
711
712 if (meaningfulErrors.Empty())
713 {
714 yield break;
715 }
716
717 foreach (Error error in meaningfulErrors
718 .Where(e => e.Tag != ErrorType.MutuallyExclusiveSetError))
719 {
720 StringBuilder line = new StringBuilder(indent.Spaces())
721 .Append(formatError(error));
722
723 yield return line.ToString();
724 }
725
726 string mutuallyErrs =
727 formatMutuallyExclusiveSetErrors(meaningfulErrors.OfType<MutuallyExclusiveSetError>());
728
729 if (mutuallyErrs.Length > 0)
730 {
731 string[] lines = mutuallyErrs
732 .Split(new[] { Environment.NewLine },
733 StringSplitOptions.None
734 );
735
736 foreach (string line in lines)
737 {
738 yield return line;
739 }
740 }
741 }
742
750 public static string RenderUsageText<T>(ParserResult<T> parserResult)
751 {
752 return RenderUsageText(parserResult, example => example);
753 }
754
763 public static string RenderUsageText<T>(ParserResult<T> parserResult, Func<Example, Example> mapperFunc)
764 {
765 return string.Join(Environment.NewLine, RenderUsageTextAsLines(parserResult, mapperFunc));
766 }
767
776 public static IEnumerable<string> RenderUsageTextAsLines<T>(ParserResult<T> parserResult,
777 Func<Example, Example> mapperFunc)
778 {
779 if (parserResult == null)
780 {
781 throw new ArgumentNullException("parserResult");
782 }
783
785
786 if (usage.MatchNothing())
787 {
788 yield break;
789 }
790
791 Tuple<UsageAttribute, IEnumerable<Example>> usageTuple = usage.FromJustOrFail();
792 IEnumerable<Example> examples = usageTuple.Item2;
793 string appAlias = usageTuple.Item1.ApplicationAlias ?? ReflectionHelper.GetAssemblyName();
794
795 foreach (Example e in examples)
796 {
797 Example example = mapperFunc(e);
798
799 StringBuilder exampleText = new StringBuilder(example.HelpText)
800 .Append(':');
801
802 yield return exampleText.ToString();
803 IEnumerable<UnParserSettings> styles = example.GetFormatStylesOrDefault();
804
805 foreach (UnParserSettings s in styles)
806 {
807 StringBuilder commandLine = new StringBuilder(OptionPrefixWidth.Spaces())
808 .Append(appAlias)
809 .Append(' ')
810 .Append(Parser.Default.FormatCommandLine(example.Sample,
811 config =>
812 {
813 config.PreferShortName = s.PreferShortName;
814 config.GroupSwitches = s.GroupSwitches;
815 config.UseEqualToken = s.UseEqualToken;
816 config.SkipDefault = s.SkipDefault;
817 }
818 )
819 );
820
821 yield return commandLine.ToString();
822 }
823 }
824 }
825
830 public override string ToString()
831 {
832 const int ExtraLength = 10;
833
834 int sbLength = heading.SafeLength() +
835 copyright.SafeLength() +
836 preOptionsHelp.SafeLength() +
837 optionsHelp.SafeLength() +
838 postOptionsHelp.SafeLength() +
839 ExtraLength;
840 StringBuilder result = new StringBuilder(sbLength);
841
842 result.Append(heading)
843 .AppendWhen(!string.IsNullOrEmpty(copyright),
844 Environment.NewLine,
846 )
847 .AppendWhen(preOptionsHelp.SafeLength() > 0,
848 NewLineIfNeededBefore(preOptionsHelp),
849 Environment.NewLine,
850 preOptionsHelp.ToString()
851 )
852 .AppendWhen(optionsHelp.SafeLength() > 0,
853 Environment.NewLine,
854 Environment.NewLine,
855 optionsHelp.SafeToString()
856 )
857 .AppendWhen(postOptionsHelp.SafeLength() > 0,
858 NewLineIfNeededBefore(postOptionsHelp),
859 Environment.NewLine,
860 postOptionsHelp.ToString()
861 );
862
863 string NewLineIfNeededBefore(StringBuilder sb)
864 {
866 result.Length > 0 &&
867 !result.SafeEndsWith(Environment.NewLine) &&
868 !sb.SafeStartsWith(Environment.NewLine))
869 {
870 return Environment.NewLine;
871 }
872
873 return null;
874 }
875
876 return result.ToString();
877 }
878
879 internal static void AddLine(StringBuilder builder, string value, int maximumLength)
880 {
881 if (builder == null)
882 {
883 throw new ArgumentNullException(nameof(builder));
884 }
885
886 if (value == null)
887 {
888 throw new ArgumentNullException(nameof(value));
889 }
890
891 if (maximumLength < 1)
892 {
893 throw new ArgumentOutOfRangeException(nameof(value));
894 }
895
896 value = value.TrimEnd();
897
898 builder.AppendWhen(builder.Length > 0, Environment.NewLine);
899 builder.Append(TextWrapper.WrapAndIndentText(value, 0, maximumLength));
900 }
901
902 private IEnumerable<Specification> GetSpecificationsFromType(Type type)
903 {
904 IEnumerable<Specification> specs = type.GetSpecifications(Specification.FromProperty);
905
906 IEnumerable<OptionSpecification> optionSpecs = specs
907 .OfType<OptionSpecification>();
908
909 if (AutoHelp)
910 {
911 optionSpecs = optionSpecs.Concat(new[] { MakeHelpEntry() });
912 }
913
914 if (AutoVersion)
915 {
916 optionSpecs = optionSpecs.Concat(new[] { MakeVersionEntry() });
917 }
918
919 IOrderedEnumerable<ValueSpecification> valueSpecs = specs
920 .OfType<ValueSpecification>()
921 .OrderBy(v => v.Index);
922
923 return Enumerable.Empty<Specification>()
924 .Concat(optionSpecs)
925 .Concat(valueSpecs);
926 }
927
929 {
930 return type.GetUsageData()
931 .Map(tuple =>
932 {
933 PropertyInfo prop = tuple.Item1;
934 UsageAttribute attr = tuple.Item2;
935
936 IEnumerable<Example> examples = (IEnumerable<Example>)prop
937 .GetValue(null,
938 BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty,
939 null,
940 null,
941 null
942 );
943
944 return Tuple.Create(attr, examples);
945 }
946 );
947 }
948
949 private IEnumerable<Specification> AdaptVerbsToSpecifications(IEnumerable<Type> types)
950 {
951 IEnumerable<OptionSpecification> optionSpecs = from verbTuple in Verb.SelectFromTypes(types)
952 select
953 OptionSpecification.NewSwitch(string.Empty,
954 verbTuple.Item1.Name.Concat(verbTuple.Item1.Aliases)
955 .ToDelimitedString(", "),
956 false,
957 verbTuple.Item1.IsDefault
958 ? "(Default Verb) " + verbTuple.Item1.HelpText
959 : verbTuple.Item1.HelpText, //Default verb
960 string.Empty,
961 verbTuple.Item1.Hidden
962 );
963
964 if (AutoHelp)
965 {
966 optionSpecs = optionSpecs.Concat(new[] { MakeHelpEntry() });
967 }
968
969 if (AutoVersion)
970 {
971 optionSpecs = optionSpecs.Concat(new[] { MakeVersionEntry() });
972 }
973
974 return optionSpecs;
975 }
976
977 private HelpText AddOptionsImpl(IEnumerable<Specification> specifications,
978 string requiredWord,
979 string optionGroupWord,
980 int maximumLength)
981 {
982 int maxLength = GetMaxLength(specifications);
983
984 optionsHelp = new StringBuilder(BuilderCapacity);
985
986 int remainingSpace = maximumLength - (maxLength + TotalOptionPadding);
987
988 if (OptionComparison != null)
989 {
990 int i = -1;
991
992 List<ComparableOption> comparables = specifications.ToList()
993 .Select(s =>
994 {
995 i++;
996
997 return ToComparableOption(s, i);
998 }
999 )
1000 .ToList();
1001 comparables.Sort(OptionComparison);
1002
1003 foreach (ComparableOption comparable in comparables)
1004 {
1005 Specification spec = specifications.ElementAt(comparable.Index);
1006 AddOption(requiredWord, optionGroupWord, maxLength, spec, remainingSpace);
1007 }
1008 }
1009 else
1010 {
1011 specifications.ForEach(option =>
1012 AddOption(requiredWord, optionGroupWord, maxLength, option, remainingSpace)
1013 );
1014 }
1015
1016 return this;
1017 }
1018
1020 {
1021 return OptionSpecification.NewSwitch(string.Empty,
1022 "help",
1023 false,
1025 string.Empty
1026 );
1027 }
1028
1030 {
1031 return OptionSpecification.NewSwitch(string.Empty,
1032 "version",
1033 false,
1035 string.Empty
1036 );
1037 }
1038
1039 private HelpText AddPreOptionsLine(string value, int maximumLength)
1040 {
1041 AddLine(preOptionsHelp, value, maximumLength);
1042
1043 return this;
1044 }
1045
1046 private HelpText AddOption(string requiredWord,
1047 string optionGroupWord,
1048 int maxLength,
1049 Specification specification,
1050 int widthOfHelpText)
1051 {
1052 OptionSpecification GetOptionGroupSpecification()
1053 {
1054 if (specification.Tag == SpecificationType.Option &&
1055 specification is OptionSpecification optionSpecification &&
1056 optionSpecification.Group.Length > 0
1057 )
1058
1059 {
1060 return optionSpecification;
1061 }
1062
1063 return null;
1064 }
1065
1066 if (specification.Hidden)
1067 {
1068 return this;
1069 }
1070
1071 optionsHelp.Append(" ");
1072
1073 StringBuilder name = new StringBuilder(maxLength)
1074 .BimapIf(specification.Tag == SpecificationType.Option,
1075 it => it.Append(AddOptionName(maxLength, (OptionSpecification)specification)),
1076 it => it.Append(AddValueName(maxLength, (ValueSpecification)specification))
1077 );
1078
1080 .Append(name.Length < maxLength
1081 ? name.ToString()
1082 .PadRight(maxLength)
1083 : name.ToString()
1084 )
1085 .Append(OptionToHelpTextSeparatorWidth.Spaces());
1086
1087 string optionHelpText = specification.HelpText;
1088
1089 if (AddEnumValuesToHelpText && specification.EnumValues.Any())
1090 {
1091 optionHelpText += " Valid values: " + string.Join(", ", specification.EnumValues);
1092 }
1093
1094 specification.DefaultValue.Do(defaultValue =>
1095 optionHelpText =
1096 "(Default: {0}) ".FormatInvariant(FormatDefaultValue(defaultValue)) +
1097 optionHelpText
1098 );
1099
1100 OptionSpecification optionGroupSpecification = GetOptionGroupSpecification();
1101
1102 if (specification.Required && optionGroupSpecification == null)
1103 {
1104 optionHelpText = "{0} ".FormatInvariant(requiredWord) + optionHelpText;
1105 }
1106
1107 if (optionGroupSpecification != null)
1108 {
1109 optionHelpText = "({0}: {1}) ".FormatInvariant(optionGroupWord, optionGroupSpecification.Group) +
1110 optionHelpText;
1111 }
1112
1113 //note that we need to indent trim the start of the string because it's going to be
1114 //appended to an existing line that is as long as the indent-level
1115 string indented = TextWrapper
1116 .WrapAndIndentText(optionHelpText, maxLength + TotalOptionPadding, widthOfHelpText)
1117 .TrimStart();
1118
1120 .Append(indented)
1121 .Append(Environment.NewLine)
1122 .AppendWhen(AdditionalNewLineAfterOption, Environment.NewLine);
1123
1124 return this;
1125 }
1126
1127 private string AddOptionName(int maxLength, OptionSpecification specification)
1128 {
1129 return
1130 new StringBuilder(maxLength)
1131 .MapIf(specification.ShortName.Length > 0,
1132 it => it
1133 .AppendWhen(AddDashesToOption, '-')
1134 .AppendFormat("{0}", specification.ShortName)
1135 .AppendFormatWhen(specification.MetaValue.Length > 0, " {0}", specification.MetaValue)
1136 .AppendWhen(specification.LongName.Length > 0, ", ")
1137 )
1138 .MapIf(specification.LongName.Length > 0,
1139 it => it
1140 .AppendWhen(AddDashesToOption, "--")
1141 .AppendFormat("{0}", specification.LongName)
1142 .AppendFormatWhen(specification.MetaValue.Length > 0, "={0}", specification.MetaValue)
1143 )
1144 .ToString();
1145 }
1146
1147 private string AddValueName(int maxLength, ValueSpecification specification)
1148 {
1149 return new StringBuilder(maxLength)
1150 .BimapIf(specification.MetaName.Length > 0,
1151 it => it.AppendFormat("{0} (pos. {1})", specification.MetaName, specification.Index),
1152 it => it.AppendFormat("value pos. {0}", specification.Index)
1153 )
1154 .AppendFormatWhen(specification.MetaValue.Length > 0,
1155 " {0}",
1156 specification.MetaValue
1157 )
1158 .ToString();
1159 }
1160
1161 private HelpText AddLine(StringBuilder builder, string value)
1162 {
1163 AddLine(builder, value, MaximumDisplayWidth);
1164
1165 return this;
1166 }
1167
1168 private int GetMaxLength(IEnumerable<Specification> specifications)
1169 {
1170 return specifications.Aggregate(0,
1171 (length, spec) =>
1172 {
1173 if (spec.Hidden)
1174 {
1175 return length;
1176 }
1177
1178 int specLength = spec.Tag == SpecificationType.Option
1181
1182 return Math.Max(length, specLength);
1183 }
1184 );
1185 }
1186
1187
1189 {
1190 int specLength = 0;
1191
1192 bool hasShort = spec.ShortName.Length > 0;
1193 bool hasLong = spec.LongName.Length > 0;
1194
1195 int metaLength = 0;
1196
1197 if (spec.MetaValue.Length > 0)
1198 {
1199 metaLength = spec.MetaValue.Length + 1;
1200 }
1201
1202 if (hasShort)
1203 {
1204 ++specLength;
1205
1207 {
1208 ++specLength;
1209 }
1210
1211 specLength += metaLength;
1212 }
1213
1214 if (hasLong)
1215 {
1216 specLength += spec.LongName.Length;
1217
1219 {
1220 specLength += OptionPrefixWidth;
1221 }
1222
1223 specLength += metaLength;
1224 }
1225
1226 if (hasShort && hasLong)
1227 {
1228 specLength += OptionPrefixWidth;
1229 }
1230
1231 return specLength;
1232 }
1233
1235 {
1236 int specLength = 0;
1237
1238 bool hasMeta = spec.MetaName.Length > 0;
1239
1240 int metaLength = 0;
1241
1242 if (spec.MetaValue.Length > 0)
1243 {
1244 metaLength = spec.MetaValue.Length + 1;
1245 }
1246
1247 if (hasMeta)
1248 {
1249 specLength += spec.MetaName.Length +
1250 spec.Index.ToStringInvariant()
1251 .Length +
1252 8; //METANAME (pos. N)
1253 }
1254 else
1255 {
1256 specLength += spec.Index.ToStringInvariant()
1257 .Length +
1258 11; // "value pos. N"
1259 }
1260
1261 specLength += metaLength;
1262
1263 return specLength;
1264 }
1265
1266 private static string FormatDefaultValue<T>(T value)
1267 {
1268 if (value is bool)
1269 {
1270 return value.ToStringLocal()
1271 .ToLowerInvariant();
1272 }
1273
1274 if (value is string)
1275 {
1276 return value.ToStringLocal();
1277 }
1278
1279 IEnumerable asEnumerable = value as IEnumerable;
1280
1281 if (asEnumerable == null)
1282 {
1283 return value.ToStringLocal();
1284 }
1285
1286 StringBuilder builder = new StringBuilder();
1287
1288 foreach (object item in asEnumerable)
1289 {
1290 builder
1291 .Append(item.ToStringLocal())
1292 .Append(" ");
1293 }
1294
1295 return builder.Length > 0
1296 ? builder.ToString(0, builder.Length - 1)
1297 : string.Empty;
1298 }
1299
1300#region ordering
1301
1303 {
1305 ValueSpecification value = spec as ValueSpecification;
1306 bool required = option?.Required ?? false;
1307
1308 return new ComparableOption
1309 {
1310 Required = required,
1311 IsOption = option != null,
1312 IsValue = value != null,
1313 LongName = option?.LongName ?? value?.MetaName,
1314 ShortName = option?.ShortName,
1315 Index = index,
1316 };
1317 }
1318
1319
1320 public Comparison<ComparableOption> OptionComparison { get; set; } = null;
1321
1322 public static Comparison<ComparableOption> RequiredThenAlphaComparison = (attr1, attr2) =>
1323 {
1324 if (attr1.IsOption && attr2.IsOption)
1325 {
1326 if (attr1.Required && !attr2.Required)
1327 {
1328 return -1;
1329 }
1330
1331 if (!attr1.Required && attr2.Required)
1332 {
1333 return 1;
1334 }
1335
1336 return string.Compare(attr1.LongName, attr2.LongName, StringComparison.Ordinal);
1337 }
1338
1339 if (attr1.IsOption && attr2.IsValue)
1340 {
1341 return -1;
1342 }
1343
1344 return 1;
1345 };
1346
1347#endregion
1348 }
1349}
The Maybe type models an optional value. A value of type Maybe a either contains a value of type a (r...
Definition Maybe.cs:33
bool MatchNothing()
Matches an empty value returning true.
Definition Maybe.cs:59
static OptionSpecification NewSwitch(string shortName, string longName, bool required, string helpText, string metaValue, bool hidden=false)
static Specification FromProperty(PropertyInfo property)
IEnumerable< string > EnumValues
static IEnumerable< Tuple< Verb, Type > > SelectFromTypes(IEnumerable< Type > types)
Definition Verb.cs:47
Base type of all errors.
Definition Error.cs:110
Models an error generated when a user explicitly requests help in verb commands scenario.
Definition Error.cs:463
Type Type
System.Type of verb command.
Definition Error.cs:480
Models an error generated when a an option from another set is defined.
Definition Error.cs:401
It contains a sequence of CommandLine.Error.
Provides methods to parse command line arguments.
Definition Parser.cs:21
static Parser Default
Gets the singleton instance created with basic defaults.
Definition Parser.cs:75
Models a parser result. When inherited by CommandLine.Parsed<T>, it contains an instance of type T w...
ParserResultType Tag
Parser result type discriminator, defined as CommandLine.ParserResultType enumeration.
Models a multiline assembly license text.
Models a multiline assembly usage text.
Models a command line usage example.
Definition Example.cs:13
string HelpText
Example description.
Definition Example.cs:71
Models the heading part of an help text. You can assign it where you assign any System....
static HeadingInfo Default
Gets the default heading instance. The title is retrieved from AssemblyTitleAttribute,...
static HeadingInfo Empty
An empty object used for initialization.
HelpText AddPostOptionsText(string text)
Adds a text block of lines at the bottom, after options usage string.
Definition HelpText.cs:554
OptionSpecification MakeVersionEntry()
Definition HelpText.cs:1029
HelpText(SentenceBuilder sentenceBuilder, string heading, string copyright)
Initializes a new instance of the CommandLine.Text.HelpText class specifying heading and copyright st...
Definition HelpText.cs:110
HelpText AddPreOptionsLine(string value)
Adds a text line after copyright and before options usage strings.
Definition HelpText.cs:494
readonly StringBuilder preOptionsHelp
Definition HelpText.cs:53
HelpText AddPostOptionsLine(string value)
Adds a text line at the bottom, after options usage string.
Definition HelpText.cs:505
const int TotalOptionPadding
The total amount of extra space that needs to accounted for when indenting Option help text.
Definition HelpText.cs:50
Comparison< ComparableOption > OptionComparison
Definition HelpText.cs:1320
int GetMaxOptionLength(OptionSpecification spec)
Definition HelpText.cs:1188
HelpText AddPreOptionsText(string text)
Adds a text block of lines after copyright and before options usage strings.
Definition HelpText.cs:539
HelpText AddPreOptionsLine(string value, int maximumLength)
Definition HelpText.cs:1039
int GetMaxValueLength(ValueSpecification spec)
Definition HelpText.cs:1234
HelpText AddLine(StringBuilder builder, string value)
Definition HelpText.cs:1161
HelpText AddOptionsImpl(IEnumerable< Specification > specifications, string requiredWord, string optionGroupWord, int maximumLength)
Definition HelpText.cs:977
HelpText AddOption(string requiredWord, string optionGroupWord, int maxLength, Specification specification, int widthOfHelpText)
Definition HelpText.cs:1046
HelpText AddVerbs(params Type[] types)
Adds a text block with verbs usage string.
Definition HelpText.cs:589
SentenceBuilder SentenceBuilder
Gets the SentenceBuilder instance specified in constructor.
Definition HelpText.cs:227
bool AddEnumValuesToHelpText
Gets or sets a value indicating whether to add the values of an enum after the description of the spe...
Definition HelpText.cs:212
HelpText(SentenceBuilder sentenceBuilder, string heading)
Initializes a new instance of the CommandLine.Text.HelpText class specifying the sentence builder and...
Definition HelpText.cs:89
HelpText AddPostOptionsLines(IEnumerable< string > lines)
Adds text lines at the bottom, after options usage string.
Definition HelpText.cs:527
readonly StringBuilder postOptionsHelp
Definition HelpText.cs:52
HelpText AddOptions< T >(ParserResult< T > result)
Adds a text block with options usage string.
Definition HelpText.cs:569
static void AddLine(StringBuilder builder, string value, int maximumLength)
Definition HelpText.cs:879
HelpText(string heading)
Initializes a new instance of the CommandLine.Text.HelpText class specifying heading string.
Definition HelpText.cs:80
static HelpText DefaultParsingErrorsHandler< T >(ParserResult< T > parserResult, HelpText current)
Supplies a default parsing error handler implementation.
Definition HelpText.cs:443
HelpText AddPreOptionsLines(IEnumerable< string > lines)
Adds text lines after copyright and before options usage strings.
Definition HelpText.cs:515
int GetMaxLength(IEnumerable< Specification > specifications)
Definition HelpText.cs:1168
static Comparison< ComparableOption > RequiredThenAlphaComparison
Definition HelpText.cs:1322
string Copyright
Gets or sets the copyright string. You can directly assign a CommandLine.Text.CopyrightInfo instance.
Definition HelpText.cs:174
IEnumerable< Specification > AdaptVerbsToSpecifications(IEnumerable< Type > types)
Definition HelpText.cs:949
const int DefaultMaximumLength
Definition HelpText.cs:35
ComparableOption ToComparableOption(Specification spec, int index)
Definition HelpText.cs:1302
bool AutoVersion
Gets or sets a value indicating whether implicit option or verb 'version' should be supported.
Definition HelpText.cs:222
int MaximumDisplayWidth
Gets or sets the maximum width of the display. This determines word wrap when displaying the text.
Definition HelpText.cs:191
string AddValueName(int maxLength, ValueSpecification specification)
Definition HelpText.cs:1147
bool AddNewLineBetweenHelpSections
Gets or sets a value indicating whether to add newlines between help sections.
Definition HelpText.cs:207
static HelpText AutoBuild< T >(ParserResult< T > parserResult, Func< HelpText, HelpText > onError, Func< Example, Example > onExample, bool verbsIndex=false, int maxDisplayWidth=DefaultMaximumLength)
Creates a new instance of the CommandLine.Text.HelpText class using common defaults.
Definition HelpText.cs:253
bool AutoHelp
Gets or sets a value indicating whether implicit option or verb 'help' should be supported.
Definition HelpText.cs:217
static string RenderParsingErrorsText< T >(ParserResult< T > parserResult, Func< Error, string > formatError, Func< IEnumerable< MutuallyExclusiveSetError >, string > formatMutuallyExclusiveSetErrors, int indent)
Builds a string that contains a parsing error message.
Definition HelpText.cs:668
string Heading
Gets or sets the heading string. You can directly assign a CommandLine.Text.HeadingInfo instance.
Definition HelpText.cs:156
HelpText AddVerbs(int maximumLength, params Type[] types)
Adds a text block with verbs usage string.
Definition HelpText.cs:635
string AddOptionName(int maxLength, OptionSpecification specification)
Definition HelpText.cs:1127
IEnumerable< Specification > GetSpecificationsFromType(Type type)
Definition HelpText.cs:902
OptionSpecification MakeHelpEntry()
Definition HelpText.cs:1019
const int OptionToHelpTextSeparatorWidth
The number of spaces between an option and its associated help text.
Definition HelpText.cs:40
bool AdditionalNewLineAfterOption
Gets or sets a value indicating whether to add an additional line after the description of the specif...
Definition HelpText.cs:202
bool AddDashesToOption
Gets or sets a value indicating whether the format of options should contain dashes....
Definition HelpText.cs:197
static Maybe< Tuple< UsageAttribute, IEnumerable< Example > > > GetUsageFromType(Type type)
Definition HelpText.cs:928
HelpText(SentenceBuilder sentenceBuilder)
Initializes a new instance of the CommandLine.Text.HelpText class specifying the sentence builder.
Definition HelpText.cs:71
override string ToString()
Returns the help screen as a System.String.
Definition HelpText.cs:830
StringBuilder optionsHelp
Definition HelpText.cs:56
const int OptionPrefixWidth
The width of the option prefix (either "--" or " ".
Definition HelpText.cs:45
static IEnumerable< string > RenderUsageTextAsLines< T >(ParserResult< T > parserResult, Func< Example, Example > mapperFunc)
Builds a string sequence with usage text block created using CommandLine.Text.UsageAttribute data and...
Definition HelpText.cs:776
static string RenderUsageText< T >(ParserResult< T > parserResult)
Builds a string with usage text block created using CommandLine.Text.UsageAttribute data and metadata...
Definition HelpText.cs:750
HelpText()
Initializes a new instance of the CommandLine.Text.HelpText class.
Definition HelpText.cs:61
static IEnumerable< string > RenderParsingErrorsTextAsLines< T >(ParserResult< T > parserResult, Func< Error, string > formatError, Func< IEnumerable< MutuallyExclusiveSetError >, string > formatMutuallyExclusiveSetErrors, int indent)
Builds a sequence of string that contains a parsing error message.
Definition HelpText.cs:697
HelpText(string heading, string copyright)
Initializes a new instance of the CommandLine.Text.HelpText class specifying heading and copyright st...
Definition HelpText.cs:99
static string FormatDefaultValue< T >(T value)
Definition HelpText.cs:1266
Exposes standard delegates to provide a mean to customize part of help screen generation....
Func< string > RequiredWord
Gets a delegate that returns the word 'required'.
Func< IEnumerable< MutuallyExclusiveSetError >, string > FormatMutuallyExclusiveSetErrors
Gets a delegate that handles mutually exclusive set errors formatting. The delegates must accept a se...
Func< string > ErrorsHeadingText
Gets a delegate that returns that errors block heading text.
Func< string > OptionGroupWord
Gets a delegate that returns the word 'group'.
Func< bool, string > HelpCommandText
Get a delegate that returns the help text of help command. The delegates must accept a boolean that i...
Func< Error, string > FormatError
Gets a delegate that handles singular error formatting. The delegates must accept an Error and return...
Func< bool, string > VersionCommandText
Get a delegate that returns the help text of vesion command. The delegates must accept a boolean that...
A utility class to word-wrap and indent blocks of text.
static string WrapAndIndentText(string input, int indentLevel, int columnWidth)
Convenience method to wraps and indent a string in a single operation.
Applied to a static property that yields a sequence of CommandLine.Text.Example, provides data to ren...
IEnumerable< Type > Choices
static TypeInfo Create(Type current)
Provides settings for when formatting command line from an options instance../>.
ParserResultType
Discriminator enumeration of CommandLine.ParserResultType derivates.
ErrorType
Discriminator enumeration of CommandLine.Error derivates.
Definition Error.cs:13
Provides means to format an help screen. You can assign it in place of a System.String instance.
Definition HelpText.cs:23