| [9af201e] | 1 | /**
|
|---|
| 2 | * class HelpFormatter
|
|---|
| 3 | *
|
|---|
| 4 | * Formatter for generating usage messages and argument help strings. Only the
|
|---|
| 5 | * name of this class is considered a public API. All the methods provided by
|
|---|
| 6 | * the class are considered an implementation detail.
|
|---|
| 7 | *
|
|---|
| 8 | * Do not call in your code, use this class only for inherits your own forvatter
|
|---|
| 9 | *
|
|---|
| 10 | * ToDo add [additonal formatters][1]
|
|---|
| 11 | *
|
|---|
| 12 | * [1]:http://docs.python.org/dev/library/argparse.html#formatter-class
|
|---|
| 13 | **/
|
|---|
| 14 | 'use strict';
|
|---|
| 15 |
|
|---|
| 16 | var sprintf = require('sprintf-js').sprintf;
|
|---|
| 17 |
|
|---|
| 18 | // Constants
|
|---|
| 19 | var c = require('../const');
|
|---|
| 20 |
|
|---|
| 21 | var $$ = require('../utils');
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 | /*:nodoc:* internal
|
|---|
| 25 | * new Support(parent, heding)
|
|---|
| 26 | * - parent (object): parent section
|
|---|
| 27 | * - heading (string): header string
|
|---|
| 28 | *
|
|---|
| 29 | **/
|
|---|
| 30 | function Section(parent, heading) {
|
|---|
| 31 | this._parent = parent;
|
|---|
| 32 | this._heading = heading;
|
|---|
| 33 | this._items = [];
|
|---|
| 34 | }
|
|---|
| 35 |
|
|---|
| 36 | /*:nodoc:* internal
|
|---|
| 37 | * Section#addItem(callback) -> Void
|
|---|
| 38 | * - callback (array): tuple with function and args
|
|---|
| 39 | *
|
|---|
| 40 | * Add function for single element
|
|---|
| 41 | **/
|
|---|
| 42 | Section.prototype.addItem = function (callback) {
|
|---|
| 43 | this._items.push(callback);
|
|---|
| 44 | };
|
|---|
| 45 |
|
|---|
| 46 | /*:nodoc:* internal
|
|---|
| 47 | * Section#formatHelp(formatter) -> string
|
|---|
| 48 | * - formatter (HelpFormatter): current formatter
|
|---|
| 49 | *
|
|---|
| 50 | * Form help section string
|
|---|
| 51 | *
|
|---|
| 52 | **/
|
|---|
| 53 | Section.prototype.formatHelp = function (formatter) {
|
|---|
| 54 | var itemHelp, heading;
|
|---|
| 55 |
|
|---|
| 56 | // format the indented section
|
|---|
| 57 | if (this._parent) {
|
|---|
| 58 | formatter._indent();
|
|---|
| 59 | }
|
|---|
| 60 |
|
|---|
| 61 | itemHelp = this._items.map(function (item) {
|
|---|
| 62 | var obj, func, args;
|
|---|
| 63 |
|
|---|
| 64 | obj = formatter;
|
|---|
| 65 | func = item[0];
|
|---|
| 66 | args = item[1];
|
|---|
| 67 | return func.apply(obj, args);
|
|---|
| 68 | });
|
|---|
| 69 | itemHelp = formatter._joinParts(itemHelp);
|
|---|
| 70 |
|
|---|
| 71 | if (this._parent) {
|
|---|
| 72 | formatter._dedent();
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | // return nothing if the section was empty
|
|---|
| 76 | if (!itemHelp) {
|
|---|
| 77 | return '';
|
|---|
| 78 | }
|
|---|
| 79 |
|
|---|
| 80 | // add the heading if the section was non-empty
|
|---|
| 81 | heading = '';
|
|---|
| 82 | if (this._heading && this._heading !== c.SUPPRESS) {
|
|---|
| 83 | var currentIndent = formatter.currentIndent;
|
|---|
| 84 | heading = $$.repeat(' ', currentIndent) + this._heading + ':' + c.EOL;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | // join the section-initialize newline, the heading and the help
|
|---|
| 88 | return formatter._joinParts([ c.EOL, heading, itemHelp, c.EOL ]);
|
|---|
| 89 | };
|
|---|
| 90 |
|
|---|
| 91 | /**
|
|---|
| 92 | * new HelpFormatter(options)
|
|---|
| 93 | *
|
|---|
| 94 | * #### Options:
|
|---|
| 95 | * - `prog`: program name
|
|---|
| 96 | * - `indentIncriment`: indent step, default value 2
|
|---|
| 97 | * - `maxHelpPosition`: max help position, default value = 24
|
|---|
| 98 | * - `width`: line width
|
|---|
| 99 | *
|
|---|
| 100 | **/
|
|---|
| 101 | var HelpFormatter = module.exports = function HelpFormatter(options) {
|
|---|
| 102 | options = options || {};
|
|---|
| 103 |
|
|---|
| 104 | this._prog = options.prog;
|
|---|
| 105 |
|
|---|
| 106 | this._maxHelpPosition = options.maxHelpPosition || 24;
|
|---|
| 107 | this._width = (options.width || ((process.env.COLUMNS || 80) - 2));
|
|---|
| 108 |
|
|---|
| 109 | this._currentIndent = 0;
|
|---|
| 110 | this._indentIncriment = options.indentIncriment || 2;
|
|---|
| 111 | this._level = 0;
|
|---|
| 112 | this._actionMaxLength = 0;
|
|---|
| 113 |
|
|---|
| 114 | this._rootSection = new Section(null);
|
|---|
| 115 | this._currentSection = this._rootSection;
|
|---|
| 116 |
|
|---|
| 117 | this._whitespaceMatcher = new RegExp('\\s+', 'g');
|
|---|
| 118 | this._longBreakMatcher = new RegExp(c.EOL + c.EOL + c.EOL + '+', 'g');
|
|---|
| 119 | };
|
|---|
| 120 |
|
|---|
| 121 | HelpFormatter.prototype._indent = function () {
|
|---|
| 122 | this._currentIndent += this._indentIncriment;
|
|---|
| 123 | this._level += 1;
|
|---|
| 124 | };
|
|---|
| 125 |
|
|---|
| 126 | HelpFormatter.prototype._dedent = function () {
|
|---|
| 127 | this._currentIndent -= this._indentIncriment;
|
|---|
| 128 | this._level -= 1;
|
|---|
| 129 | if (this._currentIndent < 0) {
|
|---|
| 130 | throw new Error('Indent decreased below 0.');
|
|---|
| 131 | }
|
|---|
| 132 | };
|
|---|
| 133 |
|
|---|
| 134 | HelpFormatter.prototype._addItem = function (func, args) {
|
|---|
| 135 | this._currentSection.addItem([ func, args ]);
|
|---|
| 136 | };
|
|---|
| 137 |
|
|---|
| 138 | //
|
|---|
| 139 | // Message building methods
|
|---|
| 140 | //
|
|---|
| 141 |
|
|---|
| 142 | /**
|
|---|
| 143 | * HelpFormatter#startSection(heading) -> Void
|
|---|
| 144 | * - heading (string): header string
|
|---|
| 145 | *
|
|---|
| 146 | * Start new help section
|
|---|
| 147 | *
|
|---|
| 148 | * See alse [code example][1]
|
|---|
| 149 | *
|
|---|
| 150 | * ##### Example
|
|---|
| 151 | *
|
|---|
| 152 | * formatter.startSection(actionGroup.title);
|
|---|
| 153 | * formatter.addText(actionGroup.description);
|
|---|
| 154 | * formatter.addArguments(actionGroup._groupActions);
|
|---|
| 155 | * formatter.endSection();
|
|---|
| 156 | *
|
|---|
| 157 | **/
|
|---|
| 158 | HelpFormatter.prototype.startSection = function (heading) {
|
|---|
| 159 | this._indent();
|
|---|
| 160 | var section = new Section(this._currentSection, heading);
|
|---|
| 161 | var func = section.formatHelp.bind(section);
|
|---|
| 162 | this._addItem(func, [ this ]);
|
|---|
| 163 | this._currentSection = section;
|
|---|
| 164 | };
|
|---|
| 165 |
|
|---|
| 166 | /**
|
|---|
| 167 | * HelpFormatter#endSection -> Void
|
|---|
| 168 | *
|
|---|
| 169 | * End help section
|
|---|
| 170 | *
|
|---|
| 171 | * ##### Example
|
|---|
| 172 | *
|
|---|
| 173 | * formatter.startSection(actionGroup.title);
|
|---|
| 174 | * formatter.addText(actionGroup.description);
|
|---|
| 175 | * formatter.addArguments(actionGroup._groupActions);
|
|---|
| 176 | * formatter.endSection();
|
|---|
| 177 | **/
|
|---|
| 178 | HelpFormatter.prototype.endSection = function () {
|
|---|
| 179 | this._currentSection = this._currentSection._parent;
|
|---|
| 180 | this._dedent();
|
|---|
| 181 | };
|
|---|
| 182 |
|
|---|
| 183 | /**
|
|---|
| 184 | * HelpFormatter#addText(text) -> Void
|
|---|
| 185 | * - text (string): plain text
|
|---|
| 186 | *
|
|---|
| 187 | * Add plain text into current section
|
|---|
| 188 | *
|
|---|
| 189 | * ##### Example
|
|---|
| 190 | *
|
|---|
| 191 | * formatter.startSection(actionGroup.title);
|
|---|
| 192 | * formatter.addText(actionGroup.description);
|
|---|
| 193 | * formatter.addArguments(actionGroup._groupActions);
|
|---|
| 194 | * formatter.endSection();
|
|---|
| 195 | *
|
|---|
| 196 | **/
|
|---|
| 197 | HelpFormatter.prototype.addText = function (text) {
|
|---|
| 198 | if (text && text !== c.SUPPRESS) {
|
|---|
| 199 | this._addItem(this._formatText, [ text ]);
|
|---|
| 200 | }
|
|---|
| 201 | };
|
|---|
| 202 |
|
|---|
| 203 | /**
|
|---|
| 204 | * HelpFormatter#addUsage(usage, actions, groups, prefix) -> Void
|
|---|
| 205 | * - usage (string): usage text
|
|---|
| 206 | * - actions (array): actions list
|
|---|
| 207 | * - groups (array): groups list
|
|---|
| 208 | * - prefix (string): usage prefix
|
|---|
| 209 | *
|
|---|
| 210 | * Add usage data into current section
|
|---|
| 211 | *
|
|---|
| 212 | * ##### Example
|
|---|
| 213 | *
|
|---|
| 214 | * formatter.addUsage(this.usage, this._actions, []);
|
|---|
| 215 | * return formatter.formatHelp();
|
|---|
| 216 | *
|
|---|
| 217 | **/
|
|---|
| 218 | HelpFormatter.prototype.addUsage = function (usage, actions, groups, prefix) {
|
|---|
| 219 | if (usage !== c.SUPPRESS) {
|
|---|
| 220 | this._addItem(this._formatUsage, [ usage, actions, groups, prefix ]);
|
|---|
| 221 | }
|
|---|
| 222 | };
|
|---|
| 223 |
|
|---|
| 224 | /**
|
|---|
| 225 | * HelpFormatter#addArgument(action) -> Void
|
|---|
| 226 | * - action (object): action
|
|---|
| 227 | *
|
|---|
| 228 | * Add argument into current section
|
|---|
| 229 | *
|
|---|
| 230 | * Single variant of [[HelpFormatter#addArguments]]
|
|---|
| 231 | **/
|
|---|
| 232 | HelpFormatter.prototype.addArgument = function (action) {
|
|---|
| 233 | if (action.help !== c.SUPPRESS) {
|
|---|
| 234 | var self = this;
|
|---|
| 235 |
|
|---|
| 236 | // find all invocations
|
|---|
| 237 | var invocations = [ this._formatActionInvocation(action) ];
|
|---|
| 238 | var invocationLength = invocations[0].length;
|
|---|
| 239 |
|
|---|
| 240 | var actionLength;
|
|---|
| 241 |
|
|---|
| 242 | if (action._getSubactions) {
|
|---|
| 243 | this._indent();
|
|---|
| 244 | action._getSubactions().forEach(function (subaction) {
|
|---|
| 245 |
|
|---|
| 246 | var invocationNew = self._formatActionInvocation(subaction);
|
|---|
| 247 | invocations.push(invocationNew);
|
|---|
| 248 | invocationLength = Math.max(invocationLength, invocationNew.length);
|
|---|
| 249 |
|
|---|
| 250 | });
|
|---|
| 251 | this._dedent();
|
|---|
| 252 | }
|
|---|
| 253 |
|
|---|
| 254 | // update the maximum item length
|
|---|
| 255 | actionLength = invocationLength + this._currentIndent;
|
|---|
| 256 | this._actionMaxLength = Math.max(this._actionMaxLength, actionLength);
|
|---|
| 257 |
|
|---|
| 258 | // add the item to the list
|
|---|
| 259 | this._addItem(this._formatAction, [ action ]);
|
|---|
| 260 | }
|
|---|
| 261 | };
|
|---|
| 262 |
|
|---|
| 263 | /**
|
|---|
| 264 | * HelpFormatter#addArguments(actions) -> Void
|
|---|
| 265 | * - actions (array): actions list
|
|---|
| 266 | *
|
|---|
| 267 | * Mass add arguments into current section
|
|---|
| 268 | *
|
|---|
| 269 | * ##### Example
|
|---|
| 270 | *
|
|---|
| 271 | * formatter.startSection(actionGroup.title);
|
|---|
| 272 | * formatter.addText(actionGroup.description);
|
|---|
| 273 | * formatter.addArguments(actionGroup._groupActions);
|
|---|
| 274 | * formatter.endSection();
|
|---|
| 275 | *
|
|---|
| 276 | **/
|
|---|
| 277 | HelpFormatter.prototype.addArguments = function (actions) {
|
|---|
| 278 | var self = this;
|
|---|
| 279 | actions.forEach(function (action) {
|
|---|
| 280 | self.addArgument(action);
|
|---|
| 281 | });
|
|---|
| 282 | };
|
|---|
| 283 |
|
|---|
| 284 | //
|
|---|
| 285 | // Help-formatting methods
|
|---|
| 286 | //
|
|---|
| 287 |
|
|---|
| 288 | /**
|
|---|
| 289 | * HelpFormatter#formatHelp -> string
|
|---|
| 290 | *
|
|---|
| 291 | * Format help
|
|---|
| 292 | *
|
|---|
| 293 | * ##### Example
|
|---|
| 294 | *
|
|---|
| 295 | * formatter.addText(this.epilog);
|
|---|
| 296 | * return formatter.formatHelp();
|
|---|
| 297 | *
|
|---|
| 298 | **/
|
|---|
| 299 | HelpFormatter.prototype.formatHelp = function () {
|
|---|
| 300 | var help = this._rootSection.formatHelp(this);
|
|---|
| 301 | if (help) {
|
|---|
| 302 | help = help.replace(this._longBreakMatcher, c.EOL + c.EOL);
|
|---|
| 303 | help = $$.trimChars(help, c.EOL) + c.EOL;
|
|---|
| 304 | }
|
|---|
| 305 | return help;
|
|---|
| 306 | };
|
|---|
| 307 |
|
|---|
| 308 | HelpFormatter.prototype._joinParts = function (partStrings) {
|
|---|
| 309 | return partStrings.filter(function (part) {
|
|---|
| 310 | return (part && part !== c.SUPPRESS);
|
|---|
| 311 | }).join('');
|
|---|
| 312 | };
|
|---|
| 313 |
|
|---|
| 314 | HelpFormatter.prototype._formatUsage = function (usage, actions, groups, prefix) {
|
|---|
| 315 | if (!prefix && typeof prefix !== 'string') {
|
|---|
| 316 | prefix = 'usage: ';
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | actions = actions || [];
|
|---|
| 320 | groups = groups || [];
|
|---|
| 321 |
|
|---|
| 322 |
|
|---|
| 323 | // if usage is specified, use that
|
|---|
| 324 | if (usage) {
|
|---|
| 325 | usage = sprintf(usage, { prog: this._prog });
|
|---|
| 326 |
|
|---|
| 327 | // if no optionals or positionals are available, usage is just prog
|
|---|
| 328 | } else if (!usage && actions.length === 0) {
|
|---|
| 329 | usage = this._prog;
|
|---|
| 330 |
|
|---|
| 331 | // if optionals and positionals are available, calculate usage
|
|---|
| 332 | } else if (!usage) {
|
|---|
| 333 | var prog = this._prog;
|
|---|
| 334 | var optionals = [];
|
|---|
| 335 | var positionals = [];
|
|---|
| 336 | var actionUsage;
|
|---|
| 337 | var textWidth;
|
|---|
| 338 |
|
|---|
| 339 | // split optionals from positionals
|
|---|
| 340 | actions.forEach(function (action) {
|
|---|
| 341 | if (action.isOptional()) {
|
|---|
| 342 | optionals.push(action);
|
|---|
| 343 | } else {
|
|---|
| 344 | positionals.push(action);
|
|---|
| 345 | }
|
|---|
| 346 | });
|
|---|
| 347 |
|
|---|
| 348 | // build full usage string
|
|---|
| 349 | actionUsage = this._formatActionsUsage([].concat(optionals, positionals), groups);
|
|---|
| 350 | usage = [ prog, actionUsage ].join(' ');
|
|---|
| 351 |
|
|---|
| 352 | // wrap the usage parts if it's too long
|
|---|
| 353 | textWidth = this._width - this._currentIndent;
|
|---|
| 354 | if ((prefix.length + usage.length) > textWidth) {
|
|---|
| 355 |
|
|---|
| 356 | // break usage into wrappable parts
|
|---|
| 357 | var regexpPart = new RegExp('\\(.*?\\)+|\\[.*?\\]+|\\S+', 'g');
|
|---|
| 358 | var optionalUsage = this._formatActionsUsage(optionals, groups);
|
|---|
| 359 | var positionalUsage = this._formatActionsUsage(positionals, groups);
|
|---|
| 360 |
|
|---|
| 361 |
|
|---|
| 362 | var optionalParts = optionalUsage.match(regexpPart);
|
|---|
| 363 | var positionalParts = positionalUsage.match(regexpPart) || [];
|
|---|
| 364 |
|
|---|
| 365 | if (optionalParts.join(' ') !== optionalUsage) {
|
|---|
| 366 | throw new Error('assert "optionalParts.join(\' \') === optionalUsage"');
|
|---|
| 367 | }
|
|---|
| 368 | if (positionalParts.join(' ') !== positionalUsage) {
|
|---|
| 369 | throw new Error('assert "positionalParts.join(\' \') === positionalUsage"');
|
|---|
| 370 | }
|
|---|
| 371 |
|
|---|
| 372 | // helper for wrapping lines
|
|---|
| 373 | /*eslint-disable func-style*/ // node 0.10 compat
|
|---|
| 374 | var _getLines = function (parts, indent, prefix) {
|
|---|
| 375 | var lines = [];
|
|---|
| 376 | var line = [];
|
|---|
| 377 |
|
|---|
| 378 | var lineLength = prefix ? prefix.length - 1 : indent.length - 1;
|
|---|
| 379 |
|
|---|
| 380 | parts.forEach(function (part) {
|
|---|
| 381 | if (lineLength + 1 + part.length > textWidth) {
|
|---|
| 382 | lines.push(indent + line.join(' '));
|
|---|
| 383 | line = [];
|
|---|
| 384 | lineLength = indent.length - 1;
|
|---|
| 385 | }
|
|---|
| 386 | line.push(part);
|
|---|
| 387 | lineLength += part.length + 1;
|
|---|
| 388 | });
|
|---|
| 389 |
|
|---|
| 390 | if (line) {
|
|---|
| 391 | lines.push(indent + line.join(' '));
|
|---|
| 392 | }
|
|---|
| 393 | if (prefix) {
|
|---|
| 394 | lines[0] = lines[0].substr(indent.length);
|
|---|
| 395 | }
|
|---|
| 396 | return lines;
|
|---|
| 397 | };
|
|---|
| 398 |
|
|---|
| 399 | var lines, indent, parts;
|
|---|
| 400 | // if prog is short, follow it with optionals or positionals
|
|---|
| 401 | if (prefix.length + prog.length <= 0.75 * textWidth) {
|
|---|
| 402 | indent = $$.repeat(' ', (prefix.length + prog.length + 1));
|
|---|
| 403 | if (optionalParts) {
|
|---|
| 404 | lines = [].concat(
|
|---|
| 405 | _getLines([ prog ].concat(optionalParts), indent, prefix),
|
|---|
| 406 | _getLines(positionalParts, indent)
|
|---|
| 407 | );
|
|---|
| 408 | } else if (positionalParts) {
|
|---|
| 409 | lines = _getLines([ prog ].concat(positionalParts), indent, prefix);
|
|---|
| 410 | } else {
|
|---|
| 411 | lines = [ prog ];
|
|---|
| 412 | }
|
|---|
| 413 |
|
|---|
| 414 | // if prog is long, put it on its own line
|
|---|
| 415 | } else {
|
|---|
| 416 | indent = $$.repeat(' ', prefix.length);
|
|---|
| 417 | parts = optionalParts.concat(positionalParts);
|
|---|
| 418 | lines = _getLines(parts, indent);
|
|---|
| 419 | if (lines.length > 1) {
|
|---|
| 420 | lines = [].concat(
|
|---|
| 421 | _getLines(optionalParts, indent),
|
|---|
| 422 | _getLines(positionalParts, indent)
|
|---|
| 423 | );
|
|---|
| 424 | }
|
|---|
| 425 | lines = [ prog ].concat(lines);
|
|---|
| 426 | }
|
|---|
| 427 | // join lines into usage
|
|---|
| 428 | usage = lines.join(c.EOL);
|
|---|
| 429 | }
|
|---|
| 430 | }
|
|---|
| 431 |
|
|---|
| 432 | // prefix with 'usage:'
|
|---|
| 433 | return prefix + usage + c.EOL + c.EOL;
|
|---|
| 434 | };
|
|---|
| 435 |
|
|---|
| 436 | HelpFormatter.prototype._formatActionsUsage = function (actions, groups) {
|
|---|
| 437 | // find group indices and identify actions in groups
|
|---|
| 438 | var groupActions = [];
|
|---|
| 439 | var inserts = [];
|
|---|
| 440 | var self = this;
|
|---|
| 441 |
|
|---|
| 442 | groups.forEach(function (group) {
|
|---|
| 443 | var end;
|
|---|
| 444 | var i;
|
|---|
| 445 |
|
|---|
| 446 | var start = actions.indexOf(group._groupActions[0]);
|
|---|
| 447 | if (start >= 0) {
|
|---|
| 448 | end = start + group._groupActions.length;
|
|---|
| 449 |
|
|---|
| 450 | //if (actions.slice(start, end) === group._groupActions) {
|
|---|
| 451 | if ($$.arrayEqual(actions.slice(start, end), group._groupActions)) {
|
|---|
| 452 | group._groupActions.forEach(function (action) {
|
|---|
| 453 | groupActions.push(action);
|
|---|
| 454 | });
|
|---|
| 455 |
|
|---|
| 456 | if (!group.required) {
|
|---|
| 457 | if (inserts[start]) {
|
|---|
| 458 | inserts[start] += ' [';
|
|---|
| 459 | } else {
|
|---|
| 460 | inserts[start] = '[';
|
|---|
| 461 | }
|
|---|
| 462 | inserts[end] = ']';
|
|---|
| 463 | } else {
|
|---|
| 464 | if (inserts[start]) {
|
|---|
| 465 | inserts[start] += ' (';
|
|---|
| 466 | } else {
|
|---|
| 467 | inserts[start] = '(';
|
|---|
| 468 | }
|
|---|
| 469 | inserts[end] = ')';
|
|---|
| 470 | }
|
|---|
| 471 | for (i = start + 1; i < end; i += 1) {
|
|---|
| 472 | inserts[i] = '|';
|
|---|
| 473 | }
|
|---|
| 474 | }
|
|---|
| 475 | }
|
|---|
| 476 | });
|
|---|
| 477 |
|
|---|
| 478 | // collect all actions format strings
|
|---|
| 479 | var parts = [];
|
|---|
| 480 |
|
|---|
| 481 | actions.forEach(function (action, actionIndex) {
|
|---|
| 482 | var part;
|
|---|
| 483 | var optionString;
|
|---|
| 484 | var argsDefault;
|
|---|
| 485 | var argsString;
|
|---|
| 486 |
|
|---|
| 487 | // suppressed arguments are marked with None
|
|---|
| 488 | // remove | separators for suppressed arguments
|
|---|
| 489 | if (action.help === c.SUPPRESS) {
|
|---|
| 490 | parts.push(null);
|
|---|
| 491 | if (inserts[actionIndex] === '|') {
|
|---|
| 492 | inserts.splice(actionIndex, actionIndex);
|
|---|
| 493 | } else if (inserts[actionIndex + 1] === '|') {
|
|---|
| 494 | inserts.splice(actionIndex + 1, actionIndex + 1);
|
|---|
| 495 | }
|
|---|
| 496 |
|
|---|
| 497 | // produce all arg strings
|
|---|
| 498 | } else if (!action.isOptional()) {
|
|---|
| 499 | part = self._formatArgs(action, action.dest);
|
|---|
| 500 |
|
|---|
| 501 | // if it's in a group, strip the outer []
|
|---|
| 502 | if (groupActions.indexOf(action) >= 0) {
|
|---|
| 503 | if (part[0] === '[' && part[part.length - 1] === ']') {
|
|---|
| 504 | part = part.slice(1, -1);
|
|---|
| 505 | }
|
|---|
| 506 | }
|
|---|
| 507 | // add the action string to the list
|
|---|
| 508 | parts.push(part);
|
|---|
| 509 |
|
|---|
| 510 | // produce the first way to invoke the option in brackets
|
|---|
| 511 | } else {
|
|---|
| 512 | optionString = action.optionStrings[0];
|
|---|
| 513 |
|
|---|
| 514 | // if the Optional doesn't take a value, format is: -s or --long
|
|---|
| 515 | if (action.nargs === 0) {
|
|---|
| 516 | part = '' + optionString;
|
|---|
| 517 |
|
|---|
| 518 | // if the Optional takes a value, format is: -s ARGS or --long ARGS
|
|---|
| 519 | } else {
|
|---|
| 520 | argsDefault = action.dest.toUpperCase();
|
|---|
| 521 | argsString = self._formatArgs(action, argsDefault);
|
|---|
| 522 | part = optionString + ' ' + argsString;
|
|---|
| 523 | }
|
|---|
| 524 | // make it look optional if it's not required or in a group
|
|---|
| 525 | if (!action.required && groupActions.indexOf(action) < 0) {
|
|---|
| 526 | part = '[' + part + ']';
|
|---|
| 527 | }
|
|---|
| 528 | // add the action string to the list
|
|---|
| 529 | parts.push(part);
|
|---|
| 530 | }
|
|---|
| 531 | });
|
|---|
| 532 |
|
|---|
| 533 | // insert things at the necessary indices
|
|---|
| 534 | for (var i = inserts.length - 1; i >= 0; --i) {
|
|---|
| 535 | if (inserts[i] !== null) {
|
|---|
| 536 | parts.splice(i, 0, inserts[i]);
|
|---|
| 537 | }
|
|---|
| 538 | }
|
|---|
| 539 |
|
|---|
| 540 | // join all the action items with spaces
|
|---|
| 541 | var text = parts.filter(function (part) {
|
|---|
| 542 | return !!part;
|
|---|
| 543 | }).join(' ');
|
|---|
| 544 |
|
|---|
| 545 | // clean up separators for mutually exclusive groups
|
|---|
| 546 | text = text.replace(/([\[(]) /g, '$1'); // remove spaces
|
|---|
| 547 | text = text.replace(/ ([\])])/g, '$1');
|
|---|
| 548 | text = text.replace(/\[ *\]/g, ''); // remove empty groups
|
|---|
| 549 | text = text.replace(/\( *\)/g, '');
|
|---|
| 550 | text = text.replace(/\(([^|]*)\)/g, '$1'); // remove () from single action groups
|
|---|
| 551 |
|
|---|
| 552 | text = text.trim();
|
|---|
| 553 |
|
|---|
| 554 | // return the text
|
|---|
| 555 | return text;
|
|---|
| 556 | };
|
|---|
| 557 |
|
|---|
| 558 | HelpFormatter.prototype._formatText = function (text) {
|
|---|
| 559 | text = sprintf(text, { prog: this._prog });
|
|---|
| 560 | var textWidth = this._width - this._currentIndent;
|
|---|
| 561 | var indentIncriment = $$.repeat(' ', this._currentIndent);
|
|---|
| 562 | return this._fillText(text, textWidth, indentIncriment) + c.EOL + c.EOL;
|
|---|
| 563 | };
|
|---|
| 564 |
|
|---|
| 565 | HelpFormatter.prototype._formatAction = function (action) {
|
|---|
| 566 | var self = this;
|
|---|
| 567 |
|
|---|
| 568 | var helpText;
|
|---|
| 569 | var helpLines;
|
|---|
| 570 | var parts;
|
|---|
| 571 | var indentFirst;
|
|---|
| 572 |
|
|---|
| 573 | // determine the required width and the entry label
|
|---|
| 574 | var helpPosition = Math.min(this._actionMaxLength + 2, this._maxHelpPosition);
|
|---|
| 575 | var helpWidth = this._width - helpPosition;
|
|---|
| 576 | var actionWidth = helpPosition - this._currentIndent - 2;
|
|---|
| 577 | var actionHeader = this._formatActionInvocation(action);
|
|---|
| 578 |
|
|---|
| 579 | // no help; start on same line and add a final newline
|
|---|
| 580 | if (!action.help) {
|
|---|
| 581 | actionHeader = $$.repeat(' ', this._currentIndent) + actionHeader + c.EOL;
|
|---|
| 582 |
|
|---|
| 583 | // short action name; start on the same line and pad two spaces
|
|---|
| 584 | } else if (actionHeader.length <= actionWidth) {
|
|---|
| 585 | actionHeader = $$.repeat(' ', this._currentIndent) +
|
|---|
| 586 | actionHeader +
|
|---|
| 587 | ' ' +
|
|---|
| 588 | $$.repeat(' ', actionWidth - actionHeader.length);
|
|---|
| 589 | indentFirst = 0;
|
|---|
| 590 |
|
|---|
| 591 | // long action name; start on the next line
|
|---|
| 592 | } else {
|
|---|
| 593 | actionHeader = $$.repeat(' ', this._currentIndent) + actionHeader + c.EOL;
|
|---|
| 594 | indentFirst = helpPosition;
|
|---|
| 595 | }
|
|---|
| 596 |
|
|---|
| 597 | // collect the pieces of the action help
|
|---|
| 598 | parts = [ actionHeader ];
|
|---|
| 599 |
|
|---|
| 600 | // if there was help for the action, add lines of help text
|
|---|
| 601 | if (action.help) {
|
|---|
| 602 | helpText = this._expandHelp(action);
|
|---|
| 603 | helpLines = this._splitLines(helpText, helpWidth);
|
|---|
| 604 | parts.push($$.repeat(' ', indentFirst) + helpLines[0] + c.EOL);
|
|---|
| 605 | helpLines.slice(1).forEach(function (line) {
|
|---|
| 606 | parts.push($$.repeat(' ', helpPosition) + line + c.EOL);
|
|---|
| 607 | });
|
|---|
| 608 |
|
|---|
| 609 | // or add a newline if the description doesn't end with one
|
|---|
| 610 | } else if (actionHeader.charAt(actionHeader.length - 1) !== c.EOL) {
|
|---|
| 611 | parts.push(c.EOL);
|
|---|
| 612 | }
|
|---|
| 613 | // if there are any sub-actions, add their help as well
|
|---|
| 614 | if (action._getSubactions) {
|
|---|
| 615 | this._indent();
|
|---|
| 616 | action._getSubactions().forEach(function (subaction) {
|
|---|
| 617 | parts.push(self._formatAction(subaction));
|
|---|
| 618 | });
|
|---|
| 619 | this._dedent();
|
|---|
| 620 | }
|
|---|
| 621 | // return a single string
|
|---|
| 622 | return this._joinParts(parts);
|
|---|
| 623 | };
|
|---|
| 624 |
|
|---|
| 625 | HelpFormatter.prototype._formatActionInvocation = function (action) {
|
|---|
| 626 | if (!action.isOptional()) {
|
|---|
| 627 | var format_func = this._metavarFormatter(action, action.dest);
|
|---|
| 628 | var metavars = format_func(1);
|
|---|
| 629 | return metavars[0];
|
|---|
| 630 | }
|
|---|
| 631 |
|
|---|
| 632 | var parts = [];
|
|---|
| 633 | var argsDefault;
|
|---|
| 634 | var argsString;
|
|---|
| 635 |
|
|---|
| 636 | // if the Optional doesn't take a value, format is: -s, --long
|
|---|
| 637 | if (action.nargs === 0) {
|
|---|
| 638 | parts = parts.concat(action.optionStrings);
|
|---|
| 639 |
|
|---|
| 640 | // if the Optional takes a value, format is: -s ARGS, --long ARGS
|
|---|
| 641 | } else {
|
|---|
| 642 | argsDefault = action.dest.toUpperCase();
|
|---|
| 643 | argsString = this._formatArgs(action, argsDefault);
|
|---|
| 644 | action.optionStrings.forEach(function (optionString) {
|
|---|
| 645 | parts.push(optionString + ' ' + argsString);
|
|---|
| 646 | });
|
|---|
| 647 | }
|
|---|
| 648 | return parts.join(', ');
|
|---|
| 649 | };
|
|---|
| 650 |
|
|---|
| 651 | HelpFormatter.prototype._metavarFormatter = function (action, metavarDefault) {
|
|---|
| 652 | var result;
|
|---|
| 653 |
|
|---|
| 654 | if (action.metavar || action.metavar === '') {
|
|---|
| 655 | result = action.metavar;
|
|---|
| 656 | } else if (action.choices) {
|
|---|
| 657 | var choices = action.choices;
|
|---|
| 658 |
|
|---|
| 659 | if (typeof choices === 'string') {
|
|---|
| 660 | choices = choices.split('').join(', ');
|
|---|
| 661 | } else if (Array.isArray(choices)) {
|
|---|
| 662 | choices = choices.join(',');
|
|---|
| 663 | } else {
|
|---|
| 664 | choices = Object.keys(choices).join(',');
|
|---|
| 665 | }
|
|---|
| 666 | result = '{' + choices + '}';
|
|---|
| 667 | } else {
|
|---|
| 668 | result = metavarDefault;
|
|---|
| 669 | }
|
|---|
| 670 |
|
|---|
| 671 | return function (size) {
|
|---|
| 672 | if (Array.isArray(result)) {
|
|---|
| 673 | return result;
|
|---|
| 674 | }
|
|---|
| 675 |
|
|---|
| 676 | var metavars = [];
|
|---|
| 677 | for (var i = 0; i < size; i += 1) {
|
|---|
| 678 | metavars.push(result);
|
|---|
| 679 | }
|
|---|
| 680 | return metavars;
|
|---|
| 681 | };
|
|---|
| 682 | };
|
|---|
| 683 |
|
|---|
| 684 | HelpFormatter.prototype._formatArgs = function (action, metavarDefault) {
|
|---|
| 685 | var result;
|
|---|
| 686 | var metavars;
|
|---|
| 687 |
|
|---|
| 688 | var buildMetavar = this._metavarFormatter(action, metavarDefault);
|
|---|
| 689 |
|
|---|
| 690 | switch (action.nargs) {
|
|---|
| 691 | /*eslint-disable no-undefined*/
|
|---|
| 692 | case undefined:
|
|---|
| 693 | case null:
|
|---|
| 694 | metavars = buildMetavar(1);
|
|---|
| 695 | result = '' + metavars[0];
|
|---|
| 696 | break;
|
|---|
| 697 | case c.OPTIONAL:
|
|---|
| 698 | metavars = buildMetavar(1);
|
|---|
| 699 | result = '[' + metavars[0] + ']';
|
|---|
| 700 | break;
|
|---|
| 701 | case c.ZERO_OR_MORE:
|
|---|
| 702 | metavars = buildMetavar(2);
|
|---|
| 703 | result = '[' + metavars[0] + ' [' + metavars[1] + ' ...]]';
|
|---|
| 704 | break;
|
|---|
| 705 | case c.ONE_OR_MORE:
|
|---|
| 706 | metavars = buildMetavar(2);
|
|---|
| 707 | result = '' + metavars[0] + ' [' + metavars[1] + ' ...]';
|
|---|
| 708 | break;
|
|---|
| 709 | case c.REMAINDER:
|
|---|
| 710 | result = '...';
|
|---|
| 711 | break;
|
|---|
| 712 | case c.PARSER:
|
|---|
| 713 | metavars = buildMetavar(1);
|
|---|
| 714 | result = metavars[0] + ' ...';
|
|---|
| 715 | break;
|
|---|
| 716 | default:
|
|---|
| 717 | metavars = buildMetavar(action.nargs);
|
|---|
| 718 | result = metavars.join(' ');
|
|---|
| 719 | }
|
|---|
| 720 | return result;
|
|---|
| 721 | };
|
|---|
| 722 |
|
|---|
| 723 | HelpFormatter.prototype._expandHelp = function (action) {
|
|---|
| 724 | var params = { prog: this._prog };
|
|---|
| 725 |
|
|---|
| 726 | Object.keys(action).forEach(function (actionProperty) {
|
|---|
| 727 | var actionValue = action[actionProperty];
|
|---|
| 728 |
|
|---|
| 729 | if (actionValue !== c.SUPPRESS) {
|
|---|
| 730 | params[actionProperty] = actionValue;
|
|---|
| 731 | }
|
|---|
| 732 | });
|
|---|
| 733 |
|
|---|
| 734 | if (params.choices) {
|
|---|
| 735 | if (typeof params.choices === 'string') {
|
|---|
| 736 | params.choices = params.choices.split('').join(', ');
|
|---|
| 737 | } else if (Array.isArray(params.choices)) {
|
|---|
| 738 | params.choices = params.choices.join(', ');
|
|---|
| 739 | } else {
|
|---|
| 740 | params.choices = Object.keys(params.choices).join(', ');
|
|---|
| 741 | }
|
|---|
| 742 | }
|
|---|
| 743 |
|
|---|
| 744 | return sprintf(this._getHelpString(action), params);
|
|---|
| 745 | };
|
|---|
| 746 |
|
|---|
| 747 | HelpFormatter.prototype._splitLines = function (text, width) {
|
|---|
| 748 | var lines = [];
|
|---|
| 749 | var delimiters = [ ' ', '.', ',', '!', '?' ];
|
|---|
| 750 | var re = new RegExp('[' + delimiters.join('') + '][^' + delimiters.join('') + ']*$');
|
|---|
| 751 |
|
|---|
| 752 | text = text.replace(/[\n\|\t]/g, ' ');
|
|---|
| 753 |
|
|---|
| 754 | text = text.trim();
|
|---|
| 755 | text = text.replace(this._whitespaceMatcher, ' ');
|
|---|
| 756 |
|
|---|
| 757 | // Wraps the single paragraph in text (a string) so every line
|
|---|
| 758 | // is at most width characters long.
|
|---|
| 759 | text.split(c.EOL).forEach(function (line) {
|
|---|
| 760 | if (width >= line.length) {
|
|---|
| 761 | lines.push(line);
|
|---|
| 762 | return;
|
|---|
| 763 | }
|
|---|
| 764 |
|
|---|
| 765 | var wrapStart = 0;
|
|---|
| 766 | var wrapEnd = width;
|
|---|
| 767 | var delimiterIndex = 0;
|
|---|
| 768 | while (wrapEnd <= line.length) {
|
|---|
| 769 | if (wrapEnd !== line.length && delimiters.indexOf(line[wrapEnd] < -1)) {
|
|---|
| 770 | delimiterIndex = (re.exec(line.substring(wrapStart, wrapEnd)) || {}).index;
|
|---|
| 771 | wrapEnd = wrapStart + delimiterIndex + 1;
|
|---|
| 772 | }
|
|---|
| 773 | lines.push(line.substring(wrapStart, wrapEnd));
|
|---|
| 774 | wrapStart = wrapEnd;
|
|---|
| 775 | wrapEnd += width;
|
|---|
| 776 | }
|
|---|
| 777 | if (wrapStart < line.length) {
|
|---|
| 778 | lines.push(line.substring(wrapStart, wrapEnd));
|
|---|
| 779 | }
|
|---|
| 780 | });
|
|---|
| 781 |
|
|---|
| 782 | return lines;
|
|---|
| 783 | };
|
|---|
| 784 |
|
|---|
| 785 | HelpFormatter.prototype._fillText = function (text, width, indent) {
|
|---|
| 786 | var lines = this._splitLines(text, width);
|
|---|
| 787 | lines = lines.map(function (line) {
|
|---|
| 788 | return indent + line;
|
|---|
| 789 | });
|
|---|
| 790 | return lines.join(c.EOL);
|
|---|
| 791 | };
|
|---|
| 792 |
|
|---|
| 793 | HelpFormatter.prototype._getHelpString = function (action) {
|
|---|
| 794 | return action.help;
|
|---|
| 795 | };
|
|---|