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
74 // Opening an alignment
76 "Opens one or more alignment files or URLs in new alignment windows.",
77 Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER,
78 Opt.MULTIVALUE, Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT,
79 Opt.STORED, Opt.PRIMARY),
81 "Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
82 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.GLOB,
83 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.PRIMARY),
85 "Specifies the title for the open alignment window as string.",
86 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
87 COLOUR(Type.OPENING, "color", // being a bit soft on the Americans!
88 "Applies the colour scheme to the open alignment window. Valid values include:\n"
89 + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
90 + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
91 + "gecos-blossom,\n" + "gecos-sunset,\n"
92 + "gecos-ocean,\n" + "hydrophobic,\n"
93 + "helix-propensity,\n" + "strand-propensity,\n"
94 + "turn-propensity,\n" + "buried-index,\n"
95 + "nucleotide,\n" + "nucleotide-ambiguity,\n"
96 + "purine-pyrimidine,\n" + "rna-helices,\n"
97 + "t-coffee-scores,\n" + "sequence-id.\n" + "\n"
98 + "Names of user defined colourschemes will also work,\n"
99 + "and jalview colourscheme specifications like\n"
100 + "--colour=\"D,E=red; K,R,H=0022FF; C,c=yellow\"",
101 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
102 FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
103 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
105 TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
106 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
108 SORTBYTREE(Type.OPENING,
109 "Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
110 true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWMULTIID),
111 ANNOTATIONS(Type.OPENING,
112 "Add an annotations file or URL to the open alignment.",
113 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
115 SHOWANNOTATIONS(Type.OPENING,
116 "Enforces showing (or not showing) alignment annotations.",
117 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
119 "Enforces wrapped (or not wrapped) alignment formatting.",
120 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
121 NOSTRUCTURE(Type.OPENING,
122 "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
123 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
125 // Adding a 3D structure
126 STRUCTURE(Type.STRUCTURE,
127 "Load a structure file or URL associated with a sequence in the open alignment.\n"
128 + "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.",
129 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
130 Opt.PRIMARY, Opt.ALLOWMULTIID),
131 SEQID(Type.STRUCTURE,
132 "Specify the sequence name for the preceding --structure to be associated with.",
133 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
135 PAEMATRIX(Type.STRUCTURE,
136 "Add a PAE json matrix file to the preceding --structure.",
137 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
139 TEMPFAC(Type.STRUCTURE,
140 "Set the type of temperature factor. Possible values are:\n"
141 + "default,\n" + "plddt.",
142 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
143 STRUCTUREVIEWER(Type.STRUCTURE,
144 "Set the structure viewer to use to open the 3D structure file specified in previous --structure to name. Possible values of name are:\n"
145 + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
147 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
148 NOTEMPFAC(Type.STRUCTURE,
149 "Do not show the temperature factor annotation for the preceding --structure.",
150 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.SECRET), // keep this
153 SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
158 "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"
159 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
160 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.MULTIVALUE,
161 Opt.ALLOWMULTIID, Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
162 STRUCTUREIMAGE(Type.IMAGE,
163 "Export an image of a 3D structure opened in JMOL", Opt.STRING,
164 Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID,
167 "Set the image format for the preceding " + Arg.IMAGE.argString()
168 + " or " + Arg.STRUCTUREIMAGE.argString()
169 + ". Valid values are:\n" + "svg,\n" + "png,\n" + "eps,\n"
170 + "html,\n" + "biojs.",
171 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
172 TEXTRENDERER(Type.IMAGE,
173 "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n"
174 + "text,\n" + "lineart.",
175 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
177 "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).",
178 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
180 "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).",
181 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
183 "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).",
184 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
185 IMAGECOLOUR(Type.IMAGE, "imagecolor", // being a bit soft on the Americans!
186 "Applies the colour scheme to the open alignment window for this image, otherwise the value of "
187 + Arg.COLOUR.argString()
188 + " (or none) will apply. Valid values are the same as "
189 + Arg.COLOUR.argString() + ".",
190 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
191 BGCOLOUR(Type.IMAGE, "bgcolor", // being a bit soft on the Americans!
192 "Applies a background colour to the structure image. Valid values are named colours known to Java or RRGGBB 6 digit hex-string.",
193 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
195 STRUCTUREIMAGETYPE(Type.IMAGE,
196 "Set the structure image format for the preceding --structureimage. Valid values are:\n"
197 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
198 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
199 STRUCTUREIMAGETEXTRENDERER(Type.IMAGE,
200 "Sets whether text in a vector structure image format (SVG, EPS) should be rendered as text or vector line-art. Possible values are:\n"
201 + "text,\n" + "lineart.",
202 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
203 STRUCTUREIMAGESCALE(Type.IMAGE,
204 "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).",
205 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
206 STRUCTUREIMAGEWIDTH(Type.IMAGE,
207 "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).",
208 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
209 STRUCTUREIMAGEHEIGHT(Type.IMAGE,
210 "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).",
211 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
215 "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"
216 + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
217 + "stockholm (sto, stk),\n" + "pir (pir),\n"
218 + "blc (blc),\n" + "amsa (amsa),\n" + "json (json),\n"
219 + "pileup (pileup),\n" + "msf (msf),\n"
220 + "clustal (aln),\n" + "phylip (phy),\n"
221 + "jalview (jvp, jar).",
222 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWMULTIID,
223 Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.STDOUT, Opt.PRIMARY),
225 "Sets the format for the preceding --output file. Valid formats are:\n"
226 + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n"
227 + "blc,\n" + "amsa,\n" + "json,\n" + "pileup,\n"
228 + "msf,\n" + "clustal,\n" + "phylip,\n" + "jalview.",
229 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
231 "Process a groovy script in the file for the open alignment.",
232 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
235 "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.",
236 true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
237 OVERWRITE(Type.OUTPUT,
238 "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.",
239 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
241 "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.",
242 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
244 "Automatically create directories when outputting a file to a new directory.",
245 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
247 // controlling flow of arguments
249 "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.",
250 Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION,
251 Opt.INCREMENTDEFAULTCOUNTER),
252 SUBSTITUTIONS(Type.FLOW,
253 "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are:\n"
254 + "{basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
255 + "{dirname} - the directory (folder) name of the currently --opened file (or first --appended file),\n"
256 + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
257 + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
258 + "{n} - the value of the index counter (starting at 0).\n"
259 + "{++n} - increase and substitute the value of the index counter,\n"
260 + "{} - the value of the current alignment window default index.",
261 true, Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
263 "Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
264 + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
265 + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
266 Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.GLOB,
267 Opt.ALLOWSUBSTITUTIONS),
268 NPP(Type.FLOW, "n++",
269 "Increase the index counter used in argument value substitutions.",
270 Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION),
272 "Apply the following output arguments to all sets of linked arguments.",
273 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
275 "Apply the following output arguments to all of the last --open'ed set of linked arguments.",
276 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
278 "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
281 "Secret arg to not quit after --headless mode for tests",
282 Opt.UNARY, Opt.SECRET),
283 ALLSTRUCTURES(Type.FLOW,
284 "Apply the following 3D structure formatting arguments to all structures within the open alignment.",
285 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
288 TESTOUTPUT(Type.CONFIG,
289 "Allow specific stdout information. For testing purposes only.",
290 Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
291 SETPROP(Type.CONFIG, "Set an individual Java System property.",
292 Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.SECRET), // not in use
295 "This argument does nothing on its own, but can be used with linkedIds.",
296 Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET),
298 // private options (inserted during arg processing)
299 SETARGFILE(Type.FLOW,
300 "Sets the current value of the argfilename. Inserted before argfilecontents.",
301 Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTIVALUE, Opt.PRIVATE,
303 UNSETARGFILE(Type.FLOW,
304 "Unsets the current value of the argfilename. Inserted after argfile contents.",
305 Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.PRIVATE, Opt.NOACTION),
307 // these last two have no purpose in the normal Jalview application but are
308 // used by jalview.bin.Launcher to set memory settings. They are not used by
309 // argparser but are here for Usage statement reasons.
310 JVMMEMPC(Type.CONFIG,
311 "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
312 + "The equals sign (\"=\") separator must be used with no spaces.",
313 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
314 JVMMEMMAX(Type.CONFIG,
315 "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"
316 + "The equals sign (\"=\") separator must be used with no spaces.",
317 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
321 public static enum Opt
324 * A BOOLEAN Arg can be specified as --arg or --noarg to give true or false.
325 * A default can be given with setOptions(bool, Opt....).
326 * Use ArgParser.isSet(Arg) to see if this arg was not specified.
328 BOOLEAN("can be negated with " + ArgParser.DOUBLEDASH
329 + ArgParser.NEGATESTRING + "..."),
332 * A STRING Arg will take a value either through --arg=value or --arg value.
334 STRING("expects a value"),
336 * A UNARY Arg is a boolean value, true if present, false if not.
337 * Like BOOLEAN but without the --noarg option.
341 * A MULTI Arg can be specified multiple times.
342 * Multiple values are stored in the ArgValuesMap (along with their positional index) for each linkedId.
344 MULTIVALUE("can be specified multiple times"),
346 * A Linked Arg can be linked to others through a --arg[linkedId] or --arg[linkedId]=value.
347 * If no linkedId is specified then the current default linkedId will be used.
349 LINKED("is linked to an alignment"),
351 * A NODUPLICATES Arg can only have one value (per linkedId).
352 * The first value will be used and subsequent values ignored with a warning.
354 NODUPLICATEVALUES("cannot have the same value more than once"),
356 * A BOOTSTRAP Arg value(s) can be determined at an earlier stage than non-BOOTSTRAP Args.
357 * Substitutions do not happen in BOOTSTRAP Args and they cannot be linked or contain SubVals.
358 * See jalview.bin.argparser.BootstrapArgs.
360 BOOTSTRAP("a configuration argument"),
362 * A GLOB Arg can expand wildcard filename "globs" (e.g. path/* /filename*).
363 * If the Arg value is given as --arg filename* then the shell will have expanded the glob already,
364 * but if specified as --arg=filename* then the Java glob expansion method will be used
365 * (see FileUtils.getFilenamesFromGlob()).
366 * Note that this might be different from the shell expansion rules.
368 GLOB("can take multiple filenames with wildcards"),
370 * A NOACTION Arg does not perform a data task,
371 * usually used to control flow in ArgParser.parse(args).
375 * An ALLOWSUBSTITUTIONS Arg allows substitutions in its linkedId,
376 * SubVals and values.
378 ALLOWSUBSTITUTIONS("values can use substitutions"),
380 * A PRIVATE Arg is used internally, and cannot be specified by the user.
384 * A SECRET Arg is used by development processes and although it can be set by the user,
385 * it is not displayed to the user.
389 * An ALLOWALL Arg can use the '*' linkedId to apply to all known linkedIds
391 ALLOWMULTIID("can be used with " + ArgParser.DOUBLEDASH + "all"),
393 * If an Arg has the INCREMENTDEFAULTCOUNTER option and the default linkedId is used,
394 * the defaultLinkedIdCounter is incremented *first*.
396 INCREMENTDEFAULTCOUNTER("starts a new default alignment"),
398 * An INPUT Arg counts as an input for REQUIREINPUT
402 * A REQUIREINPUT Arg can only be applied via --all if there is an input
403 * (i.e. --open or --append)
407 * An OUTPUTFILE Arg provides an output filename. With Opt.ALLOWALL *.ext is shorthand for
408 * --all --output={basename}.ext
410 OUTPUTFILE("output file --headless will be assumed unless --gui used"),
412 * A STDOUT Arg can take an output filename that can be '-' to mean print to STDOUT.
414 STDOUT("allows the output filename '" + ArgParser.STDOUTFILENAME
415 + "' to mean output to STDOUT"),
417 * A STORED Arg resets and creates a new set of "opened" linkedIds
421 * A HELP Arg is a --help type arg
423 HELP("provides a help statement"),
425 * A PRIMARY Arg is the main Arg for its type
427 PRIMARY("is a primary argument for its type"),
429 * A HASTYPE Arg can have an Arg.Type assigned to its ArgValue
433 * A FIRST arg gets moved to appear first in the usage statement (within type)
437 * A LAST arg gets moved to appear last in the usage statement (within type)
441 * After other args are checked, the following args can prefix a KEY=VALUE argument
443 PREFIXKEV("prefixes key=value"),
445 * do not lowercase the name when getting the arg name or arg string
451 private String description;
458 private Opt(String description)
460 this.description = description;
463 public String description()
470 public static enum Type
472 // Type restricts argument to certain usage output
474 CONFIG("arguments used to configure "
475 + ChannelProperties.getProperty("app_name") + " from startup"),
476 OPENING("arguments used to open and format alignments"),
477 STRUCTURE("arguments used to add and format 3D structure data"),
478 PROCESS("arguments used to process an alignment once opened"),
479 OUTPUT("arguments used to save data from a processed alignment"),
480 IMAGE("arguments used to export an image of an alignment or structure"),
481 // IMAGE("arguments used to export an image of an alignment"),
482 // STRUCTUREIMAGE("arguments used to export an image of an structure"),
483 FLOW("arguments that control processing of the other arguments"), //
484 ALL("all arguments"), // mostly just a place-holder for --help-all
485 NONE, // mostly a place-holder for --help
488 private String description;
495 private Type(String description)
497 this.description = description;
500 public String description()
506 private final String[] argNames;
508 private Opt[] argOptions;
510 private boolean defaultBoolValue;
512 private String description;
516 private Arg(Type type, String description, Opt... options)
518 this(type, null, description, false, options);
521 private Arg(Type type, String description, boolean defaultBoolean,
524 this(type, null, description, defaultBoolean, options);
527 private Arg(Type type, String alternativeName, String description,
530 this(type, alternativeName, description, false, options);
533 private Arg(Type type, String alternativeName, String description,
534 boolean defaultBoolean, Opt... options)
537 this.description = description;
538 this.defaultBoolValue = defaultBoolean;
539 this.setOptions(options);
540 this.argNames = alternativeName != null
542 { this.getName(), alternativeName }
547 public String argString()
549 return argString(false);
552 public String negateArgString()
554 return argString(true);
557 private String argString(boolean negate)
559 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
560 if (negate && hasOption(Opt.BOOLEAN))
561 sb.append(ArgParser.NEGATESTRING);
562 sb.append(getName());
563 return sb.toString();
566 public String toLongString()
568 StringBuilder sb = new StringBuilder();
569 sb.append(this.getClass().getName()).append('.').append(this.name());
571 if (getNames().length > 0)
573 sb.append(String.join("\", \"", getNames()));
574 if (getNames().length > 0)
577 sb.append("\nType: " + type.name());
578 sb.append("\nOpt: ");
579 // map List<Opt> to List<String> for the String.join
580 List<String> optList = Arrays.asList(argOptions).stream()
581 .map(opt -> opt.name()).collect(Collectors.toList());
582 sb.append(String.join(", ", optList));
584 return sb.toString();
587 public String[] getNames()
592 public String getName()
594 String name = hasOption(Opt.PRESERVECASE) ? this.name()
595 : this.name().toLowerCase(Locale.ROOT);
596 return name.replace('_', '-');
600 public final String toString()
605 public boolean hasOption(Opt o)
607 if (argOptions == null)
609 for (Opt option : argOptions)
617 public boolean hasAllOptions(Opt... opts)
621 if (!this.hasOption(o))
627 protected Opt[] getOptions()
632 protected void setOptions(Opt... options)
634 this.argOptions = options;
637 protected boolean getDefaultBoolValue()
639 return defaultBoolValue;
642 public Type getType()
647 protected String getDescription()
652 public static String booleanArgString(Arg a)
654 StringBuilder sb = new StringBuilder(a.argString());
655 if (a.hasOption(Opt.BOOLEAN))
658 sb.append(a.negateArgString());
660 return sb.toString();
663 public static final String usage()
668 public static final void appendUsageGeneral(StringBuilder sb,
671 for (Type t : EnumSet.allOf(Type.class))
673 if (t.description() != null)
675 StringBuilder argSb = new StringBuilder();
676 argSb.append(Arg.HELP.argString()).append(ArgParser.SINGLEDASH)
677 .append(t.name().toLowerCase(Locale.ROOT));
678 appendArgAndDescription(sb, argSb.toString(),
679 "Help for " + t.description(), null, maxArgLength);
680 sb.append(System.lineSeparator());
685 public static final String usage(List<Type> types)
687 StringBuilder sb = new StringBuilder();
689 sb.append("usage: jalview [" + Arg.HEADLESS.argString() + "] [["
690 + Arg.OPEN.argString() + "/" + Arg.APPEND.argString()
691 + "] file(s)] [args]");
692 sb.append(System.lineSeparator());
693 sb.append(System.lineSeparator());
695 if (types == null || types.contains(null))
697 // always show --help
698 appendArgAndDescription(sb, null, "Display this basic help", Arg.HELP,
700 sb.append(System.lineSeparator());
702 appendUsageGeneral(sb, DESCRIPTIONINDENT);
706 List<Arg> args = argsSortedForDisplay(types);
709 * just use a set maxArgLength of DESCRIPTIONINDENT
711 int maxArgLength = 0;
714 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
717 String argS = argDisplayString(a);
718 if (argS.length() > maxArgLength)
719 maxArgLength = argS.length();
722 int maxArgLength = DESCRIPTIONINDENT;
724 // always show --help
725 appendArgAndDescription(sb, null, null, Arg.HELP, maxArgLength);
726 sb.append(System.lineSeparator());
728 if ((args.contains(Arg.HELP) && types.contains(Type.ALL)))
730 appendUsageGeneral(sb, maxArgLength);
733 Iterator<Arg> argsI = args.iterator();
734 Type typeSection = null;
735 while (argsI.hasNext())
737 Arg a = argsI.next();
739 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET)
745 if (a.getType() != typeSection)
747 typeSection = a.getType();
748 String typeDescription = a.getType().description();
749 if (typeDescription != null && typeDescription.length() > 0)
751 // typeDescription = typeDescription.substring(0,
752 // 1).toUpperCase(Locale.ROOT) + typeDescription.substring(1);
753 typeDescription = typeDescription.toUpperCase(Locale.ROOT);
754 sb.append(typeDescription);
755 sb.append(System.lineSeparator());
756 sb.append(System.lineSeparator());
760 appendArgUsage(sb, a, maxArgLength, Platform.consoleWidth());
764 sb.append(System.lineSeparator());
768 return sb.toString();
771 private static void appendArgUsage(StringBuilder sb, Arg a,
772 int maxArgLength, int maxWidth)
774 boolean first = appendArgAndDescription(sb, null, null, a,
776 List<String> options = new ArrayList<>();
778 for (Opt o : EnumSet.allOf(Opt.class))
780 if (a.hasOption(o) && o.description() != null)
782 options.add(o.description());
786 final String optDisplaySeparator = "; ";
787 if (options.size() > 0)
790 String spacing = String.format("%-"
791 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
795 sb.append(ARGDESCRIPTIONSEPARATOR);
796 linelength += maxArgLength + ARGDESCRIPTIONSEPARATOR.length();
801 linelength += spacing.length();
803 if (options.size() > 0)
805 boolean optFirst = true;
806 Iterator<String> optionsI = options.listIterator();
807 while (optionsI.hasNext())
809 String desc = optionsI.next();
815 int descLength = desc.length()
816 + (optionsI.hasNext() ? optDisplaySeparator.length() : 0);
817 if (linelength + descLength > maxWidth)
819 sb.append(System.lineSeparator());
822 linelength += spacing.length();
824 // sb.append(linelength + "+" + desc.length() + " ");
826 linelength += desc.length();
827 if (optionsI.hasNext())
829 sb.append(optDisplaySeparator);
830 linelength += optDisplaySeparator.length();
835 sb.append(System.lineSeparator());
840 public static String argDisplayString(Arg a)
842 StringBuilder argSb = new StringBuilder();
844 a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
845 if (a.hasOption(Opt.STRING))
847 if (a.hasOption(Opt.PREFIXKEV))
849 argSb.append("key=value");
853 argSb.append("=value");
856 return argSb.toString();
859 public static boolean appendArgAndDescription(StringBuilder sb,
860 String aString, String description, Arg a, int maxArgLength)
862 return appendArgAndDescription(sb, aString, description, a,
863 maxArgLength, Platform.consoleWidth());
866 public static boolean appendArgAndDescription(StringBuilder sb,
867 String aString, String description, Arg a, int maxArgLength,
870 if (aString == null && a != null)
872 aString = argDisplayString(a);
874 if (description == null && a != null)
876 description = a.getDescription();
878 sb.append(String.format("%-" + maxArgLength + "s", aString));
879 if (aString.length() > maxArgLength)
881 sb.append(System.lineSeparator());
882 sb.append(String.format("%-" + maxArgLength + "s", ""));
885 int descLength = maxLength - maxArgLength
886 - ARGDESCRIPTIONSEPARATOR.length();
887 // reformat the descriptions lines to the right width
888 Iterator<String> descLines = null;
889 if (description != null)
891 descLines = Arrays.stream(description.split("\\n")).iterator();
893 List<String> splitDescLinesList = new ArrayList<>();
894 while (descLines != null && descLines.hasNext())
896 String line = descLines.next();
897 while (line.length() > descLength)
899 int splitIndex = line.lastIndexOf(" ", descLength);
900 splitDescLinesList.add(line.substring(0, splitIndex));
901 line = line.substring(splitIndex + 1);
903 splitDescLinesList.add(line);
906 Iterator<String> splitDescLines = splitDescLinesList.iterator();
907 boolean first = true;
908 if (splitDescLines != null)
910 while (splitDescLines.hasNext())
914 sb.append(ARGDESCRIPTIONSEPARATOR);
918 sb.append(String.format("%-"
919 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
922 sb.append(splitDescLines.next());
923 sb.append(System.lineSeparator());
930 protected static Iterator<Arg> getAllOfType(Type type)
932 return getAllOfType(type, new Opt[] {});
935 protected static Iterator<Arg> getAllOfType(Type type, Opt... options)
937 Opt[] opts = options == null ? new Opt[] {} : options;
938 return EnumSet.allOf(Arg.class).stream().filter(a -> {
939 if (a.getType() != type)
950 private static List<Arg> argsSortedForDisplay(List<Type> types)
952 List<Arg> argsToSort;
953 // if no types provided, do all
954 if (types == null || types.size() == 0 || types.contains(Type.ALL))
957 .asList(EnumSet.allOf(Arg.class).toArray(new Arg[] {}));
961 argsToSort = new ArrayList<>();
962 for (Type type : types)
966 Arg.getAllOfType(type).forEachRemaining(a -> argsToSort.add(a));
970 Collections.sort(argsToSort, new ArgDisplayComparator());
974 private static final String ARGDESCRIPTIONSEPARATOR = " - ";
976 private static final int DESCRIPTIONINDENT = 20;
980 class ArgDisplayComparator implements Comparator<Arg>
982 private int compareArgOpts(Arg a, Arg b, Opt o)
984 int i = a.hasOption(o) ? (b.hasOption(o) ? 0 : -1)
985 : (b.hasOption(o) ? 1 : 0);
989 private int compareForDisplay(Arg a, Arg b)
993 // first compare types (in enum order)
994 int i = a.getType().compareTo(b.getType());
997 // do Opt.LAST next (oddly). Reversed args important!
998 i = compareArgOpts(b, a, Opt.LAST);
1002 Opt[] optOrder = { Opt.HELP, Opt.FIRST, Opt.PRIMARY, Opt.STRING,
1004 for (Opt o : optOrder)
1006 i = compareArgOpts(a, b, o);
1010 // finally order of appearance in enum declarations
1011 return a.compareTo(b);
1015 public int compare(Arg a, Arg b)
1017 return compareForDisplay(a, b);