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.Cache;
14 import jalview.util.ChannelProperties;
19 // Initialising arguments (BOOTSTRAP)
20 HELP(Type.HELP, "h", "Display this help statement", Opt.UNARY,
21 Opt.BOOTSTRAP, Opt.HASTYPE, Opt.MULTI),
23 * Other --help-type Args will be added by the static block.
25 VERSION(Type.CONFIG, "v",
26 "Display the version of "
27 + ChannelProperties.getProperty("app_name"),
28 Opt.UNARY, Opt.BOOTSTRAP),
30 "Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed.",
31 Opt.UNARY, Opt.BOOTSTRAP),
32 JABAWS(Type.CONFIG, "Set a different URL to connect to a JABAWS server.",
33 Opt.STRING, Opt.BOOTSTRAP),
34 NEWS(Type.CONFIG, "Show (or don't show) the news feed.", true,
35 Opt.BOOLEAN, Opt.BOOTSTRAP),
37 "Show (or don't show) the About Jalview splash screen.", true,
38 Opt.BOOLEAN, Opt.BOOTSTRAP),
39 QUESTIONNAIRE(Type.CONFIG,
40 "Show (or don't show) the questionnaire if one is available.",
41 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
42 USAGESTATS(Type.CONFIG,
43 "Send (or don't send) initial launch usage stats.", true,
44 Opt.BOOLEAN, Opt.BOOTSTRAP),
45 WEBSERVICEDISCOVERY(Type.CONFIG,
46 "Attempt (or don't attempt) to connect to JABAWS web services.",
47 true, Opt.BOOLEAN, Opt.BOOTSTRAP),
49 "Use a file as the preferences file instead of the usual ~/"
50 + ChannelProperties.getProperty("preferences.filename")
52 Opt.STRING, Opt.BOOTSTRAP),
53 DEBUG(Type.CONFIG, "d", "Start Jalview in debug log level.", Opt.BOOLEAN,
55 TRACE(Type.CONFIG, "Start Jalview in trace log level.", Opt.BOOLEAN,
56 Opt.BOOTSTRAP, Opt.SECRET),
57 QUIET(Type.CONFIG, "q",
58 "Stop all output to STDOUT (after the Java Virtual Machine has started). Use ‑‑quiet a second time to stop all output to STDERR.",
59 Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP),
60 INITSUBSTITUTIONS(Type.CONFIG,
61 "Set ‑‑substitutions to be initially enabled (or initially disabled).",
62 true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
64 // Opening an alignment
66 "Opens one or more alignment files or URLs in new alignment windows.",
67 Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER, Opt.MULTI,
68 Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.STORED,
71 "Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
72 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
73 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.PRIMARY),
75 "Specifies the title for the open alignment window as string.",
76 Opt.STRING, Opt.LINKED),
77 COLOUR(Type.OPENING, "color", // being a bit soft on the Americans!
78 "Applies the colour scheme to the open alignment window. Valid values are:\n"
79 + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
80 + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
81 + "gecos-blossom,\n" + "gecos-sunset,\n"
82 + "gecos-ocean,\n" + "hydrophobic,\n"
83 + "helix-propensity,\n" + "strand-propensity,\n"
84 + "turn-propensity,\n" + "buried-index,\n"
85 + "nucleotide,\n" + "nucleotide-ambiguity,\n"
86 + "purine-pyrimidine,\n" + "rna-helices,\n"
87 + "t-coffee-scores,\n" + "sequence-id.",
88 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
89 FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
90 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
91 TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
92 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
93 SORTBYTREE(Type.OPENING,
94 "Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
95 true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWALL),
96 ANNOTATIONS(Type.OPENING,
97 "Add an annotations file or URL to the open alignment.",
98 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
99 SHOWANNOTATIONS(Type.OPENING,
100 "Enforces showing (or not showing) alignment annotations.",
101 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
103 "Enforces wrapped (or not wrapped) alignment formatting.",
104 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
105 NOSTRUCTURE(Type.OPENING,
106 "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
107 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
109 // Adding a 3D structure
110 STRUCTURE(Type.STRUCTURE,
111 "Load a structure file or URL associated with a sequence in the open alignment.\n"
112 + "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.",
113 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS,
115 SEQID(Type.STRUCTURE,
116 "Specify the sequence name for the preceding --structure to be associated with.",
117 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
118 PAEMATRIX(Type.STRUCTURE,
119 "Add a PAE json matrix file to the preceding --structure.",
120 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
121 TEMPFAC(Type.STRUCTURE,
122 "Set the type of temperature factor. Possible values are:\n"
123 + "default,\n" + "plddt.",
124 Opt.STRING, Opt.LINKED),
125 STRUCTUREVIEWER(Type.STRUCTURE,
126 "Set the structure viewer to use to open the 3D structure file specified in previous --structure to name. Possible values of name are:\n"
127 + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
129 Opt.STRING, Opt.LINKED, Opt.MULTI),
130 STRUCTUREIMAGE(Type.STRUCTURE,
131 "Export an image of a 3D structure opened in JMOL", Opt.STRING,
132 Opt.LINKED, Opt.MULTI),
133 NOTEMPFAC(Type.STRUCTURE,
134 "Do not show the temperature factor annotation for the preceding --structure.",
135 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL, Opt.SECRET), // keep this secret
138 SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
143 "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"
144 + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
145 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
146 Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY),
148 "Set the image format for the preceding --image to name. Valid values for name are: svg,\n"
149 + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
150 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
151 TEXTRENDERER(Type.IMAGE,
152 "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"
153 + "text,\n" + "lineart.",
154 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
156 "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).",
157 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
159 "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).",
160 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
162 "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).",
163 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
165 "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"
166 + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
167 + "stockholm (sto, stk),\n" + "pir (pir),\n"
168 + "blc (blc),\n" + "amsa (amsa),\n" + "json (json),\n"
169 + "pileup (pileup),\n" + "msf (msf),\n"
170 + "clustal (aln),\n" + "phylip (phy),\n"
171 + "jalview (jvp, jar).",
172 Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
173 Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY),
175 "Sets the format for the preceding --output file. Valid formats are:\n"
176 + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n"
177 + "blc,\n" + "amsa,\n" + "json,\n" + "pileup,\n"
178 + "msf,\n" + "clustal,\n" + "phylip,\n" + "jalview.",
179 Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
181 "Process a groovy script in the file for the open alignment.",
182 Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS,
185 "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.",
186 true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
187 OVERWRITE(Type.OUTPUT,
188 "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.",
189 Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
191 "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.",
192 Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
194 // controlling flow of arguments
196 "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.",
197 Opt.UNARY, Opt.MULTI, Opt.NOACTION, Opt.INCREMENTDEFAULTCOUNTER),
198 SUBSTITUTIONS(Type.FLOW,
199 "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"
200 + "{dirname}, - the directory (folder) name of the currently --opened file (or first --appended file),\n"
201 + "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
202 + "{argfiledirname} - the directory (folder) name of the current --argfile,\n"
203 + "{n} - the value of the index counter (starting at 0).\n"
204 + "{++n} - increase and substitute the value of the index counter,\n"
205 + "{} - the value of the current alignment window default index.",
206 true, Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
208 "Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
209 + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
210 + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
211 Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
212 Opt.ALLOWSUBSTITUTIONS),
213 NPP(Type.FLOW, "n++",
214 "Increase the index counter used in argument value substitutions.",
215 Opt.UNARY, Opt.MULTI, Opt.NOACTION),
217 "Apply the following output arguments to all sets of linked arguments.",
218 Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
220 "Apply the following output arguments to all of the last --open'ed set of linked arguments.",
221 Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
223 "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
227 TESTOUTPUT(Type.CONFIG,
228 "Allow specific stdout information. For testing purposes only.",
229 Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
230 SETPROP(Type.CONFIG, "Set an individual Java System property.",
231 Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.SECRET), // not in use yet
233 "This argument does nothing on its own, but can be used with linkedIds.",
234 Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION, Opt.SECRET),
236 // private options (inserted during arg processing)
237 SETARGFILE(Type.FLOW,
238 "Sets the current value of the argfilename. Inserted before argfilecontents.",
239 Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTI, Opt.PRIVATE,
241 UNSETARGFILE(Type.FLOW,
242 "Unsets the current value of the argfilename. Inserted after argfile contents.",
243 Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION),
245 // these last two have no purpose in the normal Jalview application but are
246 // used by jalview.bin.Launcher to set memory settings. They are not used by
247 // argparser but are here for Usage statement reasons.
248 JVMMEMPC(Type.CONFIG,
249 "Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
250 + "The equals sign (\"=\") separator must be used with no spaces.",
251 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING),
252 JVMMEMMAX(Type.CONFIG,
253 "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"
254 + "The equals sign (\"=\") separator must be used with no spaces.",
255 Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING),
259 public static enum Opt
261 BOOLEAN, // This Arg can be specified as --arg or --noarg to give true or
262 // false. A default can be given with setOptions(bool, Opt....).
263 // Use ArgParser.isSet(Arg) to see if this arg was not specified.
264 STRING, // This Arg can accept a value either through --arg=value or --arg
266 UNARY, // This Arg is a boolean value, true if present, false if not. Like
267 // BOOLEAN but without the --noarg option.
268 MULTI, // This Arg can be specified multiple times. Multiple values are
269 // stored in the ArgValuesMap (along with their positional index) for
271 LINKED, // This Arg can be linked to others through a --arg[linkedId] or
272 // --arg[linkedId]=value. If no linkedId is specified then the
273 // current default linkedId will be used.
274 NODUPLICATEVALUES, // This Arg can only have one value (per linkedId). The
275 // first value will be used and subsequent values ignored
277 BOOTSTRAP, // This Arg value(s) can be determined at an earlier stage than
278 // non-BOOTSTRAP Args. Substitutions do not happen in BOOTSTRAP
279 // Args and they cannot be linked or contain SubVals. See
280 // jalview.bin.argparser.BootstrapArgs.
281 GLOB, // This Arg can expand wildcard filename "globs" (e.g.
282 // path/*/filename*). If the Arg value is given as --arg filename*
283 // then the shell will have expanded the glob already, but if
284 // specified as --arg=filename* then the Java glob expansion method
285 // will be used (see FileUtils.getFilenamesFromGlob()). Note that this
286 // might be different from the shell expansion rules.
287 NOACTION, // This Arg does not perform a data task, usually used to control
288 // flow in ArgParser.parse(args).
289 ALLOWSUBSTITUTIONS, // This Arg allows substitutions in its linkedId,
290 // SubVals and values.
291 PRIVATE, // This Arg is used internally, and cannot be specified by the
293 SECRET, // This Arg is used by development processes and although it can be
294 // set by the user, it is not displayed to the user.
295 ALLOWALL, // This Arg can use the '*' linkedId to apply to all known
297 INCREMENTDEFAULTCOUNTER, // If an Arg has this option and the default
298 // linkedId is used, the defaultLinkedIdCounter is
299 // incremented *first*.
300 INPUT, // This Arg counts as an input for REQUIREINPUT
301 REQUIREINPUT, // This Arg can only be applied via --all if there is an
302 // input (i.e. --open or --append)
303 OUTPUT, // This Arg provides an output filename. With Opt.ALLOWALL *.ext is
304 // shorthand for --all --output={basename}.ext
305 STORED, // This Arg resets and creates a new set of "opened" linkedIds
306 HELP, // This Arg is a --help type arg
307 PRIMARY, // This Arg is the main Arg for its type
308 HASTYPE, // This Arg can have an Arg.Type assigned to it (and no value)
311 public static enum Type
313 // Type restricts argument to certain usage output
314 CONFIG("Arguments user to configure "
315 + ChannelProperties.getProperty("app_name") + " from startup"),
316 OPENING("Arguments used to open and format alignments"),
317 STRUCTURE("Arguments used to add and format 3D structure data"),
318 PROCESS("Arguments used to process an alignment once opened"),
319 OUTPUT("Arguments used to save data from a processed alignment"),
320 IMAGE("Arguments used to export an image of an alignment"),
321 FLOW("Arguments that control processing of the other arguments"),
322 HELP("Arguments to provide help text"), // --help
323 ALL("All arguments"), // mostly just a place-holder for --help-all
324 NONE("No specific arguments"), // mostly a place-holder for --help
325 INVALID("This type of argument doesn't exist");
327 private String description;
329 private Type(String description)
331 this.description = description;
334 public String description()
342 for (Type t : EnumSet.allOf(Type.class))
344 String type = t.name();
349 private final String[] argNames;
351 private Opt[] argOptions;
353 private boolean defaultBoolValue;
355 private String description;
359 private Arg(Type type, String description, Opt... options)
361 this(type, null, description, false, options);
364 private Arg(Type type, String description, boolean defaultBoolean,
367 this(type, null, description, defaultBoolean, options);
370 private Arg(Type type, String alternativeName, String description,
373 this(type, alternativeName, description, false, options);
376 private Arg(Type type, String alternativeName, String description,
377 boolean defaultBoolean, Opt... options)
379 this.argNames = alternativeName != null
381 { this.getName(), alternativeName }
385 this.description = description;
386 this.defaultBoolValue = defaultBoolean;
387 this.setOptions(options);
390 public String argString()
392 return argString(false);
395 public String negateArgString()
397 return argString(true);
400 private String argString(boolean negate)
402 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
403 if (negate && hasOption(Opt.BOOLEAN))
404 sb.append(ArgParser.NEGATESTRING);
405 sb.append(getName());
406 return sb.toString();
409 public String toLongString()
411 StringBuilder sb = new StringBuilder();
412 sb.append(this.getClass().getName()).append('.').append(this.name());
414 if (getNames().length > 0)
416 sb.append(String.join("\", \"", getNames()));
417 if (getNames().length > 0)
420 sb.append("\nType: " + type.name());
421 sb.append("\nOpt: ");
422 // map List<Opt> to List<String> for the String.join
423 List<String> optList = Arrays.asList(argOptions).stream()
424 .map(opt -> opt.name()).collect(Collectors.toList());
425 sb.append(String.join(", ", optList));
427 return sb.toString();
430 public String[] getNames()
435 public String getName()
437 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
441 public final String toString()
446 public boolean hasOption(Opt o)
448 if (argOptions == null)
450 for (Opt option : argOptions)
458 public boolean hasAllOptions(Opt... opts)
462 if (!this.hasOption(o))
468 protected void setOptions(Opt... options)
470 this.argOptions = options;
473 protected boolean getDefaultBoolValue()
475 return defaultBoolValue;
478 public Type getType()
483 protected String getDescription()
488 public static String booleanArgString(Arg a)
490 StringBuilder sb = new StringBuilder(a.argString());
491 if (a.hasOption(Opt.BOOLEAN))
494 sb.append(a.negateArgString());
496 return sb.toString();
499 public static final String usage()
504 public static final String usage(List<Arg> helpArgs)
506 StringBuilder sb = new StringBuilder();
508 sb.append(ChannelProperties.getProperty("app_name"));
509 String version = Cache.getDefault("VERSION", null);
512 sb.append(" version ");
513 sb.append(Cache.getDefault("VERSION", "unknown"));
515 sb.append(System.lineSeparator());
516 sb.append("Usage: jalview [files...] [args]");
517 sb.append(System.lineSeparator());
518 sb.append(System.lineSeparator());
521 Type type = Type.HELP;
522 Iterator<Arg> typeArgs = Arg.getAllOfType(type);
524 int maxArgLength = 0;
525 for (Arg a : EnumSet.allOf(Arg.class))
527 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
530 StringBuilder argSb = new StringBuilder();
531 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
533 if (a.hasOption(Opt.STRING))
534 argSb.append("=value");
535 if (argSb.length() > maxArgLength)
536 maxArgLength = argSb.length();
539 // might want to sort these
540 for (Arg a : EnumSet.allOf(Arg.class))
542 if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
544 StringBuilder argSb = new StringBuilder();
545 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
547 if (a.hasOption(Opt.STRING))
548 argSb.append("=value");
549 Iterator<String> descLines = null;
550 if (a.getDescription() != null)
552 descLines = Arrays.stream(a.getDescription().split("\\n"))
555 sb.append(String.format("%-" + maxArgLength + "s", argSb.toString()));
556 boolean first = true;
557 if (descLines != null)
559 while (descLines.hasNext())
564 sb.append(" ".repeat(maxArgLength + 3));
565 sb.append(descLines.next());
566 sb.append(System.lineSeparator());
571 List<String> options = new ArrayList<>();
573 if (a.hasOption(Opt.BOOLEAN))
575 options.add("default " + (a.getDefaultBoolValue() ? a.argString()
576 : a.negateArgString()));
579 if (a.hasOption(Opt.MULTI))
581 options.add("multiple");
584 if (a.hasOption(Opt.LINKED))
586 options.add("can be linked");
589 if (a.hasOption(Opt.GLOB))
591 options.add("allows file globs");
594 if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
596 options.add("allows substitutions");
599 if (a.hasOption(Opt.ALLOWALL))
601 options.add("can be applied to all linked arguments");
604 if (a.hasOption(Opt.PRIVATE))
606 options.add("for internal use only");
609 if (a.hasOption(Opt.SECRET))
611 options.add("for development use only");
614 if (options.size() > 0)
619 sb.append(" ".repeat(maxArgLength + 3));
621 sb.append(String.join("; ", options));
623 sb.append(System.lineSeparator());
625 sb.append(System.lineSeparator());
627 return sb.toString();
630 protected static Iterator<Arg> getAllOfType(Type type)
632 return getAllOfType(type, new Opt[] {});
635 protected static Iterator<Arg> getAllOfType(Type type, Opt... options)
637 Opt[] opts = options == null ? new Opt[] {} : options;
638 return EnumSet.allOf(Arg.class).stream().filter(a -> {
639 if (a.getType() != type)
650 private static List<Arg> sortForDisplay(Type... types)
652 List<Arg> argsToSort;
653 // if no types provided, do all
654 if (types == null || types.length == 0)
657 .asList(EnumSet.allOf(Arg.class).toArray(new Arg[] {}));
661 argsToSort = new ArrayList<>();
662 for (Type type : types)
664 Arg.getAllOfType(type).forEachRemaining(a -> argsToSort.add(a));
668 Collections.sort(argsToSort, new ArgComparator());
672 protected int compareForDisplay(Arg other)
676 // first compare types (in order of appearance)
677 int i = this.getType().compareTo(other.getType());
680 // next prioritise primary arguments
681 i = this.hasOption(Opt.PRIMARY)
682 ? (other.hasOption(Opt.PRIMARY) ? 0 : 1)
683 : (other.hasOption(Opt.PRIMARY) ? -1 : 0);
686 // finally order of appearance in enum declarations
687 i = this.compareTo(other);
695 class ArgComparator implements Comparator<Arg>
698 public int compare(Arg a, Arg b)
700 return a.compareForDisplay(b);