JAL-629 Fix a test and omit an incorrect error message for structureviewer=none
[jalview.git] / src / jalview / bin / argparser / Arg.java
index c502eec..b69ed61 100644 (file)
@@ -19,7 +19,7 @@ public enum Arg
 
   // Initialising arguments (BOOTSTRAP)
   HELP(Type.HELP, "h", "Display basic help", Opt.UNARY, Opt.BOOTSTRAP,
 
   // Initialising arguments (BOOTSTRAP)
   HELP(Type.HELP, "h", "Display basic help", Opt.UNARY, Opt.BOOTSTRAP,
-          Opt.HASTYPE, Opt.MULTI),
+          Opt.HASTYPE, Opt.MULTIVALUE),
   /*
    * Other --help-type Args will be added by the static block.
    */
   /*
    * Other --help-type Args will be added by the static block.
    */
@@ -29,8 +29,8 @@ public enum Arg
           Opt.UNARY, Opt.BOOTSTRAP),
   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),
   HEADLESS(Type.CONFIG,
           "Run Jalview in headless mode. No GUI interface will be created and Jalview will quit after all arguments have been processed. "
-                  + "Headless mode is assumed if an output file is to be generated, this can be overridden with --noheadless or --gui.",
-          Opt.BOOLEAN, Opt.BOOTSTRAP),
+                  + "Headless mode is assumed if an output file is to be generated, this can be overridden with --gui.",
+          Opt.UNARY, Opt.BOOTSTRAP),
   GUI(Type.CONFIG,
           "Do not run Jalview in headless mode.  This overrides the assumption of headless mode when an output file is to be generated.",
           Opt.UNARY, Opt.BOOTSTRAP),
   GUI(Type.CONFIG,
           "Do not run Jalview in headless mode.  This overrides the assumption of headless mode when an output file is to be generated.",
           Opt.UNARY, Opt.BOOTSTRAP),
@@ -44,9 +44,10 @@ public enum Arg
   QUESTIONNAIRE(Type.CONFIG,
           "Show (or don't show) the questionnaire if one is available.",
           true, Opt.BOOLEAN, Opt.BOOTSTRAP),
   QUESTIONNAIRE(Type.CONFIG,
           "Show (or don't show) the questionnaire if one is available.",
           true, Opt.BOOLEAN, Opt.BOOTSTRAP),
-  USAGESTATS(Type.CONFIG,
-          "Send (or don't send) initial launch usage stats.", true,
-          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.",
+          Opt.UNARY, Opt.BOOTSTRAP),
   WEBSERVICEDISCOVERY(Type.CONFIG,
           "Attempt (or don't attempt) to connect to JABAWS web services.",
           true, Opt.BOOLEAN, Opt.BOOTSTRAP),
   WEBSERVICEDISCOVERY(Type.CONFIG,
           "Attempt (or don't attempt) to connect to JABAWS web services.",
           true, Opt.BOOLEAN, Opt.BOOTSTRAP),
@@ -61,26 +62,30 @@ public enum Arg
           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.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),
+          Opt.UNARY, Opt.MULTIVALUE, Opt.BOOTSTRAP),
   INITSUBSTITUTIONS(Type.CONFIG,
           "Set ‑‑substitutions to be initially enabled (or initially disabled).",
           true, Opt.BOOLEAN, Opt.BOOTSTRAP, Opt.NOACTION, Opt.SECRET),
   INITSUBSTITUTIONS(Type.CONFIG,
           "Set ‑‑substitutions to be initially enabled (or initially disabled).",
           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.
 
   // Opening an alignment
   OPEN(Type.OPENING,
           "Opens one or more alignment files or URLs in new alignment windows.",
 
   // 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.MULTI,
-          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).",
   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.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.GLOB,
           Opt.ALLOWSUBSTITUTIONS, Opt.INPUT, Opt.PRIMARY),
   TITLE(Type.OPENING,
           "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),
+          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
   COLOUR(Type.OPENING, "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"
+          "Applies the colour scheme to the open alignment window. Valid values include:\n"
                   + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
                   + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
                   + "gecos-blossom,\n" + "gecos-sunset,\n"
                   + "clustal,\n" + "blosum62,\n" + "pc-identity,\n"
                   + "zappo,\n" + "taylor,\n" + "gecos-flower,\n"
                   + "gecos-blossom,\n" + "gecos-sunset,\n"
@@ -89,99 +94,122 @@ public enum Arg
                   + "turn-propensity,\n" + "buried-index,\n"
                   + "nucleotide,\n" + "nucleotide-ambiguity,\n"
                   + "purine-pyrimidine,\n" + "rna-helices,\n"
                   + "turn-propensity,\n" + "buried-index,\n"
                   + "nucleotide,\n" + "nucleotide-ambiguity,\n"
                   + "purine-pyrimidine,\n" + "rna-helices,\n"
-                  + "t-coffee-scores,\n" + "sequence-id.",
-          Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+                  + "t-coffee-scores,\n" + "sequence-id.\n" + "\n"
+                  + "Names of user defined colourschemes will also work,\n"
+                  + "and jalview colourscheme specifications like\n"
+                  + "--colour=\"D,E=red; K,R,H=0022FF; C,c=yellow\"",
+          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
   FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
   FEATURES(Type.OPENING, "Add a feature file or URL to the open alignment.",
-          Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
+          Opt.ALLOWMULTIID),
   TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
   TREE(Type.OPENING, "Add a tree file or URL to the open alignment.",
-          Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
+          Opt.ALLOWMULTIID),
   SORTBYTREE(Type.OPENING,
           "Enforces sorting (or not sorting) the open alignment in the order of an attached phylogenetic tree.",
   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),
+          true, Opt.LINKED, Opt.BOOLEAN, Opt.ALLOWMULTIID),
   ANNOTATIONS(Type.OPENING,
           "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),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
+          Opt.ALLOWMULTIID),
   SHOWANNOTATIONS(Type.OPENING,
           "Enforces showing (or not showing) alignment annotations.",
   SHOWANNOTATIONS(Type.OPENING,
           "Enforces showing (or not showing) alignment annotations.",
-          Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
+          Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
   WRAP(Type.OPENING,
           "Enforces wrapped (or not wrapped) alignment formatting.",
   WRAP(Type.OPENING,
           "Enforces wrapped (or not wrapped) alignment formatting.",
-          Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWALL),
+          Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
   NOSTRUCTURE(Type.OPENING,
           "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
   NOSTRUCTURE(Type.OPENING,
           "Do not open or process any 3D structure in the ‑‑open or ‑‑append files.",
-          Opt.UNARY, Opt.LINKED, Opt.ALLOWALL),
+          Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.ALLOWMULTIID),
 
   // Adding a 3D 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.",
 
   // Adding a 3D 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),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
+          Opt.PRIMARY, Opt.ALLOWMULTIID),
   SEQID(Type.STRUCTURE,
           "Specify the sequence name for the preceding --structure to be associated with.",
   SEQID(Type.STRUCTURE,
           "Specify the sequence name for the preceding --structure to be associated with.",
-          Opt.STRING, Opt.LINKED, Opt.MULTI, Opt.ALLOWSUBSTITUTIONS),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
+          Opt.ALLOWMULTIID),
   PAEMATRIX(Type.STRUCTURE,
           "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),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
+          Opt.ALLOWMULTIID),
   TEMPFAC(Type.STRUCTURE,
           "Set the type of temperature factor. Possible values are:\n"
                   + "default,\n" + "plddt.",
   TEMPFAC(Type.STRUCTURE,
           "Set the type of temperature factor. Possible values are:\n"
                   + "default,\n" + "plddt.",
-          Opt.STRING, Opt.LINKED),
+          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"
                   + "pymol.",
   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),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
   NOTEMPFAC(Type.STRUCTURE,
           "Do not show the temperature factor annotation for the preceding --structure.",
   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!
+          Opt.UNARY, Opt.LINKED, Opt.ALLOWMULTIID, Opt.SECRET), // keep this
+                                                                // secret until
+                                                                // it works!
   SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
   SHOWSSANNOTATIONS(Type.STRUCTURE, null, Opt.BOOLEAN, Opt.LINKED,
-          Opt.ALLOWALL),
+          Opt.ALLOWMULTIID),
 
   // Outputting files
   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.",
 
   // Outputting files
   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.OUTPUTFILE, Opt.PRIMARY),
+          Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.MULTIVALUE,
+          Opt.ALLOWMULTIID, Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
+  STRUCTUREIMAGE(Type.IMAGE,
+          "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,
   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.ALLOWALL),
+          "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.",
   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.ALLOWALL),
+          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).",
   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),
+          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).",
   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),
+          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).",
   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),
-  STRUCTUREIMAGE(Type.STRUCTUREIMAGE,
-          "Export an image of a 3D structure opened in JMOL", Opt.STRING,
-          Opt.LINKED, Opt.MULTI, Opt.OUTPUTFILE),
-  STRUCTUREIMAGETYPE(Type.STRUCTUREIMAGE,
+          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 or #RRGGBB.",
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
+  /*
+  STRUCTUREIMAGETYPE(Type.IMAGE,
           "Set the structure image format for the preceding --structureimage. Valid values are:\n"
                   + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
           "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.ALLOWALL),
-  STRUCTUREIMAGETEXTRENDERER(Type.STRUCTUREIMAGE,
+          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
+  STRUCTUREIMAGETEXTRENDERER(Type.IMAGE,
           "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.",
           "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.ALLOWALL),
-  STRUCTUREIMAGESCALE(Type.STRUCTUREIMAGE,
+          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
+  STRUCTUREIMAGESCALE(Type.IMAGE,
           "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).",
           "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.ALLOWALL),
-  STRUCTUREIMAGEWIDTH(Type.STRUCTUREIMAGE,
+          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
+  STRUCTUREIMAGEWIDTH(Type.IMAGE,
           "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).",
           "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.ALLOWALL),
-  STRUCTUREIMAGEHEIGHT(Type.STRUCTUREIMAGE,
+          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
+  STRUCTUREIMAGEHEIGHT(Type.IMAGE,
           "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).",
           "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.ALLOWALL),
+          Opt.STRING, Opt.LINKED, 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"
 
   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"
@@ -191,32 +219,36 @@ public enum Arg
                   + "pileup (pileup),\n" + "msf (msf),\n"
                   + "clustal (aln),\n" + "phylip (phy),\n"
                   + "jalview (jvp, jar).",
                   + "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.OUTPUTFILE, Opt.PRIMARY),
+          Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWMULTIID,
+          Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.STDOUT, 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.",
   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),
+          Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
   GROOVY(Type.PROCESS,
           "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),
+          Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWSUBSTITUTIONS,
+          Opt.ALLOWMULTIID),
   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.",
   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),
+          true, Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
   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.",
   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),
+          Opt.BOOLEAN, Opt.LINKED, Opt.ALLOWMULTIID),
   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.",
   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),
+          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.",
 
   // 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.MULTI, 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"
   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"
@@ -226,22 +258,22 @@ public enum Arg
                   + "{n} - the value of the index counter (starting at 0).\n"
                   + "{++n} - increase and substitute the value of the index counter,\n"
                   + "{} - the value of the current alignment window default index.",
                   + "{n} - the value of the index counter (starting at 0).\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),
+          true, Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
   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.",
   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.STRING, Opt.MULTIVALUE, Opt.BOOTSTRAP, Opt.GLOB,
           Opt.ALLOWSUBSTITUTIONS),
   NPP(Type.FLOW, "n++",
           "Increase the index counter used in argument value substitutions.",
           Opt.ALLOWSUBSTITUTIONS),
   NPP(Type.FLOW, "n++",
           "Increase the index counter used in argument value substitutions.",
-          Opt.UNARY, Opt.MULTI, Opt.NOACTION),
+          Opt.UNARY, Opt.MULTIVALUE, Opt.NOACTION),
   ALL(Type.FLOW,
           "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),
+          Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
   OPENED(Type.FLOW,
           "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),
+          Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
   QUIT(Type.FLOW,
           "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
           Opt.UNARY),
   QUIT(Type.FLOW,
           "After all files have been opened, appended and output, quit Jalview. In ‑‑headless mode this already happens.",
           Opt.UNARY),
@@ -250,26 +282,27 @@ public enum Arg
           Opt.UNARY, Opt.SECRET),
   ALLSTRUCTURES(Type.FLOW,
           "Apply the following 3D structure formatting arguments to all structures within the open alignment.",
           Opt.UNARY, Opt.SECRET),
   ALLSTRUCTURES(Type.FLOW,
           "Apply the following 3D structure formatting arguments to all structures within the open alignment.",
-          Opt.BOOLEAN, Opt.MULTI, Opt.NOACTION),
+          Opt.BOOLEAN, Opt.MULTIVALUE, Opt.NOACTION),
 
   // secret options
   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(Type.CONFIG, "Set an individual Java System property.",
 
   // secret options
   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(Type.CONFIG, "Set an individual Java System property.",
-          Opt.STRING, Opt.MULTI, 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.",
   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),
+          Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, Opt.NOACTION, Opt.SECRET),
 
   // private options (inserted during arg processing)
   SETARGFILE(Type.FLOW,
           "Sets the current value of the argfilename.  Inserted before argfilecontents.",
 
   // private options (inserted during arg processing)
   SETARGFILE(Type.FLOW,
           "Sets the current value of the argfilename.  Inserted before argfilecontents.",
-          Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTI, Opt.PRIVATE,
+          Opt.UNARY, Opt.LINKED, Opt.STRING, Opt.MULTIVALUE, Opt.PRIVATE,
           Opt.NOACTION),
   UNSETARGFILE(Type.FLOW,
           "Unsets the current value of the argfilename.  Inserted after argfile contents.",
           Opt.NOACTION),
   UNSETARGFILE(Type.FLOW,
           "Unsets the current value of the argfilename.  Inserted after argfile contents.",
-          Opt.UNARY, Opt.LINKED, Opt.MULTI, Opt.PRIVATE, Opt.NOACTION),
+          Opt.UNARY, Opt.LINKED, Opt.MULTIVALUE, 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
 
   // 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
@@ -287,57 +320,151 @@ public enum Arg
 
   public static enum Opt
   {
 
   public static enum Opt
   {
-    BOOLEAN, // This Arg can be specified as --arg or --noarg to give true or
-             // false. A default can be given with setOptions(bool, Opt....).
-             // Use ArgParser.isSet(Arg) to see if this arg was not specified.
-    STRING, // This Arg can accept a value either through --arg=value or --arg
-            // value.
-    UNARY, // This Arg is a boolean value, true if present, false if not. Like
-           // BOOLEAN but without the --noarg option.
-    MULTI, // This Arg can be specified multiple times. Multiple values are
-           // stored in the ArgValuesMap (along with their positional index) for
-           // each linkedId.
-    LINKED, // This Arg can be linked to others through a --arg[linkedId] or
-            // --arg[linkedId]=value. If no linkedId is specified then the
-            // current default linkedId will be used.
-    NODUPLICATEVALUES, // This Arg can only have one value (per linkedId). The
-                       // first value will be used and subsequent values ignored
-                       // with a warning.
-    BOOTSTRAP, // This Arg value(s) can be determined at an earlier stage than
-               // non-BOOTSTRAP Args. Substitutions do not happen in BOOTSTRAP
-               // Args and they cannot be linked or contain SubVals. See
-               // jalview.bin.argparser.BootstrapArgs.
-    GLOB, // This Arg can expand wildcard filename "globs" (e.g.
-          // path/*/filename*). If the Arg value is given as --arg filename*
-          // then the shell will have expanded the glob already, but if
-          // specified as --arg=filename* then the Java glob expansion method
-          // will be used (see FileUtils.getFilenamesFromGlob()). Note that this
-          // might be different from the shell expansion rules.
-    NOACTION, // This Arg does not perform a data task, usually used to control
-              // flow in ArgParser.parse(args).
-    ALLOWSUBSTITUTIONS, // This Arg allows substitutions in its linkedId,
-                        // SubVals and values.
-    PRIVATE, // This Arg is used internally, and cannot be specified by the
-             // user.
-    SECRET, // This Arg is used by development processes and although it can be
-            // set by the user, it is not displayed to the user.
-    ALLOWALL, // This Arg can use the '*' linkedId to apply to all known
-              // linkedIds
-    INCREMENTDEFAULTCOUNTER, // If an Arg has this option and the default
-                             // linkedId is used, the defaultLinkedIdCounter is
-                             // incremented *first*.
-    INPUT, // This Arg counts as an input for REQUIREINPUT
-    REQUIREINPUT, // This Arg can only be applied via --all if there is an
-                  // input (i.e. --open or --append)
-    OUTPUTFILE, // 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)
-    FIRST, // Move this arg to the first in usage statement (within type)
-    LAST, // Move this arg to the end in usage statement (within type)
+    /*
+     * A BOOLEAN Arg can be specified as --arg or --noarg to give true or false.
+     * A default can be given with setOptions(bool, Opt....).
+     * Use ArgParser.isSet(Arg) to see if this arg was not specified.
+     */
+    BOOLEAN("can be negated with " + ArgParser.DOUBLEDASH
+            + ArgParser.NEGATESTRING + "..."),
+
+    /*
+     * A STRING Arg will take a value either through --arg=value or --arg value.
+     */
+    STRING("expects a value"),
+    /*
+     * A UNARY Arg is a boolean value, true if present, false if not.
+     * Like BOOLEAN but without the --noarg option.
+     */
+    UNARY(null),
+    /*
+     * A MULTI Arg can be specified multiple times.
+     * Multiple values are stored in the ArgValuesMap (along with their positional index) for each linkedId.
+     */
+    MULTIVALUE("can be specified multiple times"),
+    /*
+     * A Linked Arg can be linked to others through a --arg[linkedId] or --arg[linkedId]=value.
+     * If no linkedId is specified then the current default linkedId will be used.
+     */
+    LINKED("is linked to an alignment"),
+    /*
+     * A NODUPLICATES Arg can only have one value (per linkedId).
+     * The first value will be used and subsequent values ignored with a warning.
+     */
+    NODUPLICATEVALUES("cannot have the same value more than once"),
+    /*
+     * A BOOTSTRAP Arg value(s) can be determined at an earlier stage than non-BOOTSTRAP Args.
+     * Substitutions do not happen in BOOTSTRAP Args and they cannot be linked or contain SubVals.
+     * See jalview.bin.argparser.BootstrapArgs.
+     */
+    BOOTSTRAP("a configuration argument"),
+    /*
+     * A GLOB Arg can expand wildcard filename "globs" (e.g. path/* /filename*).
+     * If the Arg value is given as --arg filename* then the shell will have expanded the glob already,
+     * but if specified as --arg=filename* then the Java glob expansion method will be used
+     * (see FileUtils.getFilenamesFromGlob()).
+     * Note that this might be different from the shell expansion rules.
+     */
+    GLOB("can take multiple filenames with wildcards"),
+    /*
+     * A NOACTION Arg does not perform a data task,
+     * usually used to control flow in ArgParser.parse(args).
+     */
+    NOACTION(null),
+    /*
+     * An ALLOWSUBSTITUTIONS Arg allows substitutions in its linkedId,
+     * SubVals and values.
+     */
+    ALLOWSUBSTITUTIONS("values can use substitutions"),
+    /*
+     * A PRIVATE Arg is used internally, and cannot be specified by the user.
+     */
+    PRIVATE(null),
+    /*
+     * A SECRET Arg is used by development processes and although it can be set by the user,
+     * it is not displayed to the user.
+     */
+    SECRET(null),
+    /*
+     * An ALLOWALL Arg can use the '*' linkedId to apply to all known linkedIds
+     */
+    ALLOWMULTIID("can be used with " + ArgParser.DOUBLEDASH + "all"),
+    /*
+     * If an Arg has the INCREMENTDEFAULTCOUNTER option and the default linkedId is used,
+     * the defaultLinkedIdCounter is incremented *first*.
+     */
+    INCREMENTDEFAULTCOUNTER("starts a new default alignment"),
+    /*
+     * An INPUT Arg counts as an input for REQUIREINPUT
+     */
+    INPUT(null),
+    /*
+     * A REQUIREINPUT Arg can only be applied via --all if there is an input
+     * (i.e. --open or --append)
+     */
+    REQUIREINPUT(null),
+    /*
+     * An OUTPUTFILE Arg provides an output filename. With Opt.ALLOWALL *.ext is shorthand for
+     * --all --output={basename}.ext
+     */
+    OUTPUTFILE("output file --headless will be assumed unless --gui used"),
+    /*
+     * A STDOUT Arg can take an output filename that can be '-' to mean print to STDOUT.
+     */
+    STDOUT("allows the output filename '" + ArgParser.STDOUTFILENAME
+            + "' to mean output to STDOUT"),
+    /*
+     * A STORED Arg resets and creates a new set of "opened" linkedIds
+     */
+    STORED(null),
+    /*
+     * A HELP Arg is a --help type arg
+     */
+    HELP("provides a help statement"),
+    /*
+     * A PRIMARY Arg is the main Arg for its type
+     */
+    PRIMARY("is a primary argument for its type"),
+    /*
+     * A HASTYPE Arg can have an Arg.Type assigned to its ArgValue
+     */
+    HASTYPE(null),
+    /*
+     * A FIRST arg gets moved to appear first in the usage statement (within type)
+     */
+    FIRST(null),
+    /*
+     * A LAST arg gets moved to appear last in the usage statement (within type)
+     */
+    LAST(null),
+    /*
+     * After other args are checked, the following args can prefix a KEY=VALUE argument
+     */
+    PREFIXKEV("prefixes key=value"),
+    /*
+     * do not lowercase the name when getting the arg name or arg string
+     */
+    PRESERVECASE(null),
+    //
+    ;
+
+    private String description;
+
+    private Opt()
+    {
+      description = null;
+    }
+
+    private Opt(String description)
+    {
+      this.description = description;
+    }
+
+    public String description()
+    {
+      return description;
+    }
+
   }
 
   public static enum Type
   }
 
   public static enum Type
@@ -350,8 +477,9 @@ public enum Arg
     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"),
     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"),
-    STRUCTUREIMAGE("arguments used to export an image of an structure"),
+    IMAGE("arguments used to export an image of an alignment or structure"),
+    // IMAGE("arguments used to export an image of an alignment"),
+    // STRUCTUREIMAGE("arguments used to export an image of an structure"),
     FLOW("arguments that control processing of the other arguments"), //
     ALL("all arguments"), // mostly just a place-holder for --help-all
     NONE, // mostly a place-holder for --help
     FLOW("arguments that control processing of the other arguments"), //
     ALL("all arguments"), // mostly just a place-holder for --help-all
     NONE, // mostly a place-holder for --help
@@ -405,15 +533,15 @@ public enum Arg
   private Arg(Type type, String alternativeName, String description,
           boolean defaultBoolean, Opt... options)
   {
   private Arg(Type type, String alternativeName, String description,
           boolean defaultBoolean, Opt... options)
   {
+    this.type = type;
+    this.description = description;
+    this.defaultBoolValue = defaultBoolean;
+    this.setOptions(options);
     this.argNames = alternativeName != null
             ? new String[]
             { this.getName(), alternativeName }
             : new String[]
             { this.getName() };
     this.argNames = alternativeName != null
             ? new String[]
             { this.getName(), alternativeName }
             : new String[]
             { this.getName() };
-    this.type = type;
-    this.description = description;
-    this.defaultBoolValue = defaultBoolean;
-    this.setOptions(options);
   }
 
   public String argString()
   }
 
   public String argString()
@@ -463,7 +591,9 @@ public enum Arg
 
   public String getName()
   {
 
   public String getName()
   {
-    return this.name().toLowerCase(Locale.ROOT).replace('_', '-');
+    String name = hasOption(Opt.PRESERVECASE) ? this.name()
+            : this.name().toLowerCase(Locale.ROOT);
+    return name.replace('_', '-');
   }
 
   @Override
   }
 
   @Override
@@ -627,7 +757,7 @@ public enum Arg
           }
         }
 
           }
         }
 
-        appendArgUsage(sb, a, maxArgLength);
+        appendArgUsage(sb, a, maxArgLength, Platform.consoleWidth());
 
         if (argsI.hasNext())
         {
 
         if (argsI.hasNext())
         {
@@ -639,69 +769,71 @@ public enum Arg
   }
 
   private static void appendArgUsage(StringBuilder sb, Arg a,
   }
 
   private static void appendArgUsage(StringBuilder sb, Arg a,
-          int maxArgLength)
+          int maxArgLength, int maxWidth)
   {
     boolean first = appendArgAndDescription(sb, null, null, a,
             maxArgLength);
     List<String> options = new ArrayList<>();
 
   {
     boolean first = appendArgAndDescription(sb, null, null, a,
             maxArgLength);
     List<String> options = new ArrayList<>();
 
-    if (a.hasOption(Opt.BOOLEAN))
-    {
-      options.add("default " + (a.getDefaultBoolValue() ? a.argString()
-              : a.negateArgString()));
-    }
-
-    if (a.hasOption(Opt.MULTI))
+    for (Opt o : EnumSet.allOf(Opt.class))
     {
     {
-      options.add("multiple");
-    }
-
-    if (a.hasOption(Opt.LINKED))
-    {
-      options.add("can be linked");
-    }
-
-    if (a.hasOption(Opt.GLOB))
-    {
-      options.add("allows file globs");
-    }
-
-    if (a.hasOption(Opt.ALLOWSUBSTITUTIONS))
-    {
-      options.add("allows substitutions");
-    }
-
-    if (a.hasOption(Opt.ALLOWALL))
-    {
-      options.add("can be applied to all linked arguments");
-    }
-
-    if (a.hasOption(Opt.PRIVATE))
-    {
-      options.add("for internal use only");
-    }
-
-    if (a.hasOption(Opt.SECRET))
-    {
-      options.add("for development use only");
+      if (a.hasOption(o) && o.description() != null)
+      {
+        options.add(o.description());
+      }
     }
 
     }
 
+    final String optDisplaySeparator = "; ";
     if (options.size() > 0)
     {
     if (options.size() > 0)
     {
+      int linelength = 0;
+      String spacing = String.format("%-"
+              + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
+              "");
       if (first)
       {
         sb.append(ARGDESCRIPTIONSEPARATOR);
       if (first)
       {
         sb.append(ARGDESCRIPTIONSEPARATOR);
+        linelength += maxArgLength + ARGDESCRIPTIONSEPARATOR.length();
       }
       else
       {
       }
       else
       {
-        sb.append(String.format("%-"
-                + (maxArgLength + ARGDESCRIPTIONSEPARATOR.length()) + "s",
-                ""));
+        sb.append(spacing);
+        linelength += spacing.length();
+      }
+      if (options.size() > 0)
+      {
+        boolean optFirst = true;
+        Iterator<String> optionsI = options.listIterator();
+        while (optionsI.hasNext())
+        {
+          String desc = optionsI.next();
+          if (optFirst)
+          {
+            sb.append("(");
+            linelength += 1;
+          }
+          int descLength = desc.length()
+                  + (optionsI.hasNext() ? optDisplaySeparator.length() : 0);
+          if (linelength + descLength > maxWidth)
+          {
+            sb.append(System.lineSeparator());
+            linelength = 0;
+            sb.append(spacing);
+            linelength += spacing.length();
+          }
+          // sb.append(linelength + "+" + desc.length() + " ");
+          sb.append(desc);
+          linelength += desc.length();
+          if (optionsI.hasNext())
+          {
+            sb.append(optDisplaySeparator);
+            linelength += optDisplaySeparator.length();
+          }
+          optFirst = false;
+        }
+        sb.append(')');
+        sb.append(System.lineSeparator());
       }
       }
-      sb.append("(");
-      sb.append(String.join("; ", options));
-      sb.append(')');
-      sb.append(System.lineSeparator());
     }
   }
 
     }
   }
 
@@ -711,7 +843,16 @@ public enum Arg
     argSb.append(
             a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
     if (a.hasOption(Opt.STRING))
     argSb.append(
             a.hasOption(Opt.BOOLEAN) ? booleanArgString(a) : a.argString());
     if (a.hasOption(Opt.STRING))
-      argSb.append("=value");
+    {
+      if (a.hasOption(Opt.PREFIXKEV))
+      {
+        argSb.append("key=value");
+      }
+      else
+      {
+        argSb.append("=value");
+      }
+    }
     return argSb.toString();
   }
 
     return argSb.toString();
   }