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 JAVACONSOLE(Type.CONFIG, "Show (or don't show) the Java Console.", false,
48 Opt.BOOLEAN, Opt.BOOTSTRAP),
49 NOUSAGESTATS(Type.CONFIG, "Don't send initial launch usage stats.",
50 Opt.UNARY, Opt.BOOTSTRAP),
51 NOSTARTUPFILE(Type.CONFIG, "Don't show the default startup file.",
52 Opt.UNARY, Opt.BOOTSTRAP),
53 WEBSERVICEDISCOVERY(Type.CONFIG,
54 "Attempt (or don't attempt) to connect to JABAWS web services.",
55 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
57 "Use a file as the preferences file instead of the usual ~/"
58 + ChannelProperties.getProperty("preferences.filename")
60 Opt.STRING, Opt.BOOTSTRAP),
61 DEBUG(Type.CONFIG, "d", "Start Jalview in debug log level.", Opt.BOOLEAN,
63 TRACE(Type.CONFIG, "Start Jalview in trace log level.", Opt.BOOLEAN,
64 Opt.BOOTSTRAP, Opt.SECRET),
65 QUIET(Type.CONFIG, "q",
66 "Stop all output to STDOUT (after the Java Virtual Machine has started). Use ‑‑quiet a second time to stop all output to STDERR.",
67 Opt.UNARY, Opt.MULTIVALUE, Opt.BOOTSTRAP),
68 INITSUBSTITUTIONS(Type.CONFIG,
69 "Set ‑‑substitutions to be initially enabled (or initially disabled).",
70 true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
71 P(Type.CONFIG, "Set a Jalview preference value for this session.",
72 Opt.PREFIXKEV, Opt.PRESERVECASE, Opt.STRING, Opt.BOOTSTRAP,
73 Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET), // keep this secret for
76 // Opening an alignment
78 "Opens one or more alignment files or URLs in new alignment windows.",
79 Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER,
80 Opt.MULTIVALUE, Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT,
81 Opt.STORED, Opt.PRIMARY),
83 "Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
84 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.GLOB,
85 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.PRIMARY),
87 "Specifies the title for the open alignment window as string.",
88 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
89 COLOUR(Type.OPENING, "color", // being a bit soft on the Americans!
90 "Applies the colour scheme to the open alignment window. Valid values include:\n"
91 + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
92 + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
93 + "gecos-blossom,\n" + "gecos-sunset,\n"
94 + "gecos-ocean,\n" + "hydrophobic,\n"
95 + "helix-propensity,\n" + "strand-propensity,\n"
96 + "turn-propensity,\n" + "buried-index,\n"
97 + "nucleotide,\n" + "nucleotide-ambiguity,\n"
98 + "purine-pyrimidine,\n" + "rna-helices,\n"
99 + "t-coffee-scores,\n" + "sequence-id.\n" + "\n"
100 + "Names of user defined colourschemes will also work,\n"
101 + "and jalview colourscheme specifications like\n"
102 + "--colour=\"D,E=red; K,R,H=0022FF; C,c=yellow\"",
103 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
104 FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
105 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
107 TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
108 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
110 SORTBYTREE(Type.OPENING,
111 "Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
112 true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWMULTIID),
113 ANNOTATIONS(Type.OPENING,
114 "Add an annotations file or URL to the open alignment.",
115 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
117 SHOWANNOTATIONS(Type.OPENING,
118 "Enforces showing (or not showing) alignment annotations.",
119 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
121 "Enforces wrapped (or not wrapped) alignment formatting.",
122 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
123 NOSTRUCTURE(Type.OPENING,
124 "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
125 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
127 // Adding a 3D structure
128 STRUCTURE(Type.STRUCTURE,
129 "Load a structure file or URL associated with a sequence in the open alignment.\n"
130 + "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.",
131 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
132 Opt.PRIMARY, Opt.ALLOWMULTIID),
133 SEQID(Type.STRUCTURE,
134 "Specify the sequence name for the preceding --structure to be associated with.",
135 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
137 PAEMATRIX(Type.STRUCTURE,
138 "Add a PAE json matrix file to the preceding --structure.",
139 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
141 TEMPFAC(Type.STRUCTURE,
142 "Set the type of temperature factor. Possible values are:\n"
143 + "default,\n" + "plddt.",
144 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
145 STRUCTUREVIEWER(Type.STRUCTURE,
146 "Set the structure viewer to use to open the 3D structure file specified in previous --structure to name. Possible values of name are:\n"
147 + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
149 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
150 NOTEMPFAC(Type.STRUCTURE,
151 "Do not show the temperature factor annotation for the preceding --structure.",
152 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.SECRET), // keep this
155 SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
160 "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"
161 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
162 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.MULTIVALUE,
163 Opt.ALLOWMULTIID, Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
164 STRUCTUREIMAGE(Type.IMAGE,
165 "Export an image of a 3D structure opened in JMOL", Opt.STRING,
166 Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID,
169 "Set the image format for the preceding " + Arg.IMAGE.argString()
170 + " or " + Arg.STRUCTUREIMAGE.argString()
171 + ". Valid values are:\n" + "svg,\n" + "png,\n" + "eps,\n"
172 + "html,\n" + "biojs.",
173 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
174 TEXTRENDERER(Type.IMAGE,
175 "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n"
176 + "text,\n" + "lineart.",
177 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
179 "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).",
180 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
182 "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).",
183 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
185 "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).",
186 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
187 IMAGECOLOUR(Type.IMAGE, "imagecolor", // being a bit soft on the Americans!
188 "Applies the colour scheme to the open alignment window for this image, otherwise the value of "
189 + Arg.COLOUR.argString()
190 + " (or none) will apply. Valid values are the same as "
191 + Arg.COLOUR.argString() + ".",
192 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
193 BGCOLOUR(Type.IMAGE, "bgcolor", // being a bit soft on the Americans!
194 "Applies a background colour to the structure image. Valid values are named colours known to Java or RRGGBB 6 digit hex-string.",
195 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
197 STRUCTUREIMAGETYPE(Type.IMAGE,
198 "Set the structure image format for the preceding --structureimage. Valid values are:\n"
199 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
200 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
201 STRUCTUREIMAGETEXTRENDERER(Type.IMAGE,
202 "Sets whether text in a vector structure image format (SVG, EPS) should be rendered as text or vector line-art. Possible values are:\n"
203 + "text,\n" + "lineart.",
204 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
205 STRUCTUREIMAGESCALE(Type.IMAGE,
206 "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).",
207 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
208 STRUCTUREIMAGEWIDTH(Type.IMAGE,
209 "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).",
210 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
211 STRUCTUREIMAGEHEIGHT(Type.IMAGE,
212 "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).",
213 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
217 "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"
218 + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
219 + "stockholm (sto, stk),\n" + "pir (pir),\n"
220 + "blc (blc),\n" + "amsa (amsa),\n" + "json (json),\n"
221 + "pileup (pileup),\n" + "msf (msf),\n"
222 + "clustal (aln),\n" + "phylip (phy),\n"
223 + "jalview (jvp, jar).",
224 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWMULTIID,
225 Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.STDOUT, Opt.PRIMARY),
227 "Sets the format for the preceding --output file. Valid formats are:\n"
228 + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n"
229 + "blc,\n" + "amsa,\n" + "json,\n" + "pileup,\n"
230 + "msf,\n" + "clustal,\n" + "phylip,\n" + "jalview.",
231 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
233 "Process a groovy script in the file for the open alignment.",
234 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
237 "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.",
238 true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
239 OVERWRITE(Type.OUTPUT,
240 "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.",
241 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
243 "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.",
244 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
246 "Automatically create directories when outputting a file to a new directory.",
247 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
249 // controlling flow of arguments
251 "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.",
252 Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION,
253 Opt.INCREMENTDEFAULTCOUNTER),
254 SUBSTITUTIONS(Type.FLOW,
255 "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are:\n"
256 + "{basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
257 + "{dirname} - the directory (folder) name of the currently --opened file (or first --appended file),\n"
258 + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
259 + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
260 + "{n} - the value of the index counter (starting at 0).\n"
261 + "{++n} - increase and substitute the value of the index counter,\n"
262 + "{} - the value of the current alignment window default index.",
263 true, Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
265 "Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
266 + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
267 + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
268 Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.GLOB,
269 Opt.ALLOWSUBSTITUTIONS),
270 NPP(Type.FLOW, "n++",
271 "Increase the index counter used in argument value substitutions.",
272 Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION),
274 "Apply the following output arguments to all sets of linked arguments.",
275 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
277 "Apply the following output arguments to all of the last --open'ed set of linked arguments.",
278 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
280 "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
283 "Secret arg to not quit after --headless mode for tests",
284 Opt.UNARY, Opt.SECRET),
285 ALLSTRUCTURES(Type.FLOW,
286 "Apply the following 3D structure formatting arguments to all structures within the open alignment.",
287 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
290 TESTOUTPUT(Type.CONFIG,
291 "Allow specific stdout information. For testing purposes only.",
292 Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
293 SETPROP(Type.CONFIG, "Set an individual Java System property.",
294 Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.SECRET), // not in use
297 "This argument does nothing on its own, but can be used with linkedIds.",
298 Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET),
300 // private options (inserted during arg processing)
301 SETARGFILE(Type.FLOW,
302 "Sets the current value of the argfilename. Inserted before argfilecontents.",
303 Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTIVALUE, Opt.PRIVATE,
305 UNSETARGFILE(Type.FLOW,
306 "Unsets the current value of the argfilename. Inserted after argfile contents.",
307 Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.PRIVATE, Opt.NOACTION),
309 // these last two have no purpose in the normal Jalview application but are
310 // used by jalview.bin.Launcher to set memory settings. They are not used by
311 // argparser but are here for Usage statement reasons.
312 JVMMEMPC(Type.CONFIG,
313 "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
314 + "The equals sign (\"=\") separator must be used with no spaces.",
315 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
316 JVMMEMMAX(Type.CONFIG,
317 "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"
318 + "The equals sign (\"=\") separator must be used with no spaces.",
319 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
323 public static enum Opt
326 * A BOOLEAN Arg can be specified as --arg or --noarg to give true or false.
327 * A default can be given with setOptions(bool, Opt....).
328 * Use ArgParser.isSet(Arg) to see if this arg was not specified.
330 BOOLEAN("can be negated with " + ArgParser.DOUBLEDASH
331 + ArgParser.NEGATESTRING + "..."),
334 * A STRING Arg will take a value either through --arg=value or --arg value.
336 STRING("expects a value"),
338 * A UNARY Arg is a boolean value, true if present, false if not.
339 * Like BOOLEAN but without the --noarg option.
343 * A MULTI Arg can be specified multiple times.
344 * Multiple values are stored in the ArgValuesMap (along with their positional index) for each linkedId.
346 MULTIVALUE("can be specified multiple times"),
348 * A Linked Arg can be linked to others through a --arg[linkedId] or --arg[linkedId]=value.
349 * If no linkedId is specified then the current default linkedId will be used.
351 LINKED("is linked to an alignment"),
353 * A NODUPLICATES Arg can only have one value (per linkedId).
354 * The first value will be used and subsequent values ignored with a warning.
356 NODUPLICATEVALUES("cannot have the same value more than once"),
358 * A BOOTSTRAP Arg value(s) can be determined at an earlier stage than non-BOOTSTRAP Args.
359 * Substitutions do not happen in BOOTSTRAP Args and they cannot be linked or contain SubVals.
360 * See jalview.bin.argparser.BootstrapArgs.
362 BOOTSTRAP("a configuration argument"),
364 * A GLOB Arg can expand wildcard filename "globs" (e.g. path/* /filename*).
365 * If the Arg value is given as --arg filename* then the shell will have expanded the glob already,
366 * but if specified as --arg=filename* then the Java glob expansion method will be used
367 * (see FileUtils.getFilenamesFromGlob()).
368 * Note that this might be different from the shell expansion rules.
370 GLOB("can take multiple filenames with wildcards"),
372 * A NOACTION Arg does not perform a data task,
373 * usually used to control flow in ArgParser.parse(args).
377 * An ALLOWSUBSTITUTIONS Arg allows substitutions in its linkedId,
378 * SubVals and values.
380 ALLOWSUBSTITUTIONS("values can use substitutions"),
382 * A PRIVATE Arg is used internally, and cannot be specified by the user.
386 * A SECRET Arg is used by development processes and although it can be set by the user,
387 * it is not displayed to the user.
391 * An ALLOWALL Arg can use the '*' linkedId to apply to all known linkedIds
393 ALLOWMULTIID("can be used with " + ArgParser.DOUBLEDASH + "all"),
395 * If an Arg has the INCREMENTDEFAULTCOUNTER option and the default linkedId is used,
396 * the defaultLinkedIdCounter is incremented *first*.
398 INCREMENTDEFAULTCOUNTER("starts a new default alignment"),
400 * An INPUT Arg counts as an input for REQUIREINPUT
404 * A REQUIREINPUT Arg can only be applied via --all if there is an input
405 * (i.e. --open or --append)
409 * An OUTPUTFILE Arg provides an output filename. With Opt.ALLOWALL *.ext is shorthand for
410 * --all --output={basename}.ext
412 OUTPUTFILE("output file --headless will be assumed unless --gui used"),
414 * A STDOUT Arg can take an output filename that can be '-' to mean print to STDOUT.
416 STDOUT("allows the output filename '" + ArgParser.STDOUTFILENAME
417 + "' to mean output to STDOUT"),
419 * A STORED Arg resets and creates a new set of "opened" linkedIds
423 * A HELP Arg is a --help type arg
425 HELP("provides a help statement"),
427 * A PRIMARY Arg is the main Arg for its type
429 PRIMARY("is a primary argument for its type"),
431 * A HASTYPE Arg can have an Arg.Type assigned to its ArgValue
435 * A FIRST arg gets moved to appear first in the usage statement (within type)
439 * A LAST arg gets moved to appear last in the usage statement (within type)
443 * After other args are checked, the following args can prefix a KEY=VALUE argument
445 PREFIXKEV("prefixes key=value"),
447 * do not lowercase the name when getting the arg name or arg string
453 private String description;
460 private Opt(String description)
462 this.description = description;
465 public String description()
472 public static enum Type
474 // Type restricts argument to certain usage output
476 CONFIG("arguments used to configure "
477 + ChannelProperties.getProperty("app_name") + " from startup"),
478 OPENING("arguments used to open and format alignments"),
479 STRUCTURE("arguments used to add and format 3D structure data"),
480 PROCESS("arguments used to process an alignment once opened"),
481 OUTPUT("arguments used to save data from a processed alignment"),
482 IMAGE("arguments used to export an image of an alignment or structure"),
483 // IMAGE("arguments used to export an image of an alignment"),
484 // STRUCTUREIMAGE("arguments used to export an image of an structure"),
485 FLOW("arguments that control processing of the other arguments"), //
486 ALL("all arguments"), // mostly just a place-holder for --help-all
487 NONE, // mostly a place-holder for --help
490 private String description;
497 private Type(String description)
499 this.description = description;
502 public String description()
508 private final String[] argNames;
510 private Opt[] argOptions;
512 private boolean defaultBoolValue;
514 private String description;
518 private Arg(Type type, String description, Opt... options)
520 this(type, null, description, false, options);
523 private Arg(Type type, String description, boolean defaultBoolean,
526 this(type, null, description, defaultBoolean, options);
529 private Arg(Type type, String alternativeName, String description,
532 this(type, alternativeName, description, false, options);
535 private Arg(Type type, String alternativeName, String description,
536 boolean defaultBoolean, Opt... options)
539 this.description = description;
540 this.defaultBoolValue = defaultBoolean;
541 this.setOptions(options);
542 this.argNames = alternativeName != null
544 { this.getName(), alternativeName }
549 public String argString()
551 return argString(false);
554 public String negateArgString()
556 return argString(true);
559 private String argString(boolean negate)
561 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
562 if (negate && hasOption(Opt.BOOLEAN))
563 sb.append(ArgParser.NEGATESTRING);
564 sb.append(getName());
565 return sb.toString();
568 public String toLongString()
570 StringBuilder sb = new StringBuilder();
571 sb.append(this.getClass().getName()).append('.').append(this.name());
573 if (getNames().length > 0)
575 sb.append(String.join("\", \"", getNames()));
576 if (getNames().length > 0)
579 sb.append("\nType: " + type.name());
580 sb.append("\nOpt: ");
581 // map List<Opt> to List<String> for the String.join
582 List<String> optList = Arrays.asList(argOptions).stream()
583 .map(opt -> opt.name()).collect(Collectors.toList());
584 sb.append(String.join(", ", optList));
586 return sb.toString();
589 public String[] getNames()
594 public String getName()
596 String name = hasOption(Opt.PRESERVECASE) ? this.name()
597 : this.name().toLowerCase(Locale.ROOT);
598 return name.replace('_', '-');
602 public final String toString()
607 public boolean hasOption(Opt o)
609 if (argOptions == null)
611 for (Opt option : argOptions)
619 public boolean hasAllOptions(Opt... opts)
623 if (!this.hasOption(o))
629 protected Opt[] getOptions()
634 protected void setOptions(Opt... options)
636 this.argOptions = options;
639 protected boolean getDefaultBoolValue()
641 return defaultBoolValue;
644 public Type getType()
649 protected String getDescription()
654 public static String booleanArgString(Arg a)
656 StringBuilder sb = new StringBuilder(a.argString());
657 if (a.hasOption(Opt.BOOLEAN))
660 sb.append(a.negateArgString());
662 return sb.toString();
665 public static final String usage()
670 public static final void appendUsageGeneral(StringBuilder sb,
673 for (Type t : EnumSet.allOf(Type.class))
675 if (t.description() != null)
677 StringBuilder argSb = new StringBuilder();
678 argSb.append(Arg.HELP.argString()).append(ArgParser.SINGLEDASH)
679 .append(t.name().toLowerCase(Locale.ROOT));
680 appendArgAndDescription(sb, argSb.toString(),
681 "Help for " + t.description(), null, maxArgLength);
682 sb.append(System.lineSeparator());
687 public static final String usage(List<Type> types)
689 StringBuilder sb = new StringBuilder();
691 sb.append("usage: jalview [" + Arg.HEADLESS.argString() + "] [["
692 + Arg.OPEN.argString() + "/" + Arg.APPEND.argString()
693 + "] file(s)] [args]");
694 sb.append(System.lineSeparator());
695 sb.append(System.lineSeparator());
697 if (types == null || types.contains(null))
699 // always show --help
700 appendArgAndDescription(sb, null, "Display this basic help", Arg.HELP,
702 sb.append(System.lineSeparator());
704 appendUsageGeneral(sb, DESCRIPTIONINDENT);
708 List<Arg> args = argsSortedForDisplay(types);
711 * just use a set maxArgLength of DESCRIPTIONINDENT
713 int maxArgLength = 0;
716 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
719 String argS = argDisplayString(a);
720 if (argS.length() > maxArgLength)
721 maxArgLength = argS.length();
724 int maxArgLength = DESCRIPTIONINDENT;
726 // always show --help
727 appendArgAndDescription(sb, null, null, Arg.HELP, maxArgLength);
728 sb.append(System.lineSeparator());
730 if ((args.contains(Arg.HELP) && types.contains(Type.ALL)))
732 appendUsageGeneral(sb, maxArgLength);
735 Iterator<Arg> argsI = args.iterator();
736 Type typeSection = null;
737 while (argsI.hasNext())
739 Arg a = argsI.next();
741 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET)
747 if (a.getType() != typeSection)
749 typeSection = a.getType();
750 String typeDescription = a.getType().description();
751 if (typeDescription != null && typeDescription.length() > 0)
753 // typeDescription = typeDescription.substring(0,
754 // 1).toUpperCase(Locale.ROOT) + typeDescription.substring(1);
755 typeDescription = typeDescription.toUpperCase(Locale.ROOT);
756 sb.append(typeDescription);
757 sb.append(System.lineSeparator());
758 sb.append(System.lineSeparator());
762 appendArgUsage(sb, a, maxArgLength, Platform.consoleWidth());
766 sb.append(System.lineSeparator());
770 return sb.toString();
773 private static void appendArgUsage(StringBuilder sb, Arg a,
774 int maxArgLength, int maxWidth)
776 boolean first = appendArgAndDescription(sb, null, null, a,
778 List<String> options = new ArrayList<>();
780 for (Opt o : EnumSet.allOf(Opt.class))
782 if (a.hasOption(o) && o.description() != null)
784 options.add(o.description());
788 final String optDisplaySeparator = "; ";
789 if (options.size() > 0)
792 String spacing = String.format("%-"
793 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
797 sb.append(ARGDESCRIPTIONSEPARATOR);
798 linelength += maxArgLength + ARGDESCRIPTIONSEPARATOR.length();
803 linelength += spacing.length();
805 if (options.size() > 0)
807 boolean optFirst = true;
808 Iterator<String> optionsI = options.listIterator();
809 while (optionsI.hasNext())
811 String desc = optionsI.next();
817 int descLength = desc.length()
818 + (optionsI.hasNext() ? optDisplaySeparator.length() : 0);
819 if (linelength + descLength > maxWidth)
821 sb.append(System.lineSeparator());
824 linelength += spacing.length();
826 // sb.append(linelength + "+" + desc.length() + " ");
828 linelength += desc.length();
829 if (optionsI.hasNext())
831 sb.append(optDisplaySeparator);
832 linelength += optDisplaySeparator.length();
837 sb.append(System.lineSeparator());
842 public static String argDisplayString(Arg a)
844 StringBuilder argSb = new StringBuilder();
846 a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
847 if (a.hasOption(Opt.STRING))
849 if (a.hasOption(Opt.PREFIXKEV))
851 argSb.append("key=value");
855 argSb.append("=value");
858 return argSb.toString();
861 public static boolean appendArgAndDescription(StringBuilder sb,
862 String aString, String description, Arg a, int maxArgLength)
864 return appendArgAndDescription(sb, aString, description, a,
865 maxArgLength, Platform.consoleWidth());
868 public static boolean appendArgAndDescription(StringBuilder sb,
869 String aString, String description, Arg a, int maxArgLength,
872 if (aString == null && a != null)
874 aString = argDisplayString(a);
876 if (description == null && a != null)
878 description = a.getDescription();
880 sb.append(String.format("%-" + maxArgLength + "s", aString));
881 if (aString.length() > maxArgLength)
883 sb.append(System.lineSeparator());
884 sb.append(String.format("%-" + maxArgLength + "s", ""));
887 int descLength = maxLength - maxArgLength
888 - ARGDESCRIPTIONSEPARATOR.length();
889 // reformat the descriptions lines to the right width
890 Iterator<String> descLines = null;
891 if (description != null)
893 descLines = Arrays.stream(description.split("\\n")).iterator();
895 List<String> splitDescLinesList = new ArrayList<>();
896 while (descLines != null && descLines.hasNext())
898 String line = descLines.next();
899 while (line.length() > descLength)
901 int splitIndex = line.lastIndexOf(" ", descLength);
902 splitDescLinesList.add(line.substring(0, splitIndex));
903 line = line.substring(splitIndex + 1);
905 splitDescLinesList.add(line);
908 Iterator<String> splitDescLines = splitDescLinesList.iterator();
909 boolean first = true;
910 if (splitDescLines != null)
912 while (splitDescLines.hasNext())
916 sb.append(ARGDESCRIPTIONSEPARATOR);
920 sb.append(String.format("%-"
921 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
924 sb.append(splitDescLines.next());
925 sb.append(System.lineSeparator());
932 protected static Iterator<Arg> getAllOfType(Type type)
934 return getAllOfType(type, new Opt[] {});
937 protected static Iterator<Arg> getAllOfType(Type type, Opt... options)
939 Opt[] opts = options == null ? new Opt[] {} : options;
940 return EnumSet.allOf(Arg.class).stream().filter(a -> {
941 if (a.getType() != type)
952 private static List<Arg> argsSortedForDisplay(List<Type> types)
954 List<Arg> argsToSort;
955 // if no types provided, do all
956 if (types == null || types.size() == 0 || types.contains(Type.ALL))
959 .asList(EnumSet.allOf(Arg.class).toArray(new Arg[] {}));
963 argsToSort = new ArrayList<>();
964 for (Type type : types)
968 Arg.getAllOfType(type).forEachRemaining(a -> argsToSort.add(a));
972 Collections.sort(argsToSort, new ArgDisplayComparator());
976 private static final String ARGDESCRIPTIONSEPARATOR = " - ";
978 private static final int DESCRIPTIONINDENT = 20;
982 class ArgDisplayComparator implements Comparator<Arg>
984 private int compareArgOpts(Arg a, Arg b, Opt o)
986 int i = a.hasOption(o) ? (b.hasOption(o) ? 0 : -1)
987 : (b.hasOption(o) ? 1 : 0);
991 private int compareForDisplay(Arg a, Arg b)
995 // first compare types (in enum order)
996 int i = a.getType().compareTo(b.getType());
999 // do Opt.LAST next (oddly). Reversed args important!
1000 i = compareArgOpts(b, a, Opt.LAST);
1004 Opt[] optOrder = { Opt.HELP, Opt.FIRST, Opt.PRIMARY, Opt.STRING,
1006 for (Opt o : optOrder)
1008 i = compareArgOpts(a, b, o);
1012 // finally order of appearance in enum declarations
1013 return a.compareTo(b);
1017 public int compare(Arg a, Arg b)
1019 return compareForDisplay(a, b);