e22cfc696c62cfe03dea57399c944faea5283308
[jalview.git] / src / jalview / bin / argparser / Arg.java
1 package jalview.bin.argparser;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.EnumSet;
6 import java.util.List;
7 import java.util.Locale;
8 import java.util.stream.Collectors;
9
10 public enum Arg
11 {
12   HELP("h"), CALCULATION, MENUBAR, STATUS, SHOWOVERVIEW, ANNOTATIONS,
13   COLOUR, FEATURES, GROOVY, GROUPS, HEADLESS, JABAWS, ANNOTATION,
14   ANNOTATION2, DISPLAY, GUI, NEWS, SORTBYTREE, USAGESTATS, OPEN, OPENNEW,
15   PROPS, QUESTIONNAIRE, SETPROP, TREE, VDOC, VSESS, OUTPUT, OUTPUTTYPE,
16   SSANNOTATION, NOTEMPFAC, TEMPFAC, TEMPFAC_LABEL, TEMPFAC_DESC,
17   TEMPFAC_SHADING, TITLE, PAEMATRIX, WRAP, NOSTRUCTURE, STRUCTURE, IMAGE,
18   QUIT, CLOSE, DEBUG("d"), QUIET("q"), ARGFILE, INCREMENT, NPP("n++"),
19   SUBSTITUTIONS, INITSUBSTITUTIONS, NIL, SPLASH, SETARGFILE, UNSETARGFILE;
20
21   protected static enum Opt
22   {
23     BOOLEAN, STRING, UNARY, MULTI, LINKED, NODUPLICATEVALUES, BOOTSTRAP,
24     GLOB, NOACTION, ALLOWSUBSTITUTIONS, PRIVATE
25   }
26
27   static
28   {
29     HELP.setOptions("Display this help message", Opt.UNARY, Opt.BOOTSTRAP);
30     CALCULATION.setOptions(true, Opt.BOOLEAN); // default "true" implies only
31                                                // expecting "--nocalculation"
32     MENUBAR.setOptions(true, Opt.BOOLEAN);
33     STATUS.setOptions(true, Opt.BOOLEAN);
34     SHOWOVERVIEW.setOptions(Opt.UNARY, Opt.LINKED);
35     ANNOTATIONS.setOptions(Opt.STRING, Opt.LINKED);
36     COLOUR.setOptions(Opt.STRING, Opt.LINKED);
37     FEATURES.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
38             Opt.ALLOWSUBSTITUTIONS);
39     GROOVY.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
40             Opt.ALLOWSUBSTITUTIONS);
41     GROUPS.setOptions(Opt.STRING, Opt.LINKED);
42     HEADLESS.setOptions(Opt.UNARY, Opt.BOOTSTRAP);
43     JABAWS.setOptions(Opt.STRING);
44     ANNOTATION.setOptions(true, Opt.BOOLEAN, Opt.LINKED);
45     ANNOTATION2.setOptions(true, Opt.BOOLEAN, Opt.LINKED);
46     DISPLAY.setOptions(true, Opt.BOOLEAN);
47     GUI.setOptions(true, Opt.BOOLEAN);
48     NEWS.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
49     SPLASH.setOptions(true, Opt.BOOLEAN, Opt.BOOTSTRAP);
50     // expects a string value
51     SORTBYTREE.setOptions(true, Opt.BOOLEAN);
52     USAGESTATS.setOptions(true, Opt.BOOLEAN);
53     OPEN.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
54             Opt.ALLOWSUBSTITUTIONS);
55     OPENNEW.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
56             Opt.ALLOWSUBSTITUTIONS);
57     PROPS.setOptions(Opt.STRING, Opt.BOOTSTRAP);
58     QUESTIONNAIRE.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
59     SETPROP.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP);
60     TREE.setOptions(Opt.STRING);
61
62     VDOC.setOptions(Opt.UNARY);
63     VSESS.setOptions(Opt.UNARY);
64
65     OUTPUT.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS);
66     OUTPUTTYPE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI);
67
68     SSANNOTATION.setOptions(Opt.BOOLEAN, Opt.LINKED);
69     NOTEMPFAC.setOptions(Opt.UNARY, Opt.LINKED);
70     TEMPFAC.setOptions(Opt.STRING, Opt.LINKED);
71     TEMPFAC_LABEL.setOptions(Opt.STRING, Opt.LINKED);
72     TEMPFAC_DESC.setOptions(Opt.STRING, Opt.LINKED);
73     TEMPFAC_SHADING.setOptions(Opt.BOOLEAN, Opt.LINKED);
74     TITLE.setOptions(Opt.STRING, Opt.LINKED);
75     PAEMATRIX.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
76             Opt.ALLOWSUBSTITUTIONS);
77     NOSTRUCTURE.setOptions(Opt.UNARY, Opt.LINKED);
78     STRUCTURE.setOptions(Opt.STRING, Opt.LINKED, Opt.MULTI,
79             Opt.ALLOWSUBSTITUTIONS);
80     WRAP.setOptions(Opt.BOOLEAN, Opt.LINKED);
81     IMAGE.setOptions(Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS);
82     QUIT.setOptions(Opt.UNARY);
83     CLOSE.setOptions(Opt.UNARY, Opt.LINKED);
84     DEBUG.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP);
85     QUIET.setOptions(Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP);
86     ARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
87             Opt.ALLOWSUBSTITUTIONS);
88     INCREMENT.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
89     NPP.setOptions(Opt.UNARY, Opt.MULTI, Opt.NOACTION);
90     SUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION);
91     INITSUBSTITUTIONS.setOptions(Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION);
92     NIL.setOptions(Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION);
93     SETARGFILE.setOptions(Opt.STRING, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
94     UNSETARGFILE.setOptions(Opt.MULTI, Opt.PRIVATE, Opt.NOACTION);
95     // Opt.BOOTSTRAP args are parsed (not linked with no SubVals so using a
96     // simplified parser, see jalview.bin.argparser.BootstrapArgs)
97     // before a full parse of arguments and so can be accessible at an earlier
98     // stage to (e.g.) set debug log level, provide a props file (that might set
99     // log level), run headlessly, read an argfile instead of other args.
100   }
101
102   private final String[] argNames;
103
104   private Opt[] argOptions;
105
106   private boolean defaultBoolValue = false;
107
108   private String description = null;
109
110   private Arg()
111   {
112     this(new String[0]);
113   }
114
115   private Arg(String... names)
116   {
117     int length = (names == null || names.length == 0
118             || (names.length == 1 && names[0] == null)) ? 1
119                     : names.length + 1;
120     this.argNames = new String[length];
121     this.argNames[0] = this.getName();
122     if (length > 1)
123       System.arraycopy(names, 0, this.argNames, 1, names.length);
124   }
125
126   public String argString()
127   {
128     return argString(false);
129   }
130
131   public String negateArgString()
132   {
133     return argString(true);
134   }
135
136   private String argString(boolean negate)
137   {
138     StringBuilder sb = new StringBuilder(ArgParser.DOUBLEDASH);
139     if (negate && hasOption(Opt.BOOLEAN))
140       sb.append(ArgParser.NEGATESTRING);
141     sb.append(getName());
142     return sb.toString();
143   }
144
145   public String toLongString()
146   {
147     StringBuilder sb = new StringBuilder();
148     sb.append(this.getClass().getName()).append('.').append(this.name());
149     sb.append('(');
150     if (getNames().length > 0)
151       sb.append('"');
152     sb.append(String.join("\", \"", getNames()));
153     if (getNames().length > 0)
154       sb.append('"');
155     sb.append(")\n");
156     sb.append("\nOpt: ");
157     // map List<Opt> to List<String> for the String.join
158     List<String> optList = Arrays.asList(argOptions).stream()
159             .map(opt -> opt.name()).collect(Collectors.toList());
160     sb.append(String.join(", ", optList));
161     sb.append("\n");
162     return sb.toString();
163   }
164
165   public String[] getNames()
166   {
167     return argNames;
168   }
169
170   public String getName()
171   {
172     return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
173   }
174
175   @Override
176   public final String toString()
177   {
178     return getName();
179   }
180
181   public boolean hasOption(Opt o)
182   {
183     if (argOptions == null)
184       return false;
185     for (Opt option : argOptions)
186     {
187       if (o == option)
188         return true;
189     }
190     return false;
191   }
192
193   protected void setOptions(Opt... options)
194   {
195     setOptions("", false, options);
196   }
197
198   protected void setOptions(String desc, Opt... options)
199   {
200     setOptions(desc, false, options);
201   }
202
203   protected void setOptions(boolean defaultBoolValue, Opt... options)
204   {
205     setOptions("", defaultBoolValue, options);
206   }
207
208   protected void setOptions(String desc, boolean defaultBoolValue,
209           Opt... options)
210   {
211     this.description = desc;
212     this.defaultBoolValue = defaultBoolValue;
213     this.argOptions = options;
214   }
215
216   protected boolean getDefaultBoolValue()
217   {
218     return defaultBoolValue;
219   }
220
221   private void setDescription(String d)
222   {
223     description = d;
224   }
225
226   protected String getDescription()
227   {
228     return description;
229   }
230
231   public static String booleanArgString(Arg a)
232   {
233     StringBuilder sb = new StringBuilder(a.argString());
234     if (a.hasOption(Opt.BOOLEAN))
235     {
236       sb.append('/');
237       sb.append(a.negateArgString());
238     }
239     return sb.toString();
240   }
241
242   public static final String usage()
243   {
244     StringBuilder sb = new StringBuilder();
245
246     sb.append("Usage: jalview [args]");
247     sb.append(System.lineSeparator());
248
249     int maxArgLength = 0;
250     for (Arg a : EnumSet.allOf(Arg.class))
251     {
252       if (a.hasOption(Opt.PRIVATE))
253         continue;
254       StringBuilder argSb = new StringBuilder();
255       argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
256               : a.argString());
257       if (a.hasOption(Opt.STRING))
258         argSb.append("=value");
259       if (argSb.length() > maxArgLength)
260         maxArgLength = argSb.length();
261     }
262
263     // might want to sort these
264     for (Arg a : EnumSet.allOf(Arg.class))
265     {
266       if (a.hasOption(Opt.PRIVATE))
267         continue;
268       StringBuilder argSb = new StringBuilder();
269       argSb.append(a.hasOption(Opt.BOOLEAN) ? booleanArgString(a)
270               : a.argString());
271       if (a.hasOption(Opt.STRING))
272         argSb.append("=value");
273       sb.append(String.format("%-" + maxArgLength + "s  - %s",
274               argSb.toString(), a.getDescription()));
275
276       List<String> options = new ArrayList<>();
277
278       if (a.hasOption(Opt.BOOLEAN))
279       {
280         options.add("default " + (a.getDefaultBoolValue() ? a.argString()
281                 : a.negateArgString()));
282       }
283
284       if (a.hasOption(Opt.MULTI))
285       {
286         options.add("multiple");
287       }
288
289       if (a.hasOption(Opt.LINKED))
290       {
291         options.add("can be linked");
292       }
293
294       if (a.hasOption(Opt.GLOB))
295       {
296         options.add("allows file globs");
297       }
298
299       if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
300       {
301         options.add("allows substitutions");
302       }
303
304       if (options.size() > 0)
305       {
306         sb.append(" (");
307         sb.append(String.join("; ", options));
308         sb.append(')');
309       }
310       sb.append(System.lineSeparator());
311     }
312     return sb.toString();
313   }
314 }