langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java
changeset 41252 058d83c9b1c7
parent 40508 74ef30d16fb9
child 41448 6689bce0cd65
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java	Thu Sep 29 21:31:09 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java	Fri Sep 30 13:15:22 2016 -0700
@@ -31,14 +31,18 @@
 import java.io.PrintWriter;
 import java.nio.file.Path;
 import java.text.BreakIterator;
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
@@ -61,6 +65,7 @@
 import jdk.javadoc.doclet.Doclet;
 import jdk.javadoc.doclet.Doclet.Option;
 import jdk.javadoc.doclet.DocletEnvironment;
+import jdk.javadoc.internal.doclets.toolkit.Resources;
 
 import static javax.tools.DocumentationTool.Location.*;
 
@@ -168,7 +173,10 @@
     }
 
     void usage(boolean exit) {
-        usage("main.usage", "-help", "main.usage.foot", exit);
+        usage("main.usage", "-help", "main.usage.foot");
+
+        if (exit)
+            throw new Messager.ExitJavadoc();
     }
 
     @Override
@@ -177,30 +185,128 @@
     }
 
     void Xusage(boolean exit) {
-        usage("main.Xusage", "-X", "main.Xusage.foot", exit);
-    }
-
-    private void usage(String main, String option, String foot, boolean exit) {
-        messager.notice(main);
-        // let doclet print usage information (does nothing on error)
-        if (docletClass != null) {
-            String name = doclet.getName();
-            Set<Option> supportedOptions = doclet.getSupportedOptions();
-            messager.notice("main.doclet.usage.header", name);
-            Option.Kind myKind = option.equals("-X")
-                    ? Option.Kind.EXTENDED
-                    : Option.Kind.STANDARD;
-            supportedOptions.stream()
-                    .filter(opt -> opt.getKind() == myKind)
-                    .forEach(opt -> messager.printNotice(opt.toString()));
-        }
-        if (foot != null)
-            messager.notice(foot);
+        usage("main.Xusage", "-X", "main.Xusage.foot");
 
         if (exit)
             throw new Messager.ExitJavadoc();
     }
 
+    private void usage(String header, String option, String footer) {
+        messager.notice(header);
+        showToolOptions(option.equals("-X") ? OptionKind.EXTENDED : OptionKind.STANDARD);
+
+        // let doclet print usage information
+        if (docletClass != null) {
+            String name = doclet.getName();
+            messager.notice("main.doclet.usage.header", name);
+            showDocletOptions(option.equals("-X") ? Option.Kind.EXTENDED : Option.Kind.STANDARD);
+        }
+
+        if (footer != null)
+            messager.notice(footer);
+    }
+
+    void showToolOptions(OptionKind kind) {
+        Comparator<ToolOption> comp = new Comparator<ToolOption>() {
+            final Collator collator = Collator.getInstance(Locale.US);
+            { collator.setStrength(Collator.PRIMARY); }
+
+            @Override
+            public int compare(ToolOption o1, ToolOption o2) {
+                return collator.compare(o1.primaryName, o2.primaryName);
+            }
+        };
+
+        Stream.of(ToolOption.values())
+                    .filter(opt -> opt.kind == kind)
+                    .sorted(comp)
+                    .forEach(opt -> showToolOption(opt));
+    }
+
+    void showToolOption(ToolOption option) {
+        List<String> names = option.getNames();
+        String parameters;
+        if (option.hasArg || option.primaryName.endsWith(":")) {
+            String sep = (option == ToolOption.J) || option.primaryName.endsWith(":") ? "" : " ";
+            parameters = sep + option.getParameters(messager);
+        } else {
+            parameters = "";
+        }
+        String description = option.getDescription(messager);
+        showUsage(names, parameters, description);
+    }
+
+    void showDocletOptions(Option.Kind kind) {
+        Comparator<Doclet.Option> comp = new Comparator<Doclet.Option>() {
+            final Collator collator = Collator.getInstance(Locale.US);
+            { collator.setStrength(Collator.PRIMARY); }
+
+            @Override
+            public int compare(Doclet.Option o1, Doclet.Option o2) {
+                return collator.compare(o1.getName(), o2.getName());
+            }
+        };
+
+        doclet.getSupportedOptions().stream()
+                .filter(opt -> opt.getKind() == kind)
+                .sorted(comp)
+                .forEach(opt -> showDocletOption(opt));
+    }
+
+    void showDocletOption(Doclet.Option option) {
+        List<String> names = Arrays.asList(option.getName());
+        String parameters;
+        if (option.getArgumentCount() > 0 || option.getName().endsWith(":")) {
+            String sep = option.getName().endsWith(":") ? "" : " ";
+            parameters = sep + option.getParameters();
+        } else {
+            parameters = "";
+        }
+        String description = option.getDescription();
+        showUsage(names, parameters, description);
+    }
+
+    // The following constants are intended to format the output to
+    // be similar to that of the java launcher: i.e. "java -help".
+
+    /** The indent for the option synopsis. */
+    private static final String SMALL_INDENT = "    ";
+    /** The automatic indent for the description. */
+    private static final String LARGE_INDENT = "                  ";
+    /** The space allowed for the synopsis, if the description is to be shown on the same line. */
+    private static final int DEFAULT_SYNOPSIS_WIDTH = 13;
+    /** The nominal maximum line length, when seeing if text will fit on a line. */
+    private static final int DEFAULT_MAX_LINE_LENGTH = 80;
+    /** The format for a single-line help entry. */
+    private static final String COMPACT_FORMAT = SMALL_INDENT + "%-" + DEFAULT_SYNOPSIS_WIDTH + "s %s";
+
+    void showUsage(List<String> names, String parameters, String description) {
+        String synopses = names.stream()
+                .map(s -> s + parameters)
+                .collect(Collectors.joining(", "));
+        // If option synopses and description fit on a single line of reasonable length,
+        // display using COMPACT_FORMAT
+        if (synopses.length() < DEFAULT_SYNOPSIS_WIDTH
+                && !description.contains("\n")
+                && (SMALL_INDENT.length() + DEFAULT_SYNOPSIS_WIDTH + 1 + description.length() <= DEFAULT_MAX_LINE_LENGTH)) {
+            messager.printNotice(String.format(COMPACT_FORMAT, synopses, description));
+            return;
+        }
+
+        // If option synopses fit on a single line of reasonable length, show that;
+        // otherwise, show 1 per line
+        if (synopses.length() <= DEFAULT_MAX_LINE_LENGTH) {
+            messager.printNotice(SMALL_INDENT + synopses);
+        } else {
+            for (String name: names) {
+                messager.printNotice(SMALL_INDENT + name + parameters);
+            }
+        }
+
+        // Finally, show the description
+        messager.printNotice(LARGE_INDENT + description.replace("\n", "\n" + LARGE_INDENT));
+    }
+
 
     /**
      * Main program - external wrapper. In order to maintain backward
@@ -433,14 +539,37 @@
             docletOptions = doclet.getSupportedOptions();
         }
         String arg = args.get(idx);
+        String argBase, argVal;
+        if (arg.startsWith("--") && arg.contains("=")) {
+            int sep = arg.indexOf("=");
+            argBase = arg.substring(0, sep);
+            argVal = arg.substring(sep + 1);
+        } else {
+            argBase = arg;
+            argVal = null;
+        }
 
         for (Doclet.Option opt : docletOptions) {
-            if (opt.matches(arg)) {
-                if (args.size() - idx < opt.getArgumentCount()) {
-                    usageError("main.requires_argument", arg);
+            if (opt.matches(argBase)) {
+                if (argVal != null) {
+                    switch (opt.getArgumentCount()) {
+                        case 0:
+                            usageError("main.unnecessary_arg_provided", argBase);
+                            break;
+                        case 1:
+                            opt.process(arg, Arrays.asList(argVal).listIterator());
+                            break;
+                        default:
+                            usageError("main.only_one_argument_with_equals", argBase);
+                            break;
+                    }
+                } else {
+                    if (args.size() - idx -1 < opt.getArgumentCount()) {
+                        usageError("main.requires_argument", arg);
+                    }
+                    opt.process(arg, args.listIterator(idx + 1));
+                    idx += opt.getArgumentCount();
                 }
-                opt.process(arg, args.listIterator(idx + 1));
-                idx += opt.getArgumentCount();
                 return idx;
             }
         }
@@ -463,11 +592,11 @@
         // Step 1: loop through the args, set locale early on, if found.
         for (int i = 0 ; i < argv.size() ; i++) {
             String arg = argv.get(i);
-            if (arg.equals(ToolOption.LOCALE.opt)) {
+            if (arg.equals(ToolOption.LOCALE.primaryName)) {
                 checkOneArg(argv, i++);
                 String lname = argv.get(i);
                 locale = getLocale(lname);
-            } else if (arg.equals(ToolOption.DOCLET.opt)) {
+            } else if (arg.equals(ToolOption.DOCLET.primaryName)) {
                 checkOneArg(argv, i++);
                 if (userDocletName != null) {
                     usageError("main.more_than_one_doclet_specified_0_and_1",
@@ -478,7 +607,7 @@
                             docletName, argv.get(i));
                 }
                 userDocletName = argv.get(i);
-            } else if (arg.equals(ToolOption.DOCLETPATH.opt)) {
+            } else if (arg.equals(ToolOption.DOCLETPATH.primaryName)) {
                 checkOneArg(argv, i++);
                 if (userDocletPath == null) {
                     userDocletPath = argv.get(i);
@@ -599,8 +728,12 @@
                 handleDocletOptions(i, args, true);
 
                 if (o.hasArg) {
-                    checkOneArg(args, i++);
-                    o.process(this, args.get(i));
+                    if (arg.startsWith("--") && arg.contains("=")) {
+                        o.process(this, arg.substring(arg.indexOf('=') + 1));
+                    } else {
+                        checkOneArg(args, i++);
+                        o.process(this, args.get(i));
+                    }
                 } else if (o.hasSuffix) {
                     o.process(this, arg);
                 } else {