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