import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
{
// Initialising arguments (BOOTSTRAP)
- HELP("h", "Display this help statement", Opt.UNARY, Opt.BOOTSTRAP),
- VERSION("v",
+ HELP(Type.HELP, "h", "Display this help statement", Opt.UNARY,
+ Opt.BOOTSTRAP, Opt.HASTYPE),
+ /*
+ * Other --help-type Args will be added by the static block.
+ */
+ VERSION(Type.CONFIG, "v",
"Display the version of "
+ ChannelProperties.getProperty("app_name"),
Opt.UNARY, Opt.BOOTSTRAP),
- HEADLESS(
+ HEADLESS(Type.CONFIG,
"Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed.",
Opt.UNARY, Opt.BOOTSTRAP),
- JABAWS("Set a different URL to connect to a JABAWS server.", Opt.STRING,
- Opt.BOOTSTRAP),
- NEWS("Show (or don't show) the news feed.", true, Opt.BOOLEAN,
- Opt.BOOTSTRAP),
- SPLASH("Show (or don't show) the About Jalview splash screen.", true,
+ JABAWS(Type.CONFIG, "Set a different URL to connect to a JABAWS server.",
+ Opt.STRING, Opt.BOOTSTRAP),
+ NEWS(Type.CONFIG, "Show (or don't show) the news feed.", true,
+ Opt.BOOLEAN, Opt.BOOTSTRAP),
+ SPLASH(Type.CONFIG,
+ "Show (or don't show) the About Jalview splash screen.", true,
Opt.BOOLEAN, Opt.BOOTSTRAP),
- QUESTIONNAIRE(
+ QUESTIONNAIRE(Type.CONFIG,
"Show (or don't show) the questionnaire if one is available.",
true, Opt.BOOLEAN, Opt.BOOTSTRAP),
- USAGESTATS("Send (or don't send) initial launch usage stats.", true,
+ USAGESTATS(Type.CONFIG,
+ "Send (or don't send) initial launch usage stats.", true,
Opt.BOOLEAN, Opt.BOOTSTRAP),
- WEBSERVICEDISCOVERY(
+ WEBSERVICEDISCOVERY(Type.CONFIG,
"Attempt (or don't attempt) to connect to JABAWS web services.",
true, Opt.BOOLEAN, Opt.BOOTSTRAP),
- PROPS("Use a file as the preferences file instead of the usual ~/"
- + ChannelProperties.getProperty("preferences.filename")
- + " file.", Opt.STRING, Opt.BOOTSTRAP),
- DEBUG("d", "Start Jalview in debug log level.", Opt.BOOLEAN,
+ PROPS(Type.CONFIG,
+ "Use a file as the preferences file instead of the usual ~/"
+ + ChannelProperties.getProperty("preferences.filename")
+ + " file.",
+ Opt.STRING, Opt.BOOTSTRAP),
+ DEBUG(Type.CONFIG, "d", "Start Jalview in debug log level.", Opt.BOOLEAN,
Opt.BOOTSTRAP),
- TRACE("Start Jalview in trace log level.", Opt.BOOLEAN, Opt.BOOTSTRAP,
- Opt.SECRET),
- QUIET("q",
+ TRACE(Type.CONFIG, "Start Jalview in trace log level.", Opt.BOOLEAN,
+ Opt.BOOTSTRAP, Opt.SECRET),
+ QUIET(Type.CONFIG, "q",
"Stop all output to STDOUT (after the Java Virtual Machine has started). Use ‑‑quiet a second time to stop all output to STDERR.",
Opt.UNARY, Opt.MULTI, Opt.BOOTSTRAP),
- INITSUBSTITUTIONS(
+ INITSUBSTITUTIONS(Type.CONFIG,
"Set ‑‑substitutions to be initially enabled (or initially disabled).",
- true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION),
+ true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
// Opening an alignment
- OPEN("Opens one or more alignment files or URLs in new alignment windows.",
+ OPEN(Type.OPENING,
+ "Opens one or more alignment files or URLs in new alignment windows.",
Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER, Opt.MULTI,
- Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.STORED),
- APPEND("Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
+ Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.STORED,
+ Opt.PRIMARY),
+ APPEND(Type.OPENING,
+ "Appends one or more alignment files or URLs to the open alignment window (or opens a new alignment if none already open).",
Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.GLOB,
- Opt.ALLOWSUBSTITUTIONS, Opt.INPUT),
- TITLE("Specifies the title for the open alignment window as string.",
+ Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.PRIMARY),
+ TITLE(Type.OPENING,
+ "Specifies the title for the open alignment window as string.",
Opt.STRING, Opt.LINKED),
- COLOUR("color", // being a bit soft on the Americans!
+ COLOUR(Type.OPENING, "color", // being a bit soft on the Americans!
"Applies the colour scheme to the open alignment window. Valid values are:\n"
+ "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
+ "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
+ "purine-pyrimidine,\n" + "rna-helices,\n"
+ "t-coffee-scores,\n" + "sequence-id.",
Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
- FEATURES("Add a feature file or URL to the open alignment.", Opt.STRING,
- Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
- TREE("Add a tree file or URL to the open alignment.", Opt.STRING,
- Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
- SORTBYTREE(
+ FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
+ Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
+ TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
+ Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
+ SORTBYTREE(Type.OPENING,
"Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWALL),
- ANNOTATIONS("Add an annotations file or URL to the open alignment.",
+ ANNOTATIONS(Type.OPENING,
+ "Add an annotations file or URL to the open alignment.",
Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
- SHOWANNOTATIONS(
+ SHOWANNOTATIONS(Type.OPENING,
"Enforces showing (or not showing) alignment annotations.",
Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
- WRAP("Enforces wrapped (or not wrapped) alignment formatting.",
+ WRAP(Type.OPENING,
+ "Enforces wrapped (or not wrapped) alignment formatting.",
Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
- NOSTRUCTURE(
+ NOSTRUCTURE(Type.OPENING,
"Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
// Adding a 3D structure
- STRUCTURE(
+ STRUCTURE(Type.STRUCTURE,
"Load a structure file or URL associated with a sequence in the open alignment.\n"
+ "The sequence to be associated with can be specified with a following --seqid argument, or the subval modifier seqid=ID can be used. A subval INDEX can also be used to specify the INDEX-th sequence in the open alignment.",
+ Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS,
+ Opt.PRIMARY),
+ SEQID(Type.STRUCTURE,
+ "Specify the sequence name for the preceding --structure to be associated with.",
Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
- SEQID("Specify the sequence name for the preceding --structure to be associated with.",
- Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
- PAEMATRIX("Add a PAE json matrix file to the preceding --structure.",
+ PAEMATRIX(Type.STRUCTURE,
+ "Add a PAE json matrix file to the preceding --structure.",
Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
- TEMPFAC("Set the type of temperature factor. Possible values are:\n"
- + "default,\n" + "plddt.", Opt.STRING, Opt.LINKED),
- STRUCTUREVIEWER(
- "Set the structure viewer to use to open the 3d structure file specified in previous --structure to name. Possible values of name are:\n"
+ TEMPFAC(Type.STRUCTURE,
+ "Set the type of temperature factor. Possible values are:\n"
+ + "default,\n" + "plddt.",
+ Opt.STRING, Opt.LINKED),
+ STRUCTUREVIEWER(Type.STRUCTURE,
+ "Set the structure viewer to use to open the 3D structure file specified in previous --structure to name. Possible values of name are:\n"
+ "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
+ "pymol.",
Opt.STRING, Opt.LINKED, Opt.MULTI),
- NOTEMPFAC(
+ STRUCTUREIMAGE(Type.STRUCTURE,
+ "Export an image of a 3D structure opened in JMOL", Opt.STRING,
+ Opt.LINKED, Opt.MULTI),
+ NOTEMPFAC(Type.STRUCTURE,
"Do not show the temperature factor annotation for the preceding --structure.",
Opt.UNARY, Opt.LINKED, Opt.ALLOWALL, Opt.SECRET), // keep this secret
// until it
// works!
- SHOWSSANNOTATIONS(null, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
+ SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
+ Opt.ALLOWALL),
// Outputting files
- IMAGE("Output an image of the open alignment window. Format is specified by the subval modifier, a following --type argument or guessed from the file extension. Valid formats/extensions are:\n"
- + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
+ IMAGE(Type.IMAGE,
+ "Output an image of the open alignment window. Format is specified by the subval modifier, a following --type argument or guessed from the file extension. Valid formats/extensions are:\n"
+ + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
- Opt.REQUIREINPUT, Opt.OUTPUT),
- TYPE("Set the image format for the preceding --image to name. Valid values for name are: svg,\n"
- + "png,\n" + "eps,\n" + "html,\n" + "biojs.", Opt.STRING,
- Opt.LINKED, Opt.ALLOWALL),
- TEXTRENDERER(
+ Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY),
+ TYPE(Type.IMAGE,
+ "Set the image format for the preceding --image to name. Valid values for name are: svg,\n"
+ + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
+ Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+ TEXTRENDERER(Type.IMAGE,
"Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values for name are:\n"
+ "text,\n" + "lineart.",
Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
- SCALE("Sets a scaling for bitmap image format (PNG). Should be given as a floating point number. If used in conjunction with --width and --height then the smallest scaling will be used (scale, width and height provide bounds for the image).",
+ SCALE(Type.IMAGE,
+ "Sets a scaling for bitmap image format (PNG). Should be given as a floating point number. If used in conjunction with --width and --height then the smallest scaling will be used (scale, width and height provide bounds for the image).",
+ Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+ WIDTH(Type.IMAGE,
+ "Sets a width for bitmap image format (PNG) with the height maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --height then the smallest scaling will be used (scale, width and height provide bounds for the image).",
Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
- WIDTH("Sets a width for bitmap image format (PNG) with the height maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --height then the smallest scaling will be used (scale, width and height provide bounds for the image).",
+ HEIGHT(Type.IMAGE,
+ "Sets a height for bitmap image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --width then the smallest scaling will be used (scale, width and height provide bounds for the image).",
Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
- HEIGHT("Sets a height for bitmap image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --width then the smallest scaling will be used (scale, width and height provide bounds for the image).",
+ OUTPUT(Type.OUTPUT,
+ "Export the open alignment to file filename. The format name is specified by the subval modifier format=name, a following --format name argument or guessed from the file extension. Valid format names (and file extensions) are:\n"
+ + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
+ + "stockholm (sto, stk),\n" + "pir (pir),\n"
+ + "blc (blc),\n" + "amsa (amsa),\n" + "json (json),\n"
+ + "pileup (pileup),\n" + "msf (msf),\n"
+ + "clustal (aln),\n" + "phylip (phy),\n"
+ + "jalview (jvp, jar).",
+ Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
+ Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY),
+ FORMAT(Type.OUTPUT,
+ "Sets the format for the preceding --output file. Valid formats are:\n"
+ + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n"
+ + "blc,\n" + "amsa,\n" + "json,\n" + "pileup,\n"
+ + "msf,\n" + "clustal,\n" + "phylip,\n" + "jalview.",
Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
- OUTPUT("Export the open alignment to file filename. The format name is specified by the subval modifier format=name, a following --format name argument or guessed from the file extension. Valid format names (and file extensions) are:\n"
- + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
- + "stockholm (sto, stk),\n" + "pir (pir),\n" + "blc (blc),\n"
- + "amsa (amsa),\n" + "json (json),\n" + "pileup (pileup),\n"
- + "msf (msf),\n" + "clustal (aln),\n" + "phylip (phy),\n"
- + "jalview (jvp, jar).", Opt.STRING, Opt.LINKED,
- Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL, Opt.REQUIREINPUT,
- Opt.OUTPUT),
- FORMAT("Sets the format for the preceding --output file. Valid formats are:\n"
- + "fasta,\n" + "pfam,\n" + "stockholm,\n" + "pir,\n" + "blc,\n"
- + "amsa,\n" + "json,\n" + "pileup,\n" + "msf,\n" + "clustal,\n"
- + "phylip,\n" + "jalview.", Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
- GROOVY("Process a groovy script in the file for the open alignment.",
+ GROOVY(Type.PROCESS,
+ "Process a groovy script in the file for the open alignment.",
Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS,
Opt.ALLOWALL),
- BACKUPS("Enable (or disable) writing backup files when saving an ‑‑output file. This applies to the current open alignment. To apply to all ‑‑output and ‑‑image files, use after ‑‑all.",
+ BACKUPS(Type.OUTPUT,
+ "Enable (or disable) writing backup files when saving an ‑‑output file. This applies to the current open alignment. To apply to all ‑‑output and ‑‑image files, use after ‑‑all.",
true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
- OVERWRITE(
+ OVERWRITE(Type.OUTPUT,
"Enable (or disable) overwriting of output files without backups enabled. This applies to the current open alignment. To apply to all ‑‑output and ‑‑image files, use after ‑‑all.",
Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
- CLOSE("Close the current open alignment window. This occurs after other output arguments. This applies to the current open alignment. To apply to all ‑‑output and ‑‑image files, use after ‑‑all.",
+ CLOSE(Type.OPENING,
+ "Close the current open alignment window. This occurs after other output arguments. This applies to the current open alignment. To apply to all ‑‑output and ‑‑image files, use after ‑‑all.",
Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
// controlling flow of arguments
- NEW("Move on to a new alignment window. This will ensure --append will start a new alignment window and other linked arguments will apply to the new alignment window.",
+ NEW(Type.FLOW,
+ "Move on to a new alignment window. This will ensure --append will start a new alignment window and other linked arguments will apply to the new alignment window.",
Opt.UNARY, Opt.MULTI, Opt.NOACTION, Opt.INCREMENTDEFAULTCOUNTER),
- SUBSTITUTIONS(
+ SUBSTITUTIONS(Type.FLOW,
"The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are {basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
+ "{dirname}, - the directory (folder) name of the currently --opened file (or first --appended file),\n"
+ "{argfilebasename} - the filename-without-extension of the current --argfile,\n"
+ "{++n} - increase and substitute the value of the index counter,\n"
+ "{} - the value of the current alignment window default index.",
true, Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
- ARGFILE("Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
- + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
- + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
+ ARGFILE(Type.FLOW,
+ "Open one or more files filename and read, line-by-line, as arguments to Jalview.\n"
+ + "Values in an argfile should be given with an equals sign (\"=\") separator with no spaces.\n"
+ + "Note that if you use one or more --argfile arguments then all other non-initialising arguments will be ignored.",
Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.GLOB,
Opt.ALLOWSUBSTITUTIONS),
- NPP("n++",
+ NPP(Type.FLOW, "n++",
"Increase the index counter used in argument value substitutions.",
Opt.UNARY, Opt.MULTI, Opt.NOACTION),
- ALL("Apply the following output arguments to all sets of linked arguments.",
+ ALL(Type.FLOW,
+ "Apply the following output arguments to all sets of linked arguments.",
Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
- OPENED("Apply the following output arguments to all of the last --open'ed set of linked arguments.",
+ OPENED(Type.FLOW,
+ "Apply the following output arguments to all of the last --open'ed set of linked arguments.",
Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
- QUIT("After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
+ QUIT(Type.FLOW,
+ "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
Opt.UNARY),
// secret options
- TESTOUTPUT(
+ TESTOUTPUT(Type.CONFIG,
"Allow specific stdout information. For testing purposes only.",
Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
- SETPROP("Set an individual Java System property.", Opt.STRING, Opt.MULTI,
- Opt.BOOTSTRAP, Opt.SECRET), // not in use yet
- NIL("This argument does nothing on its own, but can be used with linkedIds.",
+ SETPROP(Type.CONFIG, "Set an individual Java System property.",
+ Opt.STRING, Opt.MULTI, Opt.BOOTSTRAP, Opt.SECRET), // not in use yet
+ NIL(Type.FLOW,
+ "This argument does nothing on its own, but can be used with linkedIds.",
Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.NOACTION, Opt.SECRET),
// private options (inserted during arg processing)
- SETARGFILE(
+ SETARGFILE(Type.FLOW,
"Sets the current value of the argfilename. Inserted before argfilecontents.",
Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTI, Opt.PRIVATE,
Opt.NOACTION),
- UNSETARGFILE(
+ UNSETARGFILE(Type.FLOW,
"Unsets the current value of the argfilename. Inserted after argfile contents.",
Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION),
// these last two have no purpose in the normal Jalview application but are
// used by jalview.bin.Launcher to set memory settings. They are not used by
// argparser but are here for Usage statement reasons.
- JVMMEMPC(
+ JVMMEMPC(Type.CONFIG,
"Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
+ "The equals sign (\"=\") separator must be used with no spaces.",
Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING),
- JVMMEMMAX(
+ JVMMEMMAX(Type.CONFIG,
"Limit maximum heap size (memory) to MAXMEMORY. MAXMEMORY can be specified in bytes, kilobytes(k), megabytes(m), gigabytes(g) or if you're lucky enough, terabytes(t). This defaults to 32g if total physical memory can be detected, or to 8g if total physical memory cannot be detected.\n"
+ "The equals sign (\"=\") separator must be used with no spaces.",
Opt.NOACTION, Opt.BOOTSTRAP, Opt.STRING),
OUTPUT, // This Arg provides an output filename. With Opt.ALLOWALL *.ext is
// shorthand for --all --output={basename}.ext
STORED, // This Arg resets and creates a new set of "opened" linkedIds
+ HELP, // This Arg is a --help type arg
+ PRIMARY, // This Arg is the main Arg for its type
+ HASTYPE, // This Arg can have an Arg.Type assigned to it (and no value)
+ }
+
+ public static enum Type
+ {
+ // Type restricts argument to certain usage output
+ CONFIG("Arguments user to configure "
+ + ChannelProperties.getProperty("app_name") + " from startup"),
+ OPENING("Arguments used to open and format alignments"),
+ STRUCTURE("Arguments used to add and format 3D structure data"),
+ PROCESS("Arguments used to process an alignment once opened"),
+ OUTPUT("Arguments used to save data from a processed alignment"),
+ IMAGE("Arguments used to export an image of an alignment"),
+ FLOW("Arguments that control processing of the other arguments"),
+ ALL("All arguments"), // mostly just a place-holder for --help-all
+ HELP("Arguments to provide help text");
+
+ private String description;
+
+ private Type(String description)
+ {
+ this.description = description;
+ }
+
+ public String description()
+ {
+ return description;
+ }
+ }
+
+ static
+ {
+ for (Type t : EnumSet.allOf(Type.class))
+ {
+ String type = t.name();
+
+ }
}
private final String[] argNames;
private Opt[] argOptions;
- private boolean defaultBoolValue = false;
+ private boolean defaultBoolValue;
+
+ private String description;
- private String description = null;
+ private Type type;
- private Arg(String description, Opt... options)
+ private Arg(Type type, String description, Opt... options)
{
- this(null, description, false, options);
+ this(type, null, description, false, options);
}
- private Arg(String description, boolean defaultBoolean, Opt... options)
+ private Arg(Type type, String description, boolean defaultBoolean,
+ Opt... options)
{
- this(null, description, defaultBoolean, options);
+ this(type, null, description, defaultBoolean, options);
}
- private Arg(String alternativeName, String description, Opt... options)
+ private Arg(Type type, String alternativeName, String description,
+ Opt... options)
{
- this(alternativeName, description, false, options);
+ this(type, alternativeName, description, false, options);
}
- private Arg(String alternativeName, String description,
+ private Arg(Type type, String alternativeName, String description,
boolean defaultBoolean, Opt... options)
{
this.argNames = alternativeName != null
{ this.getName(), alternativeName }
: new String[]
{ this.getName() };
+ this.type = type;
this.description = description;
this.defaultBoolValue = defaultBoolean;
this.setOptions(options);
if (getNames().length > 0)
sb.append('"');
sb.append(")\n");
+ sb.append("\nType: " + type.name());
sb.append("\nOpt: ");
// map List<Opt> to List<String> for the String.join
List<String> optList = Arrays.asList(argOptions).stream()
return false;
}
+ public boolean hasAllOptions(Opt... opts)
+ {
+ for (Opt o : opts)
+ {
+ if (!this.hasOption(o))
+ return false;
+ }
+ return true;
+ }
+
protected void setOptions(Opt... options)
{
this.argOptions = options;
return defaultBoolValue;
}
+ public Type getType()
+ {
+ return this.type;
+ }
+
protected String getDescription()
{
return description;
public static final String usage()
{
+ return usage(null);
+ }
+
+ public static final String usage(List<Arg> helpArgs)
+ {
StringBuilder sb = new StringBuilder();
sb.append(ChannelProperties.getProperty("app_name"));
sb.append(System.lineSeparator());
sb.append(System.lineSeparator());
+ // PROGRAM THIS!
+ Type type = Type.HELP;
+ Iterator<Arg> typeArgs = Arg.getAllOfType(type);
+
int maxArgLength = 0;
for (Arg a : EnumSet.allOf(Arg.class))
{
}
return sb.toString();
}
+
+ protected static Iterator<Arg> getAllOfType(Type type)
+ {
+ return getAllOfType(type, new Opt[] {});
+ }
+
+ protected static Iterator<Arg> getAllOfType(Type type, Opt... options)
+ {
+ Opt[] opts = options == null ? new Opt[] {} : options;
+ return EnumSet.allOf(Arg.class).stream().filter(a -> {
+ if (a.getType() != type)
+ return false;
+ for (Opt o : opts)
+ {
+ if (!a.hasOption(o))
+ return false;
+ }
+ return true;
+ }).iterator();
+ }
+
+ private static List<Arg> sortForDisplay(Type... types)
+ {
+ List<Arg> argsToSort;
+ // if no types provided, do all
+ if (types == null || types.length == 0)
+ {
+ argsToSort = Arrays
+ .asList(EnumSet.allOf(Arg.class).toArray(new Arg[] {}));
+ }
+ else
+ {
+ argsToSort = new ArrayList<>();
+ for (Type type : types)
+ {
+ Arg.getAllOfType(type).forEachRemaining(a -> argsToSort.add(a));
+ }
+ }
+
+ Collections.sort(argsToSort, new ArgComparator());
+ return argsToSort;
+ }
+
+ protected int compareForDisplay(Arg other)
+ {
+ if (other == null)
+ return 1;
+ // first compare types (in order of appearance)
+ int i = this.getType().compareTo(other.getType());
+ if (i == 0)
+ {
+ // next prioritise primary arguments
+ i = this.hasOption(Opt.PRIMARY)
+ ? (other.hasOption(Opt.PRIMARY) ? 0 : 1)
+ : (other.hasOption(Opt.PRIMARY) ? -1 : 0);
+ if (i == 0)
+ {
+ // finally order of appearance in enum declarations
+ i = this.compareTo(other);
+ }
+ }
+ return i;
+ }
+
+}
+
+class ArgComparator implements Comparator<Arg>
+{
+ @Override
+ public int compare(Arg a, Arg b)
+ {
+ return a.compareForDisplay(b);
+ }
}
\ No newline at end of file
import jalview.bin.Console;
import jalview.bin.Jalview;
import jalview.bin.argparser.Arg.Opt;
+import jalview.bin.argparser.Arg.Type;
import jalview.util.FileUtils;
import jalview.util.HttpUtils;
public class ArgParser
{
+ protected static final String SINGLEDASH = "-";
+
protected static final String DOUBLEDASH = "--";
protected static final char EQUALS = '=';
// --argfile name
private static final String ARGFILEDIRNAME = "{argfiledirname}";
- // an output file wildcard to signify --output=*.ext is really --all --output
- // {basename}.ext
- private static final String OUTPUTWILDCARD = "*.";
-
// flag to say whether {n} subtitutions in output filenames should be made.
// Turn on and off with --substitutions and --nosubstitutions
// Start with it on
if (argMap.containsKey(argName))
{
Console.warn("Trying to add argument name multiple times: '"
- + argName + "'"); // RESTORE THIS WHEN
- // MERGED
+ + argName + "'");
if (argMap.get(argName) != a)
{
Console.error(
openEachInitialFilenames = false;
}
- String argName = null;
- String val = null;
- List<String> globVals = null; // for Opt.GLOB only
- SubVals globSubVals = null; // also for use by Opt.GLOB only
- String linkedId = null;
+ // look for double-dash, e.g. --arg
if (arg.startsWith(DOUBLEDASH))
{
+ String argName = null;
+ String val = null;
+ List<String> globVals = null; // for Opt.GLOB only
+ SubVals globSubVals = null; // also for use by Opt.GLOB only
+ String linkedId = null;
+ Type type = null;
+
+ // look for equals e.g. --arg=value
int equalPos = arg.indexOf(EQUALS);
if (equalPos > -1)
{
{
argName = arg.substring(DOUBLEDASH.length());
}
+
+ // look for linked ID e.g. --arg[linkedID]
int idOpen = argName.indexOf('[');
int idClose = argName.indexOf(']');
-
if (idOpen > -1 && idClose == argName.length() - 1)
{
linkedId = argName.substring(idOpen + 1, idClose);
argName = argName.substring(0, idOpen);
}
+ // look for type modification e.g. --help-opening
+ int dashPos = argName.indexOf(SINGLEDASH);
+ if (dashPos > -1)
+ {
+ String potentialArgName = argName.substring(0, dashPos);
+ Arg potentialArg = argMap.get(potentialArgName);
+ if (potentialArg != null && potentialArg.hasOption(Opt.HASTYPE))
+ {
+ argName = argName.substring(0, dashPos);
+ String typeName = argName.substring(dashPos + 1);
+ type = Type.valueOf(typeName);
+ }
+ }
+
Arg a = argMap.get(argName);
- // check for boolean prepended by "no"
+ // check for boolean prepended by "no" e.g. --nowrap
boolean negated = false;
if (a == null && argName.startsWith(NEGATESTRING) && argMap
.containsKey(argName.substring(NEGATESTRING.length())))
}
String autoCounterString = null;
- boolean usingAutoCounterLinkedId = false;
String defaultLinkedId = defaultLinkedId(false);
boolean usingDefaultLinkedId = false;
if (a.hasOption(Opt.LINKED))
autoCounterString = Integer.toString(linkedIdAutoCounter);
linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER,
autoCounterString);
- usingAutoCounterLinkedId = true;
Console.debug(
"Changing linkedId to '" + linkedId + "' from " + arg);
}
autoCounterString = Integer.toString(++linkedIdAutoCounter);
linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER,
autoCounterString);
- usingAutoCounterLinkedId = true;
Console.debug(
"Changing linkedId to '" + linkedId + "' from " + arg);
}
{
String v = gve.nextElement();
SubVals vsv = new SubVals(globSubVals, v);
- addValue(linkedId, avs, vsv, v, argIndex++, true);
+ addValue(linkedId, type, avs, vsv, v, argIndex++, true);
// if we're using defaultLinkedId and the arg increments the
// counter:
if (gve.hasMoreElements() && usingDefaultLinkedId
}
else
{
- addValue(linkedId, avs, val, argIndex, true);
+ addValue(linkedId, type, avs, val, argIndex, true);
}
}
else if (a.hasOption(Opt.BOOLEAN))
{
- setBoolean(linkedId, avs, !negated, argIndex);
+ setBoolean(linkedId, type, avs, !negated, argIndex);
setNegated(linkedId, avs, negated);
}
else if (a.hasOption(Opt.UNARY))
{
- setBoolean(linkedId, avs, true, argIndex);
+ setBoolean(linkedId, type, avs, true, argIndex);
}
// remove the '*' or 'open*' linkedId that should be empty if it was
// the following methods look for the "*" linkedId and add the argvalue to all
// linkedId ArgValues if it does.
// This version inserts the subvals sv into all created values
- private void addValue(String linkedId, ArgValues avs, SubVals sv,
- String v, int argIndex, boolean doSubs)
+ private void addValue(String linkedId, Type type, ArgValues avs,
+ SubVals sv, String v, int argIndex, boolean doSubs)
{
- this.argValueOperation(Op.ADDVALUE, linkedId, avs, sv, v, false,
+ this.argValueOperation(Op.ADDVALUE, linkedId, type, avs, sv, v, false,
argIndex, doSubs);
}
- private void addValue(String linkedId, ArgValues avs, String v,
+ private void addValue(String linkedId, Type type, ArgValues avs, String v,
int argIndex, boolean doSubs)
{
- this.argValueOperation(Op.ADDVALUE, linkedId, avs, null, v, false,
+ this.argValueOperation(Op.ADDVALUE, linkedId, type, avs, null, v, false,
argIndex, doSubs);
}
- private void setBoolean(String linkedId, ArgValues avs, boolean b,
- int argIndex)
+ private void setBoolean(String linkedId, Type type, ArgValues avs,
+ boolean b, int argIndex)
{
- this.argValueOperation(Op.SETBOOLEAN, linkedId, avs, null, null, b,
- argIndex, false);
+ this.argValueOperation(Op.SETBOOLEAN, linkedId, type, avs, null, null,
+ b, argIndex, false);
}
private void setNegated(String linkedId, ArgValues avs, boolean b)
{
- this.argValueOperation(Op.SETNEGATED, linkedId, avs, null, null, b, 0,
- false);
+ this.argValueOperation(Op.SETNEGATED, linkedId, null, avs, null, null,
+ b, 0, false);
}
private void incrementCount(String linkedId, ArgValues avs)
{
- this.argValueOperation(Op.INCREMENTCOUNT, linkedId, avs, null, null,
- false, 0, false);
+ this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, avs, null,
+ null, false, 0, false);
}
private enum Op
// The following operations look for the "*" and "open*" linkedIds and add the
// argvalue to all appropriate linkedId ArgValues if it does.
// If subvals are supplied, they are inserted into all new set values.
- private void argValueOperation(Op op, String linkedId, ArgValues avs,
- SubVals sv, String v, boolean b, int argIndex, boolean doSubs)
+ private void argValueOperation(Op op, String linkedId, Type type,
+ ArgValues avs, SubVals sv, String v, boolean b, int argIndex,
+ boolean doSubs)
{
Arg a = avs.arg();
val = makeSubstitutions(v, id);
sv = new SubVals(sv, val);
}
- tavs.addValue(sv, val, argIndex, true);
+ tavs.addValue(sv, type, val, argIndex, true);
}
else
{
{
val = makeSubstitutions(v, id);
}
- tavs.addValue(val, argIndex, true);
+ tavs.addValue(type, val, argIndex, true);
}
finaliseStoringArgValue(id, tavs);
break;
case SETBOOLEAN:
- tavs.setBoolean(b, argIndex, true);
+ tavs.setBoolean(type, b, argIndex, true);
finaliseStoringArgValue(id, tavs);
break;
val = makeSubstitutions(v, linkedId);
sv = new SubVals(sv, val);
}
- avs.addValue(sv, val, argIndex, false);
+ avs.addValue(sv, type, val, argIndex, false);
}
else
{
{
val = makeSubstitutions(v, linkedId);
}
- avs.addValue(val, argIndex, false);
+ avs.addValue(type, val, argIndex, false);
}
finaliseStoringArgValue(linkedId, avs);
break;
case SETBOOLEAN:
- avs.setBoolean(b, argIndex, false);
+ avs.setBoolean(type, b, argIndex, false);
finaliseStoringArgValue(linkedId, avs);
break;