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, ANNOTATIONS,
13 COLOUR, FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, DISPLAY, GUI, NEWS,
14 SORTBYTREE, USAGESTATS, APPEND, OPEN, PROPS, QUESTIONNAIRE, SETPROP, TREE,
15 VDOC, VSESS, OUTPUT, SSANNOTATIONS, NOTEMPFAC, TEMPFAC, TITLE, PAEMATRIX,
16 WRAP, NOSTRUCTURE, STRUCTURE, STRUCTUREVIEWER, IMAGE, TYPE, RENDERER,
17 QUIT, CLOSE, DEBUG("d"), QUIET("q"), ARGFILE, NEW, NPP("n++"),
18 SUBSTITUTIONS, INITSUBSTITUTIONS, NIL, SPLASH, SETARGFILE, UNSETARGFILE,
19 WEBSERVICEDISCOVERY, ALL;
21 protected static enum Opt
23 BOOLEAN, // This Arg can be specified as --arg or --noarg to give true or
24 // false. A default can be given with setOptions(bool, Opt....).
25 // Use ArgParser.isSet(Arg) to see if this arg was not specified.
26 STRING, // This Arg can accept a value either through --arg=value or --arg
28 UNARY, // This Arg is a boolean value, true if present, false if not. Like
29 // BOOLEAN but without the --noarg option.
30 MULTI, // This Arg can be specified multiple times. Multiple values are
31 // stored in the ArgValuesMap (along with their positional index) for
33 LINKED, // This Arg can be linked to others through a --arg[linkedId] or
34 // --arg[linkedId]=value. If no linkedId is specified then the
35 // current default linkedId will be used.
36 NODUPLICATEVALUES, // This Arg can only have one value (per linkedId). The
37 // first value will be used and subsequent values ignored
39 BOOTSTRAP, // This Arg value(s) can be determined at an earlier stage than
40 // non-BOOTSTRAP Args. Substitutions do not happen in BOOTSTRAP
41 // Args and they cannot be linked or contain SubVals. See
42 // jalview.bin.argparser.BootstrapArgs.
43 GLOB, // This Arg can expand wildcard filename "globs" (e.g.
44 // path/*/filename*). If the Arg value is given as --arg filename*
45 // then the shell will have expanded the glob already, but if
46 // specified as --arg=filename* then the Java glob expansion method
47 // will be used (see FileUtils.getFilenamesFromGlob()). Note that this
48 // might be different from the shell expansion rules.
49 NOACTION, // This Arg does not perform a data task, usually used to control
50 // flow in ArgParser.parse(args).
51 ALLOWSUBSTITUTIONS, // This Arg allows substitutions in its linkedId,
52 // SubVals and values.
53 PRIVATE, // This Arg is used internally, and cannot be specified by the
55 ALLOWALL, // This Arg can use the '*' linkedId to apply to all known
57 INCREMENTDEFAULTCOUNTER, // If an Arg has this option and the default
58 // linkedId is used, the defaultLinkedIdCounter is
59 // incremented *first*.
60 INPUT, // This Arg counts as an input for REQUIREINPUT
61 REQUIREINPUT, // This Arg can only be applied via --all if there is an
62 // input (i.e. --open or --append)
67 HELP.setOptions("Display this help message", Opt.UNARY, Opt.BOOTSTRAP);
68 CALCULATION.setOptions(true, Opt.BOOLEAN); // default "true" implies only
69 // expecting "--nocalculation"
70 MENUBAR.setOptions(true, Opt.BOOLEAN);
71 STATUS.setOptions(true, Opt.BOOLEAN);
72 SHOWOVERVIEW.setOptions(Opt.UNARY, Opt.LINKED);
73 ANNOTATIONS.setOptions(Opt.BOOLEAN, Opt.LINKED);
74 COLOUR.setOptions(Opt.STRING, Opt.LINKED);
75 FEATURES.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
76 Opt.ALLOWSUBSTITUTIONS);
77 GROOVY.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
78 Opt.ALLOWSUBSTITUTIONS);
79 GROUPS.setOptions(Opt.STRING, Opt.LINKED);
80 HEADLESS.setOptions(Opt.UNARY, Opt.BOOTSTRAP);
81 JABAWS.setOptions(Opt.STRING);
82 DISPLAY.setOptions(true, Opt.BOOLEAN);
83 GUI.setOptions(true, Opt.BOOLEAN);
84 NEWS.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
85 SPLASH.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
86 // expects a string value
87 SORTBYTREE.setOptions(true, Opt.BOOLEAN);
88 USAGESTATS.setOptions(true, Opt.BOOLEAN);
89 APPEND.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
90 Opt.ALLOWSUBSTITUTIONS, Opt.INPUT);
91 OPEN.setOptions(Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER,
92 Opt.MULTI, Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT);
93 PROPS.setOptions(Opt.STRING, Opt.BOOTSTRAP);
94 QUESTIONNAIRE.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
95 SETPROP.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP);
96 TREE.setOptions(Opt.STRING);
98 VDOC.setOptions(Opt.UNARY);
99 VSESS.setOptions(Opt.UNARY);
101 OUTPUT.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS,
102 Opt.ALLOWALL, Opt.REQUIREINPUT);
104 SSANNOTATIONS.setOptions(Opt.BOOLEAN, Opt.LINKED);
105 NOTEMPFAC.setOptions(Opt.UNARY, Opt.LINKED);
106 TEMPFAC.setOptions(Opt.STRING, Opt.LINKED);
107 TITLE.setOptions(Opt.STRING, Opt.LINKED);
108 PAEMATRIX.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
109 Opt.ALLOWSUBSTITUTIONS);
110 NOSTRUCTURE.setOptions(Opt.UNARY, Opt.LINKED);
111 STRUCTURE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
112 Opt.ALLOWSUBSTITUTIONS);
113 STRUCTUREVIEWER.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
114 WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED);
115 IMAGE.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS,
116 Opt.ALLOWALL, Opt.REQUIREINPUT);
117 TYPE.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWALL);
118 RENDERER.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWALL);
119 QUIT.setOptions(Opt.UNARY);
120 CLOSE.setOptions(Opt.UNARY, Opt.LINKED, Opt.ALLOWALL);
121 DEBUG.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
122 QUIET.setOptions(Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP);
123 ARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
124 Opt.ALLOWSUBSTITUTIONS);
125 NEW.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION,
126 Opt.INCREMENTDEFAULTCOUNTER);
127 NPP.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
128 SUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
129 INITSUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION);
130 NIL.setOptions(Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION);
131 SETARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
132 UNSETARGFILE.setOptions(Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
133 WEBSERVICEDISCOVERY.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
134 ALL.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
138 private final String[] argNames;
140 private Opt[] argOptions;
142 private boolean defaultBoolValue = false;
144 private String description = null;
151 private Arg(String... names)
153 int length = (names == null || names.length == 0
154 || (names.length == 1 && names[0] == null)) ? 1
156 this.argNames = new String[length];
157 this.argNames[0] = this.getName();
159 System.arraycopy(names, 0, this.argNames, 1, names.length);
162 public String argString()
164 return argString(false);
167 public String negateArgString()
169 return argString(true);
172 private String argString(boolean negate)
174 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
175 if (negate && hasOption(Opt.BOOLEAN))
176 sb.append(ArgParser.NEGATESTRING);
177 sb.append(getName());
178 return sb.toString();
181 public String toLongString()
183 StringBuilder sb = new StringBuilder();
184 sb.append(this.getClass().getName()).append('.').append(this.name());
186 if (getNames().length > 0)
188 sb.append(String.join("\", \"", getNames()));
189 if (getNames().length > 0)
192 sb.append("\nOpt: ");
193 // map List<Opt> to List<String> for the String.join
194 List<String> optList = Arrays.asList(argOptions).stream()
195 .map(opt -> opt.name()).collect(Collectors.toList());
196 sb.append(String.join(", ", optList));
198 return sb.toString();
201 public String[] getNames()
206 public String getName()
208 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
212 public final String toString()
217 public boolean hasOption(Opt o)
219 if (argOptions == null)
221 for (Opt option : argOptions)
229 protected void setOptions(Opt... options)
231 setOptions("", false, options);
234 protected void setOptions(String desc, Opt... options)
236 setOptions(desc, false, options);
239 protected void setOptions(boolean defaultBoolValue, Opt... options)
241 setOptions("", defaultBoolValue, options);
244 protected void setOptions(String desc, boolean defaultBoolValue,
247 this.description = desc;
248 this.defaultBoolValue = defaultBoolValue;
249 this.argOptions = options;
252 protected boolean getDefaultBoolValue()
254 return defaultBoolValue;
257 private void setDescription(String d)
262 protected String getDescription()
267 public static String booleanArgString(Arg a)
269 StringBuilder sb = new StringBuilder(a.argString());
270 if (a.hasOption(Opt.BOOLEAN))
273 sb.append(a.negateArgString());
275 return sb.toString();
278 public static final String usage()
280 StringBuilder sb = new StringBuilder();
282 sb.append("Usage: jalview [args]");
283 sb.append(System.lineSeparator());
285 int maxArgLength = 0;
286 for (Arg a : EnumSet.allOf(Arg.class))
288 if (a.hasOption(Opt.PRIVATE))
290 StringBuilder argSb = new StringBuilder();
291 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
293 if (a.hasOption(Opt.STRING))
294 argSb.append("=value");
295 if (argSb.length() > maxArgLength)
296 maxArgLength = argSb.length();
299 // might want to sort these
300 for (Arg a : EnumSet.allOf(Arg.class))
302 if (a.hasOption(Opt.PRIVATE))
304 StringBuilder argSb = new StringBuilder();
305 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
307 if (a.hasOption(Opt.STRING))
308 argSb.append("=value");
309 sb.append(String.format("%-" + maxArgLength + "s - %s",
310 argSb.toString(), a.getDescription()));
312 List<String> options = new ArrayList<>();
314 if (a.hasOption(Opt.BOOLEAN))
316 options.add("default " + (a.getDefaultBoolValue() ? a.argString()
317 : a.negateArgString()));
320 if (a.hasOption(Opt.MULTI))
322 options.add("multiple");
325 if (a.hasOption(Opt.LINKED))
327 options.add("can be linked");
330 if (a.hasOption(Opt.GLOB))
332 options.add("allows file globs");
335 if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
337 options.add("allows substitutions");
340 if (options.size() > 0)
343 sb.append(String.join("; ", options));
346 sb.append(System.lineSeparator());
348 return sb.toString();