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("h", "Display this help statement", Opt.UNARY, Opt.BOOTSTRAP),
20 "Display the version of "
21 + ChannelProperties.getProperty("app_name"),
22 Opt.UNARY, Opt.BOOTSTRAP),
24 "Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed.",
25 Opt.UNARY, Opt.BOOTSTRAP),
26 JABAWS("Set a different URL to connect to a JABAWS server.", Opt.STRING,
28 NEWS("Show (or don't show) the news feed.", true, Opt.BOOLEAN,
30 SPLASH("Show (or don't show) the About Jalview splash screen.", true,
31 Opt.BOOLEAN, Opt.BOOTSTRAP),
33 "Show (or don't show) the questionnaire if one is available.",
34 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
35 USAGESTATS("Send (or don't send) initial launch usage stats.", true,
36 Opt.BOOLEAN, Opt.BOOTSTRAP),
38 "Attempt (or don't attempt) to connect to JABAWS web services.",
39 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
40 PROPS("Use a file as the preferences file instead of the usual ~/"
41 + ChannelProperties.getProperty("preferences.filename")
42 + " file.", Opt.STRING, Opt.BOOTSTRAP),
43 DEBUG("d", "Start Jalview in debug log level.", Opt.BOOLEAN,
45 TRACE("Start Jalview in trace log level.", Opt.BOOLEAN, Opt.BOOTSTRAP,
48 "Stop all output to STDOUT (after the Java Virtual Machine has started). Use ‑‑quiet a second time to stop all output to STDERR.",
49 Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP),
51 "Set ‑‑substitutions to be initially enabled (or initially disabled).",
52 true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION),
54 // Opening an alignment
55 OPEN("Opens one or more alignment files or URLs in new alignment windows.",
56 Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER, Opt.MULTI,
57 Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.STORED),
58 APPEND("Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
59 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
60 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT),
61 TITLE("Specifies the title for the open alignment window as string.",
62 Opt.STRING, Opt.LINKED),
63 COLOUR("color", // being a bit soft on the Americans!
64 "Applies the colour scheme to the open alignment window. Valid values are:\n"
65 + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
66 + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
67 + "gecos-blossom,\n" + "gecos-sunset,\n"
68 + "gecos-ocean,\n" + "hydrophobic,\n"
69 + "helix-propensity,\n" + "strand-propensity,\n"
70 + "turn-propensity,\n" + "buried-index,\n"
71 + "nucleotide,\n" + "nucleotide-ambiguity,\n"
72 + "purine-pyrimidine,\n" + "rna-helices,\n"
73 + "t-coffee-scores,\n" + "sequence-id.",
74 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
75 FEATURES("Add a feature file or URL to the open alignment.", Opt.STRING,
76 Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
77 TREE("Add a tree file or URL to the open alignment.", Opt.STRING,
78 Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
80 "Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
81 true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWALL),
82 ANNOTATIONS("Add an annotations file or URL to the open alignment.",
83 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
85 "Enforces showing (or not showing) alignment annotations.",
86 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
87 WRAP("Enforces wrapped (or not wrapped) alignment formatting.",
88 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
90 "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
91 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
93 // Adding a 3D structure
95 "Load a structure file or URL associated with a sequence in the open alignment.\n"
96 + "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.",
97 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
98 SEQID("Specify the sequence name for the preceding --structure to be associated with.",
99 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
100 PAEMATRIX("Add a PAE json matrix file to the preceding --structure.",
101 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
102 TEMPFAC("Set the type of temperature factor. Possible values are:\n"
103 + "default,\n" + "plddt.", Opt.STRING, Opt.LINKED),
105 "Set the structure viewer to use to open the 3d structure file specified in previous --structure to name. Possible values of name are:\n"
106 + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
108 Opt.STRING, Opt.LINKED, Opt.MULTI),
110 "Do not show the temperature factor annotation for the preceding --structure.",
111 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL, Opt.SECRET), // keep this secret
114 SHOWSSANNOTATIONS(null, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
117 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:\n"
118 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
119 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
120 Opt.REQUIREINPUT, Opt.OUTPUT),
121 TYPE("Set the image format for the preceding --image to name. Valid values for name are: svg,\n"
122 + "png,\n" + "eps,\n" + "html,\n" + "biojs.", Opt.STRING,
123 Opt.LINKED, Opt.ALLOWALL),
125 "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:\n"
126 + "text,\n" + "lineart.",
127 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
128 SCALE("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).",
129 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
130 WIDTH("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).",
131 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
132 HEIGHT("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).",
133 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
134 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"
135 + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
136 + "stockholm (sto, stk),\n" + "pir (pir),\n" + "blc (blc),\n"
137 + "amsa (amsa),\n" + "json (json),\n" + "pileup (pileup),\n"
138 + "msf (msf),\n" + "clustal (aln),\n" + "phylip (phy),\n"
139 + "jalview (jvp, jar).", Opt.STRING, Opt.LINKED,
140 Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL, Opt.REQUIREINPUT,
142 FORMAT("Sets the format for the preceding --output file. Valid formats are:\n"
143 + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n" + "blc,\n"
144 + "amsa,\n" + "json,\n" + "pileup,\n" + "msf,\n" + "clustal,\n"
145 + "phylip,\n" + "jalview.", Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
146 GROOVY("Process a groovy script in the file for the open alignment.",
147 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS,
149 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.",
150 true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
152 "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.",
153 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
154 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.",
155 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
157 // controlling flow of arguments
158 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.",
159 Opt.UNARY, Opt.MULTI, Opt.NOACTION, Opt.INCREMENTDEFAULTCOUNTER),
161 "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"
162 + "{dirname}, - the directory (folder) name of the currently --opened file (or first --appended file),\n"
163 + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
164 + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
165 + "{n} - the value of the index counter (starting at 0).\n"
166 + "{++n} - increase and substitute the value of the index counter,\n"
167 + "{} - the value of the current alignment window default index.",
168 true, Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
169 ARGFILE("Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
170 + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
171 + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
172 Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
173 Opt.ALLOWSUBSTITUTIONS),
175 "Increase the index counter used in argument value substitutions.",
176 Opt.UNARY, Opt.MULTI, Opt.NOACTION),
177 ALL("Apply the following output arguments to all sets of linked arguments.",
178 Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
179 OPENED("Apply the following output arguments to all of the last --open'ed set of linked arguments.",
180 Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
181 QUIT("After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
182 Opt.UNARY, Opt.BOOTSTRAP),
186 "Allow specific stdout information. For testing purposes only.",
187 Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
188 SETPROP("Set an individual Java System property.", Opt.STRING, Opt.MULTI,
189 Opt.BOOTSTRAP, Opt.SECRET), // not in use yet
190 NIL("This argument does nothing on its own, but can be used with linkedIds.",
191 Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION, Opt.SECRET),
193 // private options (inserted during arg processing)
195 "Sets the current value of the argfilename. Inserted before argfilecontents.",
196 Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTI, Opt.PRIVATE,
199 "Unsets the current value of the argfilename. Inserted after argfile contents.",
200 Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION),
201 THREADS("When opening multiple alignment windows, set a limit to alignments being processed at one time.",
202 Opt.BOOTSTRAP, Opt.STRING, Opt.NODUPLICATEVALUES, Opt.NOACTION),
204 // these last two have no purpose in the normal Jalview application but are
205 // used by jalview.bin.Launcher to set memory settings. They are not used by
206 // argparser but are here for Usage statement reasons.
208 "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
209 + "The equals sign (\"=\") separator must be used with no spaces.",
210 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING),
212 "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"
213 + "The equals sign (\"=\") separator must be used with no spaces.",
214 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING),
218 public static enum Opt
220 BOOLEAN, // This Arg can be specified as --arg or --noarg to give true or
221 // false. A default can be given with setOptions(bool, Opt....).
222 // Use ArgParser.isSet(Arg) to see if this arg was not specified.
223 STRING, // This Arg can accept a value either through --arg=value or --arg
225 UNARY, // This Arg is a boolean value, true if present, false if not. Like
226 // BOOLEAN but without the --noarg option.
227 MULTI, // This Arg can be specified multiple times. Multiple values are
228 // stored in the ArgValuesMap (along with their positional index) for
230 LINKED, // This Arg can be linked to others through a --arg[linkedId] or
231 // --arg[linkedId]=value. If no linkedId is specified then the
232 // current default linkedId will be used.
233 NODUPLICATEVALUES, // This Arg can only have one value (per linkedId). The
234 // first value will be used and subsequent values ignored
236 BOOTSTRAP, // This Arg value(s) can be determined at an earlier stage than
237 // non-BOOTSTRAP Args. Substitutions do not happen in BOOTSTRAP
238 // Args and they cannot be linked or contain SubVals. See
239 // jalview.bin.argparser.BootstrapArgs.
240 GLOB, // This Arg can expand wildcard filename "globs" (e.g.
241 // path/*/filename*). If the Arg value is given as --arg filename*
242 // then the shell will have expanded the glob already, but if
243 // specified as --arg=filename* then the Java glob expansion method
244 // will be used (see FileUtils.getFilenamesFromGlob()). Note that this
245 // might be different from the shell expansion rules.
246 NOACTION, // This Arg does not perform a data task, usually used to control
247 // flow in ArgParser.parse(args).
248 ALLOWSUBSTITUTIONS, // This Arg allows substitutions in its linkedId,
249 // SubVals and values.
250 PRIVATE, // This Arg is used internally, and cannot be specified by the
252 SECRET, // This Arg is used by development processes and although it can be
253 // set by the user, it is not displayed to the user.
254 ALLOWALL, // This Arg can use the '*' linkedId to apply to all known
256 INCREMENTDEFAULTCOUNTER, // If an Arg has this option and the default
257 // linkedId is used, the defaultLinkedIdCounter is
258 // incremented *first*.
259 INPUT, // This Arg counts as an input for REQUIREINPUT
260 REQUIREINPUT, // This Arg can only be applied via --all if there is an
261 // input (i.e. --open or --append)
262 OUTPUT, // This Arg provides an output filename. With Opt.ALLOWALL *.ext is
263 // shorthand for --all --output={basename}.ext
264 STORED, // This Arg resets and creates a new set of "opened" linkedIds
267 private final String[] argNames;
269 private Opt[] argOptions;
271 private boolean defaultBoolValue = false;
273 private String description = null;
275 private Arg(String description, Opt... options)
277 this(null, description, false, options);
280 private Arg(String description, boolean defaultBoolean, Opt... options)
282 this(null, description, defaultBoolean, options);
285 private Arg(String alternativeName, String description, Opt... options)
287 this(alternativeName, description, false, options);
290 private Arg(String alternativeName, String description,
291 boolean defaultBoolean, Opt... options)
293 this.argNames = alternativeName != null
295 { this.getName(), alternativeName }
298 this.description = description;
299 this.defaultBoolValue = defaultBoolean;
300 this.setOptions(options);
303 public String argString()
305 return argString(false);
308 public String negateArgString()
310 return argString(true);
313 private String argString(boolean negate)
315 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
316 if (negate && hasOption(Opt.BOOLEAN))
317 sb.append(ArgParser.NEGATESTRING);
318 sb.append(getName());
319 return sb.toString();
322 public String toLongString()
324 StringBuilder sb = new StringBuilder();
325 sb.append(this.getClass().getName()).append('.').append(this.name());
327 if (getNames().length > 0)
329 sb.append(String.join("\", \"", getNames()));
330 if (getNames().length > 0)
333 sb.append("\nOpt: ");
334 // map List<Opt> to List<String> for the String.join
335 List<String> optList = Arrays.asList(argOptions).stream()
336 .map(opt -> opt.name()).collect(Collectors.toList());
337 sb.append(String.join(", ", optList));
339 return sb.toString();
342 public String[] getNames()
347 public String getName()
349 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
353 public final String toString()
358 public boolean hasOption(Opt o)
360 if (argOptions == null)
362 for (Opt option : argOptions)
370 protected void setOptions(Opt... options)
372 this.argOptions = options;
375 protected boolean getDefaultBoolValue()
377 return defaultBoolValue;
380 protected String getDescription()
385 public static String booleanArgString(Arg a)
387 StringBuilder sb = new StringBuilder(a.argString());
388 if (a.hasOption(Opt.BOOLEAN))
391 sb.append(a.negateArgString());
393 return sb.toString();
396 public static final String usage()
398 StringBuilder sb = new StringBuilder();
400 sb.append(ChannelProperties.getProperty("app_name"));
401 String version = Cache.getDefault("VERSION", null);
404 sb.append(" version ");
405 sb.append(Cache.getDefault("VERSION", "unknown"));
407 sb.append(System.lineSeparator());
408 sb.append("Usage: jalview [files...] [args]");
409 sb.append(System.lineSeparator());
410 sb.append(System.lineSeparator());
412 int maxArgLength = 0;
413 for (Arg a : EnumSet.allOf(Arg.class))
415 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
418 StringBuilder argSb = new StringBuilder();
419 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
421 if (a.hasOption(Opt.STRING))
422 argSb.append("=value");
423 if (argSb.length() > maxArgLength)
424 maxArgLength = argSb.length();
427 // might want to sort these
428 for (Arg a : EnumSet.allOf(Arg.class))
430 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
432 StringBuilder argSb = new StringBuilder();
433 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
435 if (a.hasOption(Opt.STRING))
436 argSb.append("=value");
437 Iterator<String> descLines = null;
438 if (a.getDescription() != null)
440 descLines = Arrays.stream(a.getDescription().split("\\n"))
443 sb.append(String.format("%-" + maxArgLength + "s", argSb.toString()));
444 boolean first = true;
445 if (descLines != null)
447 while (descLines.hasNext())
452 sb.append(" ".repeat(maxArgLength + 3));
453 sb.append(descLines.next());
454 sb.append(System.lineSeparator());
459 List<String> options = new ArrayList<>();
461 if (a.hasOption(Opt.BOOLEAN))
463 options.add("default " + (a.getDefaultBoolValue() ? a.argString()
464 : a.negateArgString()));
467 if (a.hasOption(Opt.MULTI))
469 options.add("multiple");
472 if (a.hasOption(Opt.LINKED))
474 options.add("can be linked");
477 if (a.hasOption(Opt.GLOB))
479 options.add("allows file globs");
482 if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
484 options.add("allows substitutions");
487 if (a.hasOption(Opt.ALLOWALL))
489 options.add("can be applied to all linked arguments");
492 if (a.hasOption(Opt.PRIVATE))
494 options.add("for internal use only");
497 if (a.hasOption(Opt.SECRET))
499 options.add("for development use only");
502 if (options.size() > 0)
507 sb.append(" ".repeat(maxArgLength + 3));
509 sb.append(String.join("; ", options));
511 sb.append(System.lineSeparator());
513 sb.append(System.lineSeparator());
515 return sb.toString();