usage method

String usage()

Return a string telling the user how to use your application from the command line.

Implementation

String usage() {
  List<String?> lines = [];

  if (isNotNull(_app?.description)) {
    lines.add(_app!.description);
    lines.add('');
  }

  List<String> helpKeys = [];
  List<Group?> helpGroups = [];
  List<List<String>> helpDescriptions = [];

  final arguments =
      _mirrorParameterPairs.where((v) => isFalse(v.argument is Command));
  final commands = _mirrorParameterPairs.where((v) => v.argument is Command);

  if (arguments.isNotEmpty) {
    for (var mpp in arguments) {
      List<String?> keys = [];

      keys.addAll(mpp.keys(_app).map((v) => v!.startsWith('-') ? v : '--$v'));
      helpKeys.add(keys.join(', '));
      helpGroups.add(mpp.group);

      List<String> helpLines = [mpp.argument.help ?? 'no help available'];

      if (mpp.argument.isRequired ?? false) {
        helpLines.add('[REQUIRED]');
      }

      String? envVar = mpp.argument.environmentVariable;
      if (isNotBlank(envVar)) {
        helpLines.add('[Environment Variable: \$$envVar]');
      }

      helpLines.addAll(mpp.argument.additionalHelpLines);
      helpDescriptions.add(helpLines);
    }
  }

  const lineIndent = 2;
  const lineWidth = 80 - lineIndent;
  final linePrefix = ' ' * lineIndent;
  const optionColumnWidth = 25;
  const helpLineWidth = lineWidth - optionColumnWidth;

  {
    void trailingHelp(Group? group) {
      if (isNotNull(group?.afterHelp)) {
        lines.add('');
        lines.add(
          indent(
            hardWrap(group!.afterHelp!, lineWidth - lineIndent),
            lineIndent,
          ),
        );
      }
    }

    Group? currentGroup;

    for (var i = 0; i < helpKeys.length; i++) {
      final thisGroup = helpGroups[i];

      if (thisGroup != currentGroup) {
        trailingHelp(currentGroup);

        if (isNotNull(currentGroup)) {
          lines.add('');
        }

        lines.add(thisGroup!.name);

        if (isNotNull(thisGroup.beforeHelp)) {
          lines.add(
            indent(
              hardWrap(thisGroup.beforeHelp!, lineWidth - lineIndent),
              lineIndent,
            ),
          );
          lines.add('');
        }
      }

      var keyDisplay = linePrefix + helpKeys[i];

      var thisHelpDescriptions = helpDescriptions[i].join('\n');
      thisHelpDescriptions = hardWrap(thisHelpDescriptions, helpLineWidth);
      thisHelpDescriptions = indent(thisHelpDescriptions, optionColumnWidth);

      if (keyDisplay.length <= optionColumnWidth - 1) {
        thisHelpDescriptions = thisHelpDescriptions.replaceRange(
          0,
          keyDisplay.length,
          keyDisplay,
        );
      } else {
        lines.add(keyDisplay);
      }

      lines.add(thisHelpDescriptions);

      currentGroup = helpGroups[i] ?? currentGroup;
    }

    trailingHelp(currentGroup);
  }

  if (commands.isNotEmpty) {
    lines.add('');
    lines.add('COMMANDS');
    List<MirrorParameterPair>.from(commands)
        .sortedBy((mpp) => mpp.displayKey!)
        .forEach((mpp) {
      final String? help = _argumentHelp(mpp);
      final commandDisplay = '$linePrefix${mpp.displayKey!}';
      var commandHelp = hardWrap(
        help ?? '',
        helpLineWidth,
      );
      commandHelp = indent(commandHelp, optionColumnWidth);
      if (commandDisplay.length <= optionColumnWidth - 1) {
        commandHelp = commandHelp.replaceRange(
          0,
          commandDisplay.length,
          commandDisplay,
        );
      } else {
        lines.add(commandDisplay);
      }
      lines.add(commandHelp);
    });
  }

  if (isNotNull(_app?.extendedHelp)) {
    for (final eh in _app!.extendedHelp!) {
      if (isNull(eh.help)) {
        throw StateError('Help.help must be set');
      }

      lines.add('');

      if (isNotNull(eh.header)) {
        lines.add(hardWrap(eh.header!, lineWidth));
        lines.add(
          indent(hardWrap(eh.help!, lineWidth - lineIndent), lineIndent),
        );
      } else {
        lines.add(hardWrap(eh.help!, lineWidth));
      }
    }
  }

  return lines.join('\n');
}