com.redhat.ceylon.ceylondoc.LinkRenderer Maven / Gradle / Ivy
/*
* Copyright Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the authors tag. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*
* This particular file is subject to the "Classpath" exception as provided in the
* LICENSE file that accompanied this code.
*
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License,
* along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.redhat.ceylon.ceylondoc;
import static com.redhat.ceylon.ceylondoc.CeylondMessages.msg;
import static com.redhat.ceylon.ceylondoc.Util.getAnnotation;
import static com.redhat.ceylon.ceylondoc.Util.isAbbreviatedType;
import static com.redhat.ceylon.ceylondoc.Util.normalizeSpaces;
import static com.redhat.ceylon.model.typechecker.util.TypePrinter.abbreviateCallable;
import static com.redhat.ceylon.model.typechecker.util.TypePrinter.abbreviateEntry;
import static com.redhat.ceylon.model.typechecker.util.TypePrinter.abbreviateIterable;
import static com.redhat.ceylon.model.typechecker.util.TypePrinter.abbreviateOptional;
import static com.redhat.ceylon.model.typechecker.util.TypePrinter.abbreviateSequence;
import static com.redhat.ceylon.model.typechecker.util.TypePrinter.abbreviateSequential;
import static com.redhat.ceylon.model.typechecker.util.TypePrinter.abbreviateTuple;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.redhat.ceylon.common.Constants;
import com.redhat.ceylon.common.config.DefaultToolOptions;
import com.redhat.ceylon.compiler.java.codegen.Decl;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.model.loader.AbstractModelLoader;
import com.redhat.ceylon.model.typechecker.model.Annotated;
import com.redhat.ceylon.model.typechecker.model.Annotation;
import com.redhat.ceylon.model.typechecker.model.Class;
import com.redhat.ceylon.model.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Element;
import com.redhat.ceylon.model.typechecker.model.Function;
import com.redhat.ceylon.model.typechecker.model.FunctionOrValue;
import com.redhat.ceylon.model.typechecker.model.Interface;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.NothingType;
import com.redhat.ceylon.model.typechecker.model.Package;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.Referenceable;
import com.redhat.ceylon.model.typechecker.model.Scope;
import com.redhat.ceylon.model.typechecker.model.TypeAlias;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.TypeParameter;
import com.redhat.ceylon.model.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.model.typechecker.model.Unit;
import com.redhat.ceylon.model.typechecker.model.Value;
import com.redhat.ceylon.model.typechecker.util.TypePrinter;
public class LinkRenderer {
private Object to;
private Object from;
private CeylonDocTool ceylonDocTool;
private Writer writer;
private String customText;
private boolean withinText;
private Referenceable scope;
private String anchor;
private boolean printAbbreviated = true;
private boolean printTypeParameters = true;
private boolean printTypeParameterDetail = false;
private boolean printWikiStyleLinks = false;
private boolean printLinkDropdownMenu = true;
private boolean printParenthesisAfterMethodName = true;
private boolean printMemberContainerName = true;
private final TypePrinter producedTypeNamePrinter = new TypePrinter() {
@Override
public String getSimpleDeclarationName(Declaration declaration, Unit unit) {
String result = null;
if (declaration instanceof ClassOrInterface || declaration instanceof NothingType) {
TypeDeclaration type = (TypeDeclaration) declaration;
if (isLinkable(type)) {
String typeUrl = getUrl(type, null);
if (typeUrl != null) {
result = buildLinkElement(typeUrl, getLinkText(type), "Go to " + type.getQualifiedNameString());
}
}
if( result == null ) {
result = buildSpanElementWithNameAndTooltip(declaration);
}
} else if (declaration instanceof TypeParameter) {
result = "" + declaration.getName(unit) + "";
} else if (declaration instanceof TypedDeclaration) {
result = processTypedDeclaration((TypedDeclaration) declaration);
} else if (declaration instanceof TypeAlias) {
result = processTypeAlias((TypeAlias) declaration);
} else {
result = buildSpanElementWithNameAndTooltip(declaration);
}
return encodeResult(result);
}
@Override
public boolean printAbbreviated() {
return printAbbreviated;
}
@Override
public boolean printTypeParameters() {
return printTypeParameters;
}
@Override
public boolean printTypeParameterDetail() {
return printTypeParameterDetail;
}
@Override
public boolean printQualifyingType() {
return false;
}
};
public LinkRenderer(CeylonDocTool ceylonDocTool, Writer writer, Object from) {
this.ceylonDocTool = ceylonDocTool;
this.writer = writer;
this.from = from;
}
public LinkRenderer(LinkRenderer linkRenderer) {
this.to = linkRenderer.to;
this.from = linkRenderer.from;
this.ceylonDocTool = linkRenderer.ceylonDocTool;
this.writer = linkRenderer.writer;
this.customText = linkRenderer.customText;
this.scope = linkRenderer.scope;
this.anchor = linkRenderer.anchor;
this.printAbbreviated = linkRenderer.printAbbreviated;
this.printTypeParameters = linkRenderer.printTypeParameters;
this.printTypeParameterDetail = linkRenderer.printTypeParameterDetail;
this.printLinkDropdownMenu = linkRenderer.printLinkDropdownMenu;
}
public LinkRenderer to(Object to) {
this.to = to;
return this;
}
public LinkRenderer useCustomText(String customText) {
this.customText = customText;
return this;
}
public LinkRenderer withinText(boolean text) {
withinText = text;
return this;
}
public LinkRenderer useScope(Referenceable scope) {
this.scope = scope;
return this;
}
public LinkRenderer useAnchor(String anchor) {
this.anchor = anchor;
return this;
}
public LinkRenderer printAbbreviated(boolean printAbbreviated) {
this.printAbbreviated = printAbbreviated;
return this;
}
public LinkRenderer printTypeParameters(boolean printTypeParameters) {
this.printTypeParameters = printTypeParameters;
return this;
}
public LinkRenderer printTypeParameterDetail(boolean printTypeParameterDetail) {
this.printTypeParameterDetail = printTypeParameterDetail;
return this;
}
public LinkRenderer printWikiStyleLinks(boolean printWikiStyleLinks) {
this.printWikiStyleLinks = printWikiStyleLinks;
return this;
}
public LinkRenderer printLinkDropdownMenu(boolean printLinkDropdownMenu) {
this.printLinkDropdownMenu = printLinkDropdownMenu;
return this;
}
public LinkRenderer printParenthesisAfterMethodName(boolean printParenthesisAfterMethodName) {
this.printParenthesisAfterMethodName = printParenthesisAfterMethodName;
return this;
}
public LinkRenderer printMemberContainerName(boolean printMemberContainerName) {
this.printMemberContainerName = printMemberContainerName;
return this;
}
public String getLink() {
String link = null;
if (to instanceof String) {
if (printWikiStyleLinks) {
link = processWikiLink((String) to);
} else {
link = processAnnotationParam((String) to);
}
} else if (to instanceof Type) {
link = processProducedType((Type) to);
} else if (to instanceof Declaration) {
link = processDeclaration(((Declaration) to));
} else if (to instanceof Module) {
link = processModule((Module) to);
} else if (to instanceof Package) {
link = processPackage((Package) to);
}
return link;
}
public String getUrl() {
return getUrl(to, anchor);
}
public String getResourceUrl(String to) throws IOException {
return ceylonDocTool.getResourceUrl(from, to);
}
public String getSrcUrl(Object to) throws IOException {
return ceylonDocTool.getSrcUrl(from, to);
}
public void write() throws IOException {
writer.write(getLink());
}
private String processModule(Module module) {
String moduleUrl = getUrl(module, anchor);
if (moduleUrl != null) {
return buildLinkElement(moduleUrl, module.getNameAsString(), "Go to module");
} else {
return module.getNameAsString();
}
}
private String processPackage(Package pkg) {
String pkgUrl = getUrl(pkg, anchor);
if (pkgUrl != null) {
return buildLinkElement(pkgUrl, customText != null ? customText : pkg.getNameAsString(), "Go to package " + pkg.getNameAsString());
} else {
return pkg.getNameAsString();
}
}
private String processDeclaration(Declaration decl) {
if (decl instanceof TypeDeclaration) {
return processProducedType(((TypeDeclaration) decl).getType());
} else {
return processTypedDeclaration((TypedDeclaration) decl);
}
}
private String processProducedType(Type producedType) {
String result;
boolean wasWithinText = withinText;
withinText = false;
try {
result = producedTypeNamePrinter.print(producedType, null);
}
finally {
withinText = wasWithinText;
}
result = decodeResult(result);
if (withinText && customText==null) {
result = "" + result + "
";
}
result = decorateWithLinkDropdownMenu(result, producedType);
return result;
}
private String processTypedDeclaration(TypedDeclaration decl) {
String declName = Util.getDeclarationName(decl);
Scope declContainer = decl.getContainer();
if( isLinkable(decl) ) {
String url = getUrl(declContainer, declName);
if( url != null ) {
return buildLinkElement(url, getLinkText(decl), "Go to " + decl.getQualifiedNameString());
}
}
String result = declName;
if (withinText) {
result = "" + result + "
";
}
if (customText != null) {
result = customText;
}
return result;
}
private String processTypeAlias(TypeAlias alias) {
String aliasName = alias.getName();
Scope aliasContainer = alias.getContainer();
if (isLinkable(alias)) {
String url = getUrl(aliasContainer, aliasName);
if (url != null) {
return buildLinkElement(url, aliasName, "Go to " + alias.getQualifiedNameString());
}
}
return buildSpanElementWithNameAndTooltip(alias);
}
private String processWikiLink(final String docLinkText) {
Tree.DocLink docLink = findDocLink(docLinkText, scope);
if (docLink == null && scope instanceof Declaration) {
Declaration refinedDeclaration = ((Declaration) scope).getRefinedDeclaration();
if (refinedDeclaration != scope) {
docLink = findDocLink(docLinkText, refinedDeclaration);
}
}
if (docLink != null) {
if (docLink.getQualified() != null && docLink.getQualified().size() > 0) {
return processDeclaration(docLink.getQualified().get(docLink.getQualified().size() - 1));
} else if (docLink.getBase() != null) {
printAbbreviated = !isAbbreviatedType(docLink.getBase());
return processDeclaration(docLink.getBase());
} else if (docLink.getModule() != null) {
return processModule(docLink.getModule());
} else if (docLink.getPkg() != null) {
return processPackage(docLink.getPkg());
}
}
if (docLink != null && scope instanceof Annotated) {
Annotation docAnnotation = getAnnotation(scope.getUnit(), ((Annotated) scope).getAnnotations(), "doc");
if (docAnnotation != null) {
ceylonDocTool.warningBrokenLink(docLinkText, docLink, scope);
}
}
return getUnresolvableLink(docLinkText);
}
private String processAnnotationParam(String text) {
if( text.equals("module")) {
Module mod = getCurrentModule();
if( mod != null) {
return processModule(mod);
}
}
if (text.startsWith("module ")) {
String modName = text.substring(7);
for (Module m : ceylonDocTool.getTypeChecker().getContext().getModules().getListOfModules()) {
if (m.getNameAsString().equals(modName)) {
return processModule(m);
}
}
}
if( text.equals("package")) {
Package pkg = getCurrentPackage();
if (pkg != null) {
return processPackage(pkg);
}
}
if (text.startsWith("package ")) {
String pkgName = text.substring(8);
for (Module m : ceylonDocTool.getTypeChecker().getContext().getModules().getListOfModules()) {
if (pkgName.startsWith(m.getNameAsString() + ".")) {
Package pkg = m.getPackage(pkgName);
if (pkg != null) {
return processPackage(pkg);
}
}
}
}
if( text.equals("interface") ) {
Interface interf = getCurrentInterface();
if( interf != null ) {
return processProducedType(interf.getType());
}
}
if( text.equals("class") ) {
Class clazz = getCurrentClass();
if( clazz != null ) {
return processProducedType(clazz.getType());
}
}
String declName;
Scope currentScope;
int pkgSeparatorIndex = text.indexOf("::");
if( pkgSeparatorIndex == -1 ) {
declName = text;
currentScope = resolveScope(scope);
} else {
String pkgName = text.substring(0, pkgSeparatorIndex);
declName = text.substring(pkgSeparatorIndex+2, text.length());
currentScope = ceylonDocTool.getCurrentModule().getPackage(pkgName);
}
String[] declNames = declName.split("\\.");
Declaration currentDecl = null;
boolean isNested = false;
for (String currentDeclName : declNames) {
currentDecl = resolveDeclaration(currentScope, currentDeclName, isNested);
if (currentDecl != null) {
if( isValueWithTypeObject(currentDecl) ) {
TypeDeclaration objectType = ((Value)currentDecl).getTypeDeclaration();
currentScope = objectType;
currentDecl = objectType;
} else {
currentScope = resolveScope(currentDecl);
}
isNested = true;
} else {
break;
}
}
// we can't link to parameters yet, unless they're toplevel
if (currentDecl != null && !isParameter(currentDecl)) {
if (currentDecl instanceof TypeDeclaration) {
return processProducedType(((TypeDeclaration) currentDecl).getType());
} else {
return processTypedDeclaration((TypedDeclaration) currentDecl);
}
} else {
return getUnresolvableLink(text);
}
}
private boolean isLinkable(Declaration decl) {
if( decl == null ) {
return false;
}
if( decl.isParameter() ) {
return true;
}
if( !ceylonDocTool.isIncludeNonShared() ) {
if( !decl.isShared() ) {
return false;
}
Scope c = decl.getContainer();
while(c != null) {
boolean isShared = true;
if( c instanceof Declaration ) {
isShared = ((Declaration) c).isShared();
}
if( c instanceof Package ) {
isShared = ((Package) c).isShared();
}
if( !isShared ) {
return false;
}
c = c.getContainer();
}
}
return true;
}
private boolean isValueWithTypeObject(Declaration decl) {
if (Decl.isValue(decl)) {
TypeDeclaration typeDeclaration = ((Value) decl).getTypeDeclaration();
if (typeDeclaration instanceof Class && typeDeclaration.isAnonymous()) {
return true;
}
}
return false;
}
private boolean isParameter(Declaration decl) {
return decl instanceof FunctionOrValue
&& ((FunctionOrValue)decl).isParameter();
}
private Declaration resolveDeclaration(Scope scope, String declName, boolean isNested) {
Declaration decl = null;
if (scope != null) {
decl = scope.getMember(declName, null, false);
if (decl == null && !isNested && scope instanceof Element) {
decl = scope.getUnit().getImportedDeclaration(declName, null, false);
}
if (decl == null && !isNested && !scope.getQualifiedNameString().equals(AbstractModelLoader.CEYLON_LANGUAGE) ) {
decl = resolveDeclaration(scope.getContainer(), declName, isNested);
}
if (decl == null && declName.equals("Nothing") && scope.getQualifiedNameString().equals(AbstractModelLoader.CEYLON_LANGUAGE)) {
decl = new NothingType(scope.getUnit());
}
} else {
Package pkg = ceylonDocTool.getCurrentModule().getPackage(AbstractModelLoader.CEYLON_LANGUAGE);
if (pkg != null) {
decl = resolveDeclaration(pkg, declName, isNested);
}
}
return decl;
}
private Scope resolveScope(Referenceable referenceable) {
if (referenceable instanceof Module) {
return ((Module) referenceable).getPackage(referenceable.getNameAsString());
} else if (referenceable instanceof Scope) {
return (Scope) referenceable;
} else if (referenceable instanceof Declaration) {
return ((Declaration) referenceable).getContainer();
} else {
return null;
}
}
private boolean isInCurrentModule(Object obj) {
Module objModule = null;
if (obj instanceof Module) {
objModule = (Module) obj;
} else if (obj instanceof Scope) {
objModule = getPackage((Scope) obj).getModule();
} else if (obj instanceof Element) {
objModule = getPackage(((Element) obj).getScope()).getModule();
}
Module currentModule = ceylonDocTool.getCurrentModule();
if (currentModule != null && objModule != null) {
return currentModule.equals(objModule);
}
return false;
}
private String getUnresolvableLink(final String docLinkText) {
StringBuilder unresolvable = new StringBuilder();
unresolvable.append("");
boolean hasCustomText =
customText != null && !customText.equals(docLinkText);
if (hasCustomText) {
unresolvable.append(customText);
unresolvable.append(" (");
}
if (withinText) unresolvable.append("");
int index = docLinkText.indexOf('|')+1;
unresolvable.append(docLinkText.substring(index));
if (withinText) unresolvable.append("
");
if (hasCustomText) {
unresolvable.append(")");
}
unresolvable.append("");
return unresolvable.toString();
}
private String getLinkText(Declaration decl) {
if (customText != null) {
return customText;
}
else {
String name = Util.getDeclarationName(decl);
if( scope != null && scope.getUnit() != null ) {
name = scope.getUnit().getAliasedName(decl, name);
}
String result;
if (decl instanceof TypeDeclaration) {
result = "" + name + "";
}
else {
if (decl instanceof Function && printParenthesisAfterMethodName) {
name = name + "()";
}
result = "" + name + "";
}
if (printMemberContainerName && decl.isMember() && decl.getContainer() != from) {
result = getLinkText((Declaration) decl.getContainer()) + '.' + result;
}
return result;
}
}
private Package getPackage(Scope scope) {
while (!(scope instanceof Package)) {
scope = scope.getContainer();
}
return (Package) scope;
}
private String getUrl(Object to, String anchor) {
String url;
List methods = new ArrayList();
while(to instanceof Function){
Function method = (Function) to;
methods.add(method);
to = method.getContainer();
}
if (isInCurrentModule(to)) {
url = getLocalUrl(to);
} else {
url = getExternalUrl(to);
}
if (url != null && anchor != null) {
String sectionPackageAnchor = "#section-package";
if (url.endsWith(sectionPackageAnchor)) {
url = url.substring(0, url.length() - sectionPackageAnchor.length());
}
StringBuilder fragment = new StringBuilder();
if(!methods.isEmpty()) {
Collections.reverse(methods);
for(Function method : methods) {
fragment.append(method.getName());
fragment.append("-");
}
}
fragment.append(anchor);
url = url + "#" + fragment;
}
return url;
}
private String getLocalUrl(Object to) {
try {
return ceylonDocTool.getObjectUrl(from, to);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private String getExternalUrl(Object to) {
String url = null;
if (to instanceof Module) {
url = getExternalModuleUrl((Module)to);
if (url != null) {
url += "index.html";
}
} else if (to instanceof Package) {
Package pkg = (Package)to;
url = getExternalModuleUrl(pkg.getModule());
if (url != null) {
url += buildPackageUrlPath(pkg);
url += "index.html";
}
} else if (to instanceof ClassOrInterface) {
ClassOrInterface klass = (ClassOrInterface) to;
Package pkg = getPackage(klass);
url = getExternalModuleUrl(pkg.getModule());
if (url != null) {
url += buildPackageUrlPath(pkg);
url += ceylonDocTool.getFileName(klass);
}
}
return url;
}
private String getExternalModuleUrl(Module module) {
if( ceylonDocTool.getLinks() != null ) {
String moduleName = module.getNameAsString();
for (String link : ceylonDocTool.getLinks()) {
String[] linkParts = divideToPatternAndUrl(link);
String moduleNamePattern = linkParts[0];
String moduleRepoUrl = linkParts[1];
if (moduleNamePattern == null) {
String moduleDocUrl = buildModuleUrl(moduleRepoUrl, module);
if (isHttpProtocol(moduleDocUrl) && checkHttpUrlExist(moduleDocUrl)) {
return moduleDocUrl;
}
if (isFileProtocol(moduleDocUrl) && checkFileUrlExist(moduleDocUrl)) {
return moduleDocUrl;
}
} else if (moduleName.startsWith(moduleNamePattern)) {
return buildModuleUrl(moduleRepoUrl, module);
}
}
}
return null;
}
private String buildLinkElement(String url, String text, String toolTip) {
StringBuilder linkBuilder = new StringBuilder();
linkBuilder.append("");
if (customText==null && withinText) {
linkBuilder.append("");
}
linkBuilder.append(text);
if (customText==null && withinText) {
linkBuilder.append("
");
}
linkBuilder.append("");
return linkBuilder.toString();
}
private String buildSpanElementWithNameAndTooltip(Declaration d) {
StringBuilder spanBuilder = new StringBuilder();
spanBuilder.append("");
if (withinText) spanBuilder.append("");
spanBuilder.append(getLinkText(d));
if (withinText) spanBuilder.append("
");
spanBuilder.append("");
return spanBuilder.toString();
}
private String buildModuleUrl(String moduleRepoUrl, Module module) {
StringBuilder moduleUrlBuilder = new StringBuilder();
moduleUrlBuilder.append(moduleRepoUrl);
if (!moduleRepoUrl.endsWith("/")) {
moduleUrlBuilder.append("/");
}
moduleUrlBuilder.append(Util.join("/", module.getName()));
moduleUrlBuilder.append("/");
moduleUrlBuilder.append(module.getVersion());
moduleUrlBuilder.append("/module-doc/api/");
return moduleUrlBuilder.toString();
}
private String buildPackageUrlPath(Package pkg) {
List packagePath = pkg.getName().subList(pkg.getModule().getName().size(), pkg.getName().size());
if (!packagePath.isEmpty()) {
return Util.join("/", packagePath) + "/";
}
return "";
}
public static String[] divideToPatternAndUrl(String link) {
String moduleRepoUrl = null;
String moduleNamePattern = null;
int indexOfSeparator = link.indexOf("=");
if (indexOfSeparator != -1) {
moduleNamePattern = link.substring(0, indexOfSeparator);
moduleRepoUrl = link.substring(indexOfSeparator + 1);
} else {
moduleRepoUrl = link;
}
return new String[] { moduleNamePattern, moduleRepoUrl };
}
public static boolean isHttpProtocol(String url) {
return url.startsWith("http://") || url.startsWith("https://");
}
public static boolean isFileProtocol(String url) {
return url.startsWith("file://");
}
private boolean checkHttpUrlExist(String moduleUrl) {
Boolean result = ceylonDocTool.getModuleUrlAvailabilityCache().get(moduleUrl);
if( result == null ) {
try {
URL url = new URL(moduleUrl + "index.html");
HttpURLConnection con;
Proxy proxy = DefaultToolOptions.getDefaultProxy();
if (proxy != null) {
con = (HttpURLConnection) url.openConnection(proxy);
} else {
con = (HttpURLConnection) url.openConnection();
}
con.setConnectTimeout((int) DefaultToolOptions.getDefaultTimeout());
con.setReadTimeout((int) DefaultToolOptions.getDefaultTimeout() * Constants.READ_TIMEOUT_MULTIPLIER);
con.setRequestMethod("HEAD");
int responseCode = con.getResponseCode();
if( responseCode == HttpURLConnection.HTTP_OK ) {
result = Boolean.TRUE;
} else {
ceylonDocTool.getLogger().warning(msg("info.urlDoesNotExist", moduleUrl));
result = Boolean.FALSE;
}
}
catch (IOException e) {
ceylonDocTool.getLogger().warning(msg("info.urlDoesNotExist", moduleUrl));
result = Boolean.FALSE;
}
ceylonDocTool.getModuleUrlAvailabilityCache().put(moduleUrl, result);
}
return result.booleanValue();
}
private boolean checkFileUrlExist(String moduleUrl) {
Boolean result = ceylonDocTool.getModuleUrlAvailabilityCache().get(moduleUrl);
if( result == null ) {
File moduleDocDir = new File(moduleUrl.substring("file://".length()));
if (moduleDocDir.isDirectory() && moduleDocDir.exists()) {
result = Boolean.TRUE;
} else {
ceylonDocTool.getLogger().warning(msg("info.urlDoesNotExist", moduleUrl));
result = Boolean.FALSE;
}
ceylonDocTool.getModuleUrlAvailabilityCache().put(moduleUrl, result);
}
return result.booleanValue();
}
private static String encodeResult(String text) {
if (text != null) {
text = text.replaceAll("<", "#LT;");
text = text.replaceAll(">", "#GT;");
}
return text;
}
private static String decodeResult(String text) {
if (text != null) {
text = text.replaceAll("&", "&");
text = text.replaceAll("<", "<");
text = text.replaceAll(">", ">");
text = text.replaceAll("#LT;", "<");
text = text.replaceAll("#GT;", ">");
text = text.replaceAll("<in ", "<in ");
text = text.replaceAll(",in ", ",in ");
text = text.replaceAll("<out ", "<out ");
text = text.replaceAll(",out ", ",out ");
}
return text;
}
private String decorateWithLinkDropdownMenu(String link, Type producedType) {
if( !printLinkDropdownMenu || !printAbbreviated || !canLinkToCeylonLanguageModule() ) {
return link;
}
List producedTypes = new ArrayList();
decompose(producedType, producedTypes);
boolean containsOptional = false;
boolean containsSequential = false;
boolean containsSequence = false;
boolean containsIterable = false;
boolean containsEntry = false;
boolean containsCallable = false;
boolean containsTuple = false;
for (Type pt : producedTypes) {
if (abbreviateOptional(pt)) {
containsOptional = true;
} else if (abbreviateSequential(pt) && !link.contains("'Go to ceylon.language::Sequential'")) {
containsSequential = true;
} else if (abbreviateSequence(pt) && !link.contains("'Go to ceylon.language::Sequence'")) {
containsSequence = true;
} else if (abbreviateIterable(pt) && !link.contains("'Go to ceylon.language::Iterable'")) {
containsIterable = true;
} else if (abbreviateEntry(pt) && !link.contains("'Go to ceylon.language::Entry'")) {
containsEntry = true;
} else if (abbreviateCallable(pt) && !link.contains("'Go to ceylon.language::Callable'")) {
containsCallable = true;
} else if (abbreviateTuple(pt) && !link.contains("'Go to ceylon.language::Tuple'")) {
containsTuple = true;
}
}
Unit unit = producedType.getDeclaration().getUnit();
if( containsOptional || containsSequential || containsSequence || containsIterable || containsEntry || containsCallable || containsTuple ) {
StringBuilder sb = new StringBuilder();
sb.append("");
sb.append(link.replaceAll("class='link'", "class='link type-identifier'"));
sb.append("");
sb.append("");
sb.append(" "); // dropdown-menu
sb.append(""); // dropdown
sb.append(""); // link-dropdown
return sb.toString();
}
return link;
}
private boolean canLinkToCeylonLanguageModule() {
Module currentModule = ceylonDocTool.getCurrentModule();
if (currentModule.isLanguageModule()) {
return true;
} else {
Module languageModule = currentModule.getLanguageModule();
String languageModuleUrl = getExternalModuleUrl(languageModule);
return languageModuleUrl != null;
}
}
private void decompose(Type pt, List producedTypes) {
if (!producedTypes.contains(pt)) {
producedTypes.add(pt);
if (pt.isIntersection()) {
for (Type satisfiedType : pt.getSatisfiedTypes()) {
decompose(satisfiedType, producedTypes);
}
}
else if (pt.isUnion()) {
for (Type caseType : pt.getCaseTypes()) {
decompose(caseType, producedTypes);
}
}
if (!pt.getTypeArgumentList().isEmpty()) {
for (Type typeArgument : pt.getTypeArgumentList()) {
decompose(typeArgument, producedTypes);
}
}
}
}
private String getLinkMenuItem(Declaration decl, String description) {
String url = new LinkRenderer(this).
to(decl).
useCustomText("").
printLinkDropdownMenu(false).
printAbbreviated(false).
printTypeParameters(false).
getUrl();
StringBuilder sb = new StringBuilder();
sb.append("");
sb.append("");
sb.append("Go to ").append(decl.getName()).append(" ");
sb.append("").append(description).append("");
sb.append("");
sb.append(" ");
return sb.toString();
}
private Tree.DocLink findDocLink(final String docLinkText, Referenceable referenceable) {
final Tree.DocLink[] docLinks = new Tree.DocLink[1];
Node scopeNode = ceylonDocTool.getNode(referenceable);
if (scopeNode != null) {
scopeNode.visit(new Visitor() {
@Override
public void visit(Tree.DocLink docLink) {
String s1 = normalizeSpaces(docLinkText);
String s2 = normalizeSpaces(docLink.getText());
if (s1.equals(s2)) {
docLinks[0] = docLink;
return;
}
}
});
}
return docLinks[0];
}
private Module getCurrentModule() {
if (scope instanceof Module) {
return (Module) scope;
} else if (scope instanceof Package) {
return ((Package) scope).getModule();
} else if (scope instanceof Declaration) {
return scope.getUnit().getPackage().getModule();
}
return null;
}
private Package getCurrentPackage() {
if (scope instanceof Module) {
return ((Module) scope).getRootPackage();
} else if (scope instanceof Package) {
return (Package) scope;
} else if (scope instanceof Declaration) {
return scope.getUnit().getPackage();
}
return null;
}
private Interface getCurrentInterface() {
Object o = scope;
while (o != null) {
if (o instanceof Interface) {
return (Interface) o;
} else if (o instanceof Declaration) {
o = ((Declaration) o).getContainer();
} else {
o = null;
}
}
return null;
}
private Class getCurrentClass() {
Object o = scope;
while (o != null) {
if (o instanceof Class) {
return (Class) o;
} else if (o instanceof Declaration) {
o = ((Declaration) o).getContainer();
} else {
o = null;
}
}
return null;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy