8253735: Cleanup SearchIndexItem API
Reviewed-by: hannesw
This commit is contained in:
parent
54b340b44f
commit
bd50ccd037
@ -292,7 +292,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
|
||||
* @return the 1.4.x style anchor for the executable element.
|
||||
*/
|
||||
protected String getErasureAnchor(ExecutableElement executableElement) {
|
||||
final StringBuilder buf = new StringBuilder(writer.anchorName(executableElement));
|
||||
final StringBuilder buf = new StringBuilder(executableElement.getSimpleName());
|
||||
buf.append("(");
|
||||
List<? extends VariableElement> parameters = executableElement.getParameters();
|
||||
boolean foundTypeVariable = false;
|
||||
|
@ -25,24 +25,17 @@
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.ModuleElement;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem.Category;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
||||
@ -50,10 +43,7 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
||||
|
||||
@ -68,50 +58,35 @@ import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*
|
||||
* @see IndexBuilder
|
||||
* @see IndexBuilder
|
||||
*/
|
||||
public class AbstractIndexWriter extends HtmlDocletWriter {
|
||||
|
||||
/**
|
||||
* The index of all the members with unicode character.
|
||||
*/
|
||||
protected IndexBuilder indexBuilder;
|
||||
protected final IndexBuilder mainIndex;
|
||||
|
||||
protected Navigation navBar;
|
||||
|
||||
protected final Map<Character, List<SearchIndexItem>> tagSearchIndexMap;
|
||||
protected final Navigation navBar;
|
||||
|
||||
/**
|
||||
* This constructor will be used by {@link SplitIndexWriter}. Initializes
|
||||
* path to this file and relative path from this file.
|
||||
* Initializes the common data for writers that can generate index files
|
||||
* based on the information in {@code configuration.mainIndex}.
|
||||
*
|
||||
* @param configuration The current configuration
|
||||
* @param path Path to the file which is getting generated.
|
||||
* @param indexBuilder Unicode based Index from {@link IndexBuilder}
|
||||
* @param configuration the current configuration
|
||||
* @param path path to the file which is getting generated.
|
||||
*/
|
||||
protected AbstractIndexWriter(HtmlConfiguration configuration,
|
||||
DocPath path,
|
||||
IndexBuilder indexBuilder) {
|
||||
DocPath path) {
|
||||
super(configuration, path);
|
||||
this.indexBuilder = indexBuilder;
|
||||
this.mainIndex = configuration.mainIndex;
|
||||
this.navBar = new Navigation(null, configuration, PageMode.INDEX, path);
|
||||
Stream<SearchIndexItem> items =
|
||||
searchItems.itemsOfCategories(Category.INDEX, Category.SYSTEM_PROPERTY)
|
||||
.sorted(comparators.makeGenericSearchIndexComparator());
|
||||
this.tagSearchIndexMap = buildSearchTagIndex(items);
|
||||
}
|
||||
|
||||
protected void addContents(Character uc, List<IndexItem> memberlist,
|
||||
protected void addContents(Character uc, SortedSet<IndexItem> memberlist,
|
||||
Content contentTree) {
|
||||
addHeading(uc, contentTree);
|
||||
|
||||
HtmlTree dl = HtmlTree.DL(HtmlStyle.index);
|
||||
Map<String,Integer> duplicateLabelCheck = new HashMap<>();
|
||||
memberlist.forEach(e -> duplicateLabelCheck.compute(e.getFullyQualifiedLabel(utils),
|
||||
(k, v) -> v == null ? 1 : v + 1));
|
||||
for (IndexItem indexItem : memberlist) {
|
||||
addDescription(indexItem, dl,
|
||||
duplicateLabelCheck.get(indexItem.getFullyQualifiedLabel(utils)) > 1);
|
||||
for (IndexItem item : memberlist) {
|
||||
addDescription(item, dl);
|
||||
}
|
||||
contentTree.add(dl);
|
||||
}
|
||||
@ -125,79 +100,62 @@ public class AbstractIndexWriter extends HtmlDocletWriter {
|
||||
contentTree.add(heading);
|
||||
}
|
||||
|
||||
protected void addDescription(IndexItem indexItem, Content dl, boolean addModuleInfo) {
|
||||
SearchIndexItem si = indexItem.getSearchTag();
|
||||
if (si != null) {
|
||||
addDescription(si, dl);
|
||||
} else {
|
||||
si = new SearchIndexItem();
|
||||
si.setLabel(indexItem.getLabel());
|
||||
addElementDescription(indexItem, dl, si, addModuleInfo);
|
||||
searchItems.add(si);
|
||||
protected void addDescription(IndexItem indexItem, Content dl) {
|
||||
if (indexItem.isTagItem()) {
|
||||
addTagDescription(indexItem, dl);
|
||||
} else if (indexItem.isElementItem()) {
|
||||
addElementDescription(indexItem, dl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one line summary comment for the element.
|
||||
*
|
||||
* @param indexItem the element to be documented
|
||||
* @param item the element to be documented
|
||||
* @param dlTree the content tree to which the description will be added
|
||||
* @param si the search index item
|
||||
* @param addModuleInfo whether to include module information
|
||||
*/
|
||||
protected void addElementDescription(IndexItem indexItem, Content dlTree, SearchIndexItem si,
|
||||
boolean addModuleInfo) {
|
||||
protected void addElementDescription(IndexItem item, Content dlTree) {
|
||||
Content dt;
|
||||
Element element = indexItem.getElement();
|
||||
String label = indexItem.getLabel();
|
||||
Element element = item.getElement();
|
||||
String label = item.getLabel();
|
||||
switch (element.getKind()) {
|
||||
case MODULE:
|
||||
dt = HtmlTree.DT(getModuleLink((ModuleElement)element, new StringContent(label)));
|
||||
si.setCategory(Category.MODULES);
|
||||
dt = HtmlTree.DT(getModuleLink((ModuleElement) element, new StringContent(label)));
|
||||
dt.add(" - ").add(contents.module_).add(" " + label);
|
||||
break;
|
||||
|
||||
case PACKAGE:
|
||||
dt = HtmlTree.DT(getPackageLink((PackageElement)element, new StringContent(label)));
|
||||
dt = HtmlTree.DT(getPackageLink((PackageElement) element, new StringContent(label)));
|
||||
if (configuration.showModules) {
|
||||
si.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element)));
|
||||
item.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element)));
|
||||
}
|
||||
si.setCategory(Category.PACKAGES);
|
||||
dt.add(" - ").add(contents.package_).add(" " + label);
|
||||
break;
|
||||
|
||||
case CLASS:
|
||||
case ENUM:
|
||||
case RECORD:
|
||||
case ANNOTATION_TYPE:
|
||||
case INTERFACE:
|
||||
dt = HtmlTree.DT(getLink(new LinkInfoImpl(configuration,
|
||||
LinkInfoImpl.Kind.INDEX, (TypeElement)element).strong(true)));
|
||||
si.setContainingPackage(utils.getPackageName(utils.containingPackage(element)));
|
||||
if (configuration.showModules && addModuleInfo) {
|
||||
si.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element)));
|
||||
}
|
||||
si.setCategory(Category.TYPES);
|
||||
LinkInfoImpl.Kind.INDEX, (TypeElement) element).strong(true)));
|
||||
dt.add(" - ");
|
||||
addClassInfo((TypeElement)element, dt);
|
||||
addClassInfo((TypeElement) element, dt);
|
||||
break;
|
||||
default:
|
||||
TypeElement containingType = indexItem.getTypeElement();
|
||||
|
||||
case CONSTRUCTOR:
|
||||
case METHOD:
|
||||
case FIELD:
|
||||
case ENUM_CONSTANT:
|
||||
TypeElement containingType = item.getContainingTypeElement();
|
||||
dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.memberNameLink,
|
||||
getDocLink(LinkInfoImpl.Kind.INDEX, containingType, element, new StringContent(label))));
|
||||
si.setContainingPackage(utils.getPackageName(utils.containingPackage(element)));
|
||||
si.setContainingClass(utils.getSimpleName(containingType));
|
||||
if (configuration.showModules && addModuleInfo) {
|
||||
si.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element)));
|
||||
}
|
||||
if (utils.isExecutableElement(element)) {
|
||||
String url = HtmlTree.encodeURL(links.getName(getAnchor((ExecutableElement)element)));
|
||||
if (!label.equals(url)) {
|
||||
si.setUrl(url);
|
||||
}
|
||||
}
|
||||
si.setCategory(Category.MEMBERS);
|
||||
dt.add(" - ");
|
||||
addMemberDesc(element, containingType, dt);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
dlTree.add(dt);
|
||||
Content dd = new HtmlTree(TagName.DD);
|
||||
@ -224,19 +182,19 @@ public class AbstractIndexWriter extends HtmlDocletWriter {
|
||||
));
|
||||
}
|
||||
|
||||
protected void addDescription(SearchIndexItem sii, Content dlTree) {
|
||||
String siiPath = pathToRoot.isEmpty() ? "" : pathToRoot.getPath() + "/";
|
||||
siiPath += sii.getUrl();
|
||||
HtmlTree labelLink = HtmlTree.A(siiPath, new StringContent(sii.getLabel()));
|
||||
protected void addTagDescription(IndexItem item, Content dlTree) {
|
||||
String itemPath = pathToRoot.isEmpty() ? "" : pathToRoot.getPath() + "/";
|
||||
itemPath += item.getUrl();
|
||||
HtmlTree labelLink = HtmlTree.A(itemPath, new StringContent(item.getLabel()));
|
||||
Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.searchTagLink, labelLink));
|
||||
dt.add(" - ");
|
||||
dt.add(contents.getContent("doclet.Search_tag_in", sii.getHolder()));
|
||||
dt.add(contents.getContent("doclet.Search_tag_in", item.getHolder()));
|
||||
dlTree.add(dt);
|
||||
Content dd = new HtmlTree(TagName.DD);
|
||||
if (sii.getDescription().isEmpty()) {
|
||||
if (item.getDescription().isEmpty()) {
|
||||
dd.add(Entity.NO_BREAK_SPACE);
|
||||
} else {
|
||||
dd.add(sii.getDescription());
|
||||
dd.add(item.getDescription());
|
||||
}
|
||||
dlTree.add(dd);
|
||||
}
|
||||
@ -313,85 +271,4 @@ public class AbstractIndexWriter extends HtmlDocletWriter {
|
||||
return "I:" + links.getName(unicode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DocFileIOException if there is a problem creating any of the search index files
|
||||
*/
|
||||
protected void createSearchIndexFiles() throws DocFileIOException {
|
||||
createSearchIndexFile(DocPaths.MODULE_SEARCH_INDEX_JS,
|
||||
searchItems.itemsOfCategories(Category.MODULES),
|
||||
"moduleSearchIndex");
|
||||
if (!configuration.packages.isEmpty()) {
|
||||
SearchIndexItem si = new SearchIndexItem();
|
||||
si.setCategory(Category.PACKAGES);
|
||||
si.setLabel(resources.getText("doclet.All_Packages"));
|
||||
si.setUrl(DocPaths.ALLPACKAGES_INDEX.getPath());
|
||||
searchItems.add(si);
|
||||
}
|
||||
createSearchIndexFile(DocPaths.PACKAGE_SEARCH_INDEX_JS,
|
||||
searchItems.itemsOfCategories(Category.PACKAGES),
|
||||
"packageSearchIndex");
|
||||
SearchIndexItem si = new SearchIndexItem();
|
||||
si.setCategory(Category.TYPES);
|
||||
si.setLabel(resources.getText("doclet.All_Classes"));
|
||||
si.setUrl(DocPaths.ALLCLASSES_INDEX.getPath());
|
||||
searchItems.add(si);
|
||||
createSearchIndexFile(DocPaths.TYPE_SEARCH_INDEX_JS,
|
||||
searchItems.itemsOfCategories(Category.TYPES),
|
||||
"typeSearchIndex");
|
||||
createSearchIndexFile(DocPaths.MEMBER_SEARCH_INDEX_JS,
|
||||
searchItems.itemsOfCategories(Category.MEMBERS),
|
||||
"memberSearchIndex");
|
||||
createSearchIndexFile(DocPaths.TAG_SEARCH_INDEX_JS,
|
||||
searchItems.itemsOfCategories(Category.INDEX, Category.SYSTEM_PROPERTY),
|
||||
"tagSearchIndex");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a search index file.
|
||||
*
|
||||
* @param searchIndexJS the file for the JavaScript to be generated
|
||||
* @param searchIndex the search index items
|
||||
* @param varName the variable name to write in the JavaScript file
|
||||
* @throws DocFileIOException if there is a problem creating the search index file
|
||||
*/
|
||||
protected void createSearchIndexFile(DocPath searchIndexJS,
|
||||
Stream<SearchIndexItem> searchIndex,
|
||||
String varName)
|
||||
throws DocFileIOException
|
||||
{
|
||||
// The file needs to be created even if there are no searchIndex items
|
||||
// File could be written straight-through, without an intermediate StringBuilder
|
||||
Iterator<SearchIndexItem> index = searchIndex.iterator();
|
||||
StringBuilder searchVar = new StringBuilder("[");
|
||||
boolean first = true;
|
||||
while (index.hasNext()) {
|
||||
SearchIndexItem item = index.next();
|
||||
if (first) {
|
||||
searchVar.append(item.toString());
|
||||
first = false;
|
||||
} else {
|
||||
searchVar.append(",").append(item.toString());
|
||||
}
|
||||
}
|
||||
searchVar.append("];");
|
||||
DocFile jsFile = DocFile.createFileForOutput(configuration, searchIndexJS);
|
||||
try (Writer wr = jsFile.openWriter()) {
|
||||
wr.write(varName);
|
||||
wr.write(" = ");
|
||||
wr.write(searchVar.toString());
|
||||
wr.write("updateSearchResults();");
|
||||
} catch (IOException ie) {
|
||||
throw new DocFileIOException(jsFile, DocFileIOException.Mode.WRITE, ie);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Character, List<SearchIndexItem>> buildSearchTagIndex(
|
||||
Stream<? extends SearchIndexItem> searchItems)
|
||||
{
|
||||
return searchItems.collect(Collectors.groupingBy(i -> keyCharacter(i.getLabel())));
|
||||
}
|
||||
|
||||
protected static Character keyCharacter(String s) {
|
||||
return s.isEmpty() ? '*' : Character.toUpperCase(s.charAt(0));
|
||||
}
|
||||
}
|
||||
|
@ -133,13 +133,12 @@ public class AllClassesIndexWriter extends HtmlDocletWriter {
|
||||
.addTab(resources.errorSummary, e -> utils.isError((TypeElement)e))
|
||||
.addTab(resources.annotationTypeSummary, utils::isAnnotationType)
|
||||
.setTabScript(i -> "show(" + i + ");");
|
||||
for (Character unicode : indexBuilder.keys()) {
|
||||
for (IndexItem indexItem : indexBuilder.getMemberList(unicode)) {
|
||||
for (Character unicode : indexBuilder.getFirstCharacters()) {
|
||||
for (IndexItem indexItem : indexBuilder.getItems(unicode)) {
|
||||
TypeElement typeElement = (TypeElement) indexItem.getElement();
|
||||
if (typeElement == null || !utils.isCoreClass(typeElement)) {
|
||||
continue;
|
||||
if (typeElement != null && utils.isCoreClass(typeElement)) {
|
||||
addTableRow(table, typeElement);
|
||||
}
|
||||
addTableRow(table, typeElement);
|
||||
}
|
||||
}
|
||||
Content titleContent = contents.allClassesLabel;
|
||||
|
@ -125,7 +125,7 @@ public class ConstructorWriterImpl extends AbstractExecutableMemberWriter
|
||||
}
|
||||
constructorDocTree.add(heading);
|
||||
return HtmlTree.SECTION(HtmlStyle.detail, constructorDocTree)
|
||||
.setId(links.getName(writer.getAnchor(constructor)));
|
||||
.setId(links.getAnchor(constructor));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,6 +54,7 @@ import jdk.javadoc.internal.doclets.toolkit.WriterFactory;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
|
||||
|
||||
/**
|
||||
* Configure the output based on the command-line options.
|
||||
@ -93,7 +94,16 @@ public class HtmlConfiguration extends BaseConfiguration {
|
||||
*/
|
||||
public TypeElement currentTypeElement = null; // Set this TypeElement in the ClassWriter.
|
||||
|
||||
protected SearchIndexItems searchItems;
|
||||
/**
|
||||
* The collections of items for the main index.
|
||||
* This field is only initialized if {@code options.createIndex()}
|
||||
* is {@code true}.
|
||||
* This index is populated somewhat lazily:
|
||||
* 1. items found in doc comments are found while generating declaration pages
|
||||
* 2. items for elements are added in bulk before generating the index files
|
||||
* 3. additional items are added as needed
|
||||
*/
|
||||
protected HtmlIndexBuilder mainIndex;
|
||||
|
||||
public final Contents contents;
|
||||
|
||||
@ -201,6 +211,9 @@ public class HtmlConfiguration extends BaseConfiguration {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (options.createIndex()) {
|
||||
mainIndex = new HtmlIndexBuilder(this);
|
||||
}
|
||||
docPaths = new DocPaths(utils);
|
||||
setCreateOverview();
|
||||
setTopFile(docEnv);
|
||||
@ -352,10 +365,4 @@ public class HtmlConfiguration extends BaseConfiguration {
|
||||
}
|
||||
return super.finishOptionSettings0();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initConfiguration(DocletEnvironment docEnv) {
|
||||
super.initConfiguration(docEnv);
|
||||
searchItems = new SearchIndexItems(utils);
|
||||
}
|
||||
}
|
||||
|
@ -169,18 +169,20 @@ public class HtmlDoclet extends AbstractDoclet {
|
||||
}
|
||||
|
||||
if (options.createIndex()) {
|
||||
IndexBuilder indexBuilder = new IndexBuilder(configuration, nodeprecated);
|
||||
SystemPropertiesWriter.generate(configuration);
|
||||
configuration.mainIndex.addElements();
|
||||
if (options.splitIndex()) {
|
||||
SplitIndexWriter.generate(configuration, indexBuilder);
|
||||
SplitIndexWriter.generate(configuration);
|
||||
} else {
|
||||
SingleIndexWriter.generate(configuration, indexBuilder);
|
||||
SingleIndexWriter.generate(configuration);
|
||||
}
|
||||
AllClassesIndexWriter.generate(configuration,
|
||||
new IndexBuilder(configuration, nodeprecated, true));
|
||||
IndexBuilder allClassesIndex = new IndexBuilder(configuration, nodeprecated, true);
|
||||
allClassesIndex.addElements();
|
||||
AllClassesIndexWriter.generate(configuration, allClassesIndex);
|
||||
if (!configuration.packages.isEmpty()) {
|
||||
AllPackagesIndexWriter.generate(configuration);
|
||||
}
|
||||
SystemPropertiesWriter.generate(configuration);
|
||||
configuration.mainIndex.createSearchIndexFiles();
|
||||
}
|
||||
|
||||
if (options.createOverview()) {
|
||||
|
@ -155,8 +155,6 @@ public class HtmlDocletWriter {
|
||||
*/
|
||||
public final HtmlConfiguration configuration;
|
||||
|
||||
protected final SearchIndexItems searchItems;
|
||||
|
||||
protected final HtmlOptions options;
|
||||
|
||||
protected final Utils utils;
|
||||
@ -216,12 +214,11 @@ public class HtmlDocletWriter {
|
||||
*/
|
||||
public HtmlDocletWriter(HtmlConfiguration configuration, DocPath path) {
|
||||
this.configuration = configuration;
|
||||
this.searchItems = configuration.searchItems;
|
||||
this.options = configuration.getOptions();
|
||||
this.contents = configuration.contents;
|
||||
this.messages = configuration.messages;
|
||||
this.resources = configuration.docResources;
|
||||
this.links = new Links(path);
|
||||
this.links = new Links(path, configuration.utils);
|
||||
this.utils = configuration.utils;
|
||||
this.comparators = utils.comparators;
|
||||
this.path = path;
|
||||
@ -955,7 +952,7 @@ public class HtmlDocletWriter {
|
||||
ExecutableElement ee = (ExecutableElement)element;
|
||||
return getLink(new LinkInfoImpl(configuration, context, typeElement)
|
||||
.label(label)
|
||||
.where(links.getName(getAnchor(ee, isProperty)))
|
||||
.where(links.getAnchor(ee, isProperty))
|
||||
.strong(strong));
|
||||
}
|
||||
|
||||
@ -988,7 +985,7 @@ public class HtmlDocletWriter {
|
||||
ExecutableElement emd = (ExecutableElement) element;
|
||||
return getLink(new LinkInfoImpl(configuration, context, typeElement)
|
||||
.label(label)
|
||||
.where(links.getName(getAnchor(emd))));
|
||||
.where(links.getAnchor(emd)));
|
||||
} else if (utils.isVariableElement(element) || utils.isTypeElement(element)) {
|
||||
return getLink(new LinkInfoImpl(configuration, context, typeElement)
|
||||
.label(label).where(links.getName(element.getSimpleName().toString())));
|
||||
@ -997,27 +994,6 @@ public class HtmlDocletWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public String getAnchor(ExecutableElement executableElement) {
|
||||
return getAnchor(executableElement, false);
|
||||
}
|
||||
|
||||
public String getAnchor(ExecutableElement executableElement, boolean isProperty) {
|
||||
if (isProperty) {
|
||||
return executableElement.getSimpleName().toString();
|
||||
}
|
||||
String member = anchorName(executableElement);
|
||||
String erasedSignature = utils.makeSignature(executableElement, null, true, true);
|
||||
return member + erasedSignature;
|
||||
}
|
||||
|
||||
public String anchorName(Element member) {
|
||||
if (member.getKind() == ElementKind.CONSTRUCTOR) {
|
||||
return "<init>";
|
||||
} else {
|
||||
return utils.getSimpleName(member);
|
||||
}
|
||||
}
|
||||
|
||||
public Content seeTagToContent(Element element, DocTree see) {
|
||||
Kind kind = see.getKind();
|
||||
if (!(kind == LINK || kind == SEE || kind == LINK_PLAIN)) {
|
||||
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.Links;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||
|
||||
/**
|
||||
* Extensions to {@code IndexBuilder} to fill in remaining fields
|
||||
* in index items: {@code containingModule}, {@code containingPackage},
|
||||
* {@code containingClass}, and {@code url}, and to write out the
|
||||
* JavaScript files.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class HtmlIndexBuilder extends IndexBuilder {
|
||||
private final HtmlConfiguration configuration;
|
||||
|
||||
private final Links links;
|
||||
private final Resources resources;
|
||||
private final Utils utils;
|
||||
|
||||
/**
|
||||
* Creates a new {@code HtmlIndexBuilder}.
|
||||
*
|
||||
* @param configuration the current configuration of the doclet
|
||||
*/
|
||||
HtmlIndexBuilder(HtmlConfiguration configuration) {
|
||||
super(configuration, configuration.getOptions().noDeprecated());
|
||||
this.configuration = configuration;
|
||||
links = new Links(DocPath.empty, configuration.utils);
|
||||
resources = configuration.docResources;
|
||||
utils = configuration.utils;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* After the initial work to add the element items, the remaining fields in
|
||||
* the items are also initialized.
|
||||
*/
|
||||
public void addElements() {
|
||||
super.addElements();
|
||||
if (classesOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Map<String,Integer> duplicateLabelCheck = new HashMap<>();
|
||||
for (Character ch : getFirstCharacters()) {
|
||||
for (IndexItem item : getItems(ch)) {
|
||||
duplicateLabelCheck.compute(item.getFullyQualifiedLabel(utils),
|
||||
(k, v) -> v == null ? 1 : v + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (Character ch : getFirstCharacters()) {
|
||||
for (IndexItem item : getItems(ch)) {
|
||||
if (item.isElementItem()) {
|
||||
boolean addModuleInfo =
|
||||
duplicateLabelCheck.get(item.getFullyQualifiedLabel(utils)) > 1;
|
||||
addContainingInfo(item, addModuleInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addContainingInfo(IndexItem item, boolean addModuleInfo) {
|
||||
Element element = item.getElement();
|
||||
switch (element.getKind()) {
|
||||
case MODULE:
|
||||
break;
|
||||
|
||||
case PACKAGE:
|
||||
if (configuration.showModules) {
|
||||
item.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element)));
|
||||
}
|
||||
break;
|
||||
|
||||
case CLASS:
|
||||
case ENUM:
|
||||
case RECORD:
|
||||
case ANNOTATION_TYPE:
|
||||
case INTERFACE:
|
||||
item.setContainingPackage(utils.getPackageName(utils.containingPackage(element)));
|
||||
if (configuration.showModules && addModuleInfo) {
|
||||
item.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element)));
|
||||
}
|
||||
break;
|
||||
|
||||
case CONSTRUCTOR:
|
||||
case METHOD:
|
||||
case FIELD:
|
||||
case ENUM_CONSTANT:
|
||||
TypeElement containingType = item.getContainingTypeElement();
|
||||
item.setContainingPackage(utils.getPackageName(utils.containingPackage(element)));
|
||||
item.setContainingClass(utils.getSimpleName(containingType));
|
||||
if (configuration.showModules && addModuleInfo) {
|
||||
item.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element)));
|
||||
}
|
||||
if (utils.isExecutableElement(element)) {
|
||||
String url = HtmlTree.encodeURL(links.getAnchor((ExecutableElement) element));
|
||||
if (!url.equals(item.getLabel())) {
|
||||
item.setUrl(url);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates the set of index files used by interactive search.
|
||||
*
|
||||
* @throws DocFileIOException if there is a problem creating any of the search index files
|
||||
*/
|
||||
public void createSearchIndexFiles() throws DocFileIOException {
|
||||
// add last-minute items
|
||||
if (!configuration.packages.isEmpty()) {
|
||||
IndexItem item = IndexItem.of(IndexItem.Category.PACKAGES,
|
||||
resources.getText("doclet.All_Packages"),
|
||||
DocPaths.ALLPACKAGES_INDEX);
|
||||
add(item);
|
||||
}
|
||||
IndexItem item = IndexItem.of(IndexItem.Category.TYPES,
|
||||
resources.getText("doclet.All_Classes"),
|
||||
DocPaths.ALLCLASSES_INDEX);
|
||||
add(item);
|
||||
|
||||
for (IndexItem.Category category : IndexItem.Category.values()) {
|
||||
DocPath file;
|
||||
String varName;
|
||||
switch (category) {
|
||||
case MODULES -> {
|
||||
file = DocPaths.MODULE_SEARCH_INDEX_JS;
|
||||
varName = "moduleSearchIndex";
|
||||
}
|
||||
case PACKAGES -> {
|
||||
file = DocPaths.PACKAGE_SEARCH_INDEX_JS;
|
||||
varName = "packageSearchIndex";
|
||||
}
|
||||
case TYPES -> {
|
||||
file = DocPaths.TYPE_SEARCH_INDEX_JS;
|
||||
varName = "typeSearchIndex";
|
||||
}
|
||||
case MEMBERS -> {
|
||||
file = DocPaths.MEMBER_SEARCH_INDEX_JS;
|
||||
varName = "memberSearchIndex";
|
||||
}
|
||||
case TAGS -> {
|
||||
file = DocPaths.TAG_SEARCH_INDEX_JS;
|
||||
varName = "tagSearchIndex";
|
||||
}
|
||||
default -> throw new Error();
|
||||
}
|
||||
|
||||
createSearchIndexFile(file, getItems(category), varName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a search index file.
|
||||
*
|
||||
* @param searchIndexJS the file for the JavaScript to be generated
|
||||
* @param indexItems the search index items
|
||||
* @param varName the variable name to write in the JavaScript file
|
||||
*
|
||||
* @throws DocFileIOException if there is a problem creating the search index file
|
||||
*/
|
||||
private void createSearchIndexFile(DocPath searchIndexJS,
|
||||
SortedSet<IndexItem> indexItems,
|
||||
String varName)
|
||||
throws DocFileIOException
|
||||
{
|
||||
// The file needs to be created even if there are no searchIndex items
|
||||
DocFile jsFile = DocFile.createFileForOutput(configuration, searchIndexJS);
|
||||
try (Writer wr = jsFile.openWriter()) {
|
||||
wr.write(varName);
|
||||
wr.write(" = [");
|
||||
boolean first = true;
|
||||
for (IndexItem item : indexItems) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
wr.write(",");
|
||||
}
|
||||
wr.write(item.toJSON());
|
||||
}
|
||||
wr.write("];");
|
||||
wr.write("updateSearchResults();");
|
||||
} catch (IOException ie) {
|
||||
throw new DocFileIOException(jsFile, DocFileIOException.Mode.WRITE, ie);
|
||||
}
|
||||
}
|
||||
}
|
@ -111,7 +111,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter
|
||||
}
|
||||
methodDocTree.add(heading);
|
||||
return HtmlTree.SECTION(HtmlStyle.detail, methodDocTree)
|
||||
.setId(links.getName(writer.getAnchor(method)));
|
||||
.setId(links.getAnchor(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -284,7 +284,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter
|
||||
Content codeOverriddenTypeLink = HtmlTree.CODE(overriddenTypeLink);
|
||||
Content methlink = writer.getLink(
|
||||
new LinkInfoImpl(writer.configuration, LinkInfoImpl.Kind.MEMBER, holder)
|
||||
.where(writer.links.getName(writer.getAnchor(method)))
|
||||
.where(writer.links.getAnchor(method))
|
||||
.label(method.getSimpleName()));
|
||||
Content codeMethLink = HtmlTree.CODE(methlink);
|
||||
Content dd = HtmlTree.DD(codeMethLink);
|
||||
|
@ -142,7 +142,7 @@ public class Navigation {
|
||||
this.documentedPage = page;
|
||||
this.path = path;
|
||||
this.pathToRoot = path.parent().invert();
|
||||
this.links = new Links(path);
|
||||
this.links = new Links(path, configuration.utils);
|
||||
this.rowListTitle = configuration.getDocResources().getText("doclet.Navigation");
|
||||
this.searchLabel = contents.getContent("doclet.search");
|
||||
}
|
||||
|
@ -1,198 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
|
||||
/**
|
||||
* Index item for search.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class SearchIndexItem {
|
||||
|
||||
enum Category {
|
||||
MODULES,
|
||||
PACKAGES,
|
||||
TYPES,
|
||||
MEMBERS,
|
||||
/**
|
||||
* The category of items corresponding to {@code {@index}} tags.
|
||||
*/
|
||||
INDEX,
|
||||
/**
|
||||
* The category of items corresponding to {@code {@systemProperty}} tags.
|
||||
*/
|
||||
SYSTEM_PROPERTY
|
||||
}
|
||||
|
||||
private Category category;
|
||||
private String label = "";
|
||||
private String url = "";
|
||||
private String containingModule = "";
|
||||
private String containingPackage = "";
|
||||
private String containingClass = "";
|
||||
private String holder = "";
|
||||
private String description = "";
|
||||
private Element element;
|
||||
|
||||
public void setLabel(String l) {
|
||||
label = l;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setUrl(String u) {
|
||||
url = u;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setContainingModule(String m) {
|
||||
containingModule = m;
|
||||
}
|
||||
|
||||
public void setContainingPackage(String p) {
|
||||
containingPackage = p;
|
||||
}
|
||||
|
||||
public void setContainingClass(String c) {
|
||||
containingClass = c;
|
||||
}
|
||||
|
||||
public void setCategory(Category c) {
|
||||
category = c;
|
||||
}
|
||||
|
||||
public void setHolder(String h) {
|
||||
holder = h;
|
||||
}
|
||||
|
||||
public String getHolder() {
|
||||
return holder;
|
||||
}
|
||||
|
||||
public void setDescription(String d) {
|
||||
description = d;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
protected Category getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setElement(Element element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
public Element getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// TODO: Additional processing is required, see JDK-8238495
|
||||
StringBuilder item = new StringBuilder();
|
||||
switch (category) {
|
||||
case MODULES:
|
||||
item.append("{")
|
||||
.append("\"l\":\"").append(label).append("\"")
|
||||
.append("}");
|
||||
break;
|
||||
case PACKAGES:
|
||||
item.append("{");
|
||||
if (!containingModule.isEmpty()) {
|
||||
item.append("\"m\":\"").append(containingModule).append("\",");
|
||||
}
|
||||
item.append("\"l\":\"").append(label).append("\"");
|
||||
if (!url.isEmpty()) {
|
||||
item.append(",\"u\":\"").append(url).append("\"");
|
||||
}
|
||||
item.append("}");
|
||||
break;
|
||||
case TYPES:
|
||||
item.append("{");
|
||||
if (!containingPackage.isEmpty()) {
|
||||
item.append("\"p\":\"").append(containingPackage).append("\",");
|
||||
}
|
||||
if (!containingModule.isEmpty()) {
|
||||
item.append("\"m\":\"").append(containingModule).append("\",");
|
||||
}
|
||||
item.append("\"l\":\"").append(label).append("\"");
|
||||
if (!url.isEmpty()) {
|
||||
item.append(",\"u\":\"").append(url).append("\"");
|
||||
}
|
||||
item.append("}");
|
||||
break;
|
||||
case MEMBERS:
|
||||
item.append("{");
|
||||
if (!containingModule.isEmpty()) {
|
||||
item.append("\"m\":\"").append(containingModule).append("\",");
|
||||
}
|
||||
item.append("\"p\":\"").append(containingPackage).append("\",")
|
||||
.append("\"c\":\"").append(containingClass).append("\",")
|
||||
.append("\"l\":\"").append(label).append("\"");
|
||||
if (!url.isEmpty()) {
|
||||
item.append(",\"u\":\"").append(url).append("\"");
|
||||
}
|
||||
item.append("}");
|
||||
break;
|
||||
case INDEX:
|
||||
case SYSTEM_PROPERTY:
|
||||
item.append("{")
|
||||
.append("\"l\":\"").append(label).append("\",")
|
||||
.append("\"h\":\"").append(holder).append("\",");
|
||||
if (!description.isEmpty()) {
|
||||
item.append("\"d\":\"").append(description).append("\",");
|
||||
}
|
||||
item.append("\"u\":\"").append(url).append("\"")
|
||||
.append("}");
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unexpected category: " + category);
|
||||
}
|
||||
return item.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the part of the label after the last dot, or whole label if no dots.
|
||||
*
|
||||
* @return the simple name
|
||||
*/
|
||||
public String getSimpleName() {
|
||||
return label.substring(label.lastIndexOf('.') + 1);
|
||||
}
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem.Category;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A container for organizing {@linkplain SearchIndexItem search items}
|
||||
* by {@linkplain Category category}.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public final class SearchIndexItems {
|
||||
|
||||
private final Map<Category, Set<SearchIndexItem>> items = new HashMap<>();
|
||||
private final Utils utils;
|
||||
|
||||
public SearchIndexItems(Utils utils) {
|
||||
this.utils = Objects.requireNonNull(utils);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified item to this container.
|
||||
*
|
||||
* @param item
|
||||
* the item to add
|
||||
*/
|
||||
public void add(SearchIndexItem item) {
|
||||
Objects.requireNonNull(item);
|
||||
items.computeIfAbsent(item.getCategory(), this::newSetForCategory)
|
||||
.add(item);
|
||||
}
|
||||
|
||||
private Set<SearchIndexItem> newSetForCategory(Category category) {
|
||||
final Comparator<SearchIndexItem> cmp;
|
||||
if (category == Category.TYPES) {
|
||||
cmp = utils.comparators.makeTypeSearchIndexComparator();
|
||||
} else {
|
||||
cmp = utils.comparators.makeGenericSearchIndexComparator();
|
||||
}
|
||||
return new TreeSet<>(cmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are items of any of the specified categories
|
||||
* in this container.
|
||||
*
|
||||
* <p> Iff there exists an item {@code i} for which there is a category
|
||||
* {@code c} from the specified categories such that
|
||||
* {@code i.getCategory().equals(c)}, then {@code true} is returned.
|
||||
*
|
||||
* @param firstCategory
|
||||
* the first category
|
||||
* @param otherCategories
|
||||
* other categories (optional)
|
||||
*
|
||||
* @return {@code true} if there are items of any of the specified categories,
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* if there are {@code null} categories
|
||||
*/
|
||||
public boolean containsAnyOfCategories(Category firstCategory,
|
||||
Category... otherCategories)
|
||||
{
|
||||
return itemsOfCategories(firstCategory, otherCategories)
|
||||
.findAny()
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream of items of any of the specified categories
|
||||
* from this container.
|
||||
*
|
||||
* <p> The returned stream consists of all items {@code i} for which there
|
||||
* is a category {@code c} from the specified categories such that
|
||||
* {@code i.getCategory().equals(c)}. The stream may be empty.
|
||||
*
|
||||
* @param firstCategory
|
||||
* the first category
|
||||
* @param otherCategories
|
||||
* other categories (optional)
|
||||
*
|
||||
* @return a stream of items of the specified categories
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* if there are {@code null} categories
|
||||
*/
|
||||
public Stream<SearchIndexItem> itemsOfCategories(Category firstCategory,
|
||||
Category... otherCategories)
|
||||
{
|
||||
return concatenatedStreamOf(firstCategory, otherCategories)
|
||||
.distinct()
|
||||
.flatMap(this::itemsOf);
|
||||
}
|
||||
|
||||
private Stream<SearchIndexItem> itemsOf(Category cat) {
|
||||
Objects.requireNonNull(cat);
|
||||
return items.getOrDefault(cat, Set.of()).stream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a concatenated stream of elements.
|
||||
*
|
||||
* <p> The elements of the returned stream are encountered in the following order:
|
||||
* {@code first, remaining[0], remaining[1], ..., remaining[remaining.length - 1]}.
|
||||
*
|
||||
* @param first
|
||||
* the first element
|
||||
* @param remaining
|
||||
* the remaining elements, if any
|
||||
* @param <T>
|
||||
* the type of elements
|
||||
*
|
||||
* @return the stream of elements
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* if {@code remaining} is {@code null}
|
||||
*/
|
||||
private static <T> Stream<T> concatenatedStreamOf(T first, T[] remaining) {
|
||||
return Stream.concat(Stream.of(first), Stream.of(remaining));
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ package jdk.javadoc.internal.doclets.formats.html;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem.Category;
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
|
||||
@ -38,9 +38,9 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem.Category;
|
||||
|
||||
|
||||
/**
|
||||
@ -57,34 +57,26 @@ import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
|
||||
*/
|
||||
public class SingleIndexWriter extends AbstractIndexWriter {
|
||||
|
||||
private Set<Character> elements;
|
||||
private Set<Character> firstCharacters;
|
||||
|
||||
/**
|
||||
* Construct the SingleIndexWriter with filename "index-all.html" and the
|
||||
* {@link IndexBuilder}
|
||||
*
|
||||
* @param configuration the configuration for this doclet
|
||||
* @param filename Name of the index file to be generated.
|
||||
* @param indexBuilder Unicode based Index from {@link IndexBuilder}
|
||||
*/
|
||||
public SingleIndexWriter(HtmlConfiguration configuration,
|
||||
DocPath filename,
|
||||
IndexBuilder indexBuilder) {
|
||||
super(configuration, filename, indexBuilder);
|
||||
public SingleIndexWriter(HtmlConfiguration configuration) {
|
||||
super(configuration, DocPaths.INDEX_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate single index file, for all Unicode characters.
|
||||
*
|
||||
* @param configuration the configuration for this doclet
|
||||
* @param indexBuilder IndexBuilder built by {@link IndexBuilder}
|
||||
* @throws DocFileIOException if there is a problem generating the index
|
||||
*/
|
||||
public static void generate(HtmlConfiguration configuration,
|
||||
IndexBuilder indexBuilder) throws DocFileIOException {
|
||||
DocPath filename = DocPaths.INDEX_ALL;
|
||||
SingleIndexWriter indexgen = new SingleIndexWriter(configuration,
|
||||
filename, indexBuilder);
|
||||
public static void generate(HtmlConfiguration configuration) throws DocFileIOException {
|
||||
SingleIndexWriter indexgen = new SingleIndexWriter(configuration);
|
||||
indexgen.generateIndexFile();
|
||||
}
|
||||
|
||||
@ -101,14 +93,10 @@ public class SingleIndexWriter extends AbstractIndexWriter {
|
||||
navBar.setUserHeader(getUserHeaderFooter(true));
|
||||
headerContent.add(navBar.getContent(Navigation.Position.TOP));
|
||||
Content mainContent = new ContentBuilder();
|
||||
elements = new TreeSet<>(indexBuilder.asMap().keySet());
|
||||
elements.addAll(tagSearchIndexMap.keySet());
|
||||
firstCharacters = new TreeSet<>(mainIndex.getFirstCharacters());
|
||||
addLinksForIndexes(mainContent);
|
||||
for (Character unicode : elements) {
|
||||
if (tagSearchIndexMap.get(unicode) != null) {
|
||||
indexBuilder.addSearchTags(unicode, tagSearchIndexMap.get(unicode));
|
||||
}
|
||||
addContents(unicode, indexBuilder.getMemberList(unicode), mainContent);
|
||||
for (Character ch : firstCharacters) {
|
||||
addContents(ch, mainIndex.getItems(ch), mainContent);
|
||||
}
|
||||
addLinksForIndexes(mainContent);
|
||||
HtmlTree footer = HtmlTree.FOOTER();
|
||||
@ -122,7 +110,6 @@ public class SingleIndexWriter extends AbstractIndexWriter {
|
||||
contents.getContent("doclet.Index"))))
|
||||
.addMainContent(mainContent)
|
||||
.setFooter(footer));
|
||||
createSearchIndexFiles();
|
||||
printHtmlDocument(null, "index", body);
|
||||
}
|
||||
|
||||
@ -132,7 +119,7 @@ public class SingleIndexWriter extends AbstractIndexWriter {
|
||||
* @param contentTree the content tree to which the links for indexes will be added
|
||||
*/
|
||||
protected void addLinksForIndexes(Content contentTree) {
|
||||
for (Character ch : elements) {
|
||||
for (Character ch : firstCharacters) {
|
||||
String unicode = ch.toString();
|
||||
contentTree.add(
|
||||
links.createLink(getNameForIndex(unicode),
|
||||
@ -147,7 +134,8 @@ public class SingleIndexWriter extends AbstractIndexWriter {
|
||||
contentTree.add(links.createLink(DocPaths.ALLPACKAGES_INDEX,
|
||||
contents.allPackagesLabel));
|
||||
}
|
||||
if (searchItems.containsAnyOfCategories(Category.SYSTEM_PROPERTY)) {
|
||||
boolean anySystemProperties = !mainIndex.getItems(DocTree.Kind.SYSTEM_PROPERTY).isEmpty();
|
||||
if (anySystemProperties) {
|
||||
contentTree.add(getVerticalSeparator());
|
||||
contentTree.add(links.createLink(DocPaths.SYSTEM_PROPERTIES, contents.systemPropertiesLabel));
|
||||
}
|
||||
|
@ -29,12 +29,10 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem.Category;
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
|
||||
@ -47,6 +45,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem.Category;
|
||||
|
||||
/**
|
||||
* Generate Separate Index Files for all the member names with Indexing in
|
||||
@ -70,14 +69,12 @@ public class SplitIndexWriter extends AbstractIndexWriter {
|
||||
*
|
||||
* @param configuration the configuration for this doclet
|
||||
* @param path Path to the file which is getting generated.
|
||||
* @param indexBuilder Unicode based Index from {@link IndexBuilder}
|
||||
* @param elements the collection of characters for which to generate index files
|
||||
*/
|
||||
public SplitIndexWriter(HtmlConfiguration configuration,
|
||||
DocPath path,
|
||||
IndexBuilder indexBuilder,
|
||||
Collection<Character> elements) {
|
||||
super(configuration, path, indexBuilder);
|
||||
super(configuration, path);
|
||||
this.indexElements = new ArrayList<>(elements);
|
||||
}
|
||||
|
||||
@ -86,30 +83,19 @@ public class SplitIndexWriter extends AbstractIndexWriter {
|
||||
* the members starting with the particular unicode character.
|
||||
*
|
||||
* @param configuration the configuration for this doclet
|
||||
* @param indexBuilder IndexBuilder built by {@link IndexBuilder}
|
||||
* @throws DocFileIOException if there is a problem generating the index files
|
||||
*/
|
||||
public static void generate(HtmlConfiguration configuration,
|
||||
IndexBuilder indexBuilder) throws DocFileIOException
|
||||
{
|
||||
public static void generate(HtmlConfiguration configuration) throws DocFileIOException {
|
||||
DocPath path = DocPaths.INDEX_FILES;
|
||||
SortedSet<Character> keys = new TreeSet<>(indexBuilder.asMap().keySet());
|
||||
Set<Character> searchItemsKeys = configuration.searchItems
|
||||
.itemsOfCategories(Category.INDEX, Category.SYSTEM_PROPERTY)
|
||||
.map(i -> keyCharacter(i.getLabel()))
|
||||
.collect(Collectors.toSet());
|
||||
keys.addAll(searchItemsKeys);
|
||||
IndexBuilder mainIndex = configuration.mainIndex;
|
||||
SortedSet<Character> keys = new TreeSet<>(mainIndex.getFirstCharacters());
|
||||
ListIterator<Character> li = new ArrayList<>(keys).listIterator();
|
||||
while (li.hasNext()) {
|
||||
Character ch = li.next();
|
||||
DocPath filename = DocPaths.indexN(li.nextIndex());
|
||||
SplitIndexWriter indexgen = new SplitIndexWriter(configuration,
|
||||
path.resolve(filename),
|
||||
indexBuilder, keys);
|
||||
path.resolve(filename), keys);
|
||||
indexgen.generateIndexFile(ch);
|
||||
if (!li.hasNext()) {
|
||||
indexgen.createSearchIndexFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,10 +121,7 @@ public class SplitIndexWriter extends AbstractIndexWriter {
|
||||
contents.getContent("doclet.Index"))));
|
||||
Content mainContent = new ContentBuilder();
|
||||
addLinksForIndexes(mainContent);
|
||||
if (tagSearchIndexMap.get(unicode) != null) {
|
||||
indexBuilder.addSearchTags(unicode, tagSearchIndexMap.get(unicode));
|
||||
}
|
||||
addContents(unicode, indexBuilder.getMemberList(unicode), mainContent);
|
||||
addContents(unicode, mainIndex.getItems(unicode), mainContent);
|
||||
addLinksForIndexes(mainContent);
|
||||
main.add(mainContent);
|
||||
HtmlTree footer = HtmlTree.FOOTER();
|
||||
@ -173,7 +156,8 @@ public class SplitIndexWriter extends AbstractIndexWriter {
|
||||
contentTree.add(links.createLink(pathToRoot.resolve(DocPaths.ALLPACKAGES_INDEX),
|
||||
contents.allPackagesLabel));
|
||||
}
|
||||
if (searchItems.containsAnyOfCategories(Category.SYSTEM_PROPERTY)) {
|
||||
boolean anySystemProperties = !mainIndex.getItems(DocTree.Kind.SYSTEM_PROPERTY).isEmpty();
|
||||
if (anySystemProperties) {
|
||||
contentTree.add(getVerticalSeparator());
|
||||
contentTree.add(links.createLink(pathToRoot.resolve(DocPaths.SYSTEM_PROPERTIES),
|
||||
contents.systemPropertiesLabel));
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem.Category;
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.FixedStringContent;
|
||||
@ -40,6 +40,8 @@ import jdk.javadoc.internal.doclets.toolkit.OverviewElement;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem.Category;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import java.nio.file.Path;
|
||||
@ -85,8 +87,8 @@ public class SystemPropertiesWriter extends HtmlDocletWriter {
|
||||
}
|
||||
|
||||
private static void generate(HtmlConfiguration configuration, DocPath fileName) throws DocFileIOException {
|
||||
boolean hasSystemProperties = configuration.searchItems
|
||||
.containsAnyOfCategories(Category.SYSTEM_PROPERTY);
|
||||
boolean hasSystemProperties = configuration.mainIndex != null
|
||||
&& !configuration.mainIndex.getItems(DocTree.Kind.SYSTEM_PROPERTY).isEmpty();
|
||||
if (!hasSystemProperties) {
|
||||
// Cannot defer this check any further, because of the super() call
|
||||
// that prints out notices on creating files, etc.
|
||||
@ -132,15 +134,15 @@ public class SystemPropertiesWriter extends HtmlDocletWriter {
|
||||
* @param content HtmlTree content to which the links will be added
|
||||
*/
|
||||
protected void addSystemProperties(Content content) {
|
||||
Map<String, List<SearchIndexItem>> searchIndexMap = groupSystemProperties();
|
||||
Map<String, List<IndexItem>> searchIndexMap = groupSystemProperties();
|
||||
Content separator = new StringContent(", ");
|
||||
Table table = new Table(HtmlStyle.systemPropertiesSummary, HtmlStyle.summaryTable)
|
||||
.setCaption(contents.systemPropertiesSummaryLabel)
|
||||
.setHeader(new TableHeader(contents.propertyLabel, contents.referencedIn))
|
||||
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast);
|
||||
for (Entry<String, List<SearchIndexItem>> entry : searchIndexMap.entrySet()) {
|
||||
for (Entry<String, List<IndexItem>> entry : searchIndexMap.entrySet()) {
|
||||
Content propertyName = new StringContent(entry.getKey());
|
||||
List<SearchIndexItem> searchIndexItems = entry.getValue();
|
||||
List<IndexItem> searchIndexItems = entry.getValue();
|
||||
Content separatedReferenceLinks = new ContentBuilder();
|
||||
separatedReferenceLinks.add(createLink(searchIndexItems.get(0)));
|
||||
for (int i = 1; i < searchIndexItems.size(); i++) {
|
||||
@ -152,24 +154,23 @@ public class SystemPropertiesWriter extends HtmlDocletWriter {
|
||||
content.add(table);
|
||||
}
|
||||
|
||||
private Map<String, List<SearchIndexItem>> groupSystemProperties() {
|
||||
return searchItems
|
||||
.itemsOfCategories(Category.SYSTEM_PROPERTY)
|
||||
.collect(groupingBy(SearchIndexItem::getLabel, TreeMap::new, toList()));
|
||||
private Map<String, List<IndexItem>> groupSystemProperties() {
|
||||
return configuration.mainIndex.getItems(DocTree.Kind.SYSTEM_PROPERTY).stream()
|
||||
.collect(groupingBy(IndexItem::getLabel, TreeMap::new, toList()));
|
||||
}
|
||||
|
||||
private Content createLink(SearchIndexItem i) {
|
||||
assert i.getCategory() == Category.SYSTEM_PROPERTY : i;
|
||||
if (i.getElement() != null) {
|
||||
if (i.getElement() instanceof OverviewElement) {
|
||||
return links.createLink(pathToRoot.resolve(i.getUrl()),
|
||||
resources.getText("doclet.Overview"));
|
||||
}
|
||||
DocletElement e = ((DocletElement) i.getElement());
|
||||
private Content createLink(IndexItem i) {
|
||||
assert i.getDocTree().getKind() == DocTree.Kind.SYSTEM_PROPERTY : i;
|
||||
Element element = i.getElement();
|
||||
if (element instanceof OverviewElement) {
|
||||
return links.createLink(pathToRoot.resolve(i.getUrl()),
|
||||
resources.getText("doclet.Overview"));
|
||||
} else if (element instanceof DocletElement) {
|
||||
DocletElement e = (DocletElement) element;
|
||||
// Implementations of DocletElement do not override equals and
|
||||
// hashCode; putting instances of DocletElement in a map is not
|
||||
// incorrect, but might well be inefficient
|
||||
String t = titles.computeIfAbsent(i.getElement(), utils::getHTMLTitle);
|
||||
String t = titles.computeIfAbsent(element, utils::getHTMLTitle);
|
||||
if (t.isBlank()) {
|
||||
// The user should probably be notified (a warning?) that this
|
||||
// file does not have a title
|
||||
|
@ -41,7 +41,6 @@ import com.sun.source.doctree.DocTree;
|
||||
import com.sun.source.doctree.IndexTree;
|
||||
import com.sun.source.doctree.ParamTree;
|
||||
import com.sun.source.doctree.SystemPropertyTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem.Category;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
@ -59,6 +58,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||
|
||||
/**
|
||||
@ -111,7 +111,7 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
@Override
|
||||
protected Content indexTagOutput(Element element, DocTree tag) {
|
||||
CommentHelper ch = utils.getCommentHelper(element);
|
||||
IndexTree itt = (IndexTree)tag;
|
||||
IndexTree itt = (IndexTree) tag;
|
||||
|
||||
String tagText = ch.getText(itt.getSearchTerm());
|
||||
if (tagText.charAt(0) == '"' && tagText.charAt(tagText.length() - 1) == '"') {
|
||||
@ -120,7 +120,7 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
}
|
||||
String desc = ch.getText(itt.getDescription());
|
||||
|
||||
return createAnchorAndSearchIndex(element, tagText, desc, false);
|
||||
return createAnchorAndSearchIndex(element, tagText, desc, tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -283,7 +283,7 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
SystemPropertyTree itt = (SystemPropertyTree) tag;
|
||||
String tagText = itt.getPropertyName().toString();
|
||||
return HtmlTree.CODE(createAnchorAndSearchIndex(element, tagText,
|
||||
resources.getText("doclet.System_Property"), true));
|
||||
resources.getText("doclet.System_Property"), tag));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -366,7 +366,7 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
}
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
private Content createAnchorAndSearchIndex(Element element, String tagText, String desc, boolean isSystemProperty) {
|
||||
private Content createAnchorAndSearchIndex(Element element, String tagText, String desc, DocTree tree) {
|
||||
Content result = null;
|
||||
if (isFirstSentence && inSummary) {
|
||||
result = new StringContent(tagText);
|
||||
@ -379,77 +379,60 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
}
|
||||
result = HtmlTree.SPAN(anchorName, HtmlStyle.searchTagResult, new StringContent(tagText));
|
||||
if (options.createIndex() && !tagText.isEmpty()) {
|
||||
SearchIndexItem si = new SearchIndexItem();
|
||||
si.setLabel(tagText);
|
||||
si.setDescription(desc);
|
||||
si.setUrl(htmlWriter.path.getPath() + "#" + anchorName);
|
||||
new SimpleElementVisitor14<Void, Void>() {
|
||||
String holder = new SimpleElementVisitor14<String, Void>() {
|
||||
|
||||
@Override
|
||||
public Void visitModule(ModuleElement e, Void p) {
|
||||
si.setHolder(resources.getText("doclet.module")
|
||||
+ " " + utils.getFullyQualifiedName(e));
|
||||
return null;
|
||||
public String visitModule(ModuleElement e, Void p) {
|
||||
return resources.getText("doclet.module")
|
||||
+ " " + utils.getFullyQualifiedName(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitPackage(PackageElement e, Void p) {
|
||||
si.setHolder(resources.getText("doclet.package")
|
||||
+ " " + utils.getFullyQualifiedName(e));
|
||||
return null;
|
||||
public String visitPackage(PackageElement e, Void p) {
|
||||
return resources.getText("doclet.package")
|
||||
+ " " + utils.getFullyQualifiedName(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitType(TypeElement e, Void p) {
|
||||
si.setHolder(utils.getTypeElementName(e, true)
|
||||
+ " " + utils.getFullyQualifiedName(e));
|
||||
return null;
|
||||
public String visitType(TypeElement e, Void p) {
|
||||
return utils.getTypeElementName(e, true)
|
||||
+ " " + utils.getFullyQualifiedName(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitExecutable(ExecutableElement e, Void p) {
|
||||
si.setHolder(utils.getFullyQualifiedName(utils.getEnclosingTypeElement(e))
|
||||
+ "." + utils.getSimpleName(e)
|
||||
+ utils.flatSignature(e, htmlWriter.getCurrentPageElement()));
|
||||
return null;
|
||||
public String visitExecutable(ExecutableElement e, Void p) {
|
||||
return utils.getFullyQualifiedName(utils.getEnclosingTypeElement(e))
|
||||
+ "." + utils.getSimpleName(e)
|
||||
+ utils.flatSignature(e, htmlWriter.getCurrentPageElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitVariable(VariableElement e, Void p) {
|
||||
TypeElement te = utils.getEnclosingTypeElement(e);
|
||||
si.setHolder(utils.getFullyQualifiedName(te) + "." + utils.getSimpleName(e));
|
||||
return null;
|
||||
public String visitVariable(VariableElement e, Void p) {
|
||||
return utils.getFullyQualifiedName(utils.getEnclosingTypeElement(e))
|
||||
+ "." + utils.getSimpleName(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitUnknown(Element e, Void p) {
|
||||
public String visitUnknown(Element e, Void p) {
|
||||
if (e instanceof DocletElement) {
|
||||
DocletElement de = (DocletElement) e;
|
||||
si.setElement(de);
|
||||
switch (de.getSubKind()) {
|
||||
case OVERVIEW:
|
||||
si.setHolder(resources.getText("doclet.Overview"));
|
||||
break;
|
||||
case DOCFILE:
|
||||
si.setHolder(getHolderName(de));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return null;
|
||||
return switch (de.getSubKind()) {
|
||||
case OVERVIEW -> resources.getText("doclet.Overview");
|
||||
case DOCFILE -> getHolderName(de);
|
||||
};
|
||||
} else {
|
||||
return super.visitUnknown(e, p);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void defaultAction(Element e, Void p) {
|
||||
si.setHolder(utils.getFullyQualifiedName(e));
|
||||
return null;
|
||||
protected String defaultAction(Element e, Void p) {
|
||||
return utils.getFullyQualifiedName(e);
|
||||
}
|
||||
}.visit(element);
|
||||
si.setCategory(isSystemProperty ? Category.SYSTEM_PROPERTY : Category.INDEX);
|
||||
configuration.searchItems.add(si);
|
||||
IndexItem item = IndexItem.of(element, tree, tagText, holder, desc,
|
||||
new DocLink(htmlWriter.path, anchorName));
|
||||
configuration.mainIndex.add(item);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -25,10 +25,13 @@
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html.markup;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.SectionName;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||
|
||||
/**
|
||||
* Factory for HTML A elements, both links (with a {@code href} attribute)
|
||||
@ -47,6 +50,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
public class Links {
|
||||
|
||||
private final DocPath file;
|
||||
private final Utils utils;
|
||||
|
||||
/**
|
||||
* Creates a {@code Links} object for a specific file, to be written in a specific HTML version.
|
||||
@ -56,8 +60,9 @@ public class Links {
|
||||
*
|
||||
* @param file the file
|
||||
*/
|
||||
public Links(DocPath file) {
|
||||
public Links(DocPath file, Utils utils) {
|
||||
this.file = file;
|
||||
this.utils = utils;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -260,10 +265,36 @@ public class Links {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a name to a valid HTML name (id).
|
||||
* This depends on the HTML version specified when the {@code Links} object was created.
|
||||
* Returns the HTML id to use for an executable element.
|
||||
*
|
||||
* @param name the string that needs to be converted to a valid HTML name
|
||||
* @param executableElement the element
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public String getAnchor(ExecutableElement executableElement) {
|
||||
return getAnchor(executableElement, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML id to use for an executable element.
|
||||
*
|
||||
* @param executableElement the element
|
||||
* @param isProperty whether or not the element represents a property
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public String getAnchor(ExecutableElement executableElement, boolean isProperty) {
|
||||
String a = isProperty
|
||||
? executableElement.getSimpleName().toString()
|
||||
: executableElement.getSimpleName()
|
||||
+ utils.makeSignature(executableElement, null, true, true);
|
||||
return getName(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a name to a valid HTML id.
|
||||
*
|
||||
* @param name the string that needs to be converted to a valid HTML id
|
||||
* @return a valid HTML name
|
||||
*/
|
||||
public String getName(String name) {
|
||||
|
@ -407,10 +407,8 @@ public abstract class BaseConfiguration {
|
||||
public boolean setOptions() throws DocletException {
|
||||
initPackages();
|
||||
initModules();
|
||||
if (!finishOptionSettings0() || !finishOptionSettings())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return finishOptionSettings0()
|
||||
&& finishOptionSettings();
|
||||
}
|
||||
|
||||
private void initDestDirectory() throws DocletException {
|
||||
|
@ -26,7 +26,6 @@
|
||||
package jdk.javadoc.internal.doclets.toolkit.util;
|
||||
|
||||
import com.sun.source.doctree.SerialFieldTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
@ -279,44 +278,12 @@ public class Comparators {
|
||||
return indexUseComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a comparator for the {@code IndexItem}s in the index page. This is a composite
|
||||
* comparator that must be able to compare all kinds {@code Element}s as well as
|
||||
* {@code SearchIndexItem}s.
|
||||
*
|
||||
* @return a comparator for index page items.
|
||||
*/
|
||||
public Comparator<IndexItem> makeIndexComparator(boolean classesOnly) {
|
||||
Comparator<Element> elementComparator = classesOnly
|
||||
? makeAllClassesComparator()
|
||||
: makeIndexElementComparator();
|
||||
Comparator<SearchIndexItem> searchTagComparator =
|
||||
makeGenericSearchIndexComparator();
|
||||
|
||||
return (o1, o2) -> {
|
||||
// Compare two elements
|
||||
if (o1.getElement() != null && o2.getElement() != null) {
|
||||
return elementComparator.compare(o1.getElement(), o2.getElement());
|
||||
}
|
||||
// Compare two search tags
|
||||
if (o1.getSearchTag() != null && o2.getSearchTag() != null) {
|
||||
return searchTagComparator.compare(o1.getSearchTag(), o2.getSearchTag());
|
||||
}
|
||||
// Compare an element with a search tag.
|
||||
// Compares labels, if those are equal put the search tag first.
|
||||
int d = utils.compareStrings(o1.getLabel(), o2.getLabel());
|
||||
if (d == 0) {
|
||||
d = o1.getElement() == null ? 1 : -1;
|
||||
}
|
||||
return d;
|
||||
};
|
||||
}
|
||||
|
||||
private Comparator<TypeMirror> typeMirrorClassUseComparator = null;
|
||||
|
||||
/**
|
||||
* Compares the FullyQualifiedNames of two TypeMirrors
|
||||
* @return
|
||||
* Returns a comparator that compares the fully qualified names of two type mirrors.
|
||||
*
|
||||
* @return the comparator
|
||||
*/
|
||||
public Comparator<TypeMirror> makeTypeMirrorClassUseComparator() {
|
||||
if (typeMirrorClassUseComparator == null) {
|
||||
@ -332,10 +299,10 @@ public class Comparators {
|
||||
private Comparator<TypeMirror> typeMirrorIndexUseComparator = null;
|
||||
|
||||
/**
|
||||
* Compares the SimpleNames of TypeMirrors if equal then the
|
||||
* FullyQualifiedNames of TypeMirrors.
|
||||
* Returns a comparator that compares the simple names of two type mirrors,
|
||||
* or the fully qualified names if the simple names are equal.
|
||||
*
|
||||
* @return
|
||||
* @return the comparator
|
||||
*/
|
||||
public Comparator<TypeMirror> makeTypeMirrorIndexUseComparator() {
|
||||
if (typeMirrorIndexUseComparator == null) {
|
||||
@ -468,7 +435,7 @@ public class Comparators {
|
||||
* argument is less than, equal to, or greater than the second.
|
||||
*/
|
||||
protected int compareFullyQualifiedNames(Element e1, Element e2) {
|
||||
// add simplename to be compatible
|
||||
// add simple name to be compatible
|
||||
String thisElement = getFullyQualifiedName(e1);
|
||||
String thatElement = getFullyQualifiedName(e2);
|
||||
return utils.compareStrings(thisElement, thatElement);
|
||||
@ -527,20 +494,20 @@ public class Comparators {
|
||||
}
|
||||
|
||||
private int getKindIndex(Element e) {
|
||||
switch (e.getKind()) {
|
||||
case MODULE: return 0;
|
||||
case PACKAGE: return 1;
|
||||
case CLASS: return 2;
|
||||
case ENUM: return 3;
|
||||
case ENUM_CONSTANT: return 4;
|
||||
case RECORD: return 5;
|
||||
case INTERFACE: return 6;
|
||||
case ANNOTATION_TYPE: return 7;
|
||||
case FIELD: return 8;
|
||||
case CONSTRUCTOR: return 9;
|
||||
case METHOD: return 10;
|
||||
default: throw new IllegalArgumentException(e.getKind().toString());
|
||||
}
|
||||
return switch (e.getKind()) {
|
||||
case MODULE -> 0;
|
||||
case PACKAGE -> 1;
|
||||
case CLASS -> 2;
|
||||
case ENUM -> 3;
|
||||
case ENUM_CONSTANT -> 4;
|
||||
case RECORD -> 5;
|
||||
case INTERFACE -> 6;
|
||||
case ANNOTATION_TYPE -> 7;
|
||||
case FIELD -> 8;
|
||||
case CONSTRUCTOR -> 9;
|
||||
case METHOD -> 10;
|
||||
default -> throw new IllegalArgumentException(e.getKind().toString());
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
@ -598,48 +565,4 @@ public class Comparators {
|
||||
}.visit(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Comparator for SearchIndexItems representing types. Items are
|
||||
* compared by short name, or full string representation if names are equal.
|
||||
*
|
||||
* @return a Comparator
|
||||
*/
|
||||
public Comparator<SearchIndexItem> makeTypeSearchIndexComparator() {
|
||||
return (SearchIndexItem sii1, SearchIndexItem sii2) -> {
|
||||
int result = utils.compareStrings(sii1.getSimpleName(), sii2.getSimpleName());
|
||||
if (result == 0) {
|
||||
// TreeSet needs this to be consistent with equal so we do
|
||||
// a plain comparison of string representations as fallback.
|
||||
result = sii1.toString().compareTo(sii2.toString());
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
private Comparator<SearchIndexItem> genericSearchIndexComparator = null;
|
||||
|
||||
/**
|
||||
* Returns a Comparator for SearchIndexItems representing modules, packages, or members.
|
||||
* Items are compared by label (member name plus signature for members, package name for
|
||||
* packages, and module name for modules). If labels are equal then full string
|
||||
* representation is compared.
|
||||
*
|
||||
* @return a Comparator
|
||||
*/
|
||||
public Comparator<SearchIndexItem> makeGenericSearchIndexComparator() {
|
||||
if (genericSearchIndexComparator == null) {
|
||||
genericSearchIndexComparator = (SearchIndexItem sii1, SearchIndexItem sii2) -> {
|
||||
int result = utils.compareStrings(sii1.getLabel(), sii2.getLabel());
|
||||
if (result == 0) {
|
||||
// TreeSet needs this to be consistent with equal so we do
|
||||
// a plain comparison of string representations as fallback.
|
||||
result = sii1.toString().compareTo(sii2.toString());
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
return genericSearchIndexComparator;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,14 +33,18 @@ import javax.lang.model.element.ModuleElement;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem;
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
||||
|
||||
import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*;
|
||||
|
||||
/**
|
||||
* An alphabetical index of {@link Element elements}.
|
||||
* An alphabetical index of elements, search tags, and other items.
|
||||
* Two tables are maintained:
|
||||
* one is indexed by the first character of each items name;
|
||||
* the other is index by the item's category, indicating the JavaScript
|
||||
* file in which the item should be written.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
@ -50,10 +54,16 @@ import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.
|
||||
public class IndexBuilder {
|
||||
|
||||
/**
|
||||
* Sets of elements keyed by the first character of the names of the
|
||||
* elements in those sets.
|
||||
* Sets of items keyed by the first character of the names (labels)
|
||||
* of the items in those sets.
|
||||
*/
|
||||
private final Map<Character, SortedSet<IndexItem>> indexMap;
|
||||
private final Map<Character, SortedSet<IndexItem>> itemsByFirstChar;
|
||||
|
||||
/**
|
||||
* Sets of items keyed by the {@link IndexItem.Category category}
|
||||
* of the items in those sets.
|
||||
*/
|
||||
private final Map<IndexItem.Category, SortedSet<IndexItem>> itemsByCategory;
|
||||
|
||||
/**
|
||||
* Don't generate deprecated information if true.
|
||||
@ -63,11 +73,15 @@ public class IndexBuilder {
|
||||
/**
|
||||
* Build this index only for classes?
|
||||
*/
|
||||
private final boolean classesOnly;
|
||||
protected final boolean classesOnly;
|
||||
|
||||
private final BaseConfiguration configuration;
|
||||
private final Utils utils;
|
||||
private final Comparator<IndexItem> comparator;
|
||||
|
||||
/**
|
||||
* The comparator used for the sets in {@code itemsByFirstChar}.
|
||||
*/
|
||||
private final Comparator<IndexItem> mainComparator;
|
||||
|
||||
/**
|
||||
* Creates a new {@code IndexBuilder}.
|
||||
@ -106,15 +120,18 @@ public class IndexBuilder {
|
||||
|
||||
this.noDeprecated = noDeprecated;
|
||||
this.classesOnly = classesOnly;
|
||||
this.indexMap = new TreeMap<>();
|
||||
comparator = utils.comparators.makeIndexComparator(classesOnly);
|
||||
buildIndex();
|
||||
|
||||
itemsByFirstChar = new TreeMap<>();
|
||||
itemsByCategory = new EnumMap<>(IndexItem.Category.class);
|
||||
|
||||
mainComparator = makeIndexComparator(classesOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes all the members in all the packages and all the classes.
|
||||
* Adds all the selected modules, packages, types and their members to the index,
|
||||
* or just the type elements if {@code classesOnly} is {@code true}.
|
||||
*/
|
||||
private void buildIndex() {
|
||||
public void addElements() {
|
||||
Set<TypeElement> classes = configuration.getIncludedTypeElements();
|
||||
indexTypeElements(classes);
|
||||
if (classesOnly) {
|
||||
@ -138,6 +155,65 @@ public class IndexBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an individual item to the two collections of items.
|
||||
*
|
||||
* @param item the item to add
|
||||
*/
|
||||
public void add(IndexItem item) {
|
||||
Objects.requireNonNull(item);
|
||||
|
||||
itemsByFirstChar.computeIfAbsent(keyCharacter(item.getLabel()),
|
||||
c -> new TreeSet<>(mainComparator))
|
||||
.add(item);
|
||||
|
||||
itemsByCategory.computeIfAbsent(item.getCategory(),
|
||||
c -> new TreeSet<>(mainComparator))
|
||||
.add(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorted list of items whose names start with the
|
||||
* provided character.
|
||||
*
|
||||
* @param key index key
|
||||
* @return list of items keyed by the provided character
|
||||
*/
|
||||
public SortedSet<IndexItem> getItems(Character key) {
|
||||
return itemsByFirstChar.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of index keys.
|
||||
*/
|
||||
public List<Character> getFirstCharacters() {
|
||||
return new ArrayList<>(itemsByFirstChar.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorted list of items in a given category.
|
||||
*
|
||||
* @param cat the category
|
||||
* @return list of items keyed by the provided character
|
||||
*/
|
||||
public SortedSet<IndexItem> getItems(IndexItem.Category cat) {
|
||||
Objects.requireNonNull(cat);
|
||||
return itemsByCategory.getOrDefault(cat, Collections.emptySortedSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorted list of items with a given kind of doc tree.
|
||||
*
|
||||
* @param kind the kind
|
||||
* @return list of items keyed by the provided character
|
||||
*/
|
||||
public SortedSet<IndexItem> getItems(DocTree.Kind kind) {
|
||||
Objects.requireNonNull(kind);
|
||||
return itemsByCategory.getOrDefault(IndexItem.Category.TAGS, Collections.emptySortedSet()).stream()
|
||||
.filter(i -> i.getDocTree().getKind() == kind)
|
||||
.collect(Collectors.toCollection(() -> new TreeSet<>(mainComparator)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes all the members (fields, methods, constructors, etc.) of the
|
||||
* provided type element.
|
||||
@ -146,26 +222,23 @@ public class IndexBuilder {
|
||||
*/
|
||||
private void indexMembers(TypeElement te) {
|
||||
VisibleMemberTable vmt = configuration.getVisibleMemberTable(te);
|
||||
indexElements(vmt.getVisibleMembers(FIELDS), te);
|
||||
indexElements(vmt.getVisibleMembers(ANNOTATION_TYPE_MEMBER_OPTIONAL), te);
|
||||
indexElements(vmt.getVisibleMembers(ANNOTATION_TYPE_MEMBER_REQUIRED), te);
|
||||
indexElements(vmt.getVisibleMembers(METHODS), te);
|
||||
indexElements(vmt.getVisibleMembers(CONSTRUCTORS), te);
|
||||
indexElements(vmt.getVisibleMembers(ENUM_CONSTANTS), te);
|
||||
indexMembers(te, vmt.getVisibleMembers(FIELDS));
|
||||
indexMembers(te, vmt.getVisibleMembers(ANNOTATION_TYPE_MEMBER_OPTIONAL));
|
||||
indexMembers(te, vmt.getVisibleMembers(ANNOTATION_TYPE_MEMBER_REQUIRED));
|
||||
indexMembers(te, vmt.getVisibleMembers(METHODS));
|
||||
indexMembers(te, vmt.getVisibleMembers(CONSTRUCTORS));
|
||||
indexMembers(te, vmt.getVisibleMembers(ENUM_CONSTANTS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes the provided elements.
|
||||
*
|
||||
* @param elements a collection of elements
|
||||
* @param members a collection of elements
|
||||
*/
|
||||
private void indexElements(Iterable<? extends Element> elements, TypeElement typeElement) {
|
||||
for (Element element : elements) {
|
||||
if (shouldIndex(element)) {
|
||||
String name = utils.getSimpleName(element);
|
||||
Character ch = keyCharacter(name);
|
||||
SortedSet<IndexItem> set = indexMap.computeIfAbsent(ch, c -> new TreeSet<>(comparator));
|
||||
set.add(new IndexItem(element, typeElement, utils));
|
||||
private void indexMembers(TypeElement typeElement, Iterable<? extends Element> members) {
|
||||
for (Element member : members) {
|
||||
if (shouldIndex(member)) {
|
||||
add(IndexItem.of(typeElement, member, utils));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -178,26 +251,17 @@ public class IndexBuilder {
|
||||
private void indexTypeElements(Iterable<TypeElement> elements) {
|
||||
for (TypeElement typeElement : elements) {
|
||||
if (shouldIndex(typeElement)) {
|
||||
String name = utils.getSimpleName(typeElement);
|
||||
Character ch = keyCharacter(name);
|
||||
SortedSet<IndexItem> set = indexMap.computeIfAbsent(ch, c -> new TreeSet<>(comparator));
|
||||
set.add(new IndexItem(typeElement, utils));
|
||||
add(IndexItem.of(typeElement, utils));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Character keyCharacter(String s) {
|
||||
return s.isEmpty() ? '*' : Character.toUpperCase(s.charAt(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes all the modules.
|
||||
*/
|
||||
private void indexModules() {
|
||||
for (ModuleElement m : configuration.modules) {
|
||||
Character ch = keyCharacter(m.getQualifiedName().toString());
|
||||
SortedSet<IndexItem> set = indexMap.computeIfAbsent(ch, c -> new TreeSet<>(comparator));
|
||||
set.add(new IndexItem(m, utils));
|
||||
add(IndexItem.of(m, utils));
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,9 +272,7 @@ public class IndexBuilder {
|
||||
*/
|
||||
private void indexPackage(PackageElement packageElement) {
|
||||
if (shouldIndex(packageElement)) {
|
||||
Character ch = keyCharacter(utils.getPackageName(packageElement));
|
||||
SortedSet<IndexItem> set = indexMap.computeIfAbsent(ch, c -> new TreeSet<>(comparator));
|
||||
set.add(new IndexItem(packageElement, utils));
|
||||
add(IndexItem.of(packageElement, utils));
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,48 +298,46 @@ public class IndexBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map representation of this index.
|
||||
*
|
||||
* @return map
|
||||
*/
|
||||
public Map<Character, SortedSet<IndexItem>> asMap() {
|
||||
return indexMap;
|
||||
private static Character keyCharacter(String s) {
|
||||
return s.isEmpty() ? '*' : Character.toUpperCase(s.charAt(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorted list of elements whose names start with the
|
||||
* provided character.
|
||||
*
|
||||
* @param key index key
|
||||
* @return list of elements keyed by the provided character
|
||||
*/
|
||||
public List<IndexItem> getMemberList(Character key) {
|
||||
SortedSet<IndexItem> set = indexMap.get(key);
|
||||
if (set == null) {
|
||||
return null;
|
||||
}
|
||||
return new ArrayList<>(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of index keys.
|
||||
*/
|
||||
public List<Character> keys() {
|
||||
return new ArrayList<>(indexMap.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add search tags for the key {@code key}.
|
||||
* Returns a comparator for the {@code IndexItem}s in the index page.
|
||||
* This is a composite comparator that must be able to compare all kinds of items:
|
||||
* for element items, tag items, and others.
|
||||
*
|
||||
* @param key the index key
|
||||
* @param searchTags the search tags
|
||||
* @return a comparator for index page items
|
||||
*/
|
||||
public void addSearchTags(char key, List<SearchIndexItem> searchTags) {
|
||||
searchTags.forEach(searchTag -> {
|
||||
SortedSet<IndexItem> set = indexMap.computeIfAbsent(key, c -> new TreeSet<>(comparator));
|
||||
set.add(new IndexItem(searchTag));
|
||||
});
|
||||
private Comparator<IndexItem> makeIndexComparator(boolean classesOnly) {
|
||||
Comparator<Element> elementComparator = classesOnly
|
||||
? utils.comparators.makeAllClassesComparator()
|
||||
: utils.comparators.makeIndexElementComparator();
|
||||
|
||||
Comparator<IndexItem> labelComparator =
|
||||
(ii1, ii2) -> utils.compareStrings(ii1.getLabel(), ii2.getLabel());
|
||||
Comparator<IndexItem> searchTagComparator =
|
||||
labelComparator
|
||||
.thenComparing(IndexItem::getHolder)
|
||||
.thenComparing(IndexItem::getDescription)
|
||||
.thenComparing(IndexItem::getUrl);
|
||||
|
||||
return (ii1, ii2) -> {
|
||||
// If both are element items, compare the elements
|
||||
if (ii1.isElementItem() && ii2.isElementItem()) {
|
||||
return elementComparator.compare(ii1.getElement(), ii2.getElement());
|
||||
}
|
||||
|
||||
// If one is an element item, compare labels; if equal, put element item last
|
||||
if (ii1.isElementItem() || ii2.isElementItem()) {
|
||||
int d = labelComparator.compare(ii1, ii2);
|
||||
return d != 0 ? d : ii1.isElementItem() ? 1 : -1;
|
||||
}
|
||||
|
||||
// Otherwise, compare labels and other fields of the items
|
||||
return searchTagComparator.compare(ii1, ii2);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,16 +25,56 @@
|
||||
|
||||
package jdk.javadoc.internal.doclets.toolkit.util;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem;
|
||||
|
||||
import java.util.Objects;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.ModuleElement;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.util.SimpleElementVisitor14;
|
||||
|
||||
import com.sun.source.doctree.DocTree;
|
||||
|
||||
/**
|
||||
* A holder for an indexed {@link Element} or {@link SearchIndexItem}.
|
||||
* An item to be included in the index pages and in interactive search.
|
||||
*
|
||||
* <p>
|
||||
* Items are primarily defined by their position in the documentation,
|
||||
* which is one of:
|
||||
*
|
||||
* <ul>
|
||||
* <li>An element (module, package, type or member)
|
||||
* <li>One of a small set of tags in the doc comment for an element:
|
||||
* {@code {@index ...}}, {@code {@systemProperty ...}}, etc
|
||||
* <li>One of a small set of outliers, corresponding to summary pages:
|
||||
* "All Classes", "All Packages", etc
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* All items have a "label", which is the presentation string used
|
||||
* to display the item in the list of matching choices. The
|
||||
* label is specified when the item is created. Items also
|
||||
* have a "url" and a "description", which are provided by
|
||||
* the specific doclet.
|
||||
*
|
||||
* <p>
|
||||
* Each item provides details to be included in the search index files
|
||||
* read and processed by JavaScript.
|
||||
* Items have a "category", which is normally derived from the element
|
||||
* kind or doc tree kind; it corresponds to the JavaScript file
|
||||
* in which this item will be written.
|
||||
*
|
||||
* <p>
|
||||
* Items for an element may have one or more of the following:
|
||||
* "containing module", "containing package", "containing type".
|
||||
*
|
||||
* <p>
|
||||
* Items for a node in a doc tree have a "holder", which is a
|
||||
* text form of the enclosing element or page.
|
||||
* They will typically also have a "description" derived from
|
||||
* content in the doc tree node.
|
||||
*
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
@ -43,71 +83,494 @@ import javax.lang.model.element.TypeElement;
|
||||
*/
|
||||
public class IndexItem {
|
||||
|
||||
/**
|
||||
* The "category" used to group items for the interactive search index.
|
||||
* Categories correspond directly to the JavaScript files that will be generated.
|
||||
*/
|
||||
public enum Category {
|
||||
MODULES,
|
||||
PACKAGES,
|
||||
TYPES,
|
||||
MEMBERS,
|
||||
TAGS
|
||||
}
|
||||
|
||||
/**
|
||||
* The presentation string for the item. It must be non-empty.
|
||||
*/
|
||||
private final String label;
|
||||
|
||||
/**
|
||||
* The element for the item. It is only null for items for summary pages that are not
|
||||
* associated with any specific element.
|
||||
*
|
||||
*/
|
||||
private final Element element;
|
||||
private final SearchIndexItem searchTag;
|
||||
private String label;
|
||||
private TypeElement typeElement;
|
||||
|
||||
public IndexItem(SearchIndexItem searchTag) {
|
||||
this.element = null;
|
||||
this.searchTag = searchTag;
|
||||
this.label = searchTag.getLabel();
|
||||
/**
|
||||
* The URL pointing to the element, doc tree or page being indexed.
|
||||
* It may be empty if the information can be determined from other fields.
|
||||
*/
|
||||
private String url = "";
|
||||
|
||||
/**
|
||||
* The containing module, if any, for the item.
|
||||
* It will be empty if the element is not in a package, and may be omitted if the
|
||||
* name of the package is unique.
|
||||
*/
|
||||
private String containingModule = "";
|
||||
|
||||
/**
|
||||
* The containing package, if any, for the item.
|
||||
*/
|
||||
private String containingPackage = "";
|
||||
|
||||
/**
|
||||
* The containing class, if any, for the item.
|
||||
*/
|
||||
private String containingClass = "";
|
||||
|
||||
/**
|
||||
* Creates an index item for a module element.
|
||||
*
|
||||
* @param moduleElement the element
|
||||
* @param utils the common utilities class
|
||||
*
|
||||
* @return the item
|
||||
*/
|
||||
public static IndexItem of(ModuleElement moduleElement, Utils utils) {
|
||||
return new IndexItem(moduleElement, utils.getFullyQualifiedName(moduleElement));
|
||||
}
|
||||
|
||||
private IndexItem(Element element) {
|
||||
this.element = element;
|
||||
this.searchTag = null;
|
||||
/**
|
||||
* Creates an index item for a package element.
|
||||
*
|
||||
* @param packageElement the element
|
||||
* @param utils the common utilities class
|
||||
*
|
||||
* @return the item
|
||||
*/
|
||||
public static IndexItem of(PackageElement packageElement, Utils utils) {
|
||||
return new IndexItem(packageElement, utils.getPackageName(packageElement));
|
||||
}
|
||||
|
||||
public IndexItem(TypeElement typeElement, Utils utils) {
|
||||
this(typeElement);
|
||||
this.label = utils.getSimpleName(typeElement);
|
||||
/**
|
||||
* Creates an index item for a type element.
|
||||
* Note: use {@code getElement()} to access this value, not {@code getTypeElement}.
|
||||
*
|
||||
* @param typeElement the element
|
||||
* @param utils the common utilities class
|
||||
*
|
||||
* @return the item
|
||||
*/
|
||||
public static IndexItem of(TypeElement typeElement, Utils utils) {
|
||||
return new IndexItem(typeElement, utils.getSimpleName(typeElement));
|
||||
}
|
||||
|
||||
public IndexItem(ModuleElement moduleElement, Utils utils) {
|
||||
this(moduleElement);
|
||||
this.label = utils.getFullyQualifiedName(moduleElement);
|
||||
}
|
||||
|
||||
public IndexItem(PackageElement packageElement, Utils utils) {
|
||||
this(packageElement);
|
||||
this.label = utils.getPackageName(packageElement);
|
||||
}
|
||||
|
||||
public IndexItem(Element member, TypeElement typeElement, Utils utils) {
|
||||
this(member);
|
||||
this.typeElement = typeElement;
|
||||
/**
|
||||
* Creates an index item for a member element.
|
||||
* Note: the given type element may not be the same as the enclosing element of the member
|
||||
* in cases where the enclosing element is not visible in the documentation.
|
||||
*
|
||||
* @param typeElement the element that contains the member
|
||||
* @param member the member
|
||||
* @param utils the common utilities class
|
||||
*
|
||||
* @return the item
|
||||
*
|
||||
* @see #getContainingTypeElement()
|
||||
*/
|
||||
public static IndexItem of(TypeElement typeElement, Element member, Utils utils) {
|
||||
String name = utils.getSimpleName(member);
|
||||
if (utils.isExecutableElement(member)) {
|
||||
ExecutableElement ee = (ExecutableElement)member;
|
||||
name += utils.flatSignature(ee, typeElement);
|
||||
}
|
||||
this.label = name;
|
||||
return new IndexItem(member, name) {
|
||||
@Override
|
||||
public TypeElement getContainingTypeElement() {
|
||||
return typeElement;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an index item for a node in the doc comment for an element.
|
||||
* The node should only be one that gives rise to an entry in the index.
|
||||
*
|
||||
* @param element the element
|
||||
* @param docTree the node in the doc comment
|
||||
* @param label the label
|
||||
* @param holder the holder for the comment
|
||||
* @param description the description of the item
|
||||
* @param link the root-relative link to the item in the generated docs
|
||||
*
|
||||
* @return the item
|
||||
*/
|
||||
public static IndexItem of(Element element, DocTree docTree, String label,
|
||||
String holder, String description, DocLink link) {
|
||||
Objects.requireNonNull(element);
|
||||
Objects.requireNonNull(holder);
|
||||
Objects.requireNonNull(description);
|
||||
Objects.requireNonNull(link);
|
||||
|
||||
switch (docTree.getKind()) {
|
||||
case INDEX, SYSTEM_PROPERTY -> { }
|
||||
default -> throw new IllegalArgumentException(docTree.getKind().toString());
|
||||
}
|
||||
|
||||
return new IndexItem(element, label, link.toString()) {
|
||||
@Override
|
||||
public DocTree getDocTree() {
|
||||
return docTree;
|
||||
}
|
||||
@Override
|
||||
public Category getCategory() {
|
||||
return getCategory(docTree);
|
||||
}
|
||||
@Override
|
||||
public String getHolder() {
|
||||
return holder;
|
||||
}
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an index item for a summary page, that is not associated with any element or
|
||||
* node in a doc comment.
|
||||
*
|
||||
* @param category the category for the item
|
||||
* @param label the label for the item
|
||||
* @param path the path for the page
|
||||
*
|
||||
* @return the item
|
||||
*/
|
||||
public static IndexItem of(Category category, String label, DocPath path) {
|
||||
Objects.requireNonNull(category);
|
||||
return new IndexItem(null, label, path.getPath()) {
|
||||
@Override
|
||||
public DocTree getDocTree() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Category getCategory() {
|
||||
return category;
|
||||
}
|
||||
@Override
|
||||
public String getHolder() {
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private IndexItem(Element element, String label) {
|
||||
if (label.isEmpty()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
this.element = element;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private IndexItem(Element element, String label, String url) {
|
||||
this(element, label);
|
||||
setUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label of the item.
|
||||
*
|
||||
* @return the label
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the label after the last dot, or the whole label if there are no dots.
|
||||
*
|
||||
* @return the simple name
|
||||
*/
|
||||
public String getSimpleName() {
|
||||
return label.substring(label.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label with a fully-qualified type name.
|
||||
* (Used to determine if labels are unique or need to be qualified.)
|
||||
*
|
||||
* @param utils the common utilities class
|
||||
*
|
||||
* @return the fully qualified name
|
||||
*/
|
||||
public String getFullyQualifiedLabel(Utils utils) {
|
||||
TypeElement typeElement = getContainingTypeElement();
|
||||
if (typeElement != null) {
|
||||
return utils.getFullyQualifiedName(typeElement) + "." + label;
|
||||
} else if (element != null) {
|
||||
} else if (isElementItem()) {
|
||||
return utils.getFullyQualifiedName(element);
|
||||
} else {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element associate with this item, or {@code null}.
|
||||
*
|
||||
* @return the element
|
||||
*/
|
||||
public Element getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public SearchIndexItem getSearchTag() {
|
||||
return searchTag;
|
||||
/**
|
||||
* Returns the category for this item, that indicates the JavaScript file
|
||||
* in which this item should be written.
|
||||
*
|
||||
* @return the category
|
||||
*/
|
||||
public Category getCategory() {
|
||||
return getCategory(element);
|
||||
}
|
||||
|
||||
public TypeElement getTypeElement() {
|
||||
return typeElement;
|
||||
protected Category getCategory(DocTree docTree) {
|
||||
return switch (docTree.getKind()) {
|
||||
case INDEX, SYSTEM_PROPERTY -> Category.TAGS;
|
||||
default -> throw new IllegalArgumentException(docTree.getKind().toString());
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
protected Category getCategory(Element element) {
|
||||
return new SimpleElementVisitor14<Category, Void>() {
|
||||
@Override
|
||||
public Category visitModule(ModuleElement t, Void v) {
|
||||
return Category.MODULES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category visitPackage(PackageElement e, Void v) {
|
||||
return Category.PACKAGES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category visitType(TypeElement e, Void v) {
|
||||
return Category.TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category visitVariable(VariableElement e, Void v) {
|
||||
return Category.MEMBERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category visitExecutable(ExecutableElement e, Void v) {
|
||||
return Category.MEMBERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category defaultAction(Element e, Void v) {
|
||||
throw new IllegalArgumentException(e.toString());
|
||||
}
|
||||
}.visit(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type element that is documented as containing a member element,
|
||||
* or {@code null} if this item does not represent a member element.
|
||||
*
|
||||
* @return the type element
|
||||
*/
|
||||
public TypeElement getContainingTypeElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the documentation tree node for this item, of {@code null} if this item
|
||||
* does not represent a documentation tree node.
|
||||
*
|
||||
* @return the documentation tree node
|
||||
*/
|
||||
public DocTree getDocTree() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this index is for an element.
|
||||
*
|
||||
* @return {@code true} if this index is for an element
|
||||
*/
|
||||
public boolean isElementItem() {
|
||||
return element != null && getDocTree() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this index is for a tag in a doc comment.
|
||||
*
|
||||
* @return {@code true} if this index is for a tag in a doc comment
|
||||
*/
|
||||
public boolean isTagItem() {
|
||||
return getDocTree() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL for the item, when it cannot otherwise be inferred from other fields.
|
||||
*
|
||||
* @param u the url
|
||||
*
|
||||
* @return this item
|
||||
*/
|
||||
public IndexItem setUrl(String u) {
|
||||
url = Objects.requireNonNull(u);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL for this item, or an empty string if no value has been set.
|
||||
*
|
||||
* @return the URL for this item, or an empty string if no value has been set
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the containing module for this item.
|
||||
*
|
||||
* @param m the module
|
||||
*
|
||||
* @return this item
|
||||
*/
|
||||
public IndexItem setContainingModule(String m) {
|
||||
containingModule = Objects.requireNonNull(m);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the containing package for this item.
|
||||
*
|
||||
* @param p the package
|
||||
*
|
||||
* @return this item
|
||||
*/
|
||||
public IndexItem setContainingPackage(String p) {
|
||||
containingPackage = Objects.requireNonNull(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the containing class for this item.
|
||||
*
|
||||
* @param c the class
|
||||
*
|
||||
* @return this item
|
||||
*/
|
||||
public IndexItem setContainingClass(String c) {
|
||||
containingClass = Objects.requireNonNull(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description of the element owning the documentation comment for this item,
|
||||
* or {@code null} if this is not a item for a tag for an item in a documentation tag.
|
||||
*
|
||||
* @return the description of the element that owns this item
|
||||
*/
|
||||
public String getHolder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description of the tag for this item or {@code null} if this is not a item
|
||||
* for a tag for an item in a documentation tag.
|
||||
*
|
||||
* @return the description of the tag
|
||||
*/
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing this item in JSON notation.
|
||||
*
|
||||
* @return a string representing this item in JSON notation
|
||||
*/
|
||||
public String toJSON() {
|
||||
// TODO: Additional processing is required, see JDK-8238495
|
||||
StringBuilder item = new StringBuilder();
|
||||
Category category = getCategory();
|
||||
switch (category) {
|
||||
case MODULES:
|
||||
item.append("{")
|
||||
.append("\"l\":\"").append(label).append("\"")
|
||||
.append("}");
|
||||
break;
|
||||
|
||||
case PACKAGES:
|
||||
item.append("{");
|
||||
if (!containingModule.isEmpty()) {
|
||||
item.append("\"m\":\"").append(containingModule).append("\",");
|
||||
}
|
||||
item.append("\"l\":\"").append(label).append("\"");
|
||||
if (!url.isEmpty()) {
|
||||
item.append(",\"u\":\"").append(url).append("\"");
|
||||
}
|
||||
item.append("}");
|
||||
break;
|
||||
|
||||
case TYPES:
|
||||
item.append("{");
|
||||
if (!containingPackage.isEmpty()) {
|
||||
item.append("\"p\":\"").append(containingPackage).append("\",");
|
||||
}
|
||||
if (!containingModule.isEmpty()) {
|
||||
item.append("\"m\":\"").append(containingModule).append("\",");
|
||||
}
|
||||
item.append("\"l\":\"").append(label).append("\"");
|
||||
if (!url.isEmpty()) {
|
||||
item.append(",\"u\":\"").append(url).append("\"");
|
||||
}
|
||||
item.append("}");
|
||||
break;
|
||||
|
||||
case MEMBERS:
|
||||
item.append("{");
|
||||
if (!containingModule.isEmpty()) {
|
||||
item.append("\"m\":\"").append(containingModule).append("\",");
|
||||
}
|
||||
item.append("\"p\":\"").append(containingPackage).append("\",")
|
||||
.append("\"c\":\"").append(containingClass).append("\",")
|
||||
.append("\"l\":\"").append(label).append("\"");
|
||||
if (!url.isEmpty()) {
|
||||
item.append(",\"u\":\"").append(url).append("\"");
|
||||
}
|
||||
item.append("}");
|
||||
break;
|
||||
|
||||
case TAGS:
|
||||
String holder = getHolder();
|
||||
String description = getDescription();
|
||||
item.append("{")
|
||||
.append("\"l\":\"").append(label).append("\",")
|
||||
.append("\"h\":\"").append(holder).append("\",");
|
||||
if (!description.isEmpty()) {
|
||||
item.append("\"d\":\"").append(description).append("\",");
|
||||
}
|
||||
item.append("\"u\":\"").append(url).append("\"")
|
||||
.append("}");
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new AssertionError("Unexpected category: " + category);
|
||||
}
|
||||
return item.toString();
|
||||
}
|
||||
}
|
||||
|
@ -282,8 +282,7 @@ public class Utils {
|
||||
}
|
||||
|
||||
/**
|
||||
* According to
|
||||
* <cite>The Java Language Specification</cite>,
|
||||
* According to <cite>The Java Language Specification</cite>,
|
||||
* all the outer classes and static inner classes are core classes.
|
||||
*/
|
||||
public boolean isCoreClass(TypeElement e) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user