JAL-4353 Preserve the user given 'linkedId' with ArgValue, to help with deciding...
authorBen Soares <b.soares@dundee.ac.uk>
Wed, 6 Dec 2023 17:41:35 +0000 (17:41 +0000)
committerBen Soares <b.soares@dundee.ac.uk>
Wed, 6 Dec 2023 17:41:35 +0000 (17:41 +0000)
src/jalview/bin/argparser/Arg.java
src/jalview/bin/argparser/ArgParser.java
src/jalview/bin/argparser/ArgValue.java
src/jalview/bin/argparser/ArgValues.java
src/jalview/bin/argparser/ArgValuesMap.java
src/jalview/util/ColorUtils.java

index cdb29bf..9a05c9f 100644 (file)
@@ -681,24 +681,22 @@ public enum Arg
     return this.types;
   }
 
-  public boolean hasType(Type t)
+  public boolean sharesType(Arg a)
   {
-    for (Type type : getTypes())
-    {
-      if (type == t)
-      {
-        return true;
-      }
-    }
-    return false;
+    return this.hasType(a.getTypes());
   }
 
-  public boolean sharesType(Arg a)
+  public boolean hasType(Type... types)
+  {
+    Set<Type> typesSet = new HashSet<>(Arrays.asList(types));
+    return this.hasType(typesSet);
+  }
+
+  public boolean hasType(Set<Type> typesSet)
   {
-    List<Type> aTypes = Arrays.asList(a.getTypes());
     for (Type type : getTypes())
     {
-      if (aTypes.contains(type))
+      if (typesSet.contains(type))
       {
         return true;
       }
index fe73053..12e1b1d 100644 (file)
@@ -365,6 +365,8 @@ public class ArgParser
         List<String> globVals = null; // for Opt.GLOB only
         SubVals globSubVals = null; // also for use by Opt.GLOB only
         String linkedId = null;
+        String givenLinkedId = null; // this is preserved to add to each
+                                     // "ArgValue"
         Type type = null;
 
         // look for equals e.g. --arg=value
@@ -385,6 +387,7 @@ public class ArgParser
         if (idOpen > -1 && idClose == argName.length() - 1)
         {
           linkedId = argName.substring(idOpen + 1, idClose);
+          givenLinkedId = linkedId;
           argName = argName.substring(0, idOpen);
         }
 
@@ -595,6 +598,12 @@ public class ArgParser
             {
               linkedId = MATCHALLLINKEDIDS;
             }
+            if (allLinkedIds)
+            {
+              // user has made conscious decision for these args to apply to
+              // all, so set givenLinkedId too
+              givenLinkedId = linkedId;
+            }
             else if (a.hasOption(Opt.ALLOWMULTIID)
                     && this.storedLinkedIds != null
                     && this.storedLinkedIds.size() > 0)
@@ -686,7 +695,8 @@ public class ArgParser
             {
               String v = gve.nextElement();
               SubVals vsv = new SubVals(globSubVals, v);
-              addValue(linkedId, type, avs, vsv, v, argIndex++, true);
+              addValue(linkedId, givenLinkedId, type, avs, vsv, v,
+                      argIndex++, true);
               // if we're using defaultLinkedId and the arg increments the
               // counter:
               if (gve.hasMoreElements() && usingDefaultLinkedId
@@ -703,18 +713,19 @@ public class ArgParser
           else
           {
             // addValue(linkedId, type, avs, val, argIndex, true);
-            addValue(linkedId, type, avs, addNewSubVals ? subvals : null,
-                    val, argIndex, true);
+            addValue(linkedId, givenLinkedId, type, avs,
+                    addNewSubVals ? subvals : null, val, argIndex, true);
           }
         }
         else if (a.hasOption(Opt.BOOLEAN))
         {
-          setBoolean(linkedId, type, avs, !negated, argIndex);
+          setBoolean(linkedId, givenLinkedId, type, avs, !negated,
+                  argIndex);
           setNegated(linkedId, avs, negated);
         }
         else if (a.hasOption(Opt.UNARY))
         {
-          setBoolean(linkedId, type, avs, true, argIndex);
+          setBoolean(linkedId, givenLinkedId, type, avs, true, argIndex);
         }
 
         // remove the '*' or 'open*' linkedId that should be empty if it was
@@ -1055,30 +1066,30 @@ public class ArgParser
   /**
    * This version inserts the subvals sv into all created values
    */
-  private void addValue(String linkedId, Type type, ArgValues avs,
-          SubVals sv, String v, int argIndex, boolean doSubs)
+  private void addValue(String linkedId, String givenLinkedId, Type type,
+          ArgValues avs, SubVals sv, String v, int argIndex, boolean doSubs)
   {
-    this.argValueOperation(Op.ADDVALUE, linkedId, type, avs, sv, v, false,
-            argIndex, doSubs);
+    this.argValueOperation(Op.ADDVALUE, linkedId, givenLinkedId, type, avs,
+            sv, v, false, argIndex, doSubs);
   }
 
-  private void setBoolean(String linkedId, Type type, ArgValues avs,
-          boolean b, int argIndex)
+  private void setBoolean(String linkedId, String givenLinkedId, Type type,
+          ArgValues avs, boolean b, int argIndex)
   {
-    this.argValueOperation(Op.SETBOOLEAN, linkedId, type, avs, null, null,
-            b, argIndex, false);
+    this.argValueOperation(Op.SETBOOLEAN, linkedId, givenLinkedId, type,
+            avs, null, null, b, argIndex, false);
   }
 
   private void setNegated(String linkedId, ArgValues avs, boolean b)
   {
-    this.argValueOperation(Op.SETNEGATED, linkedId, null, avs, null, null,
-            b, 0, false);
+    this.argValueOperation(Op.SETNEGATED, linkedId, null, null, avs, null,
+            null, b, 0, false);
   }
 
   private void incrementCount(String linkedId, ArgValues avs)
   {
-    this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, avs, null,
-            null, false, 0, false);
+    this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, null, avs,
+            null, null, false, 0, false);
   }
 
   private enum Op
@@ -1086,13 +1097,13 @@ public class ArgParser
     ADDVALUE, SETBOOLEAN, SETNEGATED, INCREMENTCOUNT
   }
 
-  private void argValueOperation(Op op, String linkedId, Type type,
-          ArgValues avs, SubVals sv, String v, boolean b, int argIndex,
-          boolean doSubs)
+  private void argValueOperation(Op op, String linkedId,
+          String givenLinkedId, Type type, ArgValues avs, SubVals sv,
+          String v, boolean b, int argIndex, boolean doSubs)
   {
     // default to merge subvals if subvals are provided
-    argValueOperation(op, linkedId, type, avs, sv, true, v, b, argIndex,
-            doSubs);
+    argValueOperation(op, linkedId, givenLinkedId, type, avs, sv, true, v,
+            b, argIndex, doSubs);
   }
 
   /**
@@ -1122,9 +1133,9 @@ public class ArgParser
    * @param doSubs
    *          Whether to perform substitutions on the subvals and value.
    */
-  private void argValueOperation(Op op, String linkedId, Type type,
-          ArgValues avs, SubVals sv, boolean merge, String v, boolean b,
-          int argIndex, boolean doSubs)
+  private void argValueOperation(Op op, String linkedId,
+          String givenLinkedId, Type type, ArgValues avs, SubVals sv,
+          boolean merge, String v, boolean b, int argIndex, boolean doSubs)
   {
     Arg a = avs.arg();
 
@@ -1155,15 +1166,16 @@ public class ArgParser
     // linkedIds
     if (wildcardLinkedIds != null)
     {
-      for (String id : wildcardLinkedIds)
+      for (String matchedLinkedId : wildcardLinkedIds)
       {
         // skip incorrectly stored wildcard ids!
-        if (id == null || MATCHALLLINKEDIDS.equals(id)
-                || MATCHOPENEDLINKEDIDS.equals(id))
+        if (matchedLinkedId == null
+                || MATCHALLLINKEDIDS.equals(matchedLinkedId)
+                || MATCHOPENEDLINKEDIDS.equals(matchedLinkedId))
         {
           continue;
         }
-        ArgValuesMap avm = linkedArgs.get(id);
+        ArgValuesMap avm = linkedArgs.get(matchedLinkedId);
         // don't set an output if there isn't an input
         if (a.hasOption(Opt.REQUIREINPUT)
                 && !avm.hasArgWithOption(Opt.INPUT))
@@ -1180,24 +1192,24 @@ public class ArgParser
             if (doSubs)
             {
               sv = new SubVals(sv, val, merge);
-              val = makeSubstitutions(sv.getContent(), id);
+              val = makeSubstitutions(sv.getContent(), matchedLinkedId);
             }
-            tavs.addValue(sv, type, val, argIndex, true);
+            tavs.addValue(sv, type, val, argIndex, true, givenLinkedId);
           }
           else
           {
             if (doSubs)
             {
-              val = makeSubstitutions(v, id);
+              val = makeSubstitutions(v, matchedLinkedId);
             }
-            tavs.addValue(type, val, argIndex, true);
+            tavs.addValue(type, val, argIndex, true, givenLinkedId);
           }
-          finaliseStoringArgValue(id, tavs);
+          finaliseStoringArgValue(matchedLinkedId, tavs);
           break;
 
         case SETBOOLEAN:
-          tavs.setBoolean(type, b, argIndex, true);
-          finaliseStoringArgValue(id, tavs);
+          tavs.setBoolean(type, b, argIndex, true, givenLinkedId);
+          finaliseStoringArgValue(matchedLinkedId, tavs);
           break;
 
         case SETNEGATED:
@@ -1228,7 +1240,7 @@ public class ArgParser
             val = makeSubstitutions(v, linkedId);
             sv = new SubVals(sv, val);
           }
-          avs.addValue(sv, type, val, argIndex, false);
+          avs.addValue(sv, type, val, argIndex, false, givenLinkedId);
         }
         else
         {
@@ -1236,13 +1248,13 @@ public class ArgParser
           {
             val = makeSubstitutions(v, linkedId);
           }
-          avs.addValue(type, val, argIndex, false);
+          avs.addValue(type, val, argIndex, false, givenLinkedId);
         }
         finaliseStoringArgValue(linkedId, avs);
         break;
 
       case SETBOOLEAN:
-        avs.setBoolean(type, b, argIndex, false);
+        avs.setBoolean(type, b, argIndex, false, givenLinkedId);
         finaliseStoringArgValue(linkedId, avs);
         break;
 
index eab38ca..e7ee1a2 100644 (file)
@@ -34,6 +34,12 @@ public class ArgValue implements Comparable<ArgValue>
 
   private String value;
 
+  private String givenLinkedId = null;
+
+  private String assignedLinkedId = null;
+
+  private boolean setByWildcardLinkedId = false;
+
   /*
    * Type type is only really used by --help-type
    */
@@ -48,22 +54,31 @@ public class ArgValue implements Comparable<ArgValue>
   private SubVals subVals;
 
   protected ArgValue(Arg a, SubVals sv, Type type, String content,
-          int argIndex)
+          int argIndex, boolean setByWildcardLinkedId, String givenLinkedId,
+          String assignedLinkedId)
   {
     this.arg = a;
     this.value = content;
     this.argIndex = argIndex;
     this.subVals = sv == null ? new SubVals("") : sv;
     this.setType(type);
+    this.setByWildcardLinkedId = setByWildcardLinkedId;
+    this.givenLinkedId = givenLinkedId;
+    this.assignedLinkedId = assignedLinkedId;
   }
 
-  protected ArgValue(Arg a, Type type, String value, int argIndex)
+  protected ArgValue(Arg a, Type type, String value, int argIndex,
+          boolean setByWildcardLinkedId, String givenLinkedId,
+          String assignedLinkedId)
   {
     this.arg = a;
     this.argIndex = argIndex;
     this.subVals = new SubVals(value);
     this.value = getSubVals().getContent();
     this.setType(type);
+    this.setByWildcardLinkedId = setByWildcardLinkedId;
+    this.givenLinkedId = givenLinkedId;
+    this.assignedLinkedId = assignedLinkedId;
   }
 
   protected void setType(Type t)
@@ -124,4 +139,37 @@ public class ArgValue implements Comparable<ArgValue>
   {
     return this.getArgIndex() - o.getArgIndex();
   }
+
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder();
+    sb.append(this.getArg().argString());
+    sb.append("=");
+    if (!this.getSubVals().getSubValMap().isEmpty())
+    {
+      sb.append(this.getSubVals().toString());
+    }
+    sb.append("'");
+    sb.append(this.getValue());
+    sb.append("'");
+
+    return sb.toString();
+  }
+
+  public String getGivenLinkedId()
+  {
+    return this.givenLinkedId;
+  }
+
+  public String getAssignedLinkedId()
+  {
+    return this.assignedLinkedId;
+  }
+
+  public boolean setByWildcardLinkedId()
+  {
+    // looking for deliberately user set wildcard
+    return this.setByWildcardLinkedId && this.getGivenLinkedId() != null;
+  }
 }
\ No newline at end of file
index 8e4fe2c..55e1211 100644 (file)
@@ -44,6 +44,8 @@ public class ArgValues
 
   private boolean setByWildcard = false;
 
+  private String givenLinkedId = null;
+
   private int boolIndex = -1;
 
   private List<Integer> argsIndexes;
@@ -52,16 +54,19 @@ public class ArgValues
 
   private Map<String, ArgValue> idMap = new HashMap<>();
 
+  private ArgValuesMap avm;
+
   /*
    * Type type is only really used by --help-type
    */
   private Type type = null;
 
-  protected ArgValues(Arg a)
+  protected ArgValues(Arg a, ArgValuesMap avm)
   {
     this.arg = a;
     this.argValueList = new ArrayList<ArgValue>();
     this.boolValue = arg.getDefaultBoolValue();
+    this.avm = avm;
   }
 
   protected boolean setByWildcard()
@@ -114,7 +119,7 @@ public class ArgValues
   }
 
   protected void setBoolean(Type t, boolean b, int i,
-          boolean beingSetByWildcard)
+          boolean beingSetByWildcard, String givenLinkedId)
   {
     this.setType(t);
     // don't overwrite a wildcard set boolean with a non-wildcard set boolean
@@ -123,6 +128,7 @@ public class ArgValues
     this.boolValue = b;
     this.boolIndex = i;
     this.setSetByWildcard(beingSetByWildcard);
+    this.givenLinkedId = givenLinkedId;
   }
 
   protected boolean getBoolean()
@@ -157,15 +163,17 @@ public class ArgValues
   }
 
   protected void addValue(Type type, String val, int argIndex,
-          boolean wildcard)
+          boolean wildcard, String givenLinkedId)
   {
-    addArgValue(new ArgValue(arg(), type, val, argIndex), wildcard);
+    addArgValue(new ArgValue(arg(), type, val, argIndex, wildcard,
+            givenLinkedId, avm.getLinkedId()), wildcard);
   }
 
   protected void addValue(SubVals sv, Type type, String content,
-          int argIndex, boolean wildcard)
+          int argIndex, boolean wildcard, String givenLinkedId)
   {
-    addArgValue(new ArgValue(arg(), sv, type, content, argIndex), wildcard);
+    addArgValue(new ArgValue(arg(), sv, type, content, argIndex, wildcard,
+            givenLinkedId, avm.getLinkedId()), wildcard);
   }
 
   protected void addArgValue(ArgValue av, boolean beingSetByWildcard)
@@ -238,4 +246,11 @@ public class ArgValues
     }
     return false;
   }
+
+  public boolean setByWildcardLinkedId()
+  {
+    // looking for deliberately user set wildcard
+    return this.setByWildcard && this.givenLinkedId != null;
+  }
+
 }
\ No newline at end of file
index 5d53641..8a28b87 100644 (file)
@@ -22,8 +22,10 @@ package jalview.bin.argparser;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -77,9 +79,13 @@ public class ArgValuesMap
   private void newArg(Arg a)
   {
     if (m == null)
+    {
       newMap();
+    }
     if (!containsArg(a))
-      m.put(a, new ArgValues(a));
+    {
+      m.put(a, new ArgValues(a, this));
+    }
   }
 
   public ArgValues getArgValues(Arg a)
@@ -105,16 +111,27 @@ public class ArgValuesMap
           SubVals sv)
   {
     return getArgValueListFromSubValArgOrPrefWithSubstitutionsWithinTypes(
-            null, a, Position.AFTER, av, sv, null, null, null, true);
+            null, a, Position.AFTER, av, sv, null, null, null, true, null);
   }
 
   public List<ArgValue> getArgValueListFromSubValArgOrPrefWithSubstitutionsWithinTypes(
           ArgParser ap, Arg a, ArgValuesMap.Position pos, ArgValue av,
           SubVals sv, String key, String pref, String def,
-          boolean withinTypes)
+          boolean withinTypes, Type type)
   {
     if (key == null)
+    {
       key = a.getName();
+    }
+    Set<Type> types = new HashSet<>();
+    if (type == null)
+    {
+      types.addAll(Arrays.asList(av.getArg().getTypes()));
+    }
+    else
+    {
+      types.add(type);
+    }
     List<ArgValue> avList = new ArrayList<>();
     if (sv != null && sv.has(key) && sv.get(key) != null)
     {
@@ -123,7 +140,9 @@ public class ArgValuesMap
       // protected ArgValue(Arg a, SubVals sv, Type type, String content, int
       // argIndex)
 
-      avList.add(new ArgValue(a, null, null, value, av.getArgIndex()));
+      ArgValue svav = new ArgValue(a, null, null, value, av.getArgIndex(),
+              false, null, this.getLinkedId());
+      avList.add(svav);
     }
     else if (containsArg(a))
     {
@@ -163,8 +182,9 @@ public class ArgValuesMap
       // run through every Arg used in this ArgValuesMap
       for (Arg tmpA : this.getArgKeys())
       {
-        // only interested in Opt.PRIMARY args of the same type
-        if (tmpA.sharesType(a) && tmpA.hasOption(Opt.PRIMARY))
+        // only interested in looking up to next Opt.PRIMARY args of the same
+        // type as av (or provided type)
+        if (tmpA.hasType(types) && tmpA.hasOption(Opt.PRIMARY))
         {
           for (ArgValue tmpAv : getArgValueList(tmpA))
           {
@@ -177,15 +197,17 @@ public class ArgValuesMap
           }
         }
       }
-      List<ArgValue> tmpList = List.copyOf(avList);
-      for (ArgValue tmpAv : tmpList)
+      List<ArgValue> tmpList = new ArrayList<>();
+      for (ArgValue tmpAv : avList)
       {
-        if (nextPrimaryArgOfSameTypeIndex < tmpAv.getArgIndex())
+        int tmpAvIndex = tmpAv.getArgIndex();
+        if (av.getArgIndex() < tmpAvIndex
+                && tmpAvIndex < nextPrimaryArgOfSameTypeIndex)
         {
-          // looks like this tmpAv actually belongs to a different primary Arg
-          avList.remove(tmpAv);
+          tmpList.add(tmpAv);
         }
       }
+      avList = tmpList;
     }
 
     return avList;
@@ -521,6 +543,18 @@ public class ArgValuesMap
           value = av2.getValue();
         }
       }
+
+      if (value == null)
+      {
+        // look for --all --a occurrences
+        for (ArgValue tmpAv : this.getArgValueList(a))
+        {
+          if (tmpAv.setByWildcardLinkedId())
+          {
+            value = tmpAv.getValue();
+          }
+        }
+      }
     }
     if (value == null)
     {
index e9c66bd..0e44f34 100644 (file)
@@ -267,7 +267,8 @@ public class ColorUtils
           int b = Integer.parseInt(tokens[2].trim());
           col = new Color(r, g, b);
         }
-      } catch (Exception ex)
+      } catch (IllegalArgumentException ex) // IllegalArgumentException includes
+                                            // NumberFormatException
       {
         // non-numeric token or out of 0-255 range
       }