blob: cac3b57eb90d7d6240820fe7d2138b1a38fe5fcb [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.javadoc;
import com.intellij.codeInsight.documentation.AbstractExternalFilter;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.codeInsight.documentation.PlatformDocumentationUtil;
import com.intellij.ide.BrowserUtil;
import com.intellij.lang.java.JavaDocumentationProvider;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NullableComputable;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by IntelliJ IDEA.
* User: db
* Date: May 2, 2003
* Time: 8:35:34 PM
* To change this template use Options | File Templates.
*/
public class JavaDocExternalFilter extends AbstractExternalFilter {
private final Project myProject;
private static final Trinity<Pattern, Pattern, Boolean> ourPackageInfoSettings = Trinity.create(
Pattern.compile("package\\s+[^\\s]+\\s+description", Pattern.CASE_INSENSITIVE),
Pattern.compile("START OF BOTTOM NAVBAR", Pattern.CASE_INSENSITIVE),
Boolean.TRUE
);
protected static @NonNls final Pattern ourHTMLsuffix = Pattern.compile("[.][hH][tT][mM][lL]?");
protected static @NonNls final Pattern ourParentFolderprefix = Pattern.compile("^[.][.]/");
protected static @NonNls final Pattern ourAnchorsuffix = Pattern.compile("#(.*)$");
protected static @NonNls final Pattern ourHTMLFilesuffix = Pattern.compile("/([^/]*[.][hH][tT][mM][lL]?)$");
private static @NonNls final Pattern ourHREFselector = Pattern.compile("<A.*?HREF=\"([^>\"]*)\"", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
private static @NonNls final Pattern ourMethodHeading = Pattern.compile("<H[34]>(.+?)</H[34]>", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
protected static @NonNls final String DOC_ELEMENT_PROTOCOL = "doc_element://";
@NonNls protected static final String H2 = "</H2>";
@NonNls protected static final String HTML_CLOSE = "</HTML>";
@NonNls protected static final String HTML = "<HTML>";
private final RefConvertor[] myReferenceConvertors = new RefConvertor[]{
new RefConvertor(ourHREFselector) {
@Override
protected String convertReference(String root, String href) {
if (BrowserUtil.isAbsoluteURL(href)) {
return href;
}
if (StringUtil.startsWithChar(href, '#')) {
return DOC_ELEMENT_PROTOCOL + root + href;
}
String nakedRoot = ourHTMLFilesuffix.matcher(root).replaceAll("/");
String stripped = ourHTMLsuffix.matcher(href).replaceAll("");
int len = stripped.length();
do stripped = ourParentFolderprefix.matcher(stripped).replaceAll(""); while (len > (len = stripped.length()));
final String elementRef = stripped.replaceAll("/", ".");
final String classRef = ourAnchorsuffix.matcher(elementRef).replaceAll("");
return
(JavaPsiFacade.getInstance(myProject).findClass(classRef, GlobalSearchScope.allScope(myProject)) != null)
? DocumentationManager.PSI_ELEMENT_PROTOCOL + elementRef
: DOC_ELEMENT_PROTOCOL + doAnnihilate(nakedRoot + href);
}
},
myIMGConvertor
};
public JavaDocExternalFilter(Project project) {
myProject = project;
}
@Override
protected RefConvertor[] getRefConvertors() {
return myReferenceConvertors;
}
@Nullable
public static String filterInternalDocInfo(String text) {
if (text == null) {
return null;
}
text = PlatformDocumentationUtil.fixupText(text);
return text;
}
@Override
@Nullable
public String getExternalDocInfoForElement(final String docURL, final PsiElement element) throws Exception {
String externalDoc = super.getExternalDocInfoForElement(docURL, element);
if (externalDoc != null) {
if (element instanceof PsiMethod) {
final String className = ApplicationManager.getApplication().runReadAction(
new NullableComputable<String>() {
@Override
@Nullable
public String compute() {
PsiClass aClass = ((PsiMethod)element).getContainingClass();
return aClass == null ? null : aClass.getQualifiedName();
}
}
);
Matcher matcher = ourMethodHeading.matcher(externalDoc);
final StringBuilder buffer = new StringBuilder();
DocumentationManager.createHyperlink(buffer, className, className, false);
//noinspection HardCodedStringLiteral
return matcher.replaceFirst("<H3>" + buffer.toString() + "</H3>");
}
}
return externalDoc;
}
@NotNull
@Override
protected Trinity<Pattern, Pattern, Boolean> getParseSettings(@NotNull String url) {
return url.endsWith(JavaDocumentationProvider.PACKAGE_SUMMARY_FILE) ? ourPackageInfoSettings : super.getParseSettings(url);
}
}