1- using System . Diagnostics ;
1+ using System . Diagnostics ;
22using System . Reflection ;
33using RT . Internal ;
44using RT . PostBuild ;
@@ -116,23 +116,19 @@ namespace RT.CommandLine;
116116/// the values in the enum type must also have documentation or <see cref="UndocumentedAttribute"/>, except
117117/// for the enum value that corresponds to the field’s default value if the field is not mandatory.</para>
118118/// <para>
119- /// Documentation is provided in one of the following ways:</para>
119+ /// Documentation can be provided in one of the following ways:</para>
120120/// <list type="bullet">
121121/// <item><description>
122- /// Monolingual, translation-agnostic (unlocalisable) applications use the <see
123- /// cref="DocumentationAttribute"/> to specify documentation directly.</description></item>
122+ /// Use <see cref="DocumentationAttribute"/> to specify unformatted text directly.</description></item>
124123/// <item><description>
125- /// <para>
126- /// Translatable applications must declare methods with the following signature:</para>
127- /// <code>
128- /// static string FieldNameDoc(Translation)</code>
129- /// <para>
130- /// The first parameter must be of the same type as the object passed in for the <c>applicationTr</c>
131- /// parameter of <see cref="Parse"/>. The name of the method is the name of the field or enum value
132- /// followed by <c>Doc</c>. The return value is the translated string.</para></description></item></list></description></item>
124+ /// Use <see cref="DocumentationEggsMLAttribute"/> or <see cref="DocumentationRhoMLAttribute"/> to format
125+ /// your text with coloration using one of the two markup systems.</description></item></list></description></item>
133126/// <item><description>
134127/// <see cref="IsPositionalAttribute"/> and <see cref="IsMandatoryAttribute"/> can be used together. However, a
135- /// positional field can only be made mandatory if all the positional fields preceding it are also mandatory.</description></item></list></remarks>
128+ /// positional field can only be made mandatory if all the positional fields preceding it are also mandatory.</description></item></list>
129+ /// <para>
130+ /// <see cref="SectionAttribute"/> can be used to split the help screen into sections with headers for better
131+ /// readability.</para></remarks>
136132public static class CommandLineParser
137133{
138134 /// <summary>
@@ -589,21 +585,6 @@ private static Func<int, ConsoleColoredString> getHelpGenerator(Type type, Func<
589585 }
590586 helpString . Add ( ConsoleColoredString . NewLine ) ;
591587
592- //
593- // ## CONSTRUCT THE TABLES
594- //
595-
596- var anyCommandsWithSuboptions = false ;
597- var requiredParamsTable = new TextTable { MaxWidth = wrapWidth - leftMargin , ColumnSpacing = 3 , RowSpacing = 1 , LeftMargin = leftMargin } ;
598- int requiredRow = 0 ;
599- foreach ( var f in mandatoryPositional . Select ( fld => new { Positional = true , Field = fld } ) . Concat ( mandatoryOptions . Select ( fld => new { Positional = false , Field = fld } ) ) )
600- anyCommandsWithSuboptions |= createParameterHelpRow ( ref requiredRow , requiredParamsTable , f . Field , f . Positional , helpProcessor ) ;
601-
602- var optionalParamsTable = new TextTable { MaxWidth = wrapWidth - leftMargin , ColumnSpacing = 3 , RowSpacing = 1 , LeftMargin = leftMargin } ;
603- int optionalRow = 0 ;
604- foreach ( var f in optionalPositional . Select ( fld => new { Positional = true , Field = fld } ) . Concat ( optionalOptions . Select ( fld => new { Positional = false , Field = fld } ) ) )
605- anyCommandsWithSuboptions |= createParameterHelpRow ( ref optionalRow , optionalParamsTable , f . Field , f . Positional , helpProcessor ) ;
606-
607588 // Word-wrap the documentation for the command (if any)
608589 var doc = getDocumentation ( type , helpProcessor ) ;
609590 foreach ( var line in doc . WordWrap ( wrapWidth ) )
@@ -612,26 +593,40 @@ private static Func<int, ConsoleColoredString> getHelpGenerator(Type type, Func<
612593 helpString . Add ( ConsoleColoredString . NewLine ) ;
613594 }
614595
615- // Table of required parameters
616- if ( mandatoryOptions . Count > 0 || mandatoryPositional . Count > 0 )
596+
597+ //
598+ // ## CONSTRUCT THE TABLES
599+ //
600+
601+ var anyCommandsWithSuboptions = false ;
602+ var paramsTables = new List < ( string heading , TextTable table ) > ( ) ;
603+ TextTable curTable = null ;
604+ var curRow = 0 ;
605+ var lastMandatory = false ;
606+ foreach ( var ( mandatory , positional , field ) in mandatoryPositional . Select ( fld => ( mandatory : true , positional : true , field : fld ) )
607+ . Concat ( mandatoryOptions . Select ( fld => ( mandatory : true , positional : false , field : fld ) ) )
608+ . Concat ( optionalPositional . Select ( fld => ( mandatory : false , positional : true , field : fld ) ) )
609+ . Concat ( optionalOptions . Select ( fld => ( mandatory : false , positional : false , field : fld ) ) ) )
617610 {
618- helpString . Add ( ConsoleColoredString . NewLine ) ;
619- helpString . Add ( new ConsoleColoredString ( "Required parameters:" , CmdLineColor . HelpHeading ) ) ;
620- helpString . Add ( ConsoleColoredString . NewLine ) ;
621- helpString . Add ( ConsoleColoredString . NewLine ) ;
622- requiredParamsTable . RemoveEmptyColumns ( ) ;
623- helpString . Add ( requiredParamsTable . ToColoredString ( ) ) ;
611+ var section = field . GetCustomAttribute < SectionAttribute > ( ) ;
612+ if ( curTable == null || lastMandatory != mandatory || section != null )
613+ {
614+ curTable = new TextTable { MaxWidth = wrapWidth - leftMargin , ColumnSpacing = 3 , RowSpacing = 1 , LeftMargin = leftMargin } ;
615+ paramsTables . Add ( ( section ? . Heading ?? $ "{ ( mandatory ? "Required" : "Optional" ) } parameters:", curTable ) ) ;
616+ curRow = 0 ;
617+ }
618+ anyCommandsWithSuboptions |= createParameterHelpRow ( ref curRow , curTable , field , positional , helpProcessor ) ;
619+ lastMandatory = mandatory ;
624620 }
625621
626- // Table of optional parameters
627- if ( optionalOptions . Count > 0 || optionalPositional . Count > 0 )
622+ foreach ( var ( heading , table ) in paramsTables )
628623 {
629624 helpString . Add ( ConsoleColoredString . NewLine ) ;
630- helpString . Add ( new ConsoleColoredString ( "Optional parameters:" , CmdLineColor . HelpHeading ) ) ;
625+ helpString . Add ( new ConsoleColoredString ( heading , CmdLineColor . HelpHeading ) ) ;
631626 helpString . Add ( ConsoleColoredString . NewLine ) ;
632627 helpString . Add ( ConsoleColoredString . NewLine ) ;
633- optionalParamsTable . RemoveEmptyColumns ( ) ;
634- helpString . Add ( optionalParamsTable . ToColoredString ( ) ) ;
628+ table . RemoveEmptyColumns ( ) ;
629+ helpString . Add ( table . ToColoredString ( ) ) ;
635630 }
636631
637632 // “This command accepts further arguments on the command line.”
0 commit comments