Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(619)

Side by Side Diff: lib/args/args.dart

Issue 10831371: Move args from lib/ to pkg/ . (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/args/example.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * This library lets you define parsers for parsing raw command-line arguments
7 * into a set of options and values using [GNU][] and [POSIX][] style options.
8 *
9 * ## Defining options ##
10 *
11 * To use this library, you create an [ArgParser] object which will contain
12 * the set of options you support:
13 *
14 * var parser = new ArgParser();
15 *
16 * Then you define a set of options on that parser using [addOption()] and
17 * [addFlag()]. The minimal way to create an option is:
18 *
19 * parser.addOption('name');
20 *
21 * This creates an option named "name". Options must be given a value on the
22 * command line. If you have a simple on/off flag, you can instead use:
23 *
24 * parser.addFlag('name');
25 *
26 * (From here on out "option" will refer to both "regular" options and flags.
27 * In cases where the distinction matters, we'll use "non-flag option".)
28 *
29 * Options may have an optional single-character abbreviation:
30 *
31 * parser.addOption('mode', abbr: 'm');
32 * parser.addFlag('verbose', abbr: 'v');
33 *
34 * They may also specify a default value. The default value will be used if the
35 * option isn't provided:
36 *
37 * parser.addOption('mode', defaultsTo: 'debug');
38 * parser.addFlag('verbose', defaultsTo: false);
39 *
40 * The default value for non-flag options can be any [String]. For flags, it
41 * must be a [bool].
42 *
43 * To validate non-flag options, you may provide an allowed set of values. When
44 * you do, it will throw a [FormatException] when you parse the arguments if
45 * the value for an option is not in the allowed set:
46 *
47 * parser.addOption('mode', allowed: ['debug', 'release']);
48 *
49 * You can provide a callback when you define an option. When you later parse
50 * a set of arguments, the callback for that option will be invoked with the
51 * value provided for it:
52 *
53 * parser.addOption('mode', callback: (mode) => print('Got mode $mode));
54 * parser.addFlag('verbose', callback: (verbose) {
55 * if (verbose) print('Verbose');
56 * });
57 *
58 * The callback for each option will *always* be called when you parse a set of
59 * arguments. If the option isn't provided in the args, the callback will be
60 * passed the default value, or `null` if there is none set.
61 *
62 * ## Parsing arguments ##
63 *
64 * Once you have an [ArgParser] set up with some options and flags, you use it
65 * by calling [ArgParser.parse()] with a set of arguments:
66 *
67 * var results = parser.parse(['some', 'command', 'line', 'args']);
68 *
69 * These will usually come from `new Options().arguments`, but you can pass in
70 * any list of strings. It returns an instance of [ArgResults]. This is a
71 * map-like object that will return the value of any parsed option.
72 *
73 * var parser = new ArgParser();
74 * parser.addOption('mode');
75 * parser.addFlag('verbose', defaultsTo: true);
76 * var results = parser.parse('['--mode', 'debug', 'something', 'else']);
77 *
78 * print(results['mode']); // debug
79 * print(results['verbose']); // true
80 *
81 * The [parse()] method will stop as soon as it reaches `--` or anything that
82 * it doesn't recognize as an option, flag, or option value. If there are still
83 * arguments left, they will be provided to you in
84 * [ArgResults.rest].
85 *
86 * print(results.rest); // ['something', 'else']
87 *
88 * ## Specifying options ##
89 *
90 * To actually pass in options and flags on the command line, use GNU or POSIX
91 * style. If you define an option like:
92 *
93 * parser.addOption('name', abbr: 'n');
94 *
95 * Then a value for it can be specified on the command line using any of:
96 *
97 * --name=somevalue
98 * --name somevalue
99 * -nsomevalue
100 * -n somevalue
101 *
102 * Given this flag:
103 *
104 * parser.addFlag('name', abbr: 'n');
105 *
106 * You can set it on using one of:
107 *
108 * --name
109 * -n
110 *
111 * Or set it off using:
112 *
113 * --no-name
114 *
115 * Multiple flag abbreviation can also be collapsed into a single argument. If
116 * you define:
117 *
118 * parser.addFlag('verbose', abbr: 'v');
119 * parser.addFlag('french', abbr: 'f');
120 * parser.addFlag('iambic-pentameter', abbr: 'i');
121 *
122 * Then all three flags could be set using:
123 *
124 * -vfi
125 *
126 * By default, an option has only a single value, with later option values
127 * overriding earlier ones; for example:
128 *
129 * var parser = new ArgParser();
130 * parser.addOption('mode');
131 * var results = parser.parse(['--mode', 'on', '--mode', 'off']);
132 * print(results['mode']); // prints 'off'
133 *
134 * If you need multiple values, set the [allowMultiple] flag. In that
135 * case the option can occur multiple times and when parsing arguments a
136 * List of values will be returned:
137 *
138 * var parser = new ArgParser();
139 * parser.addOption('mode', allowMultiple: true);
140 * var results = parser.parse(['--mode', 'on', '--mode', 'off']);
141 * print(results['mode']); // prints '[on, off]'
142 *
143 * ## Usage ##
144 *
145 * This library can also be used to automatically generate nice usage help
146 * text like you get when you run a program with `--help`. To use this, you
147 * will also want to provide some help text when you create your options. To
148 * define help text for the entire option, do:
149 *
150 * parser.addOption('mode', help: 'The compiler configuration',
151 * allowed: ['debug', 'release']);
152 * parser.addFlag('verbose', help: 'Show additional diagnostic info');
153 *
154 * For non-flag options, you can also provide detailed help for each expected
155 * value using a map:
156 *
157 * parser.addOption('arch', help: 'The architecture to compile for',
158 * allowedHelp: {
159 * 'ia32': 'Intel x86',
160 * 'arm': 'ARM Holding 32-bit chip'
161 * });
162 *
163 * If you define a set of options like the above, then calling this:
164 *
165 * print(parser.getUsage());
166 *
167 * Will display something like:
168 *
169 * --mode The compiler configuration
170 * [debug, release]
171 *
172 * --[no-]verbose Show additional diagnostic info
173 * --arch The architecture to compile for
174 *
175 * [arm] ARM Holding 32-bit chip
176 * [ia32] Intel x86
177 *
178 * [posix]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.h tml#tag_12_02
179 * [gnu]: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Inte rfaces
180 */
181 #library('args');
182
183 #import('utils.dart');
184
185 /**
186 * A class for taking a list of raw command line arguments and parsing out
187 * options and flags from them.
188 */
189 class ArgParser {
190 static final _SOLO_OPT = const RegExp(@'^-([a-zA-Z0-9])$');
191 static final _ABBR_OPT = const RegExp(@'^-([a-zA-Z0-9]+)(.*)$');
192 static final _LONG_OPT = const RegExp(@'^--([a-zA-Z\-_0-9]+)(=(.*))?$');
193
194 final Map<String, _Option> _options;
195
196 /**
197 * The names of the options, in the order that they were added. This way we
198 * can generate usage information in the same order.
199 */
200 // TODO(rnystrom): Use an ordered map type, if one appears.
201 final List<String> _optionNames;
202
203 /** The current argument list being parsed. Set by [parse()]. */
204 List<String> _args;
205
206 /** Index of the current argument being parsed in [_args]. */
207 int _current;
208
209 /** Creates a new ArgParser. */
210 ArgParser()
211 : _options = <String, _Option>{},
212 _optionNames = <String>[];
213
214 /**
215 * Defines a flag. Throws an [IllegalArgumentException] if:
216 *
217 * * There is already an option named [name].
218 * * There is already an option using abbreviation [abbr].
219 */
220 void addFlag(String name, [String abbr, String help, bool defaultsTo = false,
221 bool negatable = true, void callback(bool value)]) {
222 _addOption(name, abbr, help, null, null, defaultsTo, callback,
223 isFlag: true, negatable: negatable);
224 }
225
226 /**
227 * Defines a value-taking option. Throws an [IllegalArgumentException] if:
228 *
229 * * There is already an option with name [name].
230 * * There is already an option using abbreviation [abbr].
231 */
232 void addOption(String name, [String abbr, String help, List<String> allowed,
233 Map<String, String> allowedHelp, String defaultsTo,
234 void callback(bool value), bool allowMultiple = false]) {
235 _addOption(name, abbr, help, allowed, allowedHelp, defaultsTo,
236 callback, isFlag: false, allowMultiple: allowMultiple);
237 }
238
239 void _addOption(String name, String abbr, String help, List<String> allowed,
240 Map<String, String> allowedHelp, defaultsTo,
241 void callback(bool value), [bool isFlag, bool negatable = false,
242 bool allowMultiple = false]) {
243 // Make sure the name isn't in use.
244 if (_options.containsKey(name)) {
245 throw new IllegalArgumentException('Duplicate option "$name".');
246 }
247
248 // Make sure the abbreviation isn't too long or in use.
249 if (abbr != null) {
250 if (abbr.length > 1) {
251 throw new IllegalArgumentException(
252 'Abbreviation "$abbr" is longer than one character.');
253 }
254
255 var existing = _findByAbbr(abbr);
256 if (existing != null) {
257 throw new IllegalArgumentException(
258 'Abbreviation "$abbr" is already used by "${existing.name}".');
259 }
260 }
261
262 _options[name] = new _Option(name, abbr, help, allowed, allowedHelp,
263 defaultsTo, callback, isFlag: isFlag, negatable: negatable,
264 allowMultiple: allowMultiple);
265 _optionNames.add(name);
266 }
267
268 /**
269 * Parses [args], a list of command-line arguments, matches them against the
270 * flags and options defined by this parser, and returns the result.
271 */
272 ArgResults parse(List<String> args) {
273 _args = args;
274 _current = 0;
275 var results = {};
276
277 // Initialize flags to their defaults.
278 _options.forEach((name, option) {
279 if (option.allowMultiple) {
280 results[name] = [];
281 } else {
282 results[name] = option.defaultValue;
283 }
284 });
285
286 // Parse the args.
287 for (_current = 0; _current < args.length; _current++) {
288 var arg = args[_current];
289
290 if (arg == '--') {
291 // Reached the argument terminator, so stop here.
292 _current++;
293 break;
294 }
295
296 // Try to parse the current argument as an option. Note that the order
297 // here matters.
298 if (_parseSoloOption(results)) continue;
299 if (_parseAbbreviation(results)) continue;
300 if (_parseLongOption(results)) continue;
301
302 // If we got here, the argument doesn't look like an option, so stop.
303 break;
304 }
305
306 // Set unspecified multivalued arguments to their default value,
307 // if any, and invoke the callbacks.
308 for (var name in _optionNames) {
309 var option = _options[name];
310 if (option.allowMultiple &&
311 results[name].length == 0 &&
312 option.defaultValue != null) {
313 results[name].add(option.defaultValue);
314 }
315 if (option.callback != null) option.callback(results[name]);
316 }
317
318 // Add in the leftover arguments we didn't parse.
319 return new ArgResults(results,
320 _args.getRange(_current, _args.length - _current));
321 }
322
323 /**
324 * Generates a string displaying usage information for the defined options.
325 * This is basically the help text shown on the command line.
326 */
327 String getUsage() {
328 return new _Usage(this).generate();
329 }
330
331 /**
332 * Called during parsing to validate the arguments. Throws a
333 * [FormatException] if [condition] is `false`.
334 */
335 _validate(bool condition, String message) {
336 if (!condition) throw new FormatException(message);
337 }
338
339 /** Validates and stores [value] as the value for [option]. */
340 _setOption(Map results, _Option option, value) {
341 // See if it's one of the allowed values.
342 if (option.allowed != null) {
343 _validate(option.allowed.some((allow) => allow == value),
344 '"$value" is not an allowed value for option "${option.name}".');
345 }
346
347 if (option.allowMultiple) {
348 results[option.name].add(value);
349 } else {
350 results[option.name] = value;
351 }
352 }
353
354 /**
355 * Pulls the value for [option] from the next argument in [_args] (where the
356 * current option is at index [_current]. Validates that there is a valid
357 * value there.
358 */
359 void _readNextArgAsValue(Map results, _Option option) {
360 _current++;
361 // Take the option argument from the next command line arg.
362 _validate(_current < _args.length,
363 'Missing argument for "${option.name}".');
364
365 // Make sure it isn't an option itself.
366 _validate(!_ABBR_OPT.hasMatch(_args[_current]) &&
367 !_LONG_OPT.hasMatch(_args[_current]),
368 'Missing argument for "${option.name}".');
369
370 _setOption(results, option, _args[_current]);
371 }
372
373 /**
374 * Tries to parse the current argument as a "solo" option, which is a single
375 * hyphen followed by a single letter. We treat this differently than
376 * collapsed abbreviations (like "-abc") to handle the possible value that
377 * may follow it.
378 */
379 bool _parseSoloOption(Map results) {
380 var soloOpt = _SOLO_OPT.firstMatch(_args[_current]);
381 if (soloOpt == null) return false;
382
383 var option = _findByAbbr(soloOpt[1]);
384 _validate(option != null,
385 'Could not find an option or flag "-${soloOpt[1]}".');
386
387 if (option.isFlag) {
388 _setOption(results, option, true);
389 } else {
390 _readNextArgAsValue(results, option);
391 }
392
393 return true;
394 }
395
396 /**
397 * Tries to parse the current argument as a series of collapsed abbreviations
398 * (like "-abc") or a single abbreviation with the value directly attached
399 * to it (like "-mrelease").
400 */
401 bool _parseAbbreviation(Map results) {
402 var abbrOpt = _ABBR_OPT.firstMatch(_args[_current]);
403 if (abbrOpt == null) return false;
404
405 // If the first character is the abbreviation for a non-flag option, then
406 // the rest is the value.
407 var c = abbrOpt[1].substring(0, 1);
408 var first = _findByAbbr(c);
409 if (first == null) {
410 _validate(false, 'Could not find an option with short name "-$c".');
411 } else if (!first.isFlag) {
412 // The first character is a non-flag option, so the rest must be the
413 // value.
414 var value = '${abbrOpt[1].substring(1)}${abbrOpt[2]}';
415 _setOption(results, first, value);
416 } else {
417 // If we got some non-flag characters, then it must be a value, but
418 // if we got here, it's a flag, which is wrong.
419 _validate(abbrOpt[2] == '',
420 'Option "-$c" is a flag and cannot handle value '
421 '"${abbrOpt[1].substring(1)}${abbrOpt[2]}".');
422
423 // Not an option, so all characters should be flags.
424 for (var i = 0; i < abbrOpt[1].length; i++) {
425 var c = abbrOpt[1].substring(i, i + 1);
426 var option = _findByAbbr(c);
427 _validate(option != null,
428 'Could not find an option with short name "-$c".');
429
430 // In a list of short options, only the first can be a non-flag. If
431 // we get here we've checked that already.
432 _validate(option.isFlag,
433 'Option "-$c" must be a flag to be in a collapsed "-".');
434
435 _setOption(results, option, true);
436 }
437 }
438
439 return true;
440 }
441
442 /**
443 * Tries to parse the current argument as a long-form named option, which
444 * may include a value like "--mode=release" or "--mode release".
445 */
446 bool _parseLongOption(Map results) {
447 var longOpt = _LONG_OPT.firstMatch(_args[_current]);
448 if (longOpt == null) return false;
449
450 var name = longOpt[1];
451 var option = _options[name];
452 if (option != null) {
453 if (option.isFlag) {
454 _validate(longOpt[3] == null,
455 'Flag option "$name" should not be given a value.');
456
457 _setOption(results, option, true);
458 } else if (longOpt[3] != null) {
459 // We have a value like --foo=bar.
460 _setOption(results, option, longOpt[3]);
461 } else {
462 // Option like --foo, so look for the value as the next arg.
463 _readNextArgAsValue(results, option);
464 }
465 } else if (name.startsWith('no-')) {
466 // See if it's a negated flag.
467 name = name.substring('no-'.length);
468 option = _options[name];
469 _validate(option != null, 'Could not find an option named "$name".');
470 _validate(option.isFlag, 'Cannot negate non-flag option "$name".');
471 _validate(option.negatable, 'Cannot negate option "$name".');
472
473 _setOption(results, option, false);
474 } else {
475 _validate(option != null, 'Could not find an option named "$name".');
476 }
477
478 return true;
479 }
480
481 /**
482 * Finds the option whose abbreviation is [abbr], or `null` if no option has
483 * that abbreviation.
484 */
485 _Option _findByAbbr(String abbr) {
486 for (var option in _options.getValues()) {
487 if (option.abbreviation == abbr) return option;
488 }
489
490 return null;
491 }
492
493 /**
494 * Get the default value for an option. Useful after parsing to test
495 * if the user specified something other than the default.
496 */
497 getDefault(String option) {
498 if (!_options.containsKey(option)) {
499 throw new IllegalArgumentException('No option named $option');
500 }
501 return _options[option].defaultValue;
502 }
503 }
504
505 /**
506 * The results of parsing a series of command line arguments using
507 * [ArgParser.parse()]. Includes the parsed options and any remaining unparsed
508 * command line arguments.
509 */
510 class ArgResults {
511 final Map _options;
512
513 /**
514 * The remaining command-line arguments that were not parsed as options or
515 * flags. If `--` was used to separate the options from the remaining
516 * arguments, it will not be included in this list.
517 */
518 final List<String> rest;
519
520 /** Creates a new [ArgResults]. */
521 ArgResults(this._options, this.rest);
522
523 /** Gets the parsed command-line option named [name]. */
524 operator [](String name) {
525 if (!_options.containsKey(name)) {
526 throw new IllegalArgumentException(
527 'Could not find an option named "$name".');
528 }
529
530 return _options[name];
531 }
532
533 /** Get the names of the options as a [Collection]. */
534 Collection<String> get options => _options.getKeys();
535 }
536
537 class _Option {
538 final String name;
539 final String abbreviation;
540 final List allowed;
541 final defaultValue;
542 final Function callback;
543 final String help;
544 final Map<String, String> allowedHelp;
545 final bool isFlag;
546 final bool negatable;
547 final bool allowMultiple;
548
549 _Option(this.name, this.abbreviation, this.help, this.allowed,
550 this.allowedHelp, this.defaultValue, this.callback, [this.isFlag,
551 this.negatable, this.allowMultiple = false]);
552 }
553
554 /**
555 * Takes an [ArgParser] and generates a string of usage (i.e. help) text for its
556 * defined options. Internally, it works like a tabular printer. The output is
557 * divided into three horizontal columns, like so:
558 *
559 * -h, --help Prints the usage information
560 * | | | |
561 *
562 * It builds the usage text up one column at a time and handles padding with
563 * spaces and wrapping to the next line to keep the cells correctly lined up.
564 */
565 class _Usage {
566 static final NUM_COLUMNS = 3; // Abbreviation, long name, help.
567
568 /** The parser this is generating usage for. */
569 final ArgParser args;
570
571 /** The working buffer for the generated usage text. */
572 StringBuffer buffer;
573
574 /**
575 * The column that the "cursor" is currently on. If the next call to
576 * [write()] is not for this column, it will correctly handle advancing to
577 * the next column (and possibly the next row).
578 */
579 int currentColumn = 0;
580
581 /** The width in characters of each column. */
582 List<int> columnWidths;
583
584 /**
585 * The number of sequential lines of text that have been written to the last
586 * column (which shows help info). We track this so that help text that spans
587 * multiple lines can be padded with a blank line after it for separation.
588 * Meanwhile, sequential options with single-line help will be compacted next
589 * to each other.
590 */
591 int numHelpLines = 0;
592
593 /**
594 * How many newlines need to be rendered before the next bit of text can be
595 * written. We do this lazily so that the last bit of usage doesn't have
596 * dangling newlines. We only write newlines right *before* we write some
597 * real content.
598 */
599 int newlinesNeeded = 0;
600
601 _Usage(this.args);
602
603 /**
604 * Generates a string displaying usage information for the defined options.
605 * This is basically the help text shown on the command line.
606 */
607 String generate() {
608 buffer = new StringBuffer();
609
610 calculateColumnWidths();
611
612 for (var name in args._optionNames) {
613 var option = args._options[name];
614 write(0, getAbbreviation(option));
615 write(1, getLongOption(option));
616
617 if (option.help != null) write(2, option.help);
618
619 if (option.allowedHelp != null) {
620 var allowedNames = option.allowedHelp.getKeys();
621 allowedNames.sort((a, b) => a.compareTo(b));
622 newline();
623 for (var name in allowedNames) {
624 write(1, getAllowedTitle(name));
625 write(2, option.allowedHelp[name]);
626 }
627 newline();
628 } else if (option.allowed != null) {
629 write(2, buildAllowedList(option));
630 } else if (option.defaultValue != null) {
631 if (option.isFlag && option.defaultValue == true) {
632 write(2, '(defaults to on)');
633 } else if (!option.isFlag) {
634 write(2, '(defaults to "${option.defaultValue}")');
635 }
636 }
637
638 // If any given option displays more than one line of text on the right
639 // column (i.e. help, default value, allowed options, etc.) then put a
640 // blank line after it. This gives space where it's useful while still
641 // keeping simple one-line options clumped together.
642 if (numHelpLines > 1) newline();
643 }
644
645 return buffer.toString();
646 }
647
648 String getAbbreviation(_Option option) {
649 if (option.abbreviation != null) {
650 return '-${option.abbreviation}, ';
651 } else {
652 return '';
653 }
654 }
655
656 String getLongOption(_Option option) {
657 if (option.negatable) {
658 return '--[no-]${option.name}';
659 } else {
660 return '--${option.name}';
661 }
662 }
663
664 String getAllowedTitle(String allowed) {
665 return ' [$allowed]';
666 }
667
668 void calculateColumnWidths() {
669 int abbr = 0;
670 int title = 0;
671 for (var name in args._optionNames) {
672 var option = args._options[name];
673
674 // Make room in the first column if there are abbreviations.
675 abbr = Math.max(abbr, getAbbreviation(option).length);
676
677 // Make room for the option.
678 title = Math.max(title, getLongOption(option).length);
679
680 // Make room for the allowed help.
681 if (option.allowedHelp != null) {
682 for (var allowed in option.allowedHelp.getKeys()) {
683 title = Math.max(title, getAllowedTitle(allowed).length);
684 }
685 }
686 }
687
688 // Leave a gutter between the columns.
689 title += 4;
690 columnWidths = [abbr, title];
691 }
692
693 newline() {
694 newlinesNeeded++;
695 currentColumn = 0;
696 numHelpLines = 0;
697 }
698
699 write(int column, String text) {
700 var lines = text.split('\n');
701
702 // Strip leading and trailing empty lines.
703 while (lines.length > 0 && lines[0].trim() == '') {
704 lines.removeRange(0, 1);
705 }
706
707 while (lines.length > 0 && lines[lines.length - 1].trim() == '') {
708 lines.removeLast();
709 }
710
711 for (var line in lines) {
712 writeLine(column, line);
713 }
714 }
715
716 writeLine(int column, String text) {
717 // Write any pending newlines.
718 while (newlinesNeeded > 0) {
719 buffer.add('\n');
720 newlinesNeeded--;
721 }
722
723 // Advance until we are at the right column (which may mean wrapping around
724 // to the next line.
725 while (currentColumn != column) {
726 if (currentColumn < NUM_COLUMNS - 1) {
727 buffer.add(padRight('', columnWidths[currentColumn]));
728 } else {
729 buffer.add('\n');
730 }
731 currentColumn = (currentColumn + 1) % NUM_COLUMNS;
732 }
733
734 if (column < columnWidths.length) {
735 // Fixed-size column, so pad it.
736 buffer.add(padRight(text, columnWidths[column]));
737 } else {
738 // The last column, so just write it.
739 buffer.add(text);
740 }
741
742 // Advance to the next column.
743 currentColumn = (currentColumn + 1) % NUM_COLUMNS;
744
745 // If we reached the last column, we need to wrap to the next line.
746 if (column == NUM_COLUMNS - 1) newlinesNeeded++;
747
748 // Keep track of how many consecutive lines we've written in the last
749 // column.
750 if (column == NUM_COLUMNS - 1) {
751 numHelpLines++;
752 } else {
753 numHelpLines = 0;
754 }
755 }
756
757 buildAllowedList(_Option option) {
758 var allowedBuffer = new StringBuffer();
759 allowedBuffer.add('[');
760 bool first = true;
761 for (var allowed in option.allowed) {
762 if (!first) allowedBuffer.add(', ');
763 allowedBuffer.add(allowed);
764 if (allowed == option.defaultValue) {
765 allowedBuffer.add(' (default)');
766 }
767 first = false;
768 }
769 allowedBuffer.add(']');
770 return allowedBuffer.toString();
771 }
772 }
OLDNEW
« no previous file with comments | « no previous file | lib/args/example.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698