@@ -23,9 +23,11 @@ import 'util.dart';
2323 * spaces and wrapping to the next line to keep the cells correctly lined up.
2424 */
2525class OptionHelp {
26- static const NUM_COLUMNS = 3 ; // Abbreviation, long name, help.
26+ static const numColumns = 3 ; // Abbreviation, long name, help.
2727
28- /** The parser this is generating usage for. */
28+ static const gutterWidth = 4 ; // Width of gutter between columns.
29+
30+ /** The usage this is generating usage for. */
2931 final Usage usage;
3032
3133 /** The working buffer for the generated usage text. */
@@ -41,7 +43,7 @@ class OptionHelp {
4143 /** The width in characters of each column. */
4244 List <int > columnWidths;
4345
44- /** The width in characters of each column. */
46+ /** The formatters of each column. */
4547 List <Function > columnFormatters = [abbrFormatter, optionPen, helpFormatter];
4648
4749 static String abbrFormatter (String help) {
@@ -86,47 +88,65 @@ class OptionHelp {
8688
8789 calculateColumnWidths ();
8890
89- usage.options.forEach ((name, option) {
90- if (option.hide != null && option.hide) return ;
91+ usage.optionGroups.asMap ().forEach ((index, optionGroup) {
92+ if (optionGroup.hide != null && optionGroup.hide) return ;
93+
94+ var title = optionGroup.title != null
95+ ? getGroupTitle (optionGroup.title)
96+ : index == 0
97+ ? null
98+ : '_' * (columnWidths.fold (0 , (prev, next) => prev + next) - gutterWidth);
99+ if (title != null ) {
100+ if (buffer.isNotEmpty) buffer.write ("\n " );
101+ write (0 , title, format: titlePen);
102+ newline ();
103+ newline ();
104+ }
91105
92- write ( 0 , getAbbreviation ( option));
93- write ( 1 , getLongOption (name, option)) ;
106+ optionGroup.options. forEach ((name, option) {
107+ if (option.hide != null && option.hide) return ;
94108
95- var help = getHelp (option.help);
96- if (help != null ) {
97- write (2 , help);
98- }
109+ write (0 , getAbbreviation (option));
110+ write (1 , getLongOption (name, option));
99111
100- if (option.allowed is Map ) {
101- var allowedValues = getAllowedValues (option).toList (growable: false );
102- allowedValues.sort ();
103- newline ();
104- for (var name in allowedValues) {
105- write (1 , getAllowedTitle (name));
106- write (2 , option.allowed[name]);
112+ var help = getHelp (option.help);
113+ if (help != null ) {
114+ write (2 , help);
107115 }
108- newline ();
109- } else if (getAllowedValues (option) != null ) {
110- write (2 , buildAllowedList (option));
111- } else if (option.defaultsTo != null ) {
112- var defaultsTo = option is Flag && option.defaultsTo == true ?
113- 'on' :
114- option is ! Flag ? option.defaultsTo : null ;
115- if (defaultsTo != null ) {
116- write (2 , '(defaults to "$defaultsTo ")' );
116+
117+ if (option.allowed is Map ) {
118+ var allowedValues = getAllowedValues (option).toList (growable: false );
119+ allowedValues.sort ();
120+ newline ();
121+ for (var name in allowedValues) {
122+ write (1 , getAllowedTitle (name));
123+ write (2 , option.allowed[name]);
124+ }
125+ newline ();
126+ } else if (getAllowedValues (option) != null ) {
127+ write (2 , buildAllowedList (option));
128+ } else if (option.defaultsTo != null ) {
129+ var defaultsTo = option is Flag && option.defaultsTo == true ?
130+ 'on' :
131+ option is ! Flag ? option.defaultsTo : null ;
132+ if (defaultsTo != null ) {
133+ write (2 , '(defaults to "$defaultsTo ")' );
134+ }
117135 }
118- }
119136
120- // If any given option displays more than one line of text on the right
121- // column (i.e. help, default value, allowed options, etc.) then put a
122- // blank line after it. This gives space where it's useful while still
123- // keeping simple one-line options clumped together.
124- if (numHelpLines > 1 ) newline ();
137+ // If any given option displays more than one line of text on the right
138+ // column (i.e. help, default value, allowed options, etc.) then put a
139+ // blank line after it. This gives space where it's useful while still
140+ // keeping simple one-line options clumped together.
141+ if (numHelpLines > 1 ) newline ();
142+ });
125143 });
126144
127145 return buffer.toString ();
128146 }
129147
148+ String getGroupTitle (String name) => '$name :' ;
149+
130150 Iterable <String > getAllowedValues (Option option) {
131151 var allowed = option.allowed;
132152 if (allowed is Iterable ) return allowed;
@@ -164,23 +184,30 @@ class OptionHelp {
164184 void calculateColumnWidths () {
165185 int abbr = 0 ;
166186 int title = 0 ;
167- usage.options.forEach ((name, option) {
168- // Make room in the first column if there are abbreviations.
169- abbr = max (abbr, getAbbreviation (option).length);
187+ usage.optionGroups.forEach ((optionGroup) {
188+ if (optionGroup.hide != null && optionGroup.hide) return ;
189+
190+ // Make room for the group title.
191+ title = max (title, getGroupTitle (optionGroup.title).length);
170192
171- // Make room for the option.
172- title = max (title, getLongOption (name, option).length);
193+ optionGroup.options.forEach ((name, option) {
194+ // Make room in the first column if there are abbreviations.
195+ abbr = max (abbr, getAbbreviation (option).length);
173196
174- // Make room for the allowed help.
175- if (option.allowed is Map ) {
176- for (var allowed in option.allowed.keys) {
177- title = max (title, getAllowedTitle (allowed).length);
197+ // Make room for the option.
198+ title = max (title, getLongOption (name, option).length);
199+
200+ // Make room for the allowed help.
201+ if (option.allowed is Map ) {
202+ for (var allowed in option.allowed.keys) {
203+ title = max (title, getAllowedTitle (allowed).length);
204+ }
178205 }
179- }
206+ });
180207 });
181208
182209 // Leave a gutter between the columns.
183- title += 4 ;
210+ title += gutterWidth ;
184211 columnWidths = [abbr, title];
185212 }
186213
@@ -190,24 +217,24 @@ class OptionHelp {
190217 numHelpLines = 0 ;
191218 }
192219
193- void write (int column, String text) {
220+ void write (int column, String text, { format ( String )} ) {
194221 var lines = text.split ('\n ' );
195222
196223 // Strip leading and trailing empty lines.
197- while (lines.length > 0 && lines[ 0 ] .trim () == '' ) {
198- lines.removeRange ( 0 , 1 );
224+ while (lines.isNotEmpty && lines.first .trim () == '' ) {
225+ lines.removeAt ( 0 );
199226 }
200227
201- while (lines.length > 0 && lines[lines.length - 1 ] .trim () == '' ) {
228+ while (lines.isNotEmpty && lines.last .trim () == '' ) {
202229 lines.removeLast ();
203230 }
204231
205232 for (var line in lines) {
206- writeLine (column, line);
233+ writeLine (column, line, format : format );
207234 }
208235 }
209236
210- void writeLine (int column, String text) {
237+ void writeLine (int column, String text, { format ( String )} ) {
211238 // Write any pending newlines.
212239 while (newlinesNeeded > 0 ) {
213240 buffer.write ('\n ' );
@@ -217,15 +244,17 @@ class OptionHelp {
217244 // Advance until we are at the right column (which may mean wrapping around
218245 // to the next line.
219246 while (currentColumn != column) {
220- if (currentColumn < NUM_COLUMNS - 1 ) {
247+ if (currentColumn < numColumns - 1 ) {
221248 buffer.write (' ' * columnWidths[currentColumn]);
222249 } else {
223250 buffer.write ('\n ' );
224251 }
225- currentColumn = (currentColumn + 1 ) % NUM_COLUMNS ;
252+ currentColumn = (currentColumn + 1 ) % numColumns ;
226253 }
227254
228- var formatted = columnFormatters[column](text);
255+ var formatter = format != null ? format : columnFormatters[column];
256+
257+ var formatted = formatter (text);
229258 buffer.write (formatted);
230259
231260 if (column < columnWidths.length) {
@@ -234,14 +263,14 @@ class OptionHelp {
234263 }
235264
236265 // Advance to the next column.
237- currentColumn = (currentColumn + 1 ) % NUM_COLUMNS ;
266+ currentColumn = (currentColumn + 1 ) % numColumns ;
238267
239268 // If we reached the last column, we need to wrap to the next line.
240- if (column == NUM_COLUMNS - 1 ) newlinesNeeded++ ;
269+ if (column == numColumns - 1 ) newlinesNeeded++ ;
241270
242271 // Keep track of how many consecutive lines we've written in the last
243272 // column.
244- if (column == NUM_COLUMNS - 1 ) {
273+ if (column == numColumns - 1 ) {
245274 numHelpLines++ ;
246275 } else {
247276 numHelpLines = 0 ;
0 commit comments