langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java
changeset 41252 058d83c9b1c7
parent 40508 74ef30d16fb9
child 41448 6689bce0cd65
equal deleted inserted replaced
41251:6112540cd0c1 41252:058d83c9b1c7
    29 import java.io.FileNotFoundException;
    29 import java.io.FileNotFoundException;
    30 import java.io.IOException;
    30 import java.io.IOException;
    31 import java.io.PrintWriter;
    31 import java.io.PrintWriter;
    32 import java.nio.file.Path;
    32 import java.nio.file.Path;
    33 import java.text.BreakIterator;
    33 import java.text.BreakIterator;
       
    34 import java.text.Collator;
    34 import java.util.ArrayList;
    35 import java.util.ArrayList;
    35 import java.util.Arrays;
    36 import java.util.Arrays;
    36 import java.util.Collection;
    37 import java.util.Collection;
    37 import java.util.Collections;
    38 import java.util.Collections;
       
    39 import java.util.Comparator;
    38 import java.util.List;
    40 import java.util.List;
    39 import java.util.Locale;
    41 import java.util.Locale;
    40 import java.util.Objects;
    42 import java.util.Objects;
    41 import java.util.Set;
    43 import java.util.Set;
       
    44 import java.util.stream.Collectors;
       
    45 import java.util.stream.Stream;
    42 
    46 
    43 import javax.tools.JavaFileManager;
    47 import javax.tools.JavaFileManager;
    44 import javax.tools.JavaFileObject;
    48 import javax.tools.JavaFileObject;
    45 import javax.tools.StandardJavaFileManager;
    49 import javax.tools.StandardJavaFileManager;
    46 import javax.tools.StandardLocation;
    50 import javax.tools.StandardLocation;
    59 import com.sun.tools.javac.util.Options;
    63 import com.sun.tools.javac.util.Options;
    60 
    64 
    61 import jdk.javadoc.doclet.Doclet;
    65 import jdk.javadoc.doclet.Doclet;
    62 import jdk.javadoc.doclet.Doclet.Option;
    66 import jdk.javadoc.doclet.Doclet.Option;
    63 import jdk.javadoc.doclet.DocletEnvironment;
    67 import jdk.javadoc.doclet.DocletEnvironment;
       
    68 import jdk.javadoc.internal.doclets.toolkit.Resources;
    64 
    69 
    65 import static javax.tools.DocumentationTool.Location.*;
    70 import static javax.tools.DocumentationTool.Location.*;
    66 
    71 
    67 import static com.sun.tools.javac.main.Option.*;
    72 import static com.sun.tools.javac.main.Option.*;
    68 
    73 
   166     void usage() {
   171     void usage() {
   167         usage(true);
   172         usage(true);
   168     }
   173     }
   169 
   174 
   170     void usage(boolean exit) {
   175     void usage(boolean exit) {
   171         usage("main.usage", "-help", "main.usage.foot", exit);
   176         usage("main.usage", "-help", "main.usage.foot");
       
   177 
       
   178         if (exit)
       
   179             throw new Messager.ExitJavadoc();
   172     }
   180     }
   173 
   181 
   174     @Override
   182     @Override
   175     void Xusage() {
   183     void Xusage() {
   176         Xusage(true);
   184         Xusage(true);
   177     }
   185     }
   178 
   186 
   179     void Xusage(boolean exit) {
   187     void Xusage(boolean exit) {
   180         usage("main.Xusage", "-X", "main.Xusage.foot", exit);
   188         usage("main.Xusage", "-X", "main.Xusage.foot");
   181     }
   189 
   182 
   190         if (exit)
   183     private void usage(String main, String option, String foot, boolean exit) {
   191             throw new Messager.ExitJavadoc();
   184         messager.notice(main);
   192     }
   185         // let doclet print usage information (does nothing on error)
   193 
       
   194     private void usage(String header, String option, String footer) {
       
   195         messager.notice(header);
       
   196         showToolOptions(option.equals("-X") ? OptionKind.EXTENDED : OptionKind.STANDARD);
       
   197 
       
   198         // let doclet print usage information
   186         if (docletClass != null) {
   199         if (docletClass != null) {
   187             String name = doclet.getName();
   200             String name = doclet.getName();
   188             Set<Option> supportedOptions = doclet.getSupportedOptions();
       
   189             messager.notice("main.doclet.usage.header", name);
   201             messager.notice("main.doclet.usage.header", name);
   190             Option.Kind myKind = option.equals("-X")
   202             showDocletOptions(option.equals("-X") ? Option.Kind.EXTENDED : Option.Kind.STANDARD);
   191                     ? Option.Kind.EXTENDED
   203         }
   192                     : Option.Kind.STANDARD;
   204 
   193             supportedOptions.stream()
   205         if (footer != null)
   194                     .filter(opt -> opt.getKind() == myKind)
   206             messager.notice(footer);
   195                     .forEach(opt -> messager.printNotice(opt.toString()));
   207     }
   196         }
   208 
   197         if (foot != null)
   209     void showToolOptions(OptionKind kind) {
   198             messager.notice(foot);
   210         Comparator<ToolOption> comp = new Comparator<ToolOption>() {
   199 
   211             final Collator collator = Collator.getInstance(Locale.US);
   200         if (exit)
   212             { collator.setStrength(Collator.PRIMARY); }
   201             throw new Messager.ExitJavadoc();
   213 
       
   214             @Override
       
   215             public int compare(ToolOption o1, ToolOption o2) {
       
   216                 return collator.compare(o1.primaryName, o2.primaryName);
       
   217             }
       
   218         };
       
   219 
       
   220         Stream.of(ToolOption.values())
       
   221                     .filter(opt -> opt.kind == kind)
       
   222                     .sorted(comp)
       
   223                     .forEach(opt -> showToolOption(opt));
       
   224     }
       
   225 
       
   226     void showToolOption(ToolOption option) {
       
   227         List<String> names = option.getNames();
       
   228         String parameters;
       
   229         if (option.hasArg || option.primaryName.endsWith(":")) {
       
   230             String sep = (option == ToolOption.J) || option.primaryName.endsWith(":") ? "" : " ";
       
   231             parameters = sep + option.getParameters(messager);
       
   232         } else {
       
   233             parameters = "";
       
   234         }
       
   235         String description = option.getDescription(messager);
       
   236         showUsage(names, parameters, description);
       
   237     }
       
   238 
       
   239     void showDocletOptions(Option.Kind kind) {
       
   240         Comparator<Doclet.Option> comp = new Comparator<Doclet.Option>() {
       
   241             final Collator collator = Collator.getInstance(Locale.US);
       
   242             { collator.setStrength(Collator.PRIMARY); }
       
   243 
       
   244             @Override
       
   245             public int compare(Doclet.Option o1, Doclet.Option o2) {
       
   246                 return collator.compare(o1.getName(), o2.getName());
       
   247             }
       
   248         };
       
   249 
       
   250         doclet.getSupportedOptions().stream()
       
   251                 .filter(opt -> opt.getKind() == kind)
       
   252                 .sorted(comp)
       
   253                 .forEach(opt -> showDocletOption(opt));
       
   254     }
       
   255 
       
   256     void showDocletOption(Doclet.Option option) {
       
   257         List<String> names = Arrays.asList(option.getName());
       
   258         String parameters;
       
   259         if (option.getArgumentCount() > 0 || option.getName().endsWith(":")) {
       
   260             String sep = option.getName().endsWith(":") ? "" : " ";
       
   261             parameters = sep + option.getParameters();
       
   262         } else {
       
   263             parameters = "";
       
   264         }
       
   265         String description = option.getDescription();
       
   266         showUsage(names, parameters, description);
       
   267     }
       
   268 
       
   269     // The following constants are intended to format the output to
       
   270     // be similar to that of the java launcher: i.e. "java -help".
       
   271 
       
   272     /** The indent for the option synopsis. */
       
   273     private static final String SMALL_INDENT = "    ";
       
   274     /** The automatic indent for the description. */
       
   275     private static final String LARGE_INDENT = "                  ";
       
   276     /** The space allowed for the synopsis, if the description is to be shown on the same line. */
       
   277     private static final int DEFAULT_SYNOPSIS_WIDTH = 13;
       
   278     /** The nominal maximum line length, when seeing if text will fit on a line. */
       
   279     private static final int DEFAULT_MAX_LINE_LENGTH = 80;
       
   280     /** The format for a single-line help entry. */
       
   281     private static final String COMPACT_FORMAT = SMALL_INDENT + "%-" + DEFAULT_SYNOPSIS_WIDTH + "s %s";
       
   282 
       
   283     void showUsage(List<String> names, String parameters, String description) {
       
   284         String synopses = names.stream()
       
   285                 .map(s -> s + parameters)
       
   286                 .collect(Collectors.joining(", "));
       
   287         // If option synopses and description fit on a single line of reasonable length,
       
   288         // display using COMPACT_FORMAT
       
   289         if (synopses.length() < DEFAULT_SYNOPSIS_WIDTH
       
   290                 && !description.contains("\n")
       
   291                 && (SMALL_INDENT.length() + DEFAULT_SYNOPSIS_WIDTH + 1 + description.length() <= DEFAULT_MAX_LINE_LENGTH)) {
       
   292             messager.printNotice(String.format(COMPACT_FORMAT, synopses, description));
       
   293             return;
       
   294         }
       
   295 
       
   296         // If option synopses fit on a single line of reasonable length, show that;
       
   297         // otherwise, show 1 per line
       
   298         if (synopses.length() <= DEFAULT_MAX_LINE_LENGTH) {
       
   299             messager.printNotice(SMALL_INDENT + synopses);
       
   300         } else {
       
   301             for (String name: names) {
       
   302                 messager.printNotice(SMALL_INDENT + name + parameters);
       
   303             }
       
   304         }
       
   305 
       
   306         // Finally, show the description
       
   307         messager.printNotice(LARGE_INDENT + description.replace("\n", "\n" + LARGE_INDENT));
   202     }
   308     }
   203 
   309 
   204 
   310 
   205     /**
   311     /**
   206      * Main program - external wrapper. In order to maintain backward
   312      * Main program - external wrapper. In order to maintain backward
   431     int handleDocletOptions(int idx, List<String> args, boolean isToolOption) {
   537     int handleDocletOptions(int idx, List<String> args, boolean isToolOption) {
   432         if (docletOptions == null) {
   538         if (docletOptions == null) {
   433             docletOptions = doclet.getSupportedOptions();
   539             docletOptions = doclet.getSupportedOptions();
   434         }
   540         }
   435         String arg = args.get(idx);
   541         String arg = args.get(idx);
       
   542         String argBase, argVal;
       
   543         if (arg.startsWith("--") && arg.contains("=")) {
       
   544             int sep = arg.indexOf("=");
       
   545             argBase = arg.substring(0, sep);
       
   546             argVal = arg.substring(sep + 1);
       
   547         } else {
       
   548             argBase = arg;
       
   549             argVal = null;
       
   550         }
   436 
   551 
   437         for (Doclet.Option opt : docletOptions) {
   552         for (Doclet.Option opt : docletOptions) {
   438             if (opt.matches(arg)) {
   553             if (opt.matches(argBase)) {
   439                 if (args.size() - idx < opt.getArgumentCount()) {
   554                 if (argVal != null) {
   440                     usageError("main.requires_argument", arg);
   555                     switch (opt.getArgumentCount()) {
   441                 }
   556                         case 0:
   442                 opt.process(arg, args.listIterator(idx + 1));
   557                             usageError("main.unnecessary_arg_provided", argBase);
   443                 idx += opt.getArgumentCount();
   558                             break;
       
   559                         case 1:
       
   560                             opt.process(arg, Arrays.asList(argVal).listIterator());
       
   561                             break;
       
   562                         default:
       
   563                             usageError("main.only_one_argument_with_equals", argBase);
       
   564                             break;
       
   565                     }
       
   566                 } else {
       
   567                     if (args.size() - idx -1 < opt.getArgumentCount()) {
       
   568                         usageError("main.requires_argument", arg);
       
   569                     }
       
   570                     opt.process(arg, args.listIterator(idx + 1));
       
   571                     idx += opt.getArgumentCount();
       
   572                 }
   444                 return idx;
   573                 return idx;
   445             }
   574             }
   446         }
   575         }
   447         // check if arg is accepted by the tool before emitting error
   576         // check if arg is accepted by the tool before emitting error
   448         if (!isToolOption)
   577         if (!isToolOption)
   461         List<String> userTagletNames = new ArrayList<>();
   590         List<String> userTagletNames = new ArrayList<>();
   462 
   591 
   463         // Step 1: loop through the args, set locale early on, if found.
   592         // Step 1: loop through the args, set locale early on, if found.
   464         for (int i = 0 ; i < argv.size() ; i++) {
   593         for (int i = 0 ; i < argv.size() ; i++) {
   465             String arg = argv.get(i);
   594             String arg = argv.get(i);
   466             if (arg.equals(ToolOption.LOCALE.opt)) {
   595             if (arg.equals(ToolOption.LOCALE.primaryName)) {
   467                 checkOneArg(argv, i++);
   596                 checkOneArg(argv, i++);
   468                 String lname = argv.get(i);
   597                 String lname = argv.get(i);
   469                 locale = getLocale(lname);
   598                 locale = getLocale(lname);
   470             } else if (arg.equals(ToolOption.DOCLET.opt)) {
   599             } else if (arg.equals(ToolOption.DOCLET.primaryName)) {
   471                 checkOneArg(argv, i++);
   600                 checkOneArg(argv, i++);
   472                 if (userDocletName != null) {
   601                 if (userDocletName != null) {
   473                     usageError("main.more_than_one_doclet_specified_0_and_1",
   602                     usageError("main.more_than_one_doclet_specified_0_and_1",
   474                             userDocletName, argv.get(i));
   603                             userDocletName, argv.get(i));
   475                 }
   604                 }
   476                 if (docletName != null) {
   605                 if (docletName != null) {
   477                     usageError("main.more_than_one_doclet_specified_0_and_1",
   606                     usageError("main.more_than_one_doclet_specified_0_and_1",
   478                             docletName, argv.get(i));
   607                             docletName, argv.get(i));
   479                 }
   608                 }
   480                 userDocletName = argv.get(i);
   609                 userDocletName = argv.get(i);
   481             } else if (arg.equals(ToolOption.DOCLETPATH.opt)) {
   610             } else if (arg.equals(ToolOption.DOCLETPATH.primaryName)) {
   482                 checkOneArg(argv, i++);
   611                 checkOneArg(argv, i++);
   483                 if (userDocletPath == null) {
   612                 if (userDocletPath == null) {
   484                     userDocletPath = argv.get(i);
   613                     userDocletPath = argv.get(i);
   485                 } else {
   614                 } else {
   486                     userDocletPath += File.pathSeparator + argv.get(i);
   615                     userDocletPath += File.pathSeparator + argv.get(i);
   597                 // handle a doclet argument that may be needed however
   726                 // handle a doclet argument that may be needed however
   598                 // don't increment the index, and allow the tool to consume args
   727                 // don't increment the index, and allow the tool to consume args
   599                 handleDocletOptions(i, args, true);
   728                 handleDocletOptions(i, args, true);
   600 
   729 
   601                 if (o.hasArg) {
   730                 if (o.hasArg) {
   602                     checkOneArg(args, i++);
   731                     if (arg.startsWith("--") && arg.contains("=")) {
   603                     o.process(this, args.get(i));
   732                         o.process(this, arg.substring(arg.indexOf('=') + 1));
       
   733                     } else {
       
   734                         checkOneArg(args, i++);
       
   735                         o.process(this, args.get(i));
       
   736                     }
   604                 } else if (o.hasSuffix) {
   737                 } else if (o.hasSuffix) {
   605                     o.process(this, arg);
   738                     o.process(this, arg);
   606                 } else {
   739                 } else {
   607                     o.process(this);
   740                     o.process(this);
   608                 }
   741                 }