Clover icon

Coverage Report

  1. Project Clover database Thu Nov 28 2024 11:45:30 GMT
  2. Package jalview.bin.argparser

File Arg.java

 

Coverage histogram

../../../img/srcFileCovDistChart2.png
57% of files have more coverage

Code metrics

104
228
46
4
1,073
837
111
0.49
4.96
11.5
2.41

Classes

Class Line # Actions
Arg 39 205 95
0.2168674821.7%
Arg.Opt 326 3 3
0.3333333433.3%
Arg.Type 475 3 3
0.666666766.7%
ArgDisplayComparator 1034 17 10
0.00%
 

Contributing tests

This file is covered by 124 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.bin.argparser;
22   
23    import java.util.ArrayList;
24    import java.util.Arrays;
25    import java.util.Collections;
26    import java.util.Comparator;
27    import java.util.EnumSet;
28    import java.util.HashSet;
29    import java.util.Iterator;
30    import java.util.List;
31    import java.util.Locale;
32    import java.util.Set;
33    import java.util.stream.Collectors;
34   
35    import jalview.bin.argparser.Arg.Opt;
36    import jalview.util.ChannelProperties;
37    import jalview.util.Platform;
38   
 
39    public enum Arg
40    {
41   
42    // Initialising arguments (BOOTSTRAP)
43    HELP(Type.HELP, "h", "Display basic help", Opt.UNARY, Opt.BOOTSTRAP,
44    Opt.HASTYPE, Opt.MULTIVALUE),
45    /*
46    * Other --help-type Args will be added by the static block.
47    */
48    VERSION(Type.CONFIG, "v",
49    "Display the version of "
50    + ChannelProperties.getProperty("app_name"),
51    Opt.UNARY, Opt.BOOTSTRAP),
52    HEADLESS(Type.CONFIG,
53    "Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed. "
54    + "Headless mode is assumed if an output file is to be generated, this can be overridden with --gui.",
55    Opt.UNARY, Opt.BOOTSTRAP),
56    GUI(Type.CONFIG,
57    "Do not run Jalview in headless mode. This overrides the assumption of headless mode when an output file is to be generated.",
58    Opt.UNARY, Opt.BOOTSTRAP),
59    JABAWS(Type.CONFIG, "Set a different URL to connect to a JABAWS server.",
60    Opt.STRING, Opt.BOOTSTRAP),
61    NEWS(Type.CONFIG, "Show (or don't show) the news feed.", true,
62    Opt.BOOLEAN, Opt.BOOTSTRAP),
63    SPLASH(Type.CONFIG,
64    "Show (or don't show) the About Jalview splash screen.", true,
65    Opt.BOOLEAN, Opt.BOOTSTRAP),
66    QUESTIONNAIRE(Type.CONFIG,
67    "Show (or don't show) the questionnaire if one is available.",
68    true, Opt.BOOLEAN, Opt.BOOTSTRAP),
69    JAVACONSOLE(Type.CONFIG, "Show (or don't show) the Java Console.", false,
70    Opt.BOOLEAN, Opt.BOOTSTRAP),
71    NOUSAGESTATS(Type.CONFIG, "Don't send initial launch usage stats.",
72    Opt.UNARY, Opt.BOOTSTRAP),
73    NOSTARTUPFILE(Type.CONFIG, "Don't show the default startup file.",
74    Opt.UNARY, Opt.BOOTSTRAP),
75    WEBSERVICEDISCOVERY(Type.CONFIG,
76    "Attempt (or don't attempt) to connect to JABAWS web services.",
77    true, Opt.BOOLEAN, Opt.BOOTSTRAP),
78    PROPS(Type.CONFIG,
79    "Use a file as the preferences file instead of the usual ~/"
80    + ChannelProperties.getProperty("preferences.filename")
81    + " file.",
82    Opt.STRING, Opt.BOOTSTRAP),
83    DEBUG(Type.CONFIG, "d", "Start Jalview in debug log level.", Opt.BOOLEAN,
84    Opt.BOOTSTRAP),
85    TRACE(Type.CONFIG, "Start Jalview in trace log level.", Opt.BOOLEAN,
86    Opt.BOOTSTRAP, Opt.SECRET),
87    QUIET(Type.CONFIG, "q",
88    "Stop all output to STDOUT (after the Java Virtual Machine has started). Use ‑‑quiet a second time to stop all output to STDERR.",
89    Opt.UNARY, Opt.MULTIVALUE, Opt.BOOTSTRAP),
90    INITSUBSTITUTIONS(Type.CONFIG,
91    "Set ‑‑substitutions to be initially enabled (or initially disabled).",
92    true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
93    P(Type.CONFIG, "Set a Jalview preference value for this session.",
94    Opt.PREFIXKEV, Opt.PRESERVECASE, Opt.STRING, Opt.BOOTSTRAP,
95    Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET), // keep this secret for
96    // now.
97   
98    // Opening an alignment
99    OPEN(Type.OPENING,
100    "Opens one or more alignment files or URLs in new alignment windows.",
101    Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER,
102    Opt.MULTIVALUE, Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT,
103    Opt.STORED, Opt.PRIMARY),
104    APPEND(Type.OPENING,
105    "Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
106    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.GLOB,
107    Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.PRIMARY),
108    TITLE(Type.OPENING,
109    "Specifies the title for the open alignment window as string.",
110    Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
111    COLOUR(Type.OPENING, "color", // being a bit soft on the Americans!
112    "Applies the colour scheme to the open alignment window. Valid values include:\n"
113    + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
114    + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
115    + "gecos-blossom,\n" + "gecos-sunset,\n"
116    + "gecos-ocean,\n" + "hydrophobic,\n"
117    + "helix-propensity,\n" + "strand-propensity,\n"
118    + "turn-propensity,\n" + "buried-index,\n"
119    + "nucleotide,\n" + "nucleotide-ambiguity,\n"
120    + "purine-pyrimidine,\n" + "rna-helices,\n"
121    + "t-coffee-scores,\n" + "sequence-id.\n" + "\n"
122    + "Names of user defined colourschemes will also work,\n"
123    + "and jalview colourscheme specifications like\n"
124    + "--colour=\"D,E=red; K,R,H=0022FF; C,c=yellow\"",
125    Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
126    FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
127    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
128    Opt.ALLOWMULTIID),
129    TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
130    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
131    Opt.ALLOWMULTIID),
132    SORTBYTREE(Type.OPENING,
133    "Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
134    true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWMULTIID),
135    ANNOTATIONS(Type.OPENING,
136    "Add an annotations file or URL to the open alignment.",
137    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
138    Opt.ALLOWMULTIID),
139    SHOWANNOTATIONS(Type.OPENING,
140    "Enforces showing (or not showing) alignment annotations.",
141    Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
142    WRAP(Type.OPENING,
143    "Enforces wrapped (or not wrapped) alignment formatting.",
144    Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
145    NOSTRUCTURE(Type.OPENING,
146    "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
147    Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
148   
149    // Adding a 3D structure
150    STRUCTURE(Type.STRUCTURE,
151    "Load a structure file or URL associated with a sequence in the open alignment.\n"
152    + "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.",
153    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
154    Opt.PRIMARY, Opt.ALLOWMULTIID),
155    SEQID(Type.STRUCTURE,
156    "Specify the sequence name for the preceding --structure to be associated with.",
157    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
158    Opt.ALLOWMULTIID),
159    PAEMATRIX(Type.STRUCTURE,
160    "Add a PAE json matrix file to the preceding --structure.",
161    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
162    Opt.ALLOWMULTIID),
163    TEMPFAC(Type.STRUCTURE,
164    "Set the type of temperature factor. Possible values are:\n"
165    + "default,\n" + "plddt.",
166    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
167    STRUCTUREVIEWER(Type.STRUCTURE,
168    "Set the structure viewer to use to open the 3D structure file specified in previous --structure to name. Possible values of name are:\n"
169    + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
170    + "pymol.",
171    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
172    NOTEMPFAC(Type.STRUCTURE,
173    "Do not show the temperature factor annotation for the preceding --structure.",
174    Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.SECRET), // keep this
175    // secret until
176    // it works!
177    SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
178    Opt.ALLOWMULTIID),
179   
180    // Outputting files
181    IMAGE(Type.IMAGE,
182    "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"
183    + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
184    Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.MULTIVALUE,
185    Opt.ALLOWMULTIID, Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
186    STRUCTUREIMAGE(new Type[]
187    { Type.IMAGE, Type.STRUCTUREIMAGE },
188    "Export an image of a 3D structure opened in JMOL", Opt.STRING,
189    Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID,
190    Opt.PRIMARY),
191    TYPE(Type.IMAGE,
192    "Set the image format for the preceding " + Arg.IMAGE.argString()
193    + " or " + Arg.STRUCTUREIMAGE.argString()
194    + ". Valid values are:\n" + "svg,\n" + "png,\n" + "eps,\n"
195    + "html,\n" + "biojs.",
196    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
197    TEXTRENDERER(Type.IMAGE,
198    "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n"
199    + "text,\n" + "lineart.",
200    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
201    SCALE(Type.IMAGE,
202    "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).",
203    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
204    WIDTH(Type.IMAGE,
205    "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).",
206    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
207    HEIGHT(Type.IMAGE,
208    "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).",
209    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
210    IMAGECOLOUR(Type.IMAGE, "imagecolor", // being a bit soft on the Americans!
211    "Applies the colour scheme to the open alignment window for this image, otherwise the value of "
212    + Arg.COLOUR.argString()
213    + " (or none) will apply. Valid values are the same as "
214    + Arg.COLOUR.argString() + ".",
215    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
216    BGCOLOUR(Type.IMAGE, "bgcolor", // being a bit soft on the Americans!
217    "Applies a background colour to the structure image. Valid values are named colours known to Java or RRGGBB 6 digit hex-string.",
218    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
219    OUTPUT(Type.OUTPUT,
220    "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"
221    + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
222    + "stockholm (sto, stk),\n" + "pir (pir),\n"
223    + "blc (blc),\n" + "amsa (amsa),\n" + "json (json),\n"
224    + "pileup (pileup),\n" + "msf (msf),\n"
225    + "clustal (aln),\n" + "phylip (phy),\n"
226    + "jalview (jvp, jar).",
227    Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWMULTIID,
228    Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.STDOUT, Opt.PRIMARY),
229    FORMAT(Type.OUTPUT,
230    "Sets the format for the preceding --output file. Valid formats are:\n"
231    + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n"
232    + "blc,\n" + "amsa,\n" + "json,\n" + "pileup,\n"
233    + "msf,\n" + "clustal,\n" + "phylip,\n" + "jalview.",
234    Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
235    GROOVY(Type.PROCESS,
236    "Process a groovy script in the file for the open alignment.",
237    Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
238    Opt.ALLOWMULTIID),
239    BACKUPS(Type.OUTPUT,
240    "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.",
241    true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
242    OVERWRITE(Type.OUTPUT,
243    "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.",
244    Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
245    CLOSE(Type.OPENING,
246    "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.",
247    Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
248    MKDIRS(Type.OUTPUT,
249    "Automatically create directories when outputting a file to a new directory.",
250    Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
251   
252    // controlling flow of arguments
253    NEW(Type.FLOW,
254    "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.",
255    Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION,
256    Opt.INCREMENTDEFAULTCOUNTER),
257    SUBSTITUTIONS(Type.FLOW,
258    "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are:\n"
259    + "{basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
260    + "{dirname} - the directory (folder) name of the currently --opened file (or first --appended file),\n"
261    + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
262    + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
263    + "{n} - the value of the index counter (starting at 0).\n"
264    + "{++n} - increase and substitute the value of the index counter,\n"
265    + "{} - the value of the current alignment window default index.",
266    true, Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
267    ARGFILE(Type.FLOW,
268    "Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
269    + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
270    + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
271    Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.GLOB,
272    Opt.ALLOWSUBSTITUTIONS),
273    NPP(Type.FLOW, "n++",
274    "Increase the index counter used in argument value substitutions.",
275    Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION),
276    ALL(Type.FLOW,
277    "Apply the following output arguments to all sets of linked arguments.",
278    Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
279    OPENED(Type.FLOW,
280    "Apply the following output arguments to all of the last --open'ed set of linked arguments.",
281    Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
282    QUIT(Type.FLOW,
283    "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
284    Opt.UNARY),
285    NOQUIT(Type.FLOW,
286    "Secret arg to not quit after --headless mode for tests",
287    Opt.UNARY, Opt.SECRET),
288    ALLSTRUCTURES(Type.FLOW,
289    "Apply the following 3D structure formatting arguments to all structures within the open alignment.",
290    Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
291   
292    // secret options
293    TESTOUTPUT(Type.CONFIG,
294    "Allow specific stdout information. For testing purposes only.",
295    Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
296    SETPROP(Type.CONFIG, "Set an individual Java System property.",
297    Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.SECRET), // not in use
298    // yet
299    NIL(Type.FLOW,
300    "This argument does nothing on its own, but can be used with linkedIds.",
301    Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET),
302   
303    // private options (inserted during arg processing)
304    SETARGFILE(Type.FLOW,
305    "Sets the current value of the argfilename. Inserted before argfilecontents.",
306    Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTIVALUE, Opt.PRIVATE,
307    Opt.NOACTION),
308    UNSETARGFILE(Type.FLOW,
309    "Unsets the current value of the argfilename. Inserted after argfile contents.",
310    Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.PRIVATE, Opt.NOACTION),
311   
312    // these last two have no purpose in the normal Jalview application but are
313    // used by jalview.bin.Launcher to set memory settings. They are not used by
314    // argparser but are here for Usage statement and parsing reasons.
315    JVMMEMPC(Type.CONFIG,
316    "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
317    + "The equals sign (\"=\") separator must be used with no spaces.",
318    Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
319    JVMMEMMAX(Type.CONFIG,
320    "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"
321    + "The equals sign (\"=\") separator must be used with no spaces.",
322    Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
323   
324    ;
325   
 
326    public static enum Opt
327    {
328    /*
329    * A BOOLEAN Arg can be specified as --arg or --noarg to give true or false.
330    * A default can be given with setOptions(bool, Opt....).
331    * Use ArgParser.isSet(Arg) to see if this arg was not specified.
332    */
333    BOOLEAN("can be negated with " + ArgParser.DOUBLEDASH
334    + ArgParser.NEGATESTRING + "..."),
335   
336    /*
337    * A STRING Arg will take a value either through --arg=value or --arg value.
338    */
339    STRING("expects a value"),
340    /*
341    * A UNARY Arg is a boolean value, true if present, false if not.
342    * Like BOOLEAN but without the --noarg option.
343    */
344    UNARY(null),
345    /*
346    * A MULTI Arg can be specified multiple times.
347    * Multiple values are stored in the ArgValuesMap (along with their positional index) for each linkedId.
348    */
349    MULTIVALUE("can be specified multiple times"),
350    /*
351    * A Linked Arg can be linked to others through a --arg[linkedId] or --arg[linkedId]=value.
352    * If no linkedId is specified then the current default linkedId will be used.
353    */
354    LINKED("is linked to an alignment"),
355    /*
356    * A NODUPLICATES Arg can only have one value (per linkedId).
357    * The first value will be used and subsequent values ignored with a warning.
358    */
359    NODUPLICATEVALUES("cannot have the same value more than once"),
360    /*
361    * A BOOTSTRAP Arg value(s) can be determined at an earlier stage than non-BOOTSTRAP Args.
362    * Substitutions do not happen in BOOTSTRAP Args and they cannot be linked or contain SubVals.
363    * See jalview.bin.argparser.BootstrapArgs.
364    */
365    BOOTSTRAP("a configuration argument"),
366    /*
367    * A GLOB Arg can expand wildcard filename "globs" (e.g. path/* /filename*).
368    * If the Arg value is given as --arg filename* then the shell will have expanded the glob already,
369    * but if specified as --arg=filename* then the Java glob expansion method will be used
370    * (see FileUtils.getFilenamesFromGlob()).
371    * Note that this might be different from the shell expansion rules.
372    */
373    GLOB("can take multiple filenames with wildcards"),
374    /*
375    * A NOACTION Arg does not perform a data task,
376    * usually used to control flow in ArgParser.parse(args).
377    */
378    NOACTION(null),
379    /*
380    * An ALLOWSUBSTITUTIONS Arg allows substitutions in its linkedId,
381    * SubVals and values.
382    */
383    ALLOWSUBSTITUTIONS("values can use substitutions"),
384    /*
385    * A PRIVATE Arg is used internally, and cannot be specified by the user.
386    */
387    PRIVATE(null),
388    /*
389    * A SECRET Arg is used by development processes and although it can be set by the user,
390    * it is not displayed to the user.
391    */
392    SECRET(null),
393    /*
394    * An ALLOWALL Arg can use the '*' linkedId to apply to all known linkedIds
395    */
396    ALLOWMULTIID("can be used with " + ArgParser.DOUBLEDASH + "all"),
397    /*
398    * If an Arg has the INCREMENTDEFAULTCOUNTER option and the default linkedId is used,
399    * the defaultLinkedIdCounter is incremented *first*.
400    */
401    INCREMENTDEFAULTCOUNTER("starts a new default alignment"),
402    /*
403    * An INPUT Arg counts as an input for REQUIREINPUT
404    */
405    INPUT(null),
406    /*
407    * A REQUIREINPUT Arg can only be applied via --all if there is an input
408    * (i.e. --open or --append)
409    */
410    REQUIREINPUT(null),
411    /*
412    * An OUTPUTFILE Arg provides an output filename. With Opt.ALLOWALL *.ext is shorthand for
413    * --all --output={basename}.ext
414    */
415    OUTPUTFILE("output file --headless will be assumed unless --gui used"),
416    /*
417    * A STDOUT Arg can take an output filename that can be '-' to mean print to STDOUT.
418    */
419    STDOUT("allows the output filename '" + ArgParser.STDOUTFILENAME
420    + "' to mean output to STDOUT"),
421    /*
422    * A STORED Arg resets and creates a new set of "opened" linkedIds
423    */
424    STORED(null),
425    /*
426    * A HELP Arg is a --help type arg
427    */
428    HELP("provides a help statement"),
429    /*
430    * A PRIMARY Arg is the main Arg for its type
431    */
432    PRIMARY("is a primary argument for its type"),
433    /*
434    * A HASTYPE Arg can have an Arg.Type assigned to its ArgValue
435    */
436    HASTYPE(null),
437    /*
438    * A FIRST arg gets moved to appear first in the usage statement (within type)
439    */
440    FIRST(null),
441    /*
442    * A LAST arg gets moved to appear last in the usage statement (within type)
443    */
444    LAST(null),
445    /*
446    * After other args are checked, the following args can prefix a KEY=VALUE argument
447    */
448    PREFIXKEV("prefixes key=value"),
449    /*
450    * do not lowercase the name when getting the arg name or arg string
451    */
452    PRESERVECASE(null),
453    //
454    ;
455   
456    private String description;
457   
 
458  0 toggle private Opt()
459    {
460  0 description = null;
461    }
462   
 
463  1404 toggle private Opt(String description)
464    {
465  1404 this.description = description;
466    }
467   
 
468  0 toggle public String description()
469    {
470  0 return description;
471    }
472   
473    }
474   
 
475    public static enum Type
476    {
477    // Type restricts argument to certain usage output
478    HELP, // --help
479    CONFIG("arguments used to configure "
480    + ChannelProperties.getProperty("app_name") + " from startup"),
481    OPENING("arguments used to open and format alignments"),
482    STRUCTURE("arguments used to add and format 3D structure data"),
483    PROCESS("arguments used to process an alignment once opened"),
484    OUTPUT("arguments used to save data from a processed alignment"),
485    IMAGE("arguments used to export an image of an alignment"),
486    STRUCTUREIMAGE("arguments used to export an image of an structure"),
487    FLOW("arguments that control processing of the other arguments"), //
488    ALL("all arguments"), // mostly just a place-holder for --help-all
489    NONE, // mostly a place-holder for --help
490    INVALID;
491   
492    private String description;
493   
 
494  162 toggle private Type()
495    {
496  162 description = null;
497    }
498   
 
499  486 toggle private Type(String description)
500    {
501  486 this.description = description;
502    }
503   
 
504  0 toggle public String description()
505    {
506  0 return description;
507    }
508    }
509   
510    private final String[] argNames;
511   
512    private Opt[] argOptions;
513   
514    private boolean defaultBoolValue;
515   
516    private String description;
517   
518    private Type[] types;
519   
 
520  2700 toggle private Arg(Type type, String description, Opt... options)
521    {
522  2700 this(new Type[] { type }, description, options);
523    }
524   
 
525  2754 toggle private Arg(Type[] type, String description, Opt... options)
526    {
527  2754 this(type, null, description, false, options);
528    }
529   
 
530  486 toggle private Arg(Type type, String description, boolean defaultBoolean,
531    Opt... options)
532    {
533  486 this(new Type[] { type }, description, defaultBoolean, options);
534    }
535   
 
536  486 toggle private Arg(Type[] type, String description, boolean defaultBoolean,
537    Opt... options)
538    {
539  486 this(type, null, description, defaultBoolean, options);
540    }
541   
 
542  432 toggle private Arg(Type type, String alternativeName, String description,
543    Opt... options)
544    {
545  432 this(new Type[] { type }, alternativeName, description, options);
546    }
547   
 
548  432 toggle private Arg(Type[] type, String alternativeName, String description,
549    Opt... options)
550    {
551  432 this(type, alternativeName, description, false, options);
552    }
553   
 
554  0 toggle private Arg(Type type, String alternativeName, String description,
555    boolean defaultBoolean, Opt... options)
556    {
557  0 this(new Type[] { type }, alternativeName, description, defaultBoolean,
558    options);
559    }
560   
 
561  3672 toggle private Arg(Type[] type, String alternativeName, String description,
562    boolean defaultBoolean, Opt... options)
563    {
564  3672 this.types = type;
565  3672 this.description = description;
566  3672 this.defaultBoolValue = defaultBoolean;
567  3672 this.setOptions(options);
568  3672 this.argNames = alternativeName != null
569    ? new String[]
570    { this.getName(), alternativeName }
571    : new String[]
572    { this.getName() };
573    }
574   
 
575  604 toggle public String argString()
576    {
577  604 return argString(false);
578    }
579   
 
580  1 toggle public String negateArgString()
581    {
582  1 return argString(true);
583    }
584   
 
585  605 toggle private String argString(boolean negate)
586    {
587  605 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
588  605 if (negate && hasOption(Opt.BOOLEAN))
589  1 sb.append(ArgParser.NEGATESTRING);
590  605 sb.append(getName());
591  605 return sb.toString();
592    }
593   
 
594  0 toggle public String toLongString()
595    {
596  0 StringBuilder sb = new StringBuilder();
597  0 sb.append(this.getClass().getName()).append('.').append(this.name());
598  0 sb.append('(');
599  0 if (getNames().length > 0)
600  0 sb.append('"');
601  0 sb.append(String.join("\", \"", getNames()));
602  0 if (getNames().length > 0)
603  0 sb.append('"');
604  0 sb.append(")\n");
605  0 for (Type type : getTypes())
606    {
607  0 String typeName = type.name();
608  0 sb.append("\nType: " + typeName);
609    }
610  0 sb.append("\nOpt: ");
611    // map List<Opt> to List<String> for the String.join
612  0 List<String> optList = Arrays.asList(argOptions).stream()
613    .map(opt -> opt.name()).collect(Collectors.toList());
614  0 sb.append(String.join(", ", optList));
615  0 sb.append("\n");
616  0 return sb.toString();
617    }
618   
 
619  3672 toggle public String[] getNames()
620    {
621  3672 return argNames;
622    }
623   
 
624  7638 toggle public String getName()
625    {
626  7638 String name = hasOption(Opt.PRESERVECASE) ? this.name()
627    : this.name().toLowerCase(Locale.ROOT);
628  7638 return name.replace('_', '-');
629    }
630   
 
631  839 toggle @Override
632    public final String toString()
633    {
634  839 return getName();
635    }
636   
 
637  40167 toggle public boolean hasOption(Opt o)
638    {
639  40167 if (argOptions == null)
640  0 return false;
641  40167 for (Opt option : argOptions)
642    {
643  153664 if (o == option)
644  10152 return true;
645    }
646  30015 return false;
647    }
648   
 
649  0 toggle public boolean hasAllOptions(Opt... opts)
650    {
651  0 for (Opt o : opts)
652    {
653  0 if (!this.hasOption(o))
654  0 return false;
655    }
656  0 return true;
657    }
658   
 
659  880 toggle protected Opt[] getOptions()
660    {
661  880 return argOptions;
662    }
663   
 
664  3672 toggle protected void setOptions(Opt... options)
665    {
666  3672 this.argOptions = options;
667    }
668   
 
669  1782 toggle protected boolean getDefaultBoolValue()
670    {
671  1782 return defaultBoolValue;
672    }
673   
 
674  6 toggle public Type getFirstType()
675    {
676  6 return this.getTypes()[0];
677    }
678   
 
679  5046 toggle public Type[] getTypes()
680    {
681  5046 return this.types;
682    }
683   
 
684  2011 toggle public boolean sharesType(Arg a)
685    {
686  2011 return this.hasType(a.getTypes());
687    }
688   
 
689  2044 toggle public boolean hasType(Type... types)
690    {
691  2044 Set<Type> typesSet = new HashSet<>(Arrays.asList(types));
692  2044 return this.hasType(typesSet);
693    }
694   
 
695  2134 toggle public boolean hasType(Set<Type> typesSet)
696    {
697  2134 for (Type type : getTypes())
698    {
699  2183 if (typesSet.contains(type))
700    {
701  1096 return true;
702    }
703    }
704  1038 return false;
705    }
706   
 
707  0 toggle protected String getDescription()
708    {
709  0 return description;
710    }
711   
 
712  0 toggle public static String booleanArgString(Arg a)
713    {
714  0 StringBuilder sb = new StringBuilder(a.argString());
715  0 if (a.hasOption(Opt.BOOLEAN))
716    {
717  0 sb.append('/');
718  0 sb.append(a.negateArgString());
719    }
720  0 return sb.toString();
721    }
722   
 
723  0 toggle public static final String usage()
724    {
725  0 return usage(null);
726    }
727   
 
728  0 toggle public static final void appendUsageGeneral(StringBuilder sb,
729    int maxArgLength)
730    {
731  0 Set<Type> firstTypes = new HashSet<>();
732  0 for (Arg a : EnumSet.allOf(Arg.class))
733    {
734  0 if (!firstTypes.contains(a.getFirstType()))
735    {
736  0 firstTypes.add(a.getFirstType());
737    }
738    }
739  0 for (Type t : EnumSet.allOf(Type.class))
740    {
741  0 if (t.description() != null && firstTypes.contains(t))
742    {
743  0 StringBuilder argSb = new StringBuilder();
744  0 argSb.append(Arg.HELP.argString()).append(ArgParser.SINGLEDASH)
745    .append(t.name().toLowerCase(Locale.ROOT));
746  0 appendArgAndDescription(sb, argSb.toString(),
747    "Help for " + t.description(), null, maxArgLength);
748  0 sb.append(System.lineSeparator());
749    }
750    }
751    }
752   
 
753  0 toggle public static final String usage(List<Type> types)
754    {
755  0 StringBuilder sb = new StringBuilder();
756   
757  0 sb.append("usage: jalview [" + Arg.HEADLESS.argString() + "] [["
758    + Arg.OPEN.argString() + "/" + Arg.APPEND.argString()
759    + "] file(s)] [args]");
760  0 sb.append(System.lineSeparator());
761  0 sb.append(System.lineSeparator());
762   
763  0 if (types == null || types.contains(null))
764    {
765    // always show --help
766  0 appendArgAndDescription(sb, null, "Display this basic help", Arg.HELP,
767    DESCRIPTIONINDENT);
768  0 sb.append(System.lineSeparator());
769   
770  0 appendUsageGeneral(sb, DESCRIPTIONINDENT);
771    }
772    else
773    {
774  0 List<Arg> args = argsSortedForDisplay(types);
775   
776  0 int maxArgLength = DESCRIPTIONINDENT;
777   
778    // always show --help
779  0 appendArgAndDescription(sb, null, null, Arg.HELP, maxArgLength);
780  0 sb.append(System.lineSeparator());
781   
782  0 if ((args.contains(Arg.HELP) && types.contains(Type.ALL)))
783    {
784  0 appendUsageGeneral(sb, maxArgLength);
785    }
786   
787  0 Iterator<Arg> argsI = args.iterator();
788  0 Type typeSection = null;
789  0 while (argsI.hasNext())
790    {
791  0 Arg a = argsI.next();
792   
793  0 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET)
794    || a == Arg.HELP)
795    {
796  0 continue;
797    }
798   
799  0 if (a.getFirstType() != typeSection)
800    {
801  0 typeSection = a.getFirstType();
802  0 String typeDescription = a.getFirstType().description();
803  0 if (typeDescription != null && typeDescription.length() > 0)
804    {
805    // typeDescription = typeDescription.substring(0,
806    // 1).toUpperCase(Locale.ROOT) + typeDescription.substring(1);
807  0 typeDescription = typeDescription.toUpperCase(Locale.ROOT);
808  0 sb.append(typeDescription);
809  0 sb.append(System.lineSeparator());
810  0 sb.append(System.lineSeparator());
811    }
812    }
813   
814  0 appendArgUsage(sb, a, maxArgLength, Platform.consoleWidth());
815   
816  0 if (argsI.hasNext())
817    {
818  0 sb.append(System.lineSeparator());
819    }
820    }
821    }
822  0 return sb.toString();
823    }
824   
 
825  0 toggle private static void appendArgUsage(StringBuilder sb, Arg a,
826    int maxArgLength, int maxWidth)
827    {
828  0 boolean first = appendArgAndDescription(sb, null, null, a,
829    maxArgLength);
830  0 List<String> options = new ArrayList<>();
831   
832  0 for (Opt o : EnumSet.allOf(Opt.class))
833    {
834  0 if (a.hasOption(o) && o.description() != null)
835    {
836  0 options.add(o.description());
837    }
838    }
839   
840  0 final String optDisplaySeparator = "; ";
841  0 if (options.size() > 0)
842    {
843  0 int linelength = 0;
844  0 String spacing = String.format("%-"
845    + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
846    "");
847  0 if (first)
848    {
849  0 sb.append(ARGDESCRIPTIONSEPARATOR);
850  0 linelength += maxArgLength + ARGDESCRIPTIONSEPARATOR.length();
851    }
852    else
853    {
854  0 sb.append(spacing);
855  0 linelength += spacing.length();
856    }
857  0 if (options.size() > 0)
858    {
859  0 boolean optFirst = true;
860  0 Iterator<String> optionsI = options.listIterator();
861  0 while (optionsI.hasNext())
862    {
863  0 String desc = optionsI.next();
864  0 if (optFirst)
865    {
866  0 sb.append("(");
867  0 linelength += 1;
868    }
869  0 int descLength = desc.length()
870  0 + (optionsI.hasNext() ? optDisplaySeparator.length() : 0);
871  0 if (linelength + descLength > maxWidth)
872    {
873  0 sb.append(System.lineSeparator());
874  0 linelength = 0;
875  0 sb.append(spacing);
876  0 linelength += spacing.length();
877    }
878    // sb.append(linelength + "+" + desc.length() + " ");
879  0 sb.append(desc);
880  0 linelength += desc.length();
881  0 if (optionsI.hasNext())
882    {
883  0 sb.append(optDisplaySeparator);
884  0 linelength += optDisplaySeparator.length();
885    }
886  0 optFirst = false;
887    }
888  0 sb.append(')');
889  0 sb.append(System.lineSeparator());
890    }
891    }
892    }
893   
 
894  0 toggle public static String argDisplayString(Arg a)
895    {
896  0 StringBuilder argSb = new StringBuilder();
897  0 argSb.append(
898  0 a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
899  0 if (a.hasOption(Opt.STRING))
900    {
901  0 if (a.hasOption(Opt.PREFIXKEV))
902    {
903  0 argSb.append("key=value");
904    }
905    else
906    {
907  0 argSb.append("=value");
908    }
909    }
910  0 return argSb.toString();
911    }
912   
 
913  0 toggle public static boolean appendArgAndDescription(StringBuilder sb,
914    String aString, String description, Arg a, int maxArgLength)
915    {
916  0 return appendArgAndDescription(sb, aString, description, a,
917    maxArgLength, Platform.consoleWidth());
918    }
919   
 
920  0 toggle public static boolean appendArgAndDescription(StringBuilder sb,
921    String aString, String description, Arg a, int maxArgLength,
922    int maxLength)
923    {
924  0 if (aString == null && a != null)
925    {
926  0 aString = argDisplayString(a);
927    }
928  0 if (description == null && a != null)
929    {
930  0 description = a.getDescription();
931    }
932  0 sb.append(String.format("%-" + maxArgLength + "s", aString));
933  0 if (aString.length() > maxArgLength)
934    {
935  0 sb.append(System.lineSeparator());
936  0 sb.append(String.format("%-" + maxArgLength + "s", ""));
937    }
938   
939  0 int descLength = maxLength - maxArgLength
940    - ARGDESCRIPTIONSEPARATOR.length();
941    // reformat the descriptions lines to the right width
942  0 Iterator<String> descLines = null;
943  0 if (description != null)
944    {
945  0 descLines = Arrays.stream(description.split("\\n")).iterator();
946    }
947  0 List<String> splitDescLinesList = new ArrayList<>();
948  0 while (descLines != null && descLines.hasNext())
949    {
950  0 String line = descLines.next();
951  0 while (line.length() > descLength)
952    {
953  0 int splitIndex = line.lastIndexOf(" ", descLength);
954  0 splitDescLinesList.add(line.substring(0, splitIndex));
955  0 line = line.substring(splitIndex + 1);
956    }
957  0 splitDescLinesList.add(line);
958    }
959   
960  0 Iterator<String> splitDescLines = splitDescLinesList.iterator();
961  0 boolean first = true;
962  0 if (splitDescLines != null)
963    {
964  0 while (splitDescLines.hasNext())
965    {
966  0 if (first)
967    {
968  0 sb.append(ARGDESCRIPTIONSEPARATOR);
969    }
970    else
971    {
972  0 sb.append(String.format("%-"
973    + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
974    ""));
975    }
976  0 sb.append(splitDescLines.next());
977  0 sb.append(System.lineSeparator());
978  0 first = false;
979    }
980    }
981  0 return first;
982    }
983   
 
984  0 toggle protected static Iterator<Arg> getAllOfType(Type type)
985    {
986  0 return getAllOfType(type, new Opt[] {});
987    }
988   
 
989  0 toggle protected static Iterator<Arg> getAllOfType(Type type, Opt... options)
990    {
991  0 Opt[] opts = options == null ? new Opt[] {} : options;
992  0 return EnumSet.allOf(Arg.class).stream().filter(a -> {
993  0 if (!a.hasType(type))
994  0 return false;
995  0 for (Opt o : opts)
996    {
997  0 if (!a.hasOption(o))
998  0 return false;
999    }
1000  0 return true;
1001    }).iterator();
1002    }
1003   
 
1004  0 toggle private static List<Arg> argsSortedForDisplay(List<Type> types)
1005    {
1006  0 List<Arg> argsToSort;
1007    // if no types provided, do all
1008  0 if (types == null || types.size() == 0 || types.contains(Type.ALL))
1009    {
1010  0 argsToSort = Arrays
1011    .asList(EnumSet.allOf(Arg.class).toArray(new Arg[] {}));
1012    }
1013    else
1014    {
1015  0 argsToSort = new ArrayList<>();
1016  0 for (Type type : types)
1017    {
1018  0 if (type == null)
1019  0 continue;
1020  0 Arg.getAllOfType(type).forEachRemaining(a -> argsToSort.add(a));
1021    }
1022    }
1023   
1024  0 Collections.sort(argsToSort, new ArgDisplayComparator());
1025  0 return argsToSort;
1026    }
1027   
1028    private static final String ARGDESCRIPTIONSEPARATOR = " - ";
1029   
1030    private static final int DESCRIPTIONINDENT = 20;
1031   
1032    }
1033   
 
1034    class ArgDisplayComparator implements Comparator<Arg>
1035    {
 
1036  0 toggle private int compareArgOpts(Arg a, Arg b, Opt o)
1037    {
1038  0 int i = a.hasOption(o) ? (b.hasOption(o) ? 0 : -1)
1039  0 : (b.hasOption(o) ? 1 : 0);
1040  0 return i;
1041    }
1042   
 
1043  0 toggle private int compareForDisplay(Arg a, Arg b)
1044    {
1045  0 if (b == null)
1046  0 return -1;
1047    // first compare types (in enum order)
1048  0 int i = a.getFirstType().compareTo(b.getFirstType());
1049  0 if (i != 0)
1050  0 return i;
1051    // do Opt.LAST next (oddly). Reversed args important!
1052  0 i = compareArgOpts(b, a, Opt.LAST);
1053  0 if (i != 0)
1054  0 return i;
1055    // priority order
1056  0 Opt[] optOrder = { Opt.HELP, Opt.FIRST, Opt.PRIMARY, Opt.STRING,
1057    Opt.BOOLEAN };
1058  0 for (Opt o : optOrder)
1059    {
1060  0 i = compareArgOpts(a, b, o);
1061  0 if (i != 0)
1062  0 return i;
1063    }
1064    // finally order of appearance in enum declarations
1065  0 return a.compareTo(b);
1066    }
1067   
 
1068  0 toggle @Override
1069    public int compare(Arg a, Arg b)
1070    {
1071  0 return compareForDisplay(a, b);
1072    }
1073    }