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