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, QUIT, CLOSE,
17 DEBUG("d"), QUIET("q"), ARGFILE, NEWFRAME, NPP("n++"), SUBSTITUTIONS,
18 INITSUBSTITUTIONS, NIL, SPLASH, SETARGFILE, UNSETARGFILE,
19 WEBSERVICEDISCOVERY, ALLFRAMES;
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 --allframes 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 QUIT.setOptions(Opt.UNARY);
118 CLOSE.setOptions(Opt.UNARY, Opt.LINKED, Opt.ALLOWALL);
119 DEBUG.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
120 QUIET.setOptions(Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP);
121 ARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
122 Opt.ALLOWSUBSTITUTIONS);
123 NEWFRAME.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
124 NPP.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
125 SUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
126 INITSUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION);
127 NIL.setOptions(Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION);
128 SETARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
129 UNSETARGFILE.setOptions(Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
130 WEBSERVICEDISCOVERY.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
131 ALLFRAMES.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
135 private final String[] argNames;
137 private Opt[] argOptions;
139 private boolean defaultBoolValue = false;
141 private String description = null;
148 private Arg(String... names)
150 int length = (names == null || names.length == 0
151 || (names.length == 1 && names[0] == null)) ? 1
153 this.argNames = new String[length];
154 this.argNames[0] = this.getName();
156 System.arraycopy(names, 0, this.argNames, 1, names.length);
159 public String argString()
161 return argString(false);
164 public String negateArgString()
166 return argString(true);
169 private String argString(boolean negate)
171 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
172 if (negate && hasOption(Opt.BOOLEAN))
173 sb.append(ArgParser.NEGATESTRING);
174 sb.append(getName());
175 return sb.toString();
178 public String toLongString()
180 StringBuilder sb = new StringBuilder();
181 sb.append(this.getClass().getName()).append('.').append(this.name());
183 if (getNames().length > 0)
185 sb.append(String.join("\", \"", getNames()));
186 if (getNames().length > 0)
189 sb.append("\nOpt: ");
190 // map List<Opt> to List<String> for the String.join
191 List<String> optList = Arrays.asList(argOptions).stream()
192 .map(opt -> opt.name()).collect(Collectors.toList());
193 sb.append(String.join(", ", optList));
195 return sb.toString();
198 public String[] getNames()
203 public String getName()
205 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
209 public final String toString()
214 public boolean hasOption(Opt o)
216 if (argOptions == null)
218 for (Opt option : argOptions)
226 protected void setOptions(Opt... options)
228 setOptions("", false, options);
231 protected void setOptions(String desc, Opt... options)
233 setOptions(desc, false, options);
236 protected void setOptions(boolean defaultBoolValue, Opt... options)
238 setOptions("", defaultBoolValue, options);
241 protected void setOptions(String desc, boolean defaultBoolValue,
244 this.description = desc;
245 this.defaultBoolValue = defaultBoolValue;
246 this.argOptions = options;
249 protected boolean getDefaultBoolValue()
251 return defaultBoolValue;
254 private void setDescription(String d)
259 protected String getDescription()
264 public static String booleanArgString(Arg a)
266 StringBuilder sb = new StringBuilder(a.argString());
267 if (a.hasOption(Opt.BOOLEAN))
270 sb.append(a.negateArgString());
272 return sb.toString();
275 public static final String usage()
277 StringBuilder sb = new StringBuilder();
279 sb.append("Usage: jalview [args]");
280 sb.append(System.lineSeparator());
282 int maxArgLength = 0;
283 for (Arg a : EnumSet.allOf(Arg.class))
285 if (a.hasOption(Opt.PRIVATE))
287 StringBuilder argSb = new StringBuilder();
288 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
290 if (a.hasOption(Opt.STRING))
291 argSb.append("=value");
292 if (argSb.length() > maxArgLength)
293 maxArgLength = argSb.length();
296 // might want to sort these
297 for (Arg a : EnumSet.allOf(Arg.class))
299 if (a.hasOption(Opt.PRIVATE))
301 StringBuilder argSb = new StringBuilder();
302 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
304 if (a.hasOption(Opt.STRING))
305 argSb.append("=value");
306 sb.append(String.format("%-" + maxArgLength + "s - %s",
307 argSb.toString(), a.getDescription()));
309 List<String> options = new ArrayList<>();
311 if (a.hasOption(Opt.BOOLEAN))
313 options.add("default " + (a.getDefaultBoolValue() ? a.argString()
314 : a.negateArgString()));
317 if (a.hasOption(Opt.MULTI))
319 options.add("multiple");
322 if (a.hasOption(Opt.LINKED))
324 options.add("can be linked");
327 if (a.hasOption(Opt.GLOB))
329 options.add("allows file globs");
332 if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
334 options.add("allows substitutions");
337 if (options.size() > 0)
340 sb.append(String.join("; ", options));
343 sb.append(System.lineSeparator());
345 return sb.toString();