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.MULTI),
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 Opt.UNARY, Opt.BOOTSTRAP),
33 JABAWS(Type.CONFIG, "Set a different URL to connect to a JABAWS server.",
34 Opt.STRING, Opt.BOOTSTRAP),
35 NEWS(Type.CONFIG, "Show (or don't show) the news feed.", true,
36 Opt.BOOLEAN, Opt.BOOTSTRAP),
38 "Show (or don't show) the About Jalview splash screen.", true,
39 Opt.BOOLEAN, Opt.BOOTSTRAP),
40 QUESTIONNAIRE(Type.CONFIG,
41 "Show (or don't show) the questionnaire if one is available.",
42 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
43 USAGESTATS(Type.CONFIG,
44 "Send (or don't send) initial launch usage stats.", true,
45 Opt.BOOLEAN, Opt.BOOTSTRAP),
46 WEBSERVICEDISCOVERY(Type.CONFIG,
47 "Attempt (or don't attempt) to connect to JABAWS web services.",
48 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
50 "Use a file as the preferences file instead of the usual ~/"
51 + ChannelProperties.getProperty("preferences.filename")
53 Opt.STRING, Opt.BOOTSTRAP),
54 DEBUG(Type.CONFIG, "d", "Start Jalview in debug log level.", Opt.BOOLEAN,
56 TRACE(Type.CONFIG, "Start Jalview in trace log level.", Opt.BOOLEAN,
57 Opt.BOOTSTRAP, Opt.SECRET),
58 QUIET(Type.CONFIG, "q",
59 "Stop all output to STDOUT (after the Java Virtual Machine has started). Use ‑‑quiet a second time to stop all output to STDERR.",
60 Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP),
61 INITSUBSTITUTIONS(Type.CONFIG,
62 "Set ‑‑substitutions to be initially enabled (or initially disabled).",
63 true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
65 // Opening an alignment
67 "Opens one or more alignment files or URLs in new alignment windows.",
68 Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER, Opt.MULTI,
69 Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.STORED,
72 "Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
73 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
74 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.PRIMARY),
76 "Specifies the title for the open alignment window as string.",
77 Opt.STRING, Opt.LINKED),
78 COLOUR(Type.OPENING, "color", // being a bit soft on the Americans!
79 "Applies the colour scheme to the open alignment window. Valid values are:\n"
80 + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
81 + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
82 + "gecos-blossom,\n" + "gecos-sunset,\n"
83 + "gecos-ocean,\n" + "hydrophobic,\n"
84 + "helix-propensity,\n" + "strand-propensity,\n"
85 + "turn-propensity,\n" + "buried-index,\n"
86 + "nucleotide,\n" + "nucleotide-ambiguity,\n"
87 + "purine-pyrimidine,\n" + "rna-helices,\n"
88 + "t-coffee-scores,\n" + "sequence-id.",
89 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
90 FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
91 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
92 TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
93 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
94 SORTBYTREE(Type.OPENING,
95 "Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
96 true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWALL),
97 ANNOTATIONS(Type.OPENING,
98 "Add an annotations file or URL to the open alignment.",
99 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
100 SHOWANNOTATIONS(Type.OPENING,
101 "Enforces showing (or not showing) alignment annotations.",
102 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
104 "Enforces wrapped (or not wrapped) alignment formatting.",
105 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
106 NOSTRUCTURE(Type.OPENING,
107 "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
108 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
110 // Adding a 3D structure
111 STRUCTURE(Type.STRUCTURE,
112 "Load a structure file or URL associated with a sequence in the open alignment.\n"
113 + "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.",
114 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS,
116 SEQID(Type.STRUCTURE,
117 "Specify the sequence name for the preceding --structure to be associated with.",
118 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
119 PAEMATRIX(Type.STRUCTURE,
120 "Add a PAE json matrix file to the preceding --structure.",
121 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
122 TEMPFAC(Type.STRUCTURE,
123 "Set the type of temperature factor. Possible values are:\n"
124 + "default,\n" + "plddt.",
125 Opt.STRING, Opt.LINKED),
126 STRUCTUREVIEWER(Type.STRUCTURE,
127 "Set the structure viewer to use to open the 3D structure file specified in previous --structure to name. Possible values of name are:\n"
128 + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
130 Opt.STRING, Opt.LINKED, Opt.MULTI),
131 NOTEMPFAC(Type.STRUCTURE,
132 "Do not show the temperature factor annotation for the preceding --structure.",
133 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL, Opt.SECRET), // keep this secret
135 SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
140 "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"
141 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
142 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
143 Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY),
145 "Set the image format for the preceding --image. Valid values are:\n"
146 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
147 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
148 TEXTRENDERER(Type.IMAGE,
149 "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n"
150 + "text,\n" + "lineart.",
151 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
153 "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).",
154 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
156 "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).",
157 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
159 "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).",
160 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
161 STRUCTUREIMAGE(Type.STRUCTUREIMAGE,
162 "Export an image of a 3D structure opened in JMOL", Opt.STRING,
163 Opt.LINKED, Opt.MULTI),
164 STRUCTUREIMAGETYPE(Type.STRUCTUREIMAGE,
165 "Set the structure image format for the preceding --structureimage. Valid values are:\n"
166 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
167 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
168 STRUCTUREIMAGETEXTRENDERER(Type.STRUCTUREIMAGE,
169 "Sets whether text in a vector structure image format (SVG, EPS) should be rendered as text or vector line-art. Possible values are:\n"
170 + "text,\n" + "lineart.",
171 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
172 STRUCTUREIMAGESCALE(Type.STRUCTUREIMAGE,
173 "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).",
174 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
175 STRUCTUREIMAGEWIDTH(Type.STRUCTUREIMAGE,
176 "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).",
177 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
178 STRUCTUREIMAGEHEIGHT(Type.STRUCTUREIMAGE,
179 "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).",
180 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
183 "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"
184 + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
185 + "stockholm (sto, stk),\n" + "pir (pir),\n"
186 + "blc (blc),\n" + "amsa (amsa),\n" + "json (json),\n"
187 + "pileup (pileup),\n" + "msf (msf),\n"
188 + "clustal (aln),\n" + "phylip (phy),\n"
189 + "jalview (jvp, jar).",
190 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
191 Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY),
193 "Sets the format for the preceding --output file. Valid formats are:\n"
194 + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n"
195 + "blc,\n" + "amsa,\n" + "json,\n" + "pileup,\n"
196 + "msf,\n" + "clustal,\n" + "phylip,\n" + "jalview.",
197 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
199 "Process a groovy script in the file for the open alignment.",
200 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS,
203 "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.",
204 true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
205 OVERWRITE(Type.OUTPUT,
206 "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.",
207 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
209 "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.",
210 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
212 // controlling flow of arguments
214 "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.",
215 Opt.UNARY, Opt.MULTI, Opt.NOACTION, Opt.INCREMENTDEFAULTCOUNTER),
216 SUBSTITUTIONS(Type.FLOW,
217 "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are:\n"
218 + "{basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
219 + "{dirname} - the directory (folder) name of the currently --opened file (or first --appended file),\n"
220 + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
221 + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
222 + "{n} - the value of the index counter (starting at 0).\n"
223 + "{++n} - increase and substitute the value of the index counter,\n"
224 + "{} - the value of the current alignment window default index.",
225 true, Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
227 "Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
228 + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
229 + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
230 Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
231 Opt.ALLOWSUBSTITUTIONS),
232 NPP(Type.FLOW, "n++",
233 "Increase the index counter used in argument value substitutions.",
234 Opt.UNARY, Opt.MULTI, Opt.NOACTION),
236 "Apply the following output arguments to all sets of linked arguments.",
237 Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
239 "Apply the following output arguments to all of the last --open'ed set of linked arguments.",
240 Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
242 "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
245 "Secret arg to not quit after --headless mode for tests",
246 Opt.UNARY, Opt.SECRET),
247 ALLSTRUCTURES(Type.FLOW,
248 "Apply the following 3D structure formatting arguments to all structures within the open alignment.",
249 Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
252 TESTOUTPUT(Type.CONFIG,
253 "Allow specific stdout information. For testing purposes only.",
254 Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
255 SETPROP(Type.CONFIG, "Set an individual Java System property.",
256 Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.SECRET), // not in use yet
258 "This argument does nothing on its own, but can be used with linkedIds.",
259 Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION, Opt.SECRET),
261 // private options (inserted during arg processing)
262 SETARGFILE(Type.FLOW,
263 "Sets the current value of the argfilename. Inserted before argfilecontents.",
264 Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTI, Opt.PRIVATE,
266 UNSETARGFILE(Type.FLOW,
267 "Unsets the current value of the argfilename. Inserted after argfile contents.",
268 Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION),
270 // these last two have no purpose in the normal Jalview application but are
271 // used by jalview.bin.Launcher to set memory settings. They are not used by
272 // argparser but are here for Usage statement reasons.
273 JVMMEMPC(Type.CONFIG,
274 "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
275 + "The equals sign (\"=\") separator must be used with no spaces.",
276 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
277 JVMMEMMAX(Type.CONFIG,
278 "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"
279 + "The equals sign (\"=\") separator must be used with no spaces.",
280 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING, Opt.LAST),
284 public static enum Opt
286 BOOLEAN, // This Arg can be specified as --arg or --noarg to give true or
287 // false. A default can be given with setOptions(bool, Opt....).
288 // Use ArgParser.isSet(Arg) to see if this arg was not specified.
289 STRING, // This Arg can accept a value either through --arg=value or --arg
291 UNARY, // This Arg is a boolean value, true if present, false if not. Like
292 // BOOLEAN but without the --noarg option.
293 MULTI, // This Arg can be specified multiple times. Multiple values are
294 // stored in the ArgValuesMap (along with their positional index) for
296 LINKED, // This Arg can be linked to others through a --arg[linkedId] or
297 // --arg[linkedId]=value. If no linkedId is specified then the
298 // current default linkedId will be used.
299 NODUPLICATEVALUES, // This Arg can only have one value (per linkedId). The
300 // first value will be used and subsequent values ignored
302 BOOTSTRAP, // This Arg value(s) can be determined at an earlier stage than
303 // non-BOOTSTRAP Args. Substitutions do not happen in BOOTSTRAP
304 // Args and they cannot be linked or contain SubVals. See
305 // jalview.bin.argparser.BootstrapArgs.
306 GLOB, // This Arg can expand wildcard filename "globs" (e.g.
307 // path/*/filename*). If the Arg value is given as --arg filename*
308 // then the shell will have expanded the glob already, but if
309 // specified as --arg=filename* then the Java glob expansion method
310 // will be used (see FileUtils.getFilenamesFromGlob()). Note that this
311 // might be different from the shell expansion rules.
312 NOACTION, // This Arg does not perform a data task, usually used to control
313 // flow in ArgParser.parse(args).
314 ALLOWSUBSTITUTIONS, // This Arg allows substitutions in its linkedId,
315 // SubVals and values.
316 PRIVATE, // This Arg is used internally, and cannot be specified by the
318 SECRET, // This Arg is used by development processes and although it can be
319 // set by the user, it is not displayed to the user.
320 ALLOWALL, // This Arg can use the '*' linkedId to apply to all known
322 INCREMENTDEFAULTCOUNTER, // If an Arg has this option and the default
323 // linkedId is used, the defaultLinkedIdCounter is
324 // incremented *first*.
325 INPUT, // This Arg counts as an input for REQUIREINPUT
326 REQUIREINPUT, // This Arg can only be applied via --all if there is an
327 // input (i.e. --open or --append)
328 OUTPUT, // This Arg provides an output filename. With Opt.ALLOWALL *.ext is
329 // shorthand for --all --output={basename}.ext
330 STORED, // This Arg resets and creates a new set of "opened" linkedIds
331 HELP, // This Arg is a --help type arg
332 PRIMARY, // This Arg is the main Arg for its type
333 HASTYPE, // This Arg can have an Arg.Type assigned to it (and no value)
334 FIRST, // Move this arg to the first in usage statement (within type)
335 LAST, // Move this arg to the end in usage statement (within type)
338 public static enum Type
340 // Type restricts argument to certain usage output
342 CONFIG("arguments used to configure "
343 + ChannelProperties.getProperty("app_name") + " from startup"),
344 OPENING("arguments used to open and format alignments"),
345 STRUCTURE("arguments used to add and format 3D structure data"),
346 PROCESS("arguments used to process an alignment once opened"),
347 OUTPUT("arguments used to save data from a processed alignment"),
348 IMAGE("arguments used to export an image of an alignment"),
349 STRUCTUREIMAGE("arguments used to export an image of an structure"),
350 FLOW("arguments that control processing of the other arguments"), //
351 ALL("all arguments"), // mostly just a place-holder for --help-all
352 NONE, // mostly a place-holder for --help
355 private String description;
362 private Type(String description)
364 this.description = description;
367 public String description()
373 private final String[] argNames;
375 private Opt[] argOptions;
377 private boolean defaultBoolValue;
379 private String description;
383 private Arg(Type type, String description, Opt... options)
385 this(type, null, description, false, options);
388 private Arg(Type type, String description, boolean defaultBoolean,
391 this(type, null, description, defaultBoolean, options);
394 private Arg(Type type, String alternativeName, String description,
397 this(type, alternativeName, description, false, options);
400 private Arg(Type type, String alternativeName, String description,
401 boolean defaultBoolean, Opt... options)
403 this.argNames = alternativeName != null
405 { this.getName(), alternativeName }
409 this.description = description;
410 this.defaultBoolValue = defaultBoolean;
411 this.setOptions(options);
414 public String argString()
416 return argString(false);
419 public String negateArgString()
421 return argString(true);
424 private String argString(boolean negate)
426 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
427 if (negate && hasOption(Opt.BOOLEAN))
428 sb.append(ArgParser.NEGATESTRING);
429 sb.append(getName());
430 return sb.toString();
433 public String toLongString()
435 StringBuilder sb = new StringBuilder();
436 sb.append(this.getClass().getName()).append('.').append(this.name());
438 if (getNames().length > 0)
440 sb.append(String.join("\", \"", getNames()));
441 if (getNames().length > 0)
444 sb.append("\nType: " + type.name());
445 sb.append("\nOpt: ");
446 // map List<Opt> to List<String> for the String.join
447 List<String> optList = Arrays.asList(argOptions).stream()
448 .map(opt -> opt.name()).collect(Collectors.toList());
449 sb.append(String.join(", ", optList));
451 return sb.toString();
454 public String[] getNames()
459 public String getName()
461 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
465 public final String toString()
470 public boolean hasOption(Opt o)
472 if (argOptions == null)
474 for (Opt option : argOptions)
482 public boolean hasAllOptions(Opt... opts)
486 if (!this.hasOption(o))
492 protected void setOptions(Opt... options)
494 this.argOptions = options;
497 protected boolean getDefaultBoolValue()
499 return defaultBoolValue;
502 public Type getType()
507 protected String getDescription()
512 public static String booleanArgString(Arg a)
514 StringBuilder sb = new StringBuilder(a.argString());
515 if (a.hasOption(Opt.BOOLEAN))
518 sb.append(a.negateArgString());
520 return sb.toString();
523 public static final String usage()
528 public static final void appendUsageGeneral(StringBuilder sb,
531 for (Type t : EnumSet.allOf(Type.class))
533 if (t.description() != null)
535 StringBuilder argSb = new StringBuilder();
536 argSb.append(Arg.HELP.argString()).append(ArgParser.SINGLEDASH)
537 .append(t.name().toLowerCase(Locale.ROOT));
538 appendArgAndDescription(sb, argSb.toString(),
539 "Help for " + t.description(), null, maxArgLength);
540 sb.append(System.lineSeparator());
545 public static final String usage(List<Type> types)
547 StringBuilder sb = new StringBuilder();
549 sb.append("usage: jalview [" + Arg.HEADLESS.argString() + "] [["
550 + Arg.OPEN.argString() + "/" + Arg.APPEND.argString()
551 + "] file(s)] [args]");
552 sb.append(System.lineSeparator());
553 sb.append(System.lineSeparator());
555 if (types == null || types.contains(null))
557 // always show --help
558 appendArgAndDescription(sb, null, "Display this basic help", Arg.HELP,
560 sb.append(System.lineSeparator());
562 appendUsageGeneral(sb, DESCRIPTIONINDENT);
566 List<Arg> args = argsSortedForDisplay(types);
569 * just use a set maxArgLength of DESCRIPTIONINDENT
571 int maxArgLength = 0;
574 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
577 String argS = argDisplayString(a);
578 if (argS.length() > maxArgLength)
579 maxArgLength = argS.length();
582 int maxArgLength = DESCRIPTIONINDENT;
584 // always show --help
585 appendArgAndDescription(sb, null, null, Arg.HELP, maxArgLength);
586 sb.append(System.lineSeparator());
588 if ((args.contains(Arg.HELP) && types.contains(Type.ALL)))
590 appendUsageGeneral(sb, maxArgLength);
593 Iterator<Arg> argsI = args.iterator();
594 Type typeSection = null;
595 while (argsI.hasNext())
597 Arg a = argsI.next();
599 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET)
605 if (a.getType() != typeSection)
607 typeSection = a.getType();
608 String typeDescription = a.getType().description();
609 if (typeDescription != null && typeDescription.length() > 0)
611 // typeDescription = typeDescription.substring(0,
612 // 1).toUpperCase(Locale.ROOT) + typeDescription.substring(1);
613 typeDescription = typeDescription.toUpperCase(Locale.ROOT);
614 sb.append(typeDescription);
615 sb.append(System.lineSeparator());
616 sb.append(System.lineSeparator());
620 appendArgUsage(sb, a, maxArgLength);
624 sb.append(System.lineSeparator());
628 return sb.toString();
631 private static void appendArgUsage(StringBuilder sb, Arg a,
634 boolean first = appendArgAndDescription(sb, null, null, a,
636 List<String> options = new ArrayList<>();
638 if (a.hasOption(Opt.BOOLEAN))
640 options.add("default " + (a.getDefaultBoolValue() ? a.argString()
641 : a.negateArgString()));
644 if (a.hasOption(Opt.MULTI))
646 options.add("multiple");
649 if (a.hasOption(Opt.LINKED))
651 options.add("can be linked");
654 if (a.hasOption(Opt.GLOB))
656 options.add("allows file globs");
659 if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
661 options.add("allows substitutions");
664 if (a.hasOption(Opt.ALLOWALL))
666 options.add("can be applied to all linked arguments");
669 if (a.hasOption(Opt.PRIVATE))
671 options.add("for internal use only");
674 if (a.hasOption(Opt.SECRET))
676 options.add("for development use only");
679 if (options.size() > 0)
683 sb.append(ARGDESCRIPTIONSEPARATOR);
687 sb.append(String.format("%-"
688 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
692 sb.append(String.join("; ", options));
694 sb.append(System.lineSeparator());
698 public static String argDisplayString(Arg a)
700 StringBuilder argSb = new StringBuilder();
702 a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
703 if (a.hasOption(Opt.STRING))
704 argSb.append("=value");
705 return argSb.toString();
708 public static boolean appendArgAndDescription(StringBuilder sb,
709 String aString, String description, Arg a, int maxArgLength)
711 return appendArgAndDescription(sb, aString, description, a,
712 maxArgLength, Platform.consoleWidth());
715 public static boolean appendArgAndDescription(StringBuilder sb,
716 String aString, String description, Arg a, int maxArgLength,
719 if (aString == null && a != null)
721 aString = argDisplayString(a);
723 if (description == null && a != null)
725 description = a.getDescription();
727 sb.append(String.format("%-" + maxArgLength + "s", aString));
728 if (aString.length() > maxArgLength)
730 sb.append(System.lineSeparator());
731 sb.append(String.format("%-" + maxArgLength + "s", ""));
734 int descLength = maxLength - maxArgLength
735 - ARGDESCRIPTIONSEPARATOR.length();
736 // reformat the descriptions lines to the right width
737 Iterator<String> descLines = null;
738 if (description != null)
740 descLines = Arrays.stream(description.split("\\n")).iterator();
742 List<String> splitDescLinesList = new ArrayList<>();
743 while (descLines != null && descLines.hasNext())
745 String line = descLines.next();
746 while (line.length() > descLength)
748 int splitIndex = line.lastIndexOf(" ", descLength);
749 splitDescLinesList.add(line.substring(0, splitIndex));
750 line = line.substring(splitIndex + 1);
752 splitDescLinesList.add(line);
755 Iterator<String> splitDescLines = splitDescLinesList.iterator();
756 boolean first = true;
757 if (splitDescLines != null)
759 while (splitDescLines.hasNext())
763 sb.append(ARGDESCRIPTIONSEPARATOR);
767 sb.append(String.format("%-"
768 + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
771 sb.append(splitDescLines.next());
772 sb.append(System.lineSeparator());
779 protected static Iterator<Arg> getAllOfType(Type type)
781 return getAllOfType(type, new Opt[] {});
784 protected static Iterator<Arg> getAllOfType(Type type, Opt... options)
786 Opt[] opts = options == null ? new Opt[] {} : options;
787 return EnumSet.allOf(Arg.class).stream().filter(a -> {
788 if (a.getType() != type)
799 private static List<Arg> argsSortedForDisplay(List<Type> types)
801 List<Arg> argsToSort;
802 // if no types provided, do all
803 if (types == null || types.size() == 0 || types.contains(Type.ALL))
806 .asList(EnumSet.allOf(Arg.class).toArray(new Arg[] {}));
810 argsToSort = new ArrayList<>();
811 for (Type type : types)
815 Arg.getAllOfType(type).forEachRemaining(a -> argsToSort.add(a));
819 Collections.sort(argsToSort, new ArgDisplayComparator());
823 private static final String ARGDESCRIPTIONSEPARATOR = " - ";
825 private static final int DESCRIPTIONINDENT = 20;
829 class ArgDisplayComparator implements Comparator<Arg>
831 private int compareArgOpts(Arg a, Arg b, Opt o)
833 int i = a.hasOption(o) ? (b.hasOption(o) ? 0 : -1)
834 : (b.hasOption(o) ? 1 : 0);
838 private int compareForDisplay(Arg a, Arg b)
842 // first compare types (in enum order)
843 int i = a.getType().compareTo(b.getType());
846 // do Opt.LAST next (oddly). Reversed args important!
847 i = compareArgOpts(b, a, Opt.LAST);
851 Opt[] optOrder = { Opt.HELP, Opt.FIRST, Opt.PRIMARY, Opt.STRING,
853 for (Opt o : optOrder)
855 i = compareArgOpts(a, b, o);
859 // finally order of appearance in enum declarations
860 return a.compareTo(b);
864 public int compare(Arg a, Arg b)
866 return compareForDisplay(a, b);