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