X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fbin%2Fargparser%2FArg.java;h=2f259786a0216cc55fcfaebbd60df788cd25e83b;hb=388622051f3d669942d9df63557c7a1401d7ff6d;hp=958569e04b9cf662f6a60e849f651de42220d88f;hpb=ef4d508e2a165ee0656ae6071d4a2bace94a516a;p=jalview.git diff --git a/src/jalview/bin/argparser/Arg.java b/src/jalview/bin/argparser/Arg.java index 958569e..2f25978 100644 --- a/src/jalview/bin/argparser/Arg.java +++ b/src/jalview/bin/argparser/Arg.java @@ -28,7 +28,11 @@ public enum Arg + ChannelProperties.getProperty("app_name"), Opt.UNARY, Opt.BOOTSTRAP), HEADLESS(Type.CONFIG, - "Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed.", + "Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed. " + + "Headless mode is assumed if an output file is to be generated, this can be overridden with --noheadless or --gui.", + Opt.BOOLEAN, Opt.BOOTSTRAP), + GUI(Type.CONFIG, + "Do not run Jalview in headless mode. This overrides the assumption of headless mode when an output file is to be generated.", Opt.UNARY, Opt.BOOTSTRAP), JABAWS(Type.CONFIG, "Set a different URL to connect to a JABAWS server.", Opt.STRING, Opt.BOOTSTRAP), @@ -40,9 +44,10 @@ public enum Arg QUESTIONNAIRE(Type.CONFIG, "Show (or don't show) the questionnaire if one is available.", true, Opt.BOOLEAN, Opt.BOOTSTRAP), - USAGESTATS(Type.CONFIG, - "Send (or don't send) initial launch usage stats.", true, - Opt.BOOLEAN, Opt.BOOTSTRAP), + NOUSAGESTATS(Type.CONFIG, "Don't send initial launch usage stats.", + Opt.UNARY, Opt.BOOTSTRAP), + NOSTARTUPFILE(Type.CONFIG, "Don't show the default startup file.", + Opt.UNARY, Opt.BOOTSTRAP), WEBSERVICEDISCOVERY(Type.CONFIG, "Attempt (or don't attempt) to connect to JABAWS web services.", true, Opt.BOOLEAN, Opt.BOOTSTRAP), @@ -61,6 +66,9 @@ public enum Arg INITSUBSTITUTIONS(Type.CONFIG, "Set ‑‑substitutions to be initially enabled (or initially disabled).", true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET), + P(Type.CONFIG, "Set a Jalview preference value for this session.", + Opt.PREFIXKEV, Opt.PRESERVECASE, Opt.STRING, Opt.BOOTSTRAP, + Opt.MULTI, Opt.NOACTION, Opt.SECRET), // keep this secret for now. // Opening an alignment OPEN(Type.OPENING, @@ -76,7 +84,7 @@ public enum Arg "Specifies the title for the open alignment window as string.", Opt.STRING, Opt.LINKED), COLOUR(Type.OPENING, "color", // being a bit soft on the Americans! - "Applies the colour scheme to the open alignment window. Valid values are:\n" + "Applies the colour scheme to the open alignment window. Valid values include:\n" + "clustal,\n" + "blosum62,\n" + "pc-identity,\n" + "zappo,\n" + "taylor,\n" + "gecos-flower,\n" + "gecos-blossom,\n" + "gecos-sunset,\n" @@ -85,7 +93,11 @@ public enum Arg + "turn-propensity,\n" + "buried-index,\n" + "nucleotide,\n" + "nucleotide-ambiguity,\n" + "purine-pyrimidine,\n" + "rna-helices,\n" - + "t-coffee-scores,\n" + "sequence-id.", + + "t-coffee-scores,\n" + "sequence-id.\n" + +"\n" + + "Names of user defined colourschemes will also work,\n" + +"and jalview colourscheme specifications like\n" + +"--colour=\"D,E=red; K,R,H=0022FF; C,c=yellow\"", Opt.STRING, Opt.LINKED, Opt.ALLOWALL), FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.", Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS), @@ -128,14 +140,10 @@ public enum Arg + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n" + "pymol.", Opt.STRING, Opt.LINKED, Opt.MULTI), - STRUCTUREIMAGE(Type.STRUCTURE, - "Export an image of a 3D structure opened in JMOL", Opt.STRING, - Opt.LINKED, Opt.MULTI), NOTEMPFAC(Type.STRUCTURE, "Do not show the temperature factor annotation for the preceding --structure.", Opt.UNARY, Opt.LINKED, Opt.ALLOWALL, Opt.SECRET), // keep this secret - // until it - // works! + // until it works! SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL), @@ -144,13 +152,13 @@ public enum Arg "Output an image of the open alignment window. Format is specified by the subval modifier, a following --type argument or guessed from the file extension. Valid formats/extensions are:\n" + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.", Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL, - Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY), + Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY), TYPE(Type.IMAGE, - "Set the image format for the preceding --image to name. Valid values for name are: svg,\n" - + "png,\n" + "eps,\n" + "html,\n" + "biojs.", + "Set the image format for the preceding --image. Valid values are:\n" + + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.", Opt.STRING, Opt.LINKED, Opt.ALLOWALL), TEXTRENDERER(Type.IMAGE, - "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values for name are:\n" + "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n" + "text,\n" + "lineart.", Opt.STRING, Opt.LINKED, Opt.ALLOWALL), SCALE(Type.IMAGE, @@ -162,6 +170,27 @@ public enum Arg HEIGHT(Type.IMAGE, "Sets a height for bitmap image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --width then the smallest scaling will be used (scale, width and height provide bounds for the image).", Opt.STRING, Opt.LINKED, Opt.ALLOWALL), + STRUCTUREIMAGE(Type.STRUCTUREIMAGE, + "Export an image of a 3D structure opened in JMOL", Opt.STRING, + Opt.LINKED, Opt.MULTI, Opt.OUTPUTFILE), + STRUCTUREIMAGETYPE(Type.STRUCTUREIMAGE, + "Set the structure image format for the preceding --structureimage. Valid values are:\n" + + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.", + Opt.STRING, Opt.LINKED, Opt.ALLOWALL), + STRUCTUREIMAGETEXTRENDERER(Type.STRUCTUREIMAGE, + "Sets whether text in a vector structure image format (SVG, EPS) should be rendered as text or vector line-art. Possible values are:\n" + + "text,\n" + "lineart.", + Opt.STRING, Opt.LINKED, Opt.ALLOWALL), + STRUCTUREIMAGESCALE(Type.STRUCTUREIMAGE, + "Sets a scaling for bitmap structure image format (PNG). Should be given as a floating point number. If used in conjunction with --structureimagewidth and --structureimageheight then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).", + Opt.STRING, Opt.LINKED, Opt.ALLOWALL), + STRUCTUREIMAGEWIDTH(Type.STRUCTUREIMAGE, + "Sets a width for bitmap structure image format (PNG) with the height maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --structureimagescale and --structureimageheight then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).", + Opt.STRING, Opt.LINKED, Opt.ALLOWALL), + STRUCTUREIMAGEHEIGHT(Type.STRUCTUREIMAGE, + "Sets a height for bitmap structure image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --structureimagescale and --structureimagewidth then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).", + Opt.STRING, Opt.LINKED, Opt.ALLOWALL), + OUTPUT(Type.OUTPUT, "Export the open alignment to file filename. The format name is specified by the subval modifier format=name, a following --format name argument or guessed from the file extension. Valid format names (and file extensions) are:\n" + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n" @@ -171,7 +200,7 @@ public enum Arg + "clustal (aln),\n" + "phylip (phy),\n" + "jalview (jvp, jar).", Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL, - Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY), + Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY), FORMAT(Type.OUTPUT, "Sets the format for the preceding --output file. Valid formats are:\n" + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n" @@ -197,8 +226,9 @@ public enum Arg "Move on to a new alignment window. This will ensure --append will start a new alignment window and other linked arguments will apply to the new alignment window.", Opt.UNARY, Opt.MULTI, Opt.NOACTION, Opt.INCREMENTDEFAULTCOUNTER), SUBSTITUTIONS(Type.FLOW, - "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are {basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n" - + "{dirname}, - the directory (folder) name of the currently --opened file (or first --appended file),\n" + "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are:\n" + + "{basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n" + + "{dirname} - the directory (folder) name of the currently --opened file (or first --appended file),\n" + "{argfilebasename} - the filename-without-extension of the current --argfile,\n" + "{argfiledirname} - the directory (folder) name of the current --argfile,\n" + "{n} - the value of the index counter (starting at 0).\n" @@ -223,6 +253,12 @@ public enum Arg QUIT(Type.FLOW, "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.", Opt.UNARY), + NOQUIT(Type.FLOW, + "Secret arg to not quit after --headless mode for tests", + Opt.UNARY, Opt.SECRET), + ALLSTRUCTURES(Type.FLOW, + "Apply the following 3D structure formatting arguments to all structures within the open alignment.", + Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION), // secret options TESTOUTPUT(Type.CONFIG, @@ -259,56 +295,146 @@ public enum Arg public static enum Opt { - BOOLEAN, // This Arg can be specified as --arg or --noarg to give true or - // false. A default can be given with setOptions(bool, Opt....). - // Use ArgParser.isSet(Arg) to see if this arg was not specified. - STRING, // This Arg can accept a value either through --arg=value or --arg - // value. - UNARY, // This Arg is a boolean value, true if present, false if not. Like - // BOOLEAN but without the --noarg option. - MULTI, // This Arg can be specified multiple times. Multiple values are - // stored in the ArgValuesMap (along with their positional index) for - // each linkedId. - LINKED, // This Arg can be linked to others through a --arg[linkedId] or - // --arg[linkedId]=value. If no linkedId is specified then the - // current default linkedId will be used. - NODUPLICATEVALUES, // This Arg can only have one value (per linkedId). The - // first value will be used and subsequent values ignored - // with a warning. - BOOTSTRAP, // This Arg value(s) can be determined at an earlier stage than - // non-BOOTSTRAP Args. Substitutions do not happen in BOOTSTRAP - // Args and they cannot be linked or contain SubVals. See - // jalview.bin.argparser.BootstrapArgs. - GLOB, // This Arg can expand wildcard filename "globs" (e.g. - // path/*/filename*). If the Arg value is given as --arg filename* - // then the shell will have expanded the glob already, but if - // specified as --arg=filename* then the Java glob expansion method - // will be used (see FileUtils.getFilenamesFromGlob()). Note that this - // might be different from the shell expansion rules. - NOACTION, // This Arg does not perform a data task, usually used to control - // flow in ArgParser.parse(args). - ALLOWSUBSTITUTIONS, // This Arg allows substitutions in its linkedId, - // SubVals and values. - PRIVATE, // This Arg is used internally, and cannot be specified by the - // user. - SECRET, // This Arg is used by development processes and although it can be - // set by the user, it is not displayed to the user. - ALLOWALL, // This Arg can use the '*' linkedId to apply to all known - // linkedIds - INCREMENTDEFAULTCOUNTER, // If an Arg has this option and the default - // linkedId is used, the defaultLinkedIdCounter is - // incremented *first*. - INPUT, // This Arg counts as an input for REQUIREINPUT - REQUIREINPUT, // This Arg can only be applied via --all if there is an - // input (i.e. --open or --append) - OUTPUT, // This Arg provides an output filename. With Opt.ALLOWALL *.ext is - // shorthand for --all --output={basename}.ext - STORED, // This Arg resets and creates a new set of "opened" linkedIds - HELP, // This Arg is a --help type arg - PRIMARY, // This Arg is the main Arg for its type - HASTYPE, // This Arg can have an Arg.Type assigned to it (and no value) - FIRST, // Move this arg to the first in usage statement (within type) - LAST, // Move this arg to the end in usage statement (within type) + /* + * A BOOLEAN Arg can be specified as --arg or --noarg to give true or false. + * A default can be given with setOptions(bool, Opt....). + * Use ArgParser.isSet(Arg) to see if this arg was not specified. + */ + BOOLEAN("can be negated with " + ArgParser.DOUBLEDASH + + ArgParser.NEGATESTRING + "..."), + + /* + * A STRING Arg will take a value either through --arg=value or --arg value. + */ + STRING("expects a value"), + /* + * A UNARY Arg is a boolean value, true if present, false if not. + * Like BOOLEAN but without the --noarg option. + */ + UNARY(null), + /* + * A MULTI Arg can be specified multiple times. + * Multiple values are stored in the ArgValuesMap (along with their positional index) for each linkedId. + */ + MULTI("can be specified multiple times"), + /* + * A Linked Arg can be linked to others through a --arg[linkedId] or --arg[linkedId]=value. + * If no linkedId is specified then the current default linkedId will be used. + */ + LINKED("is linked to an alignment"), + /* + * A NODUPLICATES Arg can only have one value (per linkedId). + * The first value will be used and subsequent values ignored with a warning. + */ + NODUPLICATEVALUES("cannot have the same value more than once"), + /* + * A BOOTSTRAP Arg value(s) can be determined at an earlier stage than non-BOOTSTRAP Args. + * Substitutions do not happen in BOOTSTRAP Args and they cannot be linked or contain SubVals. + * See jalview.bin.argparser.BootstrapArgs. + */ + BOOTSTRAP("a configuration argument"), + /* + * A GLOB Arg can expand wildcard filename "globs" (e.g. path/* /filename*). + * If the Arg value is given as --arg filename* then the shell will have expanded the glob already, + * but if specified as --arg=filename* then the Java glob expansion method will be used + * (see FileUtils.getFilenamesFromGlob()). + * Note that this might be different from the shell expansion rules. + */ + GLOB("can take multiple filenames with wildcards"), + /* + * A NOACTION Arg does not perform a data task, + * usually used to control flow in ArgParser.parse(args). + */ + NOACTION(null), + /* + * An ALLOWSUBSTITUTIONS Arg allows substitutions in its linkedId, + * SubVals and values. + */ + ALLOWSUBSTITUTIONS("values can use substitutions"), + /* + * A PRIVATE Arg is used internally, and cannot be specified by the user. + */ + PRIVATE(null), + /* + * A SECRET Arg is used by development processes and although it can be set by the user, + * it is not displayed to the user. + */ + SECRET(null), + /* + * An ALLOWALL Arg can use the '*' linkedId to apply to all known linkedIds + */ + ALLOWALL("can be used with " + ArgParser.DOUBLEDASH + "all"), + /* + * If an Arg has the INCREMENTDEFAULTCOUNTER option and the default linkedId is used, + * the defaultLinkedIdCounter is incremented *first*. + */ + INCREMENTDEFAULTCOUNTER("starts a new default alignment"), + /* + * An INPUT Arg counts as an input for REQUIREINPUT + */ + INPUT(null), + /* + * A REQUIREINPUT Arg can only be applied via --all if there is an input + * (i.e. --open or --append) + */ + REQUIREINPUT(null), + /* + * An OUTPUTFILE Arg provides an output filename. With Opt.ALLOWALL *.ext is shorthand for + * --all --output={basename}.ext + */ + OUTPUTFILE("output file --headless will be assumed unless --gui used"), + /* + * A STORED Arg resets and creates a new set of "opened" linkedIds + */ + STORED(null), + /* + * A HELP Arg is a --help type arg + */ + HELP("provides a help statement"), + /* + * A PRIMARY Arg is the main Arg for its type + */ + PRIMARY("is a primary argument for its type"), + /* + * A HASTYPE Arg can have an Arg.Type assigned to its ArgValue + */ + HASTYPE(null), + /* + * A FIRST arg gets moved to appear first in the usage statement (within type) + */ + FIRST(null), + /* + * A LAST arg gets moved to appear last in the usage statement (within type) + */ + LAST(null), + /* + * After other args are checked, the following args can prefix a KEY=VALUE argument + */ + PREFIXKEV("prefixes key=value"), + /* + * do not lowercase the name when getting the arg name or arg string + */ + PRESERVECASE(null), + // + ; + + private String description; + + private Opt() + { + description = null; + } + + private Opt(String description) + { + this.description = description; + } + + public String description() + { + return description; + } + } public static enum Type @@ -322,6 +448,7 @@ public enum Arg PROCESS("arguments used to process an alignment once opened"), OUTPUT("arguments used to save data from a processed alignment"), IMAGE("arguments used to export an image of an alignment"), + STRUCTUREIMAGE("arguments used to export an image of an structure"), FLOW("arguments that control processing of the other arguments"), // ALL("all arguments"), // mostly just a place-holder for --help-all NONE, // mostly a place-holder for --help @@ -375,15 +502,15 @@ public enum Arg private Arg(Type type, String alternativeName, String description, boolean defaultBoolean, Opt... options) { + this.type = type; + this.description = description; + this.defaultBoolValue = defaultBoolean; + this.setOptions(options); this.argNames = alternativeName != null ? new String[] { this.getName(), alternativeName } : new String[] { this.getName() }; - this.type = type; - this.description = description; - this.defaultBoolValue = defaultBoolean; - this.setOptions(options); } public String argString() @@ -433,7 +560,9 @@ public enum Arg public String getName() { - return this.name().toLowerCase(Locale.ROOT).replace('_', '-'); + String name = hasOption(Opt.PRESERVECASE) ? this.name() + : this.name().toLowerCase(Locale.ROOT); + return name.replace('_', '-'); } @Override @@ -464,6 +593,11 @@ public enum Arg return true; } + protected Opt[] getOptions() + { + return argOptions; + } + protected void setOptions(Opt... options) { this.argOptions = options; @@ -521,9 +655,9 @@ public enum Arg { StringBuilder sb = new StringBuilder(); - sb.append("usage: jalview [" + Arg.HEADLESS.argString() + "] [" + sb.append("usage: jalview [" + Arg.HEADLESS.argString() + "] [[" + Arg.OPEN.argString() + "/" + Arg.APPEND.argString() - + " file(s)] [args]"); + + "] file(s)] [args]"); sb.append(System.lineSeparator()); sb.append(System.lineSeparator()); @@ -566,6 +700,7 @@ public enum Arg } Iterator argsI = args.iterator(); + Type typeSection = null; while (argsI.hasNext()) { Arg a = argsI.next(); @@ -576,79 +711,98 @@ public enum Arg continue; } - appendArgUsage(sb, a, maxArgLength); + if (a.getType() != typeSection) + { + typeSection = a.getType(); + String typeDescription = a.getType().description(); + if (typeDescription != null && typeDescription.length() > 0) + { + // typeDescription = typeDescription.substring(0, + // 1).toUpperCase(Locale.ROOT) + typeDescription.substring(1); + typeDescription = typeDescription.toUpperCase(Locale.ROOT); + sb.append(typeDescription); + sb.append(System.lineSeparator()); + sb.append(System.lineSeparator()); + } + } + + appendArgUsage(sb, a, maxArgLength, Platform.consoleWidth()); if (argsI.hasNext()) + { sb.append(System.lineSeparator()); + } } } return sb.toString(); } private static void appendArgUsage(StringBuilder sb, Arg a, - int maxArgLength) + int maxArgLength, int maxWidth) { boolean first = appendArgAndDescription(sb, null, null, a, maxArgLength); List options = new ArrayList<>(); - if (a.hasOption(Opt.BOOLEAN)) - { - options.add("default " + (a.getDefaultBoolValue() ? a.argString() - : a.negateArgString())); - } - - if (a.hasOption(Opt.MULTI)) - { - options.add("multiple"); - } - - if (a.hasOption(Opt.LINKED)) - { - options.add("can be linked"); - } - - if (a.hasOption(Opt.GLOB)) - { - options.add("allows file globs"); - } - - if (a.hasOption(Opt.ALLOWSUBSTITUTIONS)) - { - options.add("allows substitutions"); - } - - if (a.hasOption(Opt.ALLOWALL)) - { - options.add("can be applied to all linked arguments"); - } - - if (a.hasOption(Opt.PRIVATE)) - { - options.add("for internal use only"); - } - - if (a.hasOption(Opt.SECRET)) + for (Opt o : EnumSet.allOf(Opt.class)) { - options.add("for development use only"); + if (a.hasOption(o) && o.description() != null) + { + options.add(o.description()); + } } + final String optDisplaySeparator = "; "; if (options.size() > 0) { + int linelength = 0; + String spacing = String.format("%-" + + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s", + ""); if (first) { sb.append(ARGDESCRIPTIONSEPARATOR); + linelength += maxArgLength + ARGDESCRIPTIONSEPARATOR.length(); } else { - sb.append(String.format("%-" - + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s", - "")); + sb.append(spacing); + linelength += spacing.length(); + } + if (options.size() > 0) + { + boolean optFirst = true; + Iterator optionsI = options.listIterator(); + while (optionsI.hasNext()) + { + String desc = optionsI.next(); + if (optFirst) + { + sb.append("("); + linelength += 1; + } + int descLength = desc.length() + + (optionsI.hasNext() ? optDisplaySeparator.length() : 0); + if (linelength + descLength > maxWidth) + { + sb.append(System.lineSeparator()); + linelength = 0; + sb.append(spacing); + linelength += spacing.length(); + } + // sb.append(linelength + "+" + desc.length() + " "); + sb.append(desc); + linelength += desc.length(); + if (optionsI.hasNext()) + { + sb.append(optDisplaySeparator); + linelength += optDisplaySeparator.length(); + } + optFirst = false; + } + sb.append(')'); + sb.append(System.lineSeparator()); } - sb.append("("); - sb.append(String.join("; ", options)); - sb.append(')'); - sb.append(System.lineSeparator()); } } @@ -658,7 +812,16 @@ public enum Arg argSb.append( a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString()); if (a.hasOption(Opt.STRING)) - argSb.append("=value"); + { + if (a.hasOption(Opt.PREFIXKEV)) + { + argSb.append("key=value"); + } + else + { + argSb.append("=value"); + } + } return argSb.toString(); } @@ -703,15 +866,8 @@ public enum Arg while (line.length() > descLength) { int splitIndex = line.lastIndexOf(" ", descLength); - if (splitIndex > descLength) - { - break; - } - else - { - splitDescLinesList.add(line.substring(0, splitIndex)); - line = line.substring(splitIndex + 1); - } + splitDescLinesList.add(line.substring(0, splitIndex)); + line = line.substring(splitIndex + 1); } splitDescLinesList.add(line); } @@ -723,11 +879,15 @@ public enum Arg while (splitDescLines.hasNext()) { if (first) + { sb.append(ARGDESCRIPTIONSEPARATOR); + } else + { sb.append(String.format("%-" + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s", "")); + } sb.append(splitDescLines.next()); sb.append(System.lineSeparator()); first = false;