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.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.ALLOWMULTIID,
161 Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
163 "Set the image format for the preceding --image. Valid values are:\n"
164 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
165 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
166 TEXTRENDERER(Type.IMAGE,
167 "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n"
168 + "text,\n" + "lineart.",
169 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
171 "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).",
172 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
174 "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).",
175 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
177 "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).",
178 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
179 STRUCTUREIMAGE(Type.STRUCTUREIMAGE,
180 "Export an image of a 3D structure opened in JMOL", Opt.STRING,
181 Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID),
182 STRUCTUREIMAGETYPE(Type.STRUCTUREIMAGE,
183 "Set the structure image format for the preceding --structureimage. Valid values are:\n"
184 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
185 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
186 STRUCTUREIMAGETEXTRENDERER(Type.STRUCTUREIMAGE,
187 "Sets whether text in a vector structure image format (SVG, EPS) should be rendered as text or vector line-art. Possible values are:\n"
188 + "text,\n" + "lineart.",
189 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
190 STRUCTUREIMAGESCALE(Type.STRUCTUREIMAGE,
191 "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).",
192 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
193 STRUCTUREIMAGEWIDTH(Type.STRUCTUREIMAGE,
194 "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).",
195 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
196 STRUCTUREIMAGEHEIGHT(Type.STRUCTUREIMAGE,
197 "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).",
198 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
201 "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"
202 + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
203 + "stockholm (sto, stk),\n" + "pir (pir),\n"
204 + "blc (blc),\n" + "amsa (amsa),\n" + "json (json),\n"
205 + "pileup (pileup),\n" + "msf (msf),\n"
206 + "clustal (aln),\n" + "phylip (phy),\n"
207 + "jalview (jvp, jar).",
208 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWMULTIID,
209 Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.STDOUT, Opt.PRIMARY),
211 "Sets the format for the preceding --output file. Valid formats are:\n"
212 + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n"
213 + "blc,\n" + "amsa,\n" + "json,\n" + "pileup,\n"
214 + "msf,\n" + "clustal,\n" + "phylip,\n" + "jalview.",
215 Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
217 "Process a groovy script in the file for the open alignment.",
218 Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
221 "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.",
222 true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
223 OVERWRITE(Type.OUTPUT,
224 "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.",
225 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
227 "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.",
228 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
230 "Automatically create directories when outputting a file to a new directory.",
231 Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
233 // controlling flow of arguments
235 "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.",
236 Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION,
237 Opt.INCREMENTDEFAULTCOUNTER),
238 SUBSTITUTIONS(Type.FLOW,
239 "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are:\n"
240 + "{basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
241 + "{dirname} - the directory (folder) name of the currently --opened file (or first --appended file),\n"
242 + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
243 + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
244 + "{n} - the value of the index counter (starting at 0).\n"
245 + "{++n} - increase and substitute the value of the index counter,\n"
246 + "{} - the value of the current alignment window default index.",
247 true, Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
249 "Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
250 + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
251 + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
252 Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.GLOB,
253 Opt.ALLOWSUBSTITUTIONS),
254 NPP(Type.FLOW, "n++",
255 "Increase the index counter used in argument value substitutions.",
256 Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION),
258 "Apply the following output arguments to all sets of linked arguments.",
259 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
261 "Apply the following output arguments to all of the last --open'ed set of linked arguments.",
262 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
264 "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
267 "Secret arg to not quit after --headless mode for tests",
268 Opt.UNARY, Opt.SECRET),
269 ALLSTRUCTURES(Type.FLOW,
270 "Apply the following 3D structure formatting arguments to all structures within the open alignment.",
271 Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
274 TESTOUTPUT(Type.CONFIG,
275 "Allow specific stdout information. For testing purposes only.",
276 Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
277 SETPROP(Type.CONFIG, "Set an individual Java System property.",
278 Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.SECRET), // not in use
281 "This argument does nothing on its own, but can be used with linkedIds.",
282 Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET),
284 // private options (inserted during arg processing)
285 SETARGFILE(Type.FLOW,
286 "Sets the current value of the argfilename. Inserted before argfilecontents.",
287 Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTIVALUE, Opt.PRIVATE,
289 UNSETARGFILE(Type.FLOW,
290 "Unsets the current value of the argfilename. Inserted after argfile contents.",
291 Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.PRIVATE, Opt.NOACTION),
293 // these last two have no purpose in the normal Jalview application but are
294 // used by jalview.bin.Launcher to set memory settings. They are not used by
295 // argparser but are here for Usage statement reasons.
296 JVMMEMPC(Type.CONFIG,
297 "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
298 + "The equals sign (\"=\") separator must be used with no spaces.",
299 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
300 JVMMEMMAX(Type.CONFIG,
301 "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"
302 + "The equals sign (\"=\") separator must be used with no spaces.",
303 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
307 public static enum Opt
310 * A BOOLEAN Arg can be specified as --arg or --noarg to give true or false.
311 * A default can be given with setOptions(bool, Opt....).
312 * Use ArgParser.isSet(Arg) to see if this arg was not specified.
314 BOOLEAN("can be negated with " + ArgParser.DOUBLEDASH
315 + ArgParser.NEGATESTRING + "..."),
318 * A STRING Arg will take a value either through --arg=value or --arg value.
320 STRING("expects a value"),
322 * A UNARY Arg is a boolean value, true if present, false if not.
323 * Like BOOLEAN but without the --noarg option.
327 * A MULTI Arg can be specified multiple times.
328 * Multiple values are stored in the ArgValuesMap (along with their positional index) for each linkedId.
330 MULTIVALUE("can be specified multiple times"),
332 * A Linked Arg can be linked to others through a --arg[linkedId] or --arg[linkedId]=value.
333 * If no linkedId is specified then the current default linkedId will be used.
335 LINKED("is linked to an alignment"),
337 * A NODUPLICATES Arg can only have one value (per linkedId).
338 * The first value will be used and subsequent values ignored with a warning.
340 NODUPLICATEVALUES("cannot have the same value more than once"),
342 * A BOOTSTRAP Arg value(s) can be determined at an earlier stage than non-BOOTSTRAP Args.
343 * Substitutions do not happen in BOOTSTRAP Args and they cannot be linked or contain SubVals.
344 * See jalview.bin.argparser.BootstrapArgs.
346 BOOTSTRAP("a configuration argument"),
348 * A GLOB Arg can expand wildcard filename "globs" (e.g. path/* /filename*).
349 * If the Arg value is given as --arg filename* then the shell will have expanded the glob already,
350 * but if specified as --arg=filename* then the Java glob expansion method will be used
351 * (see FileUtils.getFilenamesFromGlob()).
352 * Note that this might be different from the shell expansion rules.
354 GLOB("can take multiple filenames with wildcards"),
356 * A NOACTION Arg does not perform a data task,
357 * usually used to control flow in ArgParser.parse(args).
361 * An ALLOWSUBSTITUTIONS Arg allows substitutions in its linkedId,
362 * SubVals and values.
364 ALLOWSUBSTITUTIONS("values can use substitutions"),
366 * A PRIVATE Arg is used internally, and cannot be specified by the user.
370 * A SECRET Arg is used by development processes and although it can be set by the user,
371 * it is not displayed to the user.
375 * An ALLOWALL Arg can use the '*' linkedId to apply to all known linkedIds
377 ALLOWMULTIID("can be used with " + ArgParser.DOUBLEDASH + "all"),
379 * If an Arg has the INCREMENTDEFAULTCOUNTER option and the default linkedId is used,
380 * the defaultLinkedIdCounter is incremented *first*.
382 INCREMENTDEFAULTCOUNTER("starts a new default alignment"),
384 * An INPUT Arg counts as an input for REQUIREINPUT
388 * A REQUIREINPUT Arg can only be applied via --all if there is an input
389 * (i.e. --open or --append)
393 * An OUTPUTFILE Arg provides an output filename. With Opt.ALLOWALL *.ext is shorthand for
394 * --all --output={basename}.ext
396 OUTPUTFILE("output file --headless will be assumed unless --gui used"),
398 * A STDOUT Arg can take an output filename that can be '-' to mean print to STDOUT.
400 STDOUT("allows the output filename '" + ArgParser.STDOUTFILENAME
401 + "' to mean output to STDOUT"),
403 * A STORED Arg resets and creates a new set of "opened" linkedIds
407 * A HELP Arg is a --help type arg
409 HELP("provides a help statement"),
411 * A PRIMARY Arg is the main Arg for its type
413 PRIMARY("is a primary argument for its type"),
415 * A HASTYPE Arg can have an Arg.Type assigned to its ArgValue
419 * A FIRST arg gets moved to appear first in the usage statement (within type)
423 * A LAST arg gets moved to appear last in the usage statement (within type)
427 * After other args are checked, the following args can prefix a KEY=VALUE argument
429 PREFIXKEV("prefixes key=value"),
431 * do not lowercase the name when getting the arg name or arg string
437 private String description;
444 private Opt(String description)
446 this.description = description;
449 public String description()
456 public static enum Type
458 // Type restricts argument to certain usage output
460 CONFIG("arguments used to configure "
461 + ChannelProperties.getProperty("app_name") + " from startup"),
462 OPENING("arguments used to open and format alignments"),
463 STRUCTURE("arguments used to add and format 3D structure data"),
464 PROCESS("arguments used to process an alignment once opened"),
465 OUTPUT("arguments used to save data from a processed alignment"),
466 IMAGE("arguments used to export an image of an alignment"),
467 STRUCTUREIMAGE("arguments used to export an image of an structure"),
468 FLOW("arguments that control processing of the other arguments"), //
469 ALL("all arguments"), // mostly just a place-holder for --help-all
470 NONE, // mostly a place-holder for --help
473 private String description;
480 private Type(String description)
482 this.description = description;
485 public String description()
491 private final String[] argNames;
493 private Opt[] argOptions;
495 private boolean defaultBoolValue;
497 private String description;
501 private Arg(Type type, String description, Opt... options)
503 this(type, null, description, false, options);
506 private Arg(Type type, String description, boolean defaultBoolean,
509 this(type, null, description, defaultBoolean, options);
512 private Arg(Type type, String alternativeName, String description,
515 this(type, alternativeName, description, false, options);
518 private Arg(Type type, String alternativeName, String description,
519 boolean defaultBoolean, Opt... options)
522 this.description = description;
523 this.defaultBoolValue = defaultBoolean;
524 this.setOptions(options);
525 this.argNames = alternativeName != null
527 { this.getName(), alternativeName }
532 public String argString()
534 return argString(false);
537 public String negateArgString()
539 return argString(true);
542 private String argString(boolean negate)
544 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
545 if (negate && hasOption(Opt.BOOLEAN))
546 sb.append(ArgParser.NEGATESTRING);
547 sb.append(getName());
548 return sb.toString();
551 public String toLongString()
553 StringBuilder sb = new StringBuilder();
554 sb.append(this.getClass().getName()).append('.').append(this.name());
556 if (getNames().length > 0)
558 sb.append(String.join("\", \"", getNames()));
559 if (getNames().length > 0)
562 sb.append("\nType: " + type.name());
563 sb.append("\nOpt: ");
564 // map List<Opt> to List<String> for the String.join
565 List<String> optList = Arrays.asList(argOptions).stream()
566 .map(opt -> opt.name()).collect(Collectors.toList());
567 sb.append(String.join(", ", optList));
569 return sb.toString();
572 public String[] getNames()
577 public String getName()
579 String name = hasOption(Opt.PRESERVECASE) ? this.name()
580 : this.name().toLowerCase(Locale.ROOT);
581 return name.replace('_', '-');
585 public final String toString()
590 public boolean hasOption(Opt o)
592 if (argOptions == null)
594 for (Opt option : argOptions)
602 public boolean hasAllOptions(Opt... opts)
606 if (!this.hasOption(o))
612 protected Opt[] getOptions()
617 protected void setOptions(Opt... options)
619 this.argOptions = options;
622 protected boolean getDefaultBoolValue()
624 return defaultBoolValue;
627 public Type getType()
632 protected String getDescription()
637 public static String booleanArgString(Arg a)
639 StringBuilder sb = new StringBuilder(a.argString());
640 if (a.hasOption(Opt.BOOLEAN))
643 sb.append(a.negateArgString());
645 return sb.toString();
648 public static final String usage()
653 public static final void appendUsageGeneral(StringBuilder sb,
656 for (Type t : EnumSet.allOf(Type.class))
658 if (t.description() != null)
660 StringBuilder argSb = new StringBuilder();
661 argSb.append(Arg.HELP.argString()).append(ArgParser.SINGLEDASH)
662 .append(t.name().toLowerCase(Locale.ROOT));
663 appendArgAndDescription(sb, argSb.toString(),
664 "Help for " + t.description(), null, maxArgLength);
665 sb.append(System.lineSeparator());
670 public static final String usage(List<Type> types)
672 StringBuilder sb = new StringBuilder();
674 sb.append("usage: jalview [" + Arg.HEADLESS.argString() + "] [["
675 + Arg.OPEN.argString() + "/" + Arg.APPEND.argString()
676 + "] file(s)] [args]");
677 sb.append(System.lineSeparator());
678 sb.append(System.lineSeparator());
680 if (types == null || types.contains(null))
682 // always show --help
683 appendArgAndDescription(sb, null, "Display this basic help", Arg.HELP,
685 sb.append(System.lineSeparator());
687 appendUsageGeneral(sb, DESCRIPTIONINDENT);
691 List<Arg> args = argsSortedForDisplay(types);
694 * just use a set maxArgLength of DESCRIPTIONINDENT
696 int maxArgLength = 0;
699 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
702 String argS = argDisplayString(a);
703 if (argS.length() > maxArgLength)
704 maxArgLength = argS.length();
707 int maxArgLength = DESCRIPTIONINDENT;
709 // always show --help
710 appendArgAndDescription(sb, null, null, Arg.HELP, maxArgLength);
711 sb.append(System.lineSeparator());
713 if ((args.contains(Arg.HELP) && types.contains(Type.ALL)))
715 appendUsageGeneral(sb, maxArgLength);
718 Iterator<Arg> argsI = args.iterator();
719 Type typeSection = null;
720 while (argsI.hasNext())
722 Arg a = argsI.next();
724 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET)
730 if (a.getType() != typeSection)
732 typeSection = a.getType();
733 String typeDescription = a.getType().description();
734 if (typeDescription != null && typeDescription.length() > 0)
736 // typeDescription = typeDescription.substring(0,
737 // 1).toUpperCase(Locale.ROOT) + typeDescription.substring(1);
738 typeDescription = typeDescription.toUpperCase(Locale.ROOT);
739 sb.append(typeDescription);
740 sb.append(System.lineSeparator());
741 sb.append(System.lineSeparator());
745 appendArgUsage(sb, a, maxArgLength, Platform.consoleWidth());
749 sb.append(System.lineSeparator());
753 return sb.toString();
756 private static void appendArgUsage(StringBuilder sb, Arg a,
757 int maxArgLength, int maxWidth)
759 boolean first = appendArgAndDescription(sb, null, null, a,
761 List<String> options = new ArrayList<>();
763 for (Opt o : EnumSet.allOf(Opt.class))
765 if (a.hasOption(o) && o.description() != null)
767 options.add(o.description());
771 final String optDisplaySeparator = "; ";
772 if (options.size() > 0)
775 String spacing = String.format("%-"
776 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
780 sb.append(ARGDESCRIPTIONSEPARATOR);
781 linelength += maxArgLength + ARGDESCRIPTIONSEPARATOR.length();
786 linelength += spacing.length();
788 if (options.size() > 0)
790 boolean optFirst = true;
791 Iterator<String> optionsI = options.listIterator();
792 while (optionsI.hasNext())
794 String desc = optionsI.next();
800 int descLength = desc.length()
801 + (optionsI.hasNext() ? optDisplaySeparator.length() : 0);
802 if (linelength + descLength > maxWidth)
804 sb.append(System.lineSeparator());
807 linelength += spacing.length();
809 // sb.append(linelength + "+" + desc.length() + " ");
811 linelength += desc.length();
812 if (optionsI.hasNext())
814 sb.append(optDisplaySeparator);
815 linelength += optDisplaySeparator.length();
820 sb.append(System.lineSeparator());
825 public static String argDisplayString(Arg a)
827 StringBuilder argSb = new StringBuilder();
829 a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
830 if (a.hasOption(Opt.STRING))
832 if (a.hasOption(Opt.PREFIXKEV))
834 argSb.append("key=value");
838 argSb.append("=value");
841 return argSb.toString();
844 public static boolean appendArgAndDescription(StringBuilder sb,
845 String aString, String description, Arg a, int maxArgLength)
847 return appendArgAndDescription(sb, aString, description, a,
848 maxArgLength, Platform.consoleWidth());
851 public static boolean appendArgAndDescription(StringBuilder sb,
852 String aString, String description, Arg a, int maxArgLength,
855 if (aString == null && a != null)
857 aString = argDisplayString(a);
859 if (description == null && a != null)
861 description = a.getDescription();
863 sb.append(String.format("%-" + maxArgLength + "s", aString));
864 if (aString.length() > maxArgLength)
866 sb.append(System.lineSeparator());
867 sb.append(String.format("%-" + maxArgLength + "s", ""));
870 int descLength = maxLength - maxArgLength
871 - ARGDESCRIPTIONSEPARATOR.length();
872 // reformat the descriptions lines to the right width
873 Iterator<String> descLines = null;
874 if (description != null)
876 descLines = Arrays.stream(description.split("\\n")).iterator();
878 List<String> splitDescLinesList = new ArrayList<>();
879 while (descLines != null && descLines.hasNext())
881 String line = descLines.next();
882 while (line.length() > descLength)
884 int splitIndex = line.lastIndexOf(" ", descLength);
885 splitDescLinesList.add(line.substring(0, splitIndex));
886 line = line.substring(splitIndex + 1);
888 splitDescLinesList.add(line);
891 Iterator<String> splitDescLines = splitDescLinesList.iterator();
892 boolean first = true;
893 if (splitDescLines != null)
895 while (splitDescLines.hasNext())
899 sb.append(ARGDESCRIPTIONSEPARATOR);
903 sb.append(String.format("%-"
904 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
907 sb.append(splitDescLines.next());
908 sb.append(System.lineSeparator());
915 protected static Iterator<Arg> getAllOfType(Type type)
917 return getAllOfType(type, new Opt[] {});
920 protected static Iterator<Arg> getAllOfType(Type type, Opt... options)
922 Opt[] opts = options == null ? new Opt[] {} : options;
923 return EnumSet.allOf(Arg.class).stream().filter(a -> {
924 if (a.getType() != type)
935 private static List<Arg> argsSortedForDisplay(List<Type> types)
937 List<Arg> argsToSort;
938 // if no types provided, do all
939 if (types == null || types.size() == 0 || types.contains(Type.ALL))
942 .asList(EnumSet.allOf(Arg.class).toArray(new Arg[] {}));
946 argsToSort = new ArrayList<>();
947 for (Type type : types)
951 Arg.getAllOfType(type).forEachRemaining(a -> argsToSort.add(a));
955 Collections.sort(argsToSort, new ArgDisplayComparator());
959 private static final String ARGDESCRIPTIONSEPARATOR = " - ";
961 private static final int DESCRIPTIONINDENT = 20;
965 class ArgDisplayComparator implements Comparator<Arg>
967 private int compareArgOpts(Arg a, Arg b, Opt o)
969 int i = a.hasOption(o) ? (b.hasOption(o) ? 0 : -1)
970 : (b.hasOption(o) ? 1 : 0);
974 private int compareForDisplay(Arg a, Arg b)
978 // first compare types (in enum order)
979 int i = a.getType().compareTo(b.getType());
982 // do Opt.LAST next (oddly). Reversed args important!
983 i = compareArgOpts(b, a, Opt.LAST);
987 Opt[] optOrder = { Opt.HELP, Opt.FIRST, Opt.PRIMARY, Opt.STRING,
989 for (Opt o : optOrder)
991 i = compareArgOpts(a, b, o);
995 // finally order of appearance in enum declarations
996 return a.compareTo(b);
1000 public int compare(Arg a, Arg b)
1002 return compareForDisplay(a, b);