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
61 HELP.setOptions("Display this help message", Opt.UNARY, Opt.BOOTSTRAP);
62 CALCULATION.setOptions(true, Opt.BOOLEAN); // default "true" implies only
63 // expecting "--nocalculation"
64 MENUBAR.setOptions(true, Opt.BOOLEAN);
65 STATUS.setOptions(true, Opt.BOOLEAN);
66 SHOWOVERVIEW.setOptions(Opt.UNARY, Opt.LINKED);
67 ANNOTATIONS.setOptions(Opt.BOOLEAN, Opt.LINKED);
68 COLOUR.setOptions(Opt.STRING, Opt.LINKED);
69 FEATURES.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
70 Opt.ALLOWSUBSTITUTIONS);
71 GROOVY.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
72 Opt.ALLOWSUBSTITUTIONS);
73 GROUPS.setOptions(Opt.STRING, Opt.LINKED);
74 HEADLESS.setOptions(Opt.UNARY, Opt.BOOTSTRAP);
75 JABAWS.setOptions(Opt.STRING);
76 DISPLAY.setOptions(true, Opt.BOOLEAN);
77 GUI.setOptions(true, Opt.BOOLEAN);
78 NEWS.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
79 SPLASH.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
80 // expects a string value
81 SORTBYTREE.setOptions(true, Opt.BOOLEAN);
82 USAGESTATS.setOptions(true, Opt.BOOLEAN);
83 APPEND.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
84 Opt.ALLOWSUBSTITUTIONS);
85 OPEN.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
86 Opt.ALLOWSUBSTITUTIONS);
87 PROPS.setOptions(Opt.STRING, Opt.BOOTSTRAP);
88 QUESTIONNAIRE.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
89 SETPROP.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP);
90 TREE.setOptions(Opt.STRING);
92 VDOC.setOptions(Opt.UNARY);
93 VSESS.setOptions(Opt.UNARY);
95 OUTPUT.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS,
98 SSANNOTATIONS.setOptions(Opt.BOOLEAN, Opt.LINKED);
99 NOTEMPFAC.setOptions(Opt.UNARY, Opt.LINKED);
100 TEMPFAC.setOptions(Opt.STRING, Opt.LINKED);
101 TITLE.setOptions(Opt.STRING, Opt.LINKED);
102 PAEMATRIX.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
103 Opt.ALLOWSUBSTITUTIONS);
104 NOSTRUCTURE.setOptions(Opt.UNARY, Opt.LINKED);
105 STRUCTURE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
106 Opt.ALLOWSUBSTITUTIONS);
107 STRUCTUREVIEWER.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
108 WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED);
109 IMAGE.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS,
111 QUIT.setOptions(Opt.UNARY);
112 CLOSE.setOptions(Opt.UNARY, Opt.LINKED, Opt.ALLOWALL);
113 DEBUG.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
114 QUIET.setOptions(Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP);
115 ARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
116 Opt.ALLOWSUBSTITUTIONS);
117 NEWFRAME.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
118 NPP.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
119 SUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
120 INITSUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION);
121 NIL.setOptions(Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION);
122 SETARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
123 UNSETARGFILE.setOptions(Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
124 WEBSERVICEDISCOVERY.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
125 ALLFRAMES.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
128 private final String[] argNames;
130 private Opt[] argOptions;
132 private boolean defaultBoolValue = false;
134 private String description = null;
141 private Arg(String... names)
143 int length = (names == null || names.length == 0
144 || (names.length == 1 && names[0] == null)) ? 1
146 this.argNames = new String[length];
147 this.argNames[0] = this.getName();
149 System.arraycopy(names, 0, this.argNames, 1, names.length);
152 public String argString()
154 return argString(false);
157 public String negateArgString()
159 return argString(true);
162 private String argString(boolean negate)
164 StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
165 if (negate && hasOption(Opt.BOOLEAN))
166 sb.append(ArgParser.NEGATESTRING);
167 sb.append(getName());
168 return sb.toString();
171 public String toLongString()
173 StringBuilder sb = new StringBuilder();
174 sb.append(this.getClass().getName()).append('.').append(this.name());
176 if (getNames().length > 0)
178 sb.append(String.join("\", \"", getNames()));
179 if (getNames().length > 0)
182 sb.append("\nOpt: ");
183 // map List<Opt> to List<String> for the String.join
184 List<String> optList = Arrays.asList(argOptions).stream()
185 .map(opt -> opt.name()).collect(Collectors.toList());
186 sb.append(String.join(", ", optList));
188 return sb.toString();
191 public String[] getNames()
196 public String getName()
198 return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
202 public final String toString()
207 public boolean hasOption(Opt o)
209 if (argOptions == null)
211 for (Opt option : argOptions)
219 protected void setOptions(Opt... options)
221 setOptions("", false, options);
224 protected void setOptions(String desc, Opt... options)
226 setOptions(desc, false, options);
229 protected void setOptions(boolean defaultBoolValue, Opt... options)
231 setOptions("", defaultBoolValue, options);
234 protected void setOptions(String desc, boolean defaultBoolValue,
237 this.description = desc;
238 this.defaultBoolValue = defaultBoolValue;
239 this.argOptions = options;
242 protected boolean getDefaultBoolValue()
244 return defaultBoolValue;
247 private void setDescription(String d)
252 protected String getDescription()
257 public static String booleanArgString(Arg a)
259 StringBuilder sb = new StringBuilder(a.argString());
260 if (a.hasOption(Opt.BOOLEAN))
263 sb.append(a.negateArgString());
265 return sb.toString();
268 public static final String usage()
270 StringBuilder sb = new StringBuilder();
272 sb.append("Usage: jalview [args]");
273 sb.append(System.lineSeparator());
275 int maxArgLength = 0;
276 for (Arg a : EnumSet.allOf(Arg.class))
278 if (a.hasOption(Opt.PRIVATE))
280 StringBuilder argSb = new StringBuilder();
281 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
283 if (a.hasOption(Opt.STRING))
284 argSb.append("=value");
285 if (argSb.length() > maxArgLength)
286 maxArgLength = argSb.length();
289 // might want to sort these
290 for (Arg a : EnumSet.allOf(Arg.class))
292 if (a.hasOption(Opt.PRIVATE))
294 StringBuilder argSb = new StringBuilder();
295 argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
297 if (a.hasOption(Opt.STRING))
298 argSb.append("=value");
299 sb.append(String.format("%-" + maxArgLength + "s - %s",
300 argSb.toString(), a.getDescription()));
302 List<String> options = new ArrayList<>();
304 if (a.hasOption(Opt.BOOLEAN))
306 options.add("default " + (a.getDefaultBoolValue() ? a.argString()
307 : a.negateArgString()));
310 if (a.hasOption(Opt.MULTI))
312 options.add("multiple");
315 if (a.hasOption(Opt.LINKED))
317 options.add("can be linked");
320 if (a.hasOption(Opt.GLOB))
322 options.add("allows file globs");
325 if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
327 options.add("allows substitutions");
330 if (options.size() > 0)
333 sb.append(String.join("; ", options));
336 sb.append(System.lineSeparator());
338 return sb.toString();