1 package jalview.bin.argparser;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.EnumSet;
6 import java.util.Iterator;
8 import java.util.Locale;
9 import java.util.stream.Collectors;
11 import jalview.bin.Cache;
12 import jalview.util.ChannelProperties;
17 // Initialising arguments (BOOTSTRAP)
18 HELP("Display this help statement", Opt.UNARY, Opt.BOOTSTRAP),
20 "Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed.",
21 Opt.UNARY, Opt.BOOTSTRAP),
22 JABAWS("Set a different URL to connect to a JABAWS server.", Opt.STRING,
24 NEWS("Show (or don't show) the news feed.", true, Opt.BOOLEAN,
26 SPLASH("Show (or don't show) the About Jalview splash screen.", true,
27 Opt.BOOLEAN, Opt.BOOTSTRAP),
29 "Show (or don't show) the questionnaire if one is available.",
30 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
31 USAGESTATS("Send (or don't send) initial launch usage stats.", true,
32 Opt.BOOLEAN, Opt.BOOTSTRAP),
34 "Attempt (or don't attempt) to connect to JABAWS web services.",
35 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
36 PROPS("Use file filename as the preferences file instead of the usual ~/.jalview_properties file.",
37 Opt.STRING, Opt.BOOTSTRAP),
38 DEBUG("Start Jalview in debug log level.", Opt.BOOLEAN, Opt.BOOTSTRAP),
39 TRACE("Start Jalview in trace log level.", Opt.BOOLEAN, Opt.BOOTSTRAP,
41 QUIET("Stop all output to STDOUT (after the Java Virtual Machine has started). Use ‑‑quiet a second time to stop all output to STDERR.",
42 Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP),
44 "Assume that ‑‑substitutions are initially enabled (or initially disabled).",
45 true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION),
47 // Opening an alignment
48 OPEN("Opens one or more alignment files filename or URLs URL in new alignment windows.",
49 Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER, Opt.MULTI,
50 Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT),
51 APPEND("Appends one or more alignment files filename or URLs URL to the open alignment window (or opens a new alignment if none already open).",
52 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
53 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT),
54 TITLE("Specifies the title for the open alignment window as string.",
55 Opt.STRING, Opt.LINKED),
56 COLOUR("Applies the colour scheme to the open alignment window. Valid values are:\n"
57 + "clustal,\n" + "blosum62,\n" + "pc-identity,\n" + "zappo,\n"
58 + "taylor,\n" + "gecos-flower,\n" + "gecos-blossom,\n"
59 + "gecos-sunset,\n" + "gecos-ocean,\n" + "hydrophobic,\n"
60 + "helix-propensity,\n" + "strand-propensity,\n"
61 + "turn-propensity,\n" + "buried-index,\n" + "nucleotide,\n"
62 + "nucleotide-ambiguity,\n" + "purine-pyrimidine,\n"
63 + "rna-helices,\n" + "t-coffee-scores,\n" + "sequence-id.",
64 Opt.STRING, Opt.LINKED),
65 FEATURES("Add a feature file filename or URL URL to the open alignment.",
66 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
67 TREE("Add a tree file filename or URL URL to the open alignment.",
68 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
70 "Enforces sorting (or not sorting) the alignment in the order of an attached phylogenetic tree.",
71 true, Opt.LINKED, Opt.BOOLEAN),
73 "Add an annotations file filename or URL URL to the open alignment.",
74 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
76 "Enforces showing (or not showing) alignment annotations.",
77 Opt.BOOLEAN, Opt.LINKED),
78 WRAP("Enforces wrapped (or not wrapped) alignment formatting.",
79 Opt.BOOLEAN, Opt.LINKED),
81 "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
82 Opt.UNARY, Opt.LINKED),
84 // Adding a 3D structure
86 "Load a structure file filename or URL URL associated with a sequence in the open alignment. 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.",
87 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
88 SEQID("Specify the sequence name for the preceding --structure to be associated with.",
89 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
91 "Add a PAE json matrix file filename to the preceding --structure.",
92 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
93 TEMPFAC("Set the type of temperature factor. Possible values for name are default, plddt.",
94 Opt.STRING, Opt.LINKED),
96 "Set the structure viewer to use to open the 3d structure file specified in previous --structure to name. Possible values of name are:\n"
97 + "none, jmol, chimera, chimerax, pymol.",
98 Opt.STRING, Opt.LINKED, Opt.MULTI),
100 "Do not show the temperature factor annotation for the preceding --structure.",
101 Opt.UNARY, Opt.LINKED),
102 SHOWSSANNOTATIONS(null, Opt.BOOLEAN, Opt.LINKED),
105 IMAGE("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: svg, png, eps, html, biojs.",
106 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
108 TYPE("Set the image format for the preceding --image to name. Valid values for name are: svg, png, eps, html, biojs.",
109 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
111 "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values for name are: text, lineart.",
112 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
113 OUTPUT("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"
114 + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
115 + "stockholm (sto, stk),\n" + "pir (pir),\n" + "blc (blc),\n"
116 + "amsa (amsa),\n" + "json (json),\n" + "pileup (pileup),\n"
117 + "msf (msf),\n" + "clustal (aln),\n" + "phylip (phy),\n"
118 + "jalview (jvp, jar).", Opt.STRING, Opt.LINKED,
119 Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL, Opt.REQUIREINPUT),
120 FORMAT("Sets the format for the preceding --output file. Valid formats are:\n"
121 + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n" + "blc,\n"
122 + "amsa,\n" + "json,\n" + "pileup,\n" + "msf,\n" + "clustal,\n"
123 + "phylip,\n" + "jalview.", Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
124 GROOVY("Process a groovy script in the file for the open alignment.",
125 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
126 BACKUPS("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.",
127 true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
129 "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.",
130 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
131 CLOSE("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.",
132 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
134 // controlling flow of arguments
135 NEW("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.",
136 Opt.UNARY, Opt.MULTI, Opt.NOACTION, Opt.INCREMENTDEFAULTCOUNTER),
138 "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are {basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
139 + "{dirname}, - the directory (folder) name of the currently --opened file (or first --appended file),\n"
140 + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
141 + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
142 + "{n} - the value of the index counter (starting at 0).\n"
143 + "{++n} - increase and substitute the value of the index counter,\n"
144 + "{} - the value of the current alignment window default index.",
145 true, Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
146 ARGFILE("Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
147 + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
148 Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
149 Opt.ALLOWSUBSTITUTIONS),
150 NPP("Increase the index counter used in argument value substitutions.",
151 Opt.UNARY, Opt.MULTI, Opt.NOACTION),
152 ALL("Apply the following output arguments to all sets of linked arguments.",
153 Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
154 QUIT("After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
159 "Allow specific stdout information. For testing purposes only.",
160 Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
161 SETPROP("Set an individual Java System property.", Opt.STRING, Opt.MULTI,
162 Opt.BOOTSTRAP, Opt.SECRET), // not in use yet
163 NIL("This argument does nothing on its own, but can be used with linkedIds.",
164 Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION, Opt.SECRET),
166 // private options (inserted during arg processing)
168 "Sets the current value of the argfilename. Inserted before argfilecontents.",
169 Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTI, Opt.PRIVATE,
172 "Unsets the current value of the argfilename. Inserted after argfile contents.",
173 Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION),
175 // these last two have no purpose in the normal Jalview application but are
176 // used by jalview.bin.Launcher to set memory settings. They are not used by
177 // argparser but are here for Usage statement reasons.
179 "Only available with standalone executable jar or jalview.bin.Launcher.\n"
180 + "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
181 + "The equals sign (\"=\") separator must be used with no spaces.",
182 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING),
184 "Only available with standalone executable jar or jalview.bin.Launcher.\n"
185 + "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"
186 + "The equals sign (\"=\") separator must be used with no spaces.",
187 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING),
191 public static enum Opt
193 BOOLEAN, // This Arg can be specified as --arg or --noarg to give true or
194 // false. A default can be given with setOptions(bool, Opt....).
195 // Use ArgParser.isSet(Arg) to see if this arg was not specified.
196 STRING, // This Arg can accept a value either through --arg=value or --arg
198 UNARY, // This Arg is a boolean value, true if present, false if not. Like
199 // BOOLEAN but without the --noarg option.
200 MULTI, // This Arg can be specified multiple times. Multiple values are
201 // stored in the ArgValuesMap (along with their positional index) for
203 LINKED, // This Arg can be linked to others through a --arg[linkedId] or
204 // --arg[linkedId]=value. If no linkedId is specified then the
205 // current default linkedId will be used.
206 NODUPLICATEVALUES, // This Arg can only have one value (per linkedId). The
207 // first value will be used and subsequent values ignored
209 BOOTSTRAP, // This Arg value(s) can be determined at an earlier stage than
210 // non-BOOTSTRAP Args. Substitutions do not happen in BOOTSTRAP
211 // Args and they cannot be linked or contain SubVals. See
212 // jalview.bin.argparser.BootstrapArgs.
213 GLOB, // This Arg can expand wildcard filename "globs" (e.g.
214 // path/*/filename*). If the Arg value is given as --arg filename*
215 // then the shell will have expanded the glob already, but if
216 // specified as --arg=filename* then the Java glob expansion method
217 // will be used (see FileUtils.getFilenamesFromGlob()). Note that this
218 // might be different from the shell expansion rules.
219 NOACTION, // This Arg does not perform a data task, usually used to control
220 // flow in ArgParser.parse(args).
221 ALLOWSUBSTITUTIONS, // This Arg allows substitutions in its linkedId,
222 // SubVals and values.
223 PRIVATE, // This Arg is used internally, and cannot be specified by the
225 SECRET, // This Arg is used by development processes and although it can be
226 // set by the user, it is not displayed to the user.
227 ALLOWALL, // This Arg can use the '*' linkedId to apply to all known
229 INCREMENTDEFAULTCOUNTER, // If an Arg has this option and the default
230 // linkedId is used, the defaultLinkedIdCounter is
231 // incremented *first*.
232 INPUT, // This Arg counts as an input for REQUIREINPUT
233 REQUIREINPUT, // This Arg can only be applied via --all if there is an
234 // input (i.e. --open or --append)
237 private final String[] argNames;
239 private Opt[] argOptions;
241 private boolean defaultBoolValue = false;
243 private String description = null;
245 private Arg(String description, Opt... options)
247 this(null, description, false, options);
250 private Arg(String description, boolean defaultBoolean, Opt... options)
252 this(null, description, defaultBoolean, options);
255 private Arg(String alternativeName, String description, Opt... options)
257 this(alternativeName, description, false, options);
260 private Arg(String alternativeName, String description,
261 boolean defaultBoolean, Opt... options)
263 this.argNames = alternativeName != null
265 { this.getName(), alternativeName }
268 this.description = description;
269 this.defaultBoolValue = defaultBoolean;
270 this.setOptions(options);
273 public String argString()
275 return argString(false);
278 public String negateArgString()
280 return argString(true);
283 private String argString(boolean negate)
285 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
286 if (negate && hasOption(Opt.BOOLEAN))
287 sb.append(ArgParser.NEGATESTRING);
288 sb.append(getName());
289 return sb.toString();
292 public String toLongString()
294 StringBuilder sb = new StringBuilder();
295 sb.append(this.getClass().getName()).append('.').append(this.name());
297 if (getNames().length > 0)
299 sb.append(String.join("\", \"", getNames()));
300 if (getNames().length > 0)
303 sb.append("\nOpt: ");
304 // map List<Opt> to List<String> for the String.join
305 List<String> optList = Arrays.asList(argOptions).stream()
306 .map(opt -> opt.name()).collect(Collectors.toList());
307 sb.append(String.join(", ", optList));
309 return sb.toString();
312 public String[] getNames()
317 public String getName()
319 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
323 public final String toString()
328 public boolean hasOption(Opt o)
330 if (argOptions == null)
332 for (Opt option : argOptions)
340 protected void setOptions(Opt... options)
342 this.argOptions = options;
345 protected boolean getDefaultBoolValue()
347 return defaultBoolValue;
350 protected String getDescription()
355 public static String booleanArgString(Arg a)
357 StringBuilder sb = new StringBuilder(a.argString());
358 if (a.hasOption(Opt.BOOLEAN))
361 sb.append(a.negateArgString());
363 return sb.toString();
366 public static final String usage()
368 StringBuilder sb = new StringBuilder();
370 sb.append(ChannelProperties.getProperty("app_name"));
371 String version = Cache.getDefault("VERSION", null);
374 sb.append(" version ");
375 sb.append(Cache.getDefault("VERSION", "unknown"));
377 sb.append(System.lineSeparator());
378 sb.append("Usage: jalview [files...] [args]");
379 sb.append(System.lineSeparator());
380 sb.append(System.lineSeparator());
382 int maxArgLength = 0;
383 for (Arg a : EnumSet.allOf(Arg.class))
385 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
388 StringBuilder argSb = new StringBuilder();
389 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
391 if (a.hasOption(Opt.STRING))
392 argSb.append("=value");
393 if (argSb.length() > maxArgLength)
394 maxArgLength = argSb.length();
397 // might want to sort these
398 for (Arg a : EnumSet.allOf(Arg.class))
400 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
402 StringBuilder argSb = new StringBuilder();
403 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
405 if (a.hasOption(Opt.STRING))
406 argSb.append("=value");
407 Iterator<String> descLines = null;
408 if (a.getDescription() != null)
410 descLines = Arrays.stream(a.getDescription().split("\\n"))
413 sb.append(String.format("%-" + maxArgLength + "s", argSb.toString()));
414 boolean first = true;
415 if (descLines != null)
417 while (descLines.hasNext())
422 sb.append(" ".repeat(maxArgLength + 3));
423 sb.append(descLines.next());
424 sb.append(System.lineSeparator());
429 List<String> options = new ArrayList<>();
431 if (a.hasOption(Opt.BOOLEAN))
433 options.add("default " + (a.getDefaultBoolValue() ? a.argString()
434 : a.negateArgString()));
437 if (a.hasOption(Opt.MULTI))
439 options.add("multiple");
442 if (a.hasOption(Opt.LINKED))
444 options.add("can be linked");
447 if (a.hasOption(Opt.GLOB))
449 options.add("allows file globs");
452 if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
454 options.add("allows substitutions");
457 if (a.hasOption(Opt.PRIVATE))
459 options.add("for internal use only");
462 if (a.hasOption(Opt.SECRET))
464 options.add("for development use only");
467 if (options.size() > 0)
472 sb.append(" ".repeat(maxArgLength + 3));
474 sb.append(String.join("; ", options));
476 sb.append(System.lineSeparator());
478 sb.append(System.lineSeparator());
480 return sb.toString();