1 package jalview.bin.argparser;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collections;
6 import java.util.Comparator;
7 import java.util.EnumSet;
8 import java.util.Iterator;
10 import java.util.Locale;
11 import java.util.stream.Collectors;
13 import jalview.bin.argparser.Arg.Opt;
14 import jalview.util.ChannelProperties;
15 import jalview.util.Platform;
20 // Initialising arguments (BOOTSTRAP)
21 HELP(Type.HELP, "h", "Display basic help", Opt.UNARY, Opt.BOOTSTRAP,
22 Opt.HASTYPE, Opt.MULTIVALUE),
24 * Other --help-type Args will be added by the static block.
26 VERSION(Type.CONFIG, "v",
27 "Display the version of "
28 + ChannelProperties.getProperty("app_name"),
29 Opt.UNARY, Opt.BOOTSTRAP),
31 "Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed. "
32 + "Headless mode is assumed if an output file is to be generated, this can be overridden with --gui.",
33 Opt.UNARY, Opt.BOOTSTRAP),
35 "Do not run Jalview in headless mode. This overrides the assumption of headless mode when an output file is to be generated.",
36 Opt.UNARY, Opt.BOOTSTRAP),
37 JABAWS(Type.CONFIG, "Set a different URL to connect to a JABAWS server.",
38 Opt.STRING, Opt.BOOTSTRAP),
39 NEWS(Type.CONFIG, "Show (or don't show) the news feed.", true,
40 Opt.BOOLEAN, Opt.BOOTSTRAP),
42 "Show (or don't show) the About Jalview splash screen.", true,
43 Opt.BOOLEAN, Opt.BOOTSTRAP),
44 QUESTIONNAIRE(Type.CONFIG,
45 "Show (or don't show) the questionnaire if one is available.",
46 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
47 NOUSAGESTATS(Type.CONFIG, "Don't send initial launch usage stats.",
48 Opt.UNARY, Opt.BOOTSTRAP),
49 NOSTARTUPFILE(Type.CONFIG, "Don't show the default startup file.",
50 Opt.UNARY, Opt.BOOTSTRAP),
51 WEBSERVICEDISCOVERY(Type.CONFIG,
52 "Attempt (or don't attempt) to connect to JABAWS web services.",
53 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
55 "Use a file as the preferences file instead of the usual ~/"
56 + ChannelProperties.getProperty("preferences.filename")
58 Opt.STRING, Opt.BOOTSTRAP),
59 DEBUG(Type.CONFIG, "d", "Start Jalview in debug log level.", Opt.BOOLEAN,
61 TRACE(Type.CONFIG, "Start Jalview in trace log level.", Opt.BOOLEAN,
62 Opt.BOOTSTRAP, Opt.SECRET),
63 QUIET(Type.CONFIG, "q",
64 "Stop all output to STDOUT (after the Java Virtual Machine has started). Use ‑‑quiet a second time to stop all output to STDERR.",
65 Opt.UNARY, Opt.MULTIVALUE, Opt.BOOTSTRAP),
66 INITSUBSTITUTIONS(Type.CONFIG,
67 "Set ‑‑substitutions to be initially enabled (or initially disabled).",
68 true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
69 P(Type.CONFIG, "Set a Jalview preference value for this session.",
70 Opt.PREFIXKEV, Opt.PRESERVECASE, Opt.STRING, Opt.BOOTSTRAP,
71 Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET), // keep this secret for now.
73 // Opening an alignment
75 "Opens one or more alignment files or URLs in new alignment windows.",
76 Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER, Opt.MULTIVALUE,
77 Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.STORED,
80 "Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
81 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.GLOB,
82 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.PRIMARY),
84 "Specifies the title for the open alignment window as string.",
85 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
86 COLOUR(Type.OPENING, "color", // being a bit soft on the Americans!
87 "Applies the colour scheme to the open alignment window. Valid values include:\n"
88 + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
89 + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
90 + "gecos-blossom,\n" + "gecos-sunset,\n"
91 + "gecos-ocean,\n" + "hydrophobic,\n"
92 + "helix-propensity,\n" + "strand-propensity,\n"
93 + "turn-propensity,\n" + "buried-index,\n"
94 + "nucleotide,\n" + "nucleotide-ambiguity,\n"
95 + "purine-pyrimidine,\n" + "rna-helices,\n"
96 + "t-coffee-scores,\n" + "sequence-id.\n" + "\n"
97 + "Names of user defined colourschemes will also work,\n"
98 + "and jalview colourscheme specifications like\n"
99 + "--colour=\"D,E=red; K,R,H=0022FF; C,c=yellow\"",
100 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
101 FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
102 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
104 TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
105 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
107 SORTBYTREE(Type.OPENING,
108 "Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
109 true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWMULTIID),
110 ANNOTATIONS(Type.OPENING,
111 "Add an annotations file or URL to the open alignment.",
112 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
114 SHOWANNOTATIONS(Type.OPENING,
115 "Enforces showing (or not showing) alignment annotations.",
116 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
118 "Enforces wrapped (or not wrapped) alignment formatting.",
119 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
120 NOSTRUCTURE(Type.OPENING,
121 "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
122 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
124 // Adding a 3D structure
125 STRUCTURE(Type.STRUCTURE,
126 "Load a structure file or URL associated with a sequence in the open alignment.\n"
127 + "The sequence to be associated with can be specified with a following --seqid argument, or the subval modifier seqid=ID can be used. A subval INDEX can also be used to specify the INDEX-th sequence in the open alignment.",
128 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
129 Opt.PRIMARY, Opt.ALLOWMULTIID),
130 SEQID(Type.STRUCTURE,
131 "Specify the sequence name for the preceding --structure to be associated with.",
132 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
134 PAEMATRIX(Type.STRUCTURE,
135 "Add a PAE json matrix file to the preceding --structure.",
136 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
138 TEMPFAC(Type.STRUCTURE,
139 "Set the type of temperature factor. Possible values are:\n"
140 + "default,\n" + "plddt.",
141 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
142 STRUCTUREVIEWER(Type.STRUCTURE,
143 "Set the structure viewer to use to open the 3D structure file specified in previous --structure to name. Possible values of name are:\n"
144 + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
146 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
147 NOTEMPFAC(Type.STRUCTURE,
148 "Do not show the temperature factor annotation for the preceding --structure.",
149 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.SECRET), // keep this secret
151 SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
156 "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"
157 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
158 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWMULTIID,
159 Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
161 "Set the image format for the preceding --image. Valid values are:\n"
162 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
163 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
164 TEXTRENDERER(Type.IMAGE,
165 "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n"
166 + "text,\n" + "lineart.",
167 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
169 "Sets a scaling for bitmap image format (PNG). Should be given as a floating point number. If used in conjunction with --width and --height then the smallest scaling will be used (scale, width and height provide bounds for the image).",
170 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
172 "Sets a width for bitmap image format (PNG) with the height maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --height then the smallest scaling will be used (scale, width and height provide bounds for the image).",
173 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
175 "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).",
176 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
177 STRUCTUREIMAGE(Type.STRUCTUREIMAGE,
178 "Export an image of a 3D structure opened in JMOL", Opt.STRING,
179 Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID),
180 STRUCTUREIMAGETYPE(Type.STRUCTUREIMAGE,
181 "Set the structure image format for the preceding --structureimage. Valid values are:\n"
182 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
183 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
184 STRUCTUREIMAGETEXTRENDERER(Type.STRUCTUREIMAGE,
185 "Sets whether text in a vector structure image format (SVG, EPS) should be rendered as text or vector line-art. Possible values are:\n"
186 + "text,\n" + "lineart.",
187 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
188 STRUCTUREIMAGESCALE(Type.STRUCTUREIMAGE,
189 "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).",
190 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
191 STRUCTUREIMAGEWIDTH(Type.STRUCTUREIMAGE,
192 "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).",
193 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
194 STRUCTUREIMAGEHEIGHT(Type.STRUCTUREIMAGE,
195 "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).",
196 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
199 "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"
200 + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
201 + "stockholm (sto, stk),\n" + "pir (pir),\n"
202 + "blc (blc),\n" + "amsa (amsa),\n" + "json (json),\n"
203 + "pileup (pileup),\n" + "msf (msf),\n"
204 + "clustal (aln),\n" + "phylip (phy),\n"
205 + "jalview (jvp, jar).",
206 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWMULTIID,
207 Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.STDOUT, Opt.PRIMARY),
209 "Sets the format for the preceding --output file. Valid formats are:\n"
210 + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n"
211 + "blc,\n" + "amsa,\n" + "json,\n" + "pileup,\n"
212 + "msf,\n" + "clustal,\n" + "phylip,\n" + "jalview.",
213 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
215 "Process a groovy script in the file for the open alignment.",
216 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
219 "Enable (or disable) writing backup files when saving an ‑‑output file. This applies to the current open alignment. To apply to all ‑‑output and ‑‑image files, use after ‑‑all.",
220 true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
221 OVERWRITE(Type.OUTPUT,
222 "Enable (or disable) overwriting of output files without backups enabled. This applies to the current open alignment. To apply to all ‑‑output and ‑‑image files, use after ‑‑all.",
223 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
225 "Close the current open alignment window. This occurs after other output arguments. This applies to the current open alignment. To apply to all ‑‑output and ‑‑image files, use after ‑‑all.",
226 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
228 // controlling flow of arguments
230 "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.",
231 Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION, Opt.INCREMENTDEFAULTCOUNTER),
232 SUBSTITUTIONS(Type.FLOW,
233 "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are:\n"
234 + "{basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
235 + "{dirname} - the directory (folder) name of the currently --opened file (or first --appended file),\n"
236 + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
237 + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
238 + "{n} - the value of the index counter (starting at 0).\n"
239 + "{++n} - increase and substitute the value of the index counter,\n"
240 + "{} - the value of the current alignment window default index.",
241 true, Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
243 "Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
244 + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
245 + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
246 Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.GLOB,
247 Opt.ALLOWSUBSTITUTIONS),
248 NPP(Type.FLOW, "n++",
249 "Increase the index counter used in argument value substitutions.",
250 Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION),
252 "Apply the following output arguments to all sets of linked arguments.",
253 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
255 "Apply the following output arguments to all of the last --open'ed set of linked arguments.",
256 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
258 "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
261 "Secret arg to not quit after --headless mode for tests",
262 Opt.UNARY, Opt.SECRET),
263 ALLSTRUCTURES(Type.FLOW,
264 "Apply the following 3D structure formatting arguments to all structures within the open alignment.",
265 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
268 TESTOUTPUT(Type.CONFIG,
269 "Allow specific stdout information. For testing purposes only.",
270 Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
271 SETPROP(Type.CONFIG, "Set an individual Java System property.",
272 Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.SECRET), // not in use yet
274 "This argument does nothing on its own, but can be used with linkedIds.",
275 Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET),
277 // private options (inserted during arg processing)
278 SETARGFILE(Type.FLOW,
279 "Sets the current value of the argfilename. Inserted before argfilecontents.",
280 Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTIVALUE, Opt.PRIVATE,
282 UNSETARGFILE(Type.FLOW,
283 "Unsets the current value of the argfilename. Inserted after argfile contents.",
284 Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.PRIVATE, Opt.NOACTION),
286 // these last two have no purpose in the normal Jalview application but are
287 // used by jalview.bin.Launcher to set memory settings. They are not used by
288 // argparser but are here for Usage statement reasons.
289 JVMMEMPC(Type.CONFIG,
290 "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
291 + "The equals sign (\"=\") separator must be used with no spaces.",
292 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
293 JVMMEMMAX(Type.CONFIG,
294 "Limit maximum heap size (memory) to MAXMEMORY. MAXMEMORY can be specified in bytes, kilobytes(k), megabytes(m), gigabytes(g) or if you're lucky enough, terabytes(t). This defaults to 32g if total physical memory can be detected, or to 8g if total physical memory cannot be detected.\n"
295 + "The equals sign (\"=\") separator must be used with no spaces.",
296 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
300 public static enum Opt
303 * A BOOLEAN Arg can be specified as --arg or --noarg to give true or false.
304 * A default can be given with setOptions(bool, Opt....).
305 * Use ArgParser.isSet(Arg) to see if this arg was not specified.
307 BOOLEAN("can be negated with " + ArgParser.DOUBLEDASH
308 + ArgParser.NEGATESTRING + "..."),
311 * A STRING Arg will take a value either through --arg=value or --arg value.
313 STRING("expects a value"),
315 * A UNARY Arg is a boolean value, true if present, false if not.
316 * Like BOOLEAN but without the --noarg option.
320 * A MULTI Arg can be specified multiple times.
321 * Multiple values are stored in the ArgValuesMap (along with their positional index) for each linkedId.
323 MULTIVALUE("can be specified multiple times"),
325 * A Linked Arg can be linked to others through a --arg[linkedId] or --arg[linkedId]=value.
326 * If no linkedId is specified then the current default linkedId will be used.
328 LINKED("is linked to an alignment"),
330 * A NODUPLICATES Arg can only have one value (per linkedId).
331 * The first value will be used and subsequent values ignored with a warning.
333 NODUPLICATEVALUES("cannot have the same value more than once"),
335 * A BOOTSTRAP Arg value(s) can be determined at an earlier stage than non-BOOTSTRAP Args.
336 * Substitutions do not happen in BOOTSTRAP Args and they cannot be linked or contain SubVals.
337 * See jalview.bin.argparser.BootstrapArgs.
339 BOOTSTRAP("a configuration argument"),
341 * A GLOB Arg can expand wildcard filename "globs" (e.g. path/* /filename*).
342 * If the Arg value is given as --arg filename* then the shell will have expanded the glob already,
343 * but if specified as --arg=filename* then the Java glob expansion method will be used
344 * (see FileUtils.getFilenamesFromGlob()).
345 * Note that this might be different from the shell expansion rules.
347 GLOB("can take multiple filenames with wildcards"),
349 * A NOACTION Arg does not perform a data task,
350 * usually used to control flow in ArgParser.parse(args).
354 * An ALLOWSUBSTITUTIONS Arg allows substitutions in its linkedId,
355 * SubVals and values.
357 ALLOWSUBSTITUTIONS("values can use substitutions"),
359 * A PRIVATE Arg is used internally, and cannot be specified by the user.
363 * A SECRET Arg is used by development processes and although it can be set by the user,
364 * it is not displayed to the user.
368 * An ALLOWALL Arg can use the '*' linkedId to apply to all known linkedIds
370 ALLOWMULTIID("can be used with " + ArgParser.DOUBLEDASH + "all"),
372 * If an Arg has the INCREMENTDEFAULTCOUNTER option and the default linkedId is used,
373 * the defaultLinkedIdCounter is incremented *first*.
375 INCREMENTDEFAULTCOUNTER("starts a new default alignment"),
377 * An INPUT Arg counts as an input for REQUIREINPUT
381 * A REQUIREINPUT Arg can only be applied via --all if there is an input
382 * (i.e. --open or --append)
386 * An OUTPUTFILE Arg provides an output filename. With Opt.ALLOWALL *.ext is shorthand for
387 * --all --output={basename}.ext
389 OUTPUTFILE("output file --headless will be assumed unless --gui used"),
391 * A STDOUT Arg can take an output filename that can be '-' to mean print to STDOUT.
393 STDOUT("allows the output filename '" + ArgParser.STDOUTFILENAME
394 + "' to mean output to STDOUT"),
396 * A STORED Arg resets and creates a new set of "opened" linkedIds
400 * A HELP Arg is a --help type arg
402 HELP("provides a help statement"),
404 * A PRIMARY Arg is the main Arg for its type
406 PRIMARY("is a primary argument for its type"),
408 * A HASTYPE Arg can have an Arg.Type assigned to its ArgValue
412 * A FIRST arg gets moved to appear first in the usage statement (within type)
416 * A LAST arg gets moved to appear last in the usage statement (within type)
420 * After other args are checked, the following args can prefix a KEY=VALUE argument
422 PREFIXKEV("prefixes key=value"),
424 * do not lowercase the name when getting the arg name or arg string
430 private String description;
437 private Opt(String description)
439 this.description = description;
442 public String description()
449 public static enum Type
451 // Type restricts argument to certain usage output
453 CONFIG("arguments used to configure "
454 + ChannelProperties.getProperty("app_name") + " from startup"),
455 OPENING("arguments used to open and format alignments"),
456 STRUCTURE("arguments used to add and format 3D structure data"),
457 PROCESS("arguments used to process an alignment once opened"),
458 OUTPUT("arguments used to save data from a processed alignment"),
459 IMAGE("arguments used to export an image of an alignment"),
460 STRUCTUREIMAGE("arguments used to export an image of an structure"),
461 FLOW("arguments that control processing of the other arguments"), //
462 ALL("all arguments"), // mostly just a place-holder for --help-all
463 NONE, // mostly a place-holder for --help
466 private String description;
473 private Type(String description)
475 this.description = description;
478 public String description()
484 private final String[] argNames;
486 private Opt[] argOptions;
488 private boolean defaultBoolValue;
490 private String description;
494 private Arg(Type type, String description, Opt... options)
496 this(type, null, description, false, options);
499 private Arg(Type type, String description, boolean defaultBoolean,
502 this(type, null, description, defaultBoolean, options);
505 private Arg(Type type, String alternativeName, String description,
508 this(type, alternativeName, description, false, options);
511 private Arg(Type type, String alternativeName, String description,
512 boolean defaultBoolean, Opt... options)
515 this.description = description;
516 this.defaultBoolValue = defaultBoolean;
517 this.setOptions(options);
518 this.argNames = alternativeName != null
520 { this.getName(), alternativeName }
525 public String argString()
527 return argString(false);
530 public String negateArgString()
532 return argString(true);
535 private String argString(boolean negate)
537 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
538 if (negate && hasOption(Opt.BOOLEAN))
539 sb.append(ArgParser.NEGATESTRING);
540 sb.append(getName());
541 return sb.toString();
544 public String toLongString()
546 StringBuilder sb = new StringBuilder();
547 sb.append(this.getClass().getName()).append('.').append(this.name());
549 if (getNames().length > 0)
551 sb.append(String.join("\", \"", getNames()));
552 if (getNames().length > 0)
555 sb.append("\nType: " + type.name());
556 sb.append("\nOpt: ");
557 // map List<Opt> to List<String> for the String.join
558 List<String> optList = Arrays.asList(argOptions).stream()
559 .map(opt -> opt.name()).collect(Collectors.toList());
560 sb.append(String.join(", ", optList));
562 return sb.toString();
565 public String[] getNames()
570 public String getName()
572 String name = hasOption(Opt.PRESERVECASE) ? this.name()
573 : this.name().toLowerCase(Locale.ROOT);
574 return name.replace('_', '-');
578 public final String toString()
583 public boolean hasOption(Opt o)
585 if (argOptions == null)
587 for (Opt option : argOptions)
595 public boolean hasAllOptions(Opt... opts)
599 if (!this.hasOption(o))
605 protected Opt[] getOptions()
610 protected void setOptions(Opt... options)
612 this.argOptions = options;
615 protected boolean getDefaultBoolValue()
617 return defaultBoolValue;
620 public Type getType()
625 protected String getDescription()
630 public static String booleanArgString(Arg a)
632 StringBuilder sb = new StringBuilder(a.argString());
633 if (a.hasOption(Opt.BOOLEAN))
636 sb.append(a.negateArgString());
638 return sb.toString();
641 public static final String usage()
646 public static final void appendUsageGeneral(StringBuilder sb,
649 for (Type t : EnumSet.allOf(Type.class))
651 if (t.description() != null)
653 StringBuilder argSb = new StringBuilder();
654 argSb.append(Arg.HELP.argString()).append(ArgParser.SINGLEDASH)
655 .append(t.name().toLowerCase(Locale.ROOT));
656 appendArgAndDescription(sb, argSb.toString(),
657 "Help for " + t.description(), null, maxArgLength);
658 sb.append(System.lineSeparator());
663 public static final String usage(List<Type> types)
665 StringBuilder sb = new StringBuilder();
667 sb.append("usage: jalview [" + Arg.HEADLESS.argString() + "] [["
668 + Arg.OPEN.argString() + "/" + Arg.APPEND.argString()
669 + "] file(s)] [args]");
670 sb.append(System.lineSeparator());
671 sb.append(System.lineSeparator());
673 if (types == null || types.contains(null))
675 // always show --help
676 appendArgAndDescription(sb, null, "Display this basic help", Arg.HELP,
678 sb.append(System.lineSeparator());
680 appendUsageGeneral(sb, DESCRIPTIONINDENT);
684 List<Arg> args = argsSortedForDisplay(types);
687 * just use a set maxArgLength of DESCRIPTIONINDENT
689 int maxArgLength = 0;
692 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
695 String argS = argDisplayString(a);
696 if (argS.length() > maxArgLength)
697 maxArgLength = argS.length();
700 int maxArgLength = DESCRIPTIONINDENT;
702 // always show --help
703 appendArgAndDescription(sb, null, null, Arg.HELP, maxArgLength);
704 sb.append(System.lineSeparator());
706 if ((args.contains(Arg.HELP) && types.contains(Type.ALL)))
708 appendUsageGeneral(sb, maxArgLength);
711 Iterator<Arg> argsI = args.iterator();
712 Type typeSection = null;
713 while (argsI.hasNext())
715 Arg a = argsI.next();
717 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET)
723 if (a.getType() != typeSection)
725 typeSection = a.getType();
726 String typeDescription = a.getType().description();
727 if (typeDescription != null && typeDescription.length() > 0)
729 // typeDescription = typeDescription.substring(0,
730 // 1).toUpperCase(Locale.ROOT) + typeDescription.substring(1);
731 typeDescription = typeDescription.toUpperCase(Locale.ROOT);
732 sb.append(typeDescription);
733 sb.append(System.lineSeparator());
734 sb.append(System.lineSeparator());
738 appendArgUsage(sb, a, maxArgLength, Platform.consoleWidth());
742 sb.append(System.lineSeparator());
746 return sb.toString();
749 private static void appendArgUsage(StringBuilder sb, Arg a,
750 int maxArgLength, int maxWidth)
752 boolean first = appendArgAndDescription(sb, null, null, a,
754 List<String> options = new ArrayList<>();
756 for (Opt o : EnumSet.allOf(Opt.class))
758 if (a.hasOption(o) && o.description() != null)
760 options.add(o.description());
764 final String optDisplaySeparator = "; ";
765 if (options.size() > 0)
768 String spacing = String.format("%-"
769 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
773 sb.append(ARGDESCRIPTIONSEPARATOR);
774 linelength += maxArgLength + ARGDESCRIPTIONSEPARATOR.length();
779 linelength += spacing.length();
781 if (options.size() > 0)
783 boolean optFirst = true;
784 Iterator<String> optionsI = options.listIterator();
785 while (optionsI.hasNext())
787 String desc = optionsI.next();
793 int descLength = desc.length()
794 + (optionsI.hasNext() ? optDisplaySeparator.length() : 0);
795 if (linelength + descLength > maxWidth)
797 sb.append(System.lineSeparator());
800 linelength += spacing.length();
802 // sb.append(linelength + "+" + desc.length() + " ");
804 linelength += desc.length();
805 if (optionsI.hasNext())
807 sb.append(optDisplaySeparator);
808 linelength += optDisplaySeparator.length();
813 sb.append(System.lineSeparator());
818 public static String argDisplayString(Arg a)
820 StringBuilder argSb = new StringBuilder();
822 a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
823 if (a.hasOption(Opt.STRING))
825 if (a.hasOption(Opt.PREFIXKEV))
827 argSb.append("key=value");
831 argSb.append("=value");
834 return argSb.toString();
837 public static boolean appendArgAndDescription(StringBuilder sb,
838 String aString, String description, Arg a, int maxArgLength)
840 return appendArgAndDescription(sb, aString, description, a,
841 maxArgLength, Platform.consoleWidth());
844 public static boolean appendArgAndDescription(StringBuilder sb,
845 String aString, String description, Arg a, int maxArgLength,
848 if (aString == null && a != null)
850 aString = argDisplayString(a);
852 if (description == null && a != null)
854 description = a.getDescription();
856 sb.append(String.format("%-" + maxArgLength + "s", aString));
857 if (aString.length() > maxArgLength)
859 sb.append(System.lineSeparator());
860 sb.append(String.format("%-" + maxArgLength + "s", ""));
863 int descLength = maxLength - maxArgLength
864 - ARGDESCRIPTIONSEPARATOR.length();
865 // reformat the descriptions lines to the right width
866 Iterator<String> descLines = null;
867 if (description != null)
869 descLines = Arrays.stream(description.split("\\n")).iterator();
871 List<String> splitDescLinesList = new ArrayList<>();
872 while (descLines != null && descLines.hasNext())
874 String line = descLines.next();
875 while (line.length() > descLength)
877 int splitIndex = line.lastIndexOf(" ", descLength);
878 splitDescLinesList.add(line.substring(0, splitIndex));
879 line = line.substring(splitIndex + 1);
881 splitDescLinesList.add(line);
884 Iterator<String> splitDescLines = splitDescLinesList.iterator();
885 boolean first = true;
886 if (splitDescLines != null)
888 while (splitDescLines.hasNext())
892 sb.append(ARGDESCRIPTIONSEPARATOR);
896 sb.append(String.format("%-"
897 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
900 sb.append(splitDescLines.next());
901 sb.append(System.lineSeparator());
908 protected static Iterator<Arg> getAllOfType(Type type)
910 return getAllOfType(type, new Opt[] {});
913 protected static Iterator<Arg> getAllOfType(Type type, Opt... options)
915 Opt[] opts = options == null ? new Opt[] {} : options;
916 return EnumSet.allOf(Arg.class).stream().filter(a -> {
917 if (a.getType() != type)
928 private static List<Arg> argsSortedForDisplay(List<Type> types)
930 List<Arg> argsToSort;
931 // if no types provided, do all
932 if (types == null || types.size() == 0 || types.contains(Type.ALL))
935 .asList(EnumSet.allOf(Arg.class).toArray(new Arg[] {}));
939 argsToSort = new ArrayList<>();
940 for (Type type : types)
944 Arg.getAllOfType(type).forEachRemaining(a -> argsToSort.add(a));
948 Collections.sort(argsToSort, new ArgDisplayComparator());
952 private static final String ARGDESCRIPTIONSEPARATOR = " - ";
954 private static final int DESCRIPTIONINDENT = 20;
958 class ArgDisplayComparator implements Comparator<Arg>
960 private int compareArgOpts(Arg a, Arg b, Opt o)
962 int i = a.hasOption(o) ? (b.hasOption(o) ? 0 : -1)
963 : (b.hasOption(o) ? 1 : 0);
967 private int compareForDisplay(Arg a, Arg b)
971 // first compare types (in enum order)
972 int i = a.getType().compareTo(b.getType());
975 // do Opt.LAST next (oddly). Reversed args important!
976 i = compareArgOpts(b, a, Opt.LAST);
980 Opt[] optOrder = { Opt.HELP, Opt.FIRST, Opt.PRIMARY, Opt.STRING,
982 for (Opt o : optOrder)
984 i = compareArgOpts(a, b, o);
988 // finally order of appearance in enum declarations
989 return a.compareTo(b);
993 public int compare(Arg a, Arg b)
995 return compareForDisplay(a, b);