JAL-4353 Preserve the user given 'linkedId' with ArgValue, to help with deciding...
[jalview.git] / src / jalview / bin / argparser / Arg.java
index 2bd8e26..9a05c9f 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.bin.argparser;
 
 import java.util.ArrayList;
@@ -5,9 +25,11 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 import jalview.bin.argparser.Arg.Opt;
@@ -44,6 +66,8 @@ public enum Arg
   QUESTIONNAIRE(Type.CONFIG,
           "Show (or don't show) the questionnaire if one is available.",
           true, Opt.BOOLEAN, Opt.BOOTSTRAP),
+  JAVACONSOLE(Type.CONFIG, "Show (or don't show) the Java Console.", false,
+          Opt.BOOLEAN, Opt.BOOTSTRAP),
   NOUSAGESTATS(Type.CONFIG, "Don't send initial launch usage stats.",
           Opt.UNARY, Opt.BOOTSTRAP),
   NOSTARTUPFILE(Type.CONFIG, "Don't show the default startup file.",
@@ -68,14 +92,15 @@ public enum Arg
           true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
   P(Type.CONFIG, "Set a Jalview preference value for this session.",
           Opt.PREFIXKEV, Opt.PRESERVECASE, Opt.STRING, Opt.BOOTSTRAP,
-          Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET), // keep this secret for now.
+          Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET), // keep this secret for
+                                                     // now.
 
   // Opening an alignment
   OPEN(Type.OPENING,
           "Opens one or more alignment files or URLs in new alignment windows.",
-          Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER, Opt.MULTIVALUE,
-          Opt.GLOB, Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.STORED,
-          Opt.PRIMARY),
+          Opt.STRING, Opt.LINKED, Opt.INCREMENTDEFAULTCOUNTER,
+          Opt.MULTIVALUE, 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.MULTIVALUE, Opt.GLOB,
@@ -138,7 +163,7 @@ public enum Arg
   TEMPFAC(Type.STRUCTURE,
           "Set the type of temperature factor. Possible values are:\n"
                   + "default,\n" + "plddt.",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
   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"
@@ -146,8 +171,9 @@ public enum Arg
           Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
   NOTEMPFAC(Type.STRUCTURE,
           "Do not show the temperature factor annotation for the preceding --structure.",
-          Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.SECRET), // keep this secret
-                                                            // until it works!
+          Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.SECRET), // keep this
+                                                                // secret until
+                                                                // it works!
   SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
           Opt.ALLOWMULTIID),
 
@@ -155,46 +181,41 @@ public enum Arg
   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.ALLOWMULTIID,
-          Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
+          Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.MULTIVALUE,
+          Opt.ALLOWMULTIID, Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
+  STRUCTUREIMAGE(new Type[]
+  { Type.IMAGE, Type.STRUCTUREIMAGE },
+          "Export an image of a 3D structure opened in JMOL", Opt.STRING,
+          Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID,
+          Opt.PRIMARY),
   TYPE(Type.IMAGE,
-          "Set the image format for the preceding --image. Valid values are:\n"
-                  + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
+          "Set the image format for the preceding " + Arg.IMAGE.argString()
+                  + " or " + Arg.STRUCTUREIMAGE.argString()
+                  + ". Valid values are:\n" + "svg,\n" + "png,\n" + "eps,\n"
+                  + "html,\n" + "biojs.",
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
   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 are:\n"
                   + "text,\n" + "lineart.",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
   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.ALLOWMULTIID),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
   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.ALLOWMULTIID),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
   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.ALLOWMULTIID),
-  STRUCTUREIMAGE(Type.STRUCTUREIMAGE,
-          "Export an image of a 3D structure opened in JMOL", Opt.STRING,
-          Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID),
-  STRUCTUREIMAGETYPE(Type.STRUCTUREIMAGE,
-          "Set the structure image format for the preceding --structureimage. Valid values are:\n"
-                  + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
-  STRUCTUREIMAGETEXTRENDERER(Type.STRUCTUREIMAGE,
-          "Sets whether text in a vector structure image format (SVG, EPS) should be rendered as text or vector line-art. Possible values are:\n"
-                  + "text,\n" + "lineart.",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
-  STRUCTUREIMAGESCALE(Type.STRUCTUREIMAGE,
-          "Sets a scaling for bitmap structure image format (PNG). Should be given as a floating point number. If used in conjunction with --structureimagewidth and --structureimageheight then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
-  STRUCTUREIMAGEWIDTH(Type.STRUCTUREIMAGE,
-          "Sets a width for bitmap structure image format (PNG) with the height maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --structureimagescale and --structureimageheight then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
-  STRUCTUREIMAGEHEIGHT(Type.STRUCTUREIMAGE,
-          "Sets a height for bitmap structure image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --structureimagescale and --structureimagewidth then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
-
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
+  IMAGECOLOUR(Type.IMAGE, "imagecolor", // being a bit soft on the Americans!
+          "Applies the colour scheme to the open alignment window for this image, otherwise the value of "
+                  + Arg.COLOUR.argString()
+                  + " (or none) will apply. Valid values are the same as "
+                  + Arg.COLOUR.argString() + ".",
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
+  BGCOLOUR(Type.IMAGE, "bgcolor", // being a bit soft on the Americans!
+          "Applies a background colour to the structure image. Valid values are named colours known to Java or RRGGBB 6 digit hex-string.",
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
   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"
@@ -224,11 +245,15 @@ public enum Arg
   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.ALLOWMULTIID),
+  MKDIRS(Type.OUTPUT,
+          "Automatically create directories when outputting a file to a new directory.",
+          Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID),
 
   // controlling flow of arguments
   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.MULTIVALUE, Opt.NOACTION, Opt.INCREMENTDEFAULTCOUNTER),
+          Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION,
+          Opt.INCREMENTDEFAULTCOUNTER),
   SUBSTITUTIONS(Type.FLOW,
           "The following argument values allow (or don't allow) subsituting filename parts. This is initially true. Valid substitutions are:\n"
                   + "{basename} - the filename-without-extension of the currently --opened file (or first --appended file),\n"
@@ -269,7 +294,8 @@ public enum Arg
           "Allow specific stdout information.  For testing purposes only.",
           Opt.UNARY, Opt.BOOTSTRAP, Opt.SECRET), // do not show this to the user
   SETPROP(Type.CONFIG, "Set an individual Java System property.",
-          Opt.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.SECRET), // not in use yet
+          Opt.STRING, Opt.MULTIVALUE, 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.MULTIVALUE, Opt.NOACTION, Opt.SECRET),
@@ -489,29 +515,53 @@ public enum Arg
 
   private String description;
 
-  private Type type;
+  private Type[] types;
 
   private Arg(Type type, String description, Opt... options)
   {
+    this(new Type[] { type }, description, options);
+  }
+
+  private Arg(Type[] type, String description, Opt... options)
+  {
     this(type, null, description, false, options);
   }
 
   private Arg(Type type, String description, boolean defaultBoolean,
           Opt... options)
   {
+    this(new Type[] { type }, description, defaultBoolean, options);
+  }
+
+  private Arg(Type[] type, String description, boolean defaultBoolean,
+          Opt... options)
+  {
     this(type, null, description, defaultBoolean, options);
   }
 
   private Arg(Type type, String alternativeName, String description,
           Opt... options)
   {
+    this(new Type[] { type }, alternativeName, description, options);
+  }
+
+  private Arg(Type[] type, String alternativeName, String description,
+          Opt... options)
+  {
     this(type, alternativeName, description, false, options);
   }
 
   private Arg(Type type, String alternativeName, String description,
           boolean defaultBoolean, Opt... options)
   {
-    this.type = type;
+    this(new Type[] { type }, alternativeName, description, defaultBoolean,
+            options);
+  }
+
+  private Arg(Type[] type, String alternativeName, String description,
+          boolean defaultBoolean, Opt... options)
+  {
+    this.types = type;
     this.description = description;
     this.defaultBoolValue = defaultBoolean;
     this.setOptions(options);
@@ -552,7 +602,11 @@ public enum Arg
     if (getNames().length > 0)
       sb.append('"');
     sb.append(")\n");
-    sb.append("\nType: " + type.name());
+    for (Type type : getTypes())
+    {
+      String typeName = type.name();
+      sb.append("\nType: " + typeName);
+    }
     sb.append("\nOpt: ");
     // map List<Opt> to List<String> for the String.join
     List<String> optList = Arrays.asList(argOptions).stream()
@@ -617,9 +671,37 @@ public enum Arg
     return defaultBoolValue;
   }
 
-  public Type getType()
+  public Type getFirstType()
+  {
+    return this.getTypes()[0];
+  }
+
+  public Type[] getTypes()
+  {
+    return this.types;
+  }
+
+  public boolean sharesType(Arg a)
+  {
+    return this.hasType(a.getTypes());
+  }
+
+  public boolean hasType(Type... types)
+  {
+    Set<Type> typesSet = new HashSet<>(Arrays.asList(types));
+    return this.hasType(typesSet);
+  }
+
+  public boolean hasType(Set<Type> typesSet)
   {
-    return this.type;
+    for (Type type : getTypes())
+    {
+      if (typesSet.contains(type))
+      {
+        return true;
+      }
+    }
+    return false;
   }
 
   protected String getDescription()
@@ -646,9 +728,17 @@ public enum Arg
   public static final void appendUsageGeneral(StringBuilder sb,
           int maxArgLength)
   {
+    Set<Type> firstTypes = new HashSet<>();
+    for (Arg a : EnumSet.allOf(Arg.class))
+    {
+      if (!firstTypes.contains(a.getFirstType()))
+      {
+        firstTypes.add(a.getFirstType());
+      }
+    }
     for (Type t : EnumSet.allOf(Type.class))
     {
-      if (t.description() != null)
+      if (t.description() != null && firstTypes.contains(t))
       {
         StringBuilder argSb = new StringBuilder();
         argSb.append(Arg.HELP.argString()).append(ArgParser.SINGLEDASH)
@@ -683,20 +773,6 @@ public enum Arg
     {
       List<Arg> args = argsSortedForDisplay(types);
 
-      /*
-       * just use a set maxArgLength of DESCRIPTIONINDENT
-       
-      int maxArgLength = 0;
-      for (Arg a : args)
-      {
-        if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
-          continue;
-      
-        String argS = argDisplayString(a);
-        if (argS.length() > maxArgLength)
-          maxArgLength = argS.length();
-      }
-      */
       int maxArgLength = DESCRIPTIONINDENT;
 
       // always show --help
@@ -720,10 +796,10 @@ public enum Arg
           continue;
         }
 
-        if (a.getType() != typeSection)
+        if (a.getFirstType() != typeSection)
         {
-          typeSection = a.getType();
-          String typeDescription = a.getType().description();
+          typeSection = a.getFirstType();
+          String typeDescription = a.getFirstType().description();
           if (typeDescription != null && typeDescription.length() > 0)
           {
             // typeDescription = typeDescription.substring(0,
@@ -914,7 +990,7 @@ public enum Arg
   {
     Opt[] opts = options == null ? new Opt[] {} : options;
     return EnumSet.allOf(Arg.class).stream().filter(a -> {
-      if (a.getType() != type)
+      if (!a.hasType(type))
         return false;
       for (Opt o : opts)
       {
@@ -969,7 +1045,7 @@ class ArgDisplayComparator implements Comparator<Arg>
     if (b == null)
       return -1;
     // first compare types (in enum order)
-    int i = a.getType().compareTo(b.getType());
+    int i = a.getFirstType().compareTo(b.getFirstType());
     if (i != 0)
       return i;
     // do Opt.LAST next (oddly). Reversed args important!