1 package jalview.bin.argparser;
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.EnumSet;
7 import java.util.Locale;
8 import java.util.stream.Collectors;
12 HELP("h"), CALCULATION, MENUBAR, STATUS, SHOWOVERVIEW, SHOWANNOTATIONS,
13 COLOUR("color"), FEATURES, ANNOTATIONS, GROOVY, GROUPS, HEADLESS, JABAWS,
14 DISPLAY, NEWS, SORTBYTREE, USAGESTATS, APPEND, OPEN, PROPS, QUESTIONNAIRE,
15 SETPROP, TREE, VDOC, VSESS, OUTPUT, SSANNOTATIONS, NOTEMPFAC, TEMPFAC,
16 TITLE, PAEMATRIX, WRAP, NOSTRUCTURE, STRUCTURE, STRUCTUREVIEWER, IMAGE,
17 TYPE, FORMAT, OVERWRITE, TEXTRENDERER, QUIT, CLOSE, DEBUG("d"), TRACE,
18 QUIET("q"), ARGFILE, NEW, NPP("n++"), SUBSTITUTIONS, INITSUBSTITUTIONS,
19 NIL, SPLASH, SETARGFILE, UNSETARGFILE, WEBSERVICEDISCOVERY, ALL, BACKUPS,
22 public static enum Opt
24 BOOLEAN, // This Arg can be specified as --arg or --noarg to give true or
25 // false. A default can be given with setOptions(bool, Opt....).
26 // Use ArgParser.isSet(Arg) to see if this arg was not specified.
27 STRING, // This Arg can accept a value either through --arg=value or --arg
29 UNARY, // This Arg is a boolean value, true if present, false if not. Like
30 // BOOLEAN but without the --noarg option.
31 MULTI, // This Arg can be specified multiple times. Multiple values are
32 // stored in the ArgValuesMap (along with their positional index) for
34 LINKED, // This Arg can be linked to others through a --arg[linkedId] or
35 // --arg[linkedId]=value. If no linkedId is specified then the
36 // current default linkedId will be used.
37 NODUPLICATEVALUES, // This Arg can only have one value (per linkedId). The
38 // first value will be used and subsequent values ignored
40 BOOTSTRAP, // This Arg value(s) can be determined at an earlier stage than
41 // non-BOOTSTRAP Args. Substitutions do not happen in BOOTSTRAP
42 // Args and they cannot be linked or contain SubVals. See
43 // jalview.bin.argparser.BootstrapArgs.
44 GLOB, // This Arg can expand wildcard filename "globs" (e.g.
45 // path/*/filename*). If the Arg value is given as --arg filename*
46 // then the shell will have expanded the glob already, but if
47 // specified as --arg=filename* then the Java glob expansion method
48 // will be used (see FileUtils.getFilenamesFromGlob()). Note that this
49 // might be different from the shell expansion rules.
50 NOACTION, // This Arg does not perform a data task, usually used to control
51 // flow in ArgParser.parse(args).
52 ALLOWSUBSTITUTIONS, // This Arg allows substitutions in its linkedId,
53 // SubVals and values.
54 PRIVATE, // This Arg is used internally, and cannot be specified by the
56 ALLOWALL, // This Arg can use the '*' linkedId to apply to all known
58 INCREMENTDEFAULTCOUNTER, // If an Arg has this option and the default
59 // linkedId is used, the defaultLinkedIdCounter is
60 // incremented *first*.
61 INPUT, // This Arg counts as an input for REQUIREINPUT
62 REQUIREINPUT, // This Arg can only be applied via --all if there is an
63 // input (i.e. --open or --append)
68 HELP.setOptions("Display this help message", Opt.UNARY, Opt.BOOTSTRAP);
69 CALCULATION.setOptions(true, Opt.BOOLEAN); // default "true" implies only
70 // expecting "--nocalculation"
71 MENUBAR.setOptions(true, Opt.BOOLEAN);
72 STATUS.setOptions(true, Opt.BOOLEAN);
73 SHOWOVERVIEW.setOptions(Opt.UNARY, Opt.LINKED);
74 SHOWANNOTATIONS.setOptions(Opt.BOOLEAN, Opt.LINKED);
75 COLOUR.setOptions(Opt.STRING, Opt.LINKED);
76 FEATURES.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
77 Opt.ALLOWSUBSTITUTIONS);
78 ANNOTATIONS.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
79 Opt.ALLOWSUBSTITUTIONS);
80 TREE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
81 Opt.ALLOWSUBSTITUTIONS);
82 GROOVY.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
83 Opt.ALLOWSUBSTITUTIONS);
84 GROUPS.setOptions(Opt.STRING, Opt.LINKED);
85 HEADLESS.setOptions(Opt.UNARY, Opt.BOOTSTRAP);
86 TESTOUTPUT.setOptions(Opt.UNARY, Opt.BOOTSTRAP);
87 JABAWS.setOptions(Opt.STRING, Opt.BOOTSTRAP);
88 DISPLAY.setOptions(true, Opt.BOOLEAN);
89 NEWS.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
90 SPLASH.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
91 SORTBYTREE.setOptions(true, Opt.LINKED, Opt.BOOLEAN);
92 QUESTIONNAIRE.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
93 USAGESTATS.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
94 WEBSERVICEDISCOVERY.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
95 APPEND.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
96 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT);
97 OPEN.setOptions(Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER,
98 Opt.MULTI, Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT);
99 PROPS.setOptions(Opt.STRING, Opt.BOOTSTRAP);
100 SETPROP.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP);
102 VDOC.setOptions(Opt.UNARY);
103 VSESS.setOptions(Opt.UNARY);
105 OUTPUT.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS,
106 Opt.ALLOWALL, Opt.REQUIREINPUT);
108 SSANNOTATIONS.setOptions(Opt.BOOLEAN, Opt.LINKED);
109 NOTEMPFAC.setOptions(Opt.UNARY, Opt.LINKED);
110 TEMPFAC.setOptions(Opt.STRING, Opt.LINKED);
111 TITLE.setOptions(Opt.STRING, Opt.LINKED);
112 PAEMATRIX.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
113 Opt.ALLOWSUBSTITUTIONS);
114 NOSTRUCTURE.setOptions(Opt.UNARY, Opt.LINKED);
115 STRUCTURE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
116 Opt.ALLOWSUBSTITUTIONS);
117 STRUCTUREVIEWER.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
118 WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED);
119 IMAGE.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS,
120 Opt.ALLOWALL, Opt.REQUIREINPUT);
121 TYPE.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWALL);
122 FORMAT.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWALL);
123 TEXTRENDERER.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWALL);
124 QUIT.setOptions(Opt.UNARY);
125 OVERWRITE.setOptions(Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL);
126 BACKUPS.setOptions(true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL);
127 CLOSE.setOptions(Opt.UNARY, Opt.LINKED, Opt.ALLOWALL);
128 DEBUG.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
129 TRACE.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
130 QUIET.setOptions(Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP);
131 ARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
132 Opt.ALLOWSUBSTITUTIONS);
133 NEW.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION,
134 Opt.INCREMENTDEFAULTCOUNTER);
135 NPP.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
136 SUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
137 INITSUBSTITUTIONS.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP,
138 Opt.NOACTION); // defaulting substitutions to true
139 NIL.setOptions(Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION);
140 SETARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
141 UNSETARGFILE.setOptions(Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
142 ALL.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
146 private final String[] argNames;
148 private Opt[] argOptions;
150 private boolean defaultBoolValue = false;
152 private String description = null;
159 private Arg(String... names)
161 int length = (names == null || names.length == 0
162 || (names.length == 1 && names[0] == null)) ? 1
164 this.argNames = new String[length];
165 this.argNames[0] = this.getName();
167 System.arraycopy(names, 0, this.argNames, 1, names.length);
170 public String argString()
172 return argString(false);
175 public String negateArgString()
177 return argString(true);
180 private String argString(boolean negate)
182 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
183 if (negate && hasOption(Opt.BOOLEAN))
184 sb.append(ArgParser.NEGATESTRING);
185 sb.append(getName());
186 return sb.toString();
189 public String toLongString()
191 StringBuilder sb = new StringBuilder();
192 sb.append(this.getClass().getName()).append('.').append(this.name());
194 if (getNames().length > 0)
196 sb.append(String.join("\", \"", getNames()));
197 if (getNames().length > 0)
200 sb.append("\nOpt: ");
201 // map List<Opt> to List<String> for the String.join
202 List<String> optList = Arrays.asList(argOptions).stream()
203 .map(opt -> opt.name()).collect(Collectors.toList());
204 sb.append(String.join(", ", optList));
206 return sb.toString();
209 public String[] getNames()
214 public String getName()
216 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
220 public final String toString()
225 public boolean hasOption(Opt o)
227 if (argOptions == null)
229 for (Opt option : argOptions)
237 protected void setOptions(Opt... options)
239 setOptions("", false, options);
242 protected void setOptions(String desc, Opt... options)
244 setOptions(desc, false, options);
247 protected void setOptions(boolean defaultBoolValue, Opt... options)
249 setOptions("", defaultBoolValue, options);
252 protected void setOptions(String desc, boolean defaultBoolValue,
255 this.description = desc;
256 this.defaultBoolValue = defaultBoolValue;
257 this.argOptions = options;
260 protected boolean getDefaultBoolValue()
262 return defaultBoolValue;
265 private void setDescription(String d)
270 protected String getDescription()
275 public static String booleanArgString(Arg a)
277 StringBuilder sb = new StringBuilder(a.argString());
278 if (a.hasOption(Opt.BOOLEAN))
281 sb.append(a.negateArgString());
283 return sb.toString();
286 public static final String usage()
288 StringBuilder sb = new StringBuilder();
290 sb.append("Usage: jalview [args]");
291 sb.append(System.lineSeparator());
293 int maxArgLength = 0;
294 for (Arg a : EnumSet.allOf(Arg.class))
296 if (a.hasOption(Opt.PRIVATE))
298 StringBuilder argSb = new StringBuilder();
299 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
301 if (a.hasOption(Opt.STRING))
302 argSb.append("=value");
303 if (argSb.length() > maxArgLength)
304 maxArgLength = argSb.length();
307 // might want to sort these
308 for (Arg a : EnumSet.allOf(Arg.class))
310 if (a.hasOption(Opt.PRIVATE))
312 StringBuilder argSb = new StringBuilder();
313 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
315 if (a.hasOption(Opt.STRING))
316 argSb.append("=value");
317 sb.append(String.format("%-" + maxArgLength + "s - %s",
318 argSb.toString(), a.getDescription()));
320 List<String> options = new ArrayList<>();
322 if (a.hasOption(Opt.BOOLEAN))
324 options.add("default " + (a.getDefaultBoolValue() ? a.argString()
325 : a.negateArgString()));
328 if (a.hasOption(Opt.MULTI))
330 options.add("multiple");
333 if (a.hasOption(Opt.LINKED))
335 options.add("can be linked");
338 if (a.hasOption(Opt.GLOB))
340 options.add("allows file globs");
343 if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
345 options.add("allows substitutions");
348 if (options.size() > 0)
351 sb.append(String.join("; ", options));
354 sb.append(System.lineSeparator());
356 return sb.toString();