start moving JavaDocumentationProvider to java-psi-impl module

This commit is contained in:
Evgeny Pasynkov
2012-11-16 15:49:49 +01:00
parent f22e0e716b
commit 258a217358
6 changed files with 191 additions and 224 deletions
@@ -16,13 +16,12 @@
package com.intellij.lang.java;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.codeInsight.documentation.PlatformDocumentationUtil;
import com.intellij.codeInsight.editorActions.CodeDocumentationUtil;
import com.intellij.codeInsight.javadoc.JavaDocExternalFilter;
import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator;
import com.intellij.codeInsight.javadoc.JavaDocUtil;
import com.intellij.codeInsight.javadoc.JavaDocumentationProviderBase;
import com.intellij.lang.CodeDocumentationAwareCommenter;
import com.intellij.lang.LangBundle;
import com.intellij.lang.LanguageCommenters;
@@ -36,7 +35,6 @@ import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -44,7 +42,6 @@ import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.psi.*;
import com.intellij.psi.impl.beanProperties.BeanPropertyElement;
import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiFormatUtil;
@@ -55,22 +52,19 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Maxim.Mossienko
*/
public class JavaDocumentationProvider implements CodeDocumentationProvider, ExternalDocumentationProvider {
public class JavaDocumentationProvider extends JavaDocumentationProviderBase implements CodeDocumentationProvider, ExternalDocumentationProvider {
private static final Logger LOG = Logger.getInstance("#" + JavaDocumentationProvider.class.getName());
private static final String LINE_SEPARATOR = "\n";
@NonNls private static final String PARAM_TAG = "@param";
@NonNls private static final String RETURN_TAG = "@return";
@NonNls private static final String THROWS_TAG = "@throws";
@NonNls public static final String HTML_EXTENSION = ".html";
@NonNls public static final String PACKAGE_SUMMARY_FILE = "package-summary.html";
@Override
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
@@ -258,6 +252,38 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext
return buffer.toString();
}
@Override
@Nullable
public List<String> findUrlForVirtualFile(final Project project, final VirtualFile virtualFile, final String relPath) {
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
Module module = fileIndex.getModuleForFile(virtualFile);
if (module == null) {
final VirtualFileSystem fs = virtualFile.getFileSystem();
if (fs instanceof JarFileSystem) {
final VirtualFile jar = ((JarFileSystem)fs).getVirtualFileForJar(virtualFile);
if (jar != null) {
module = fileIndex.getModuleForFile(jar);
}
}
}
if (module != null) {
String[] javadocPaths = JavaModuleExternalPaths.getInstance(module).getJavadocUrls();
final List<String> httpRoots = PlatformDocumentationUtil.getHttpRoots(javadocPaths, relPath);
// if found nothing and the file is from library classes, fall back to order entries
if (httpRoots != null || !fileIndex.isInLibraryClasses(virtualFile)) {
return httpRoots;
}
}
final List<OrderEntry> orderEntries = fileIndex.getOrderEntriesForFile(virtualFile);
for (OrderEntry orderEntry : orderEntries) {
final String[] files = JavadocOrderRootType.getUrls(orderEntry);
final List<String> httpRoot = PlatformDocumentationUtil.getHttpRoots(files, relPath);
if (httpRoot != null) return httpRoot;
}
return null;
}
@SuppressWarnings({"HardCodedStringLiteral"})
public static String generateMethodInfo(PsiMethod method, PsiSubstitutor substitutor) {
StringBuilder buffer = new StringBuilder();
@@ -382,6 +408,12 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext
return buffer.toString();
}
@Override
@Nullable
public String generateExternalJavadoc(final PsiElement element) {
return JavaDocExternalFilter.filterInternalDocInfo(super.generateExternalJavadoc(element));
}
@Override
public PsiComment findExistingDocComment(final PsiComment comment) {
if (comment instanceof PsiDocComment) {
@@ -495,13 +527,7 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext
@Override
public String generateDoc(final PsiElement element, final PsiElement originalElement) {
if (element instanceof PsiMethodCallExpression) {
return getMethodCandidateInfo((PsiMethodCallExpression)element);
}
//external documentation finder
return generateExternalJavadoc(element);
return super.generateDoc(element, originalElement);
}
@Override
@@ -509,14 +535,6 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext
return null;
}
@Nullable
public static String generateExternalJavadoc(final PsiElement element) {
final JavaDocInfoGenerator javaDocInfoGenerator = new JavaDocInfoGenerator(element.getProject(), element);
final List<String> docURLs = getExternalJavaDocUrl(element);
return JavaDocExternalFilter.filterInternalDocInfo(javaDocInfoGenerator.generateDocInfo(docURLs));
}
@Nullable
private static String fetchExternalJavadoc(final PsiElement element, String fromUrl, JavaDocExternalFilter filter) {
try {
@@ -531,183 +549,6 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext
return null;
}
private String getMethodCandidateInfo(PsiMethodCallExpression expr) {
final PsiResolveHelper rh = JavaPsiFacade.getInstance(expr.getProject()).getResolveHelper();
final CandidateInfo[] candidates = rh.getReferencedMethodCandidates(expr, true);
final String text = expr.getText();
if (candidates.length > 0) {
@NonNls final StringBuilder sb = new StringBuilder();
for (final CandidateInfo candidate : candidates) {
final PsiElement element = candidate.getElement();
if (!(element instanceof PsiMethod)) {
continue;
}
final String str = PsiFormatUtil.formatMethod((PsiMethod)element, candidate.getSubstitutor(),
PsiFormatUtilBase.SHOW_NAME |
PsiFormatUtilBase.SHOW_TYPE |
PsiFormatUtilBase.SHOW_PARAMETERS,
PsiFormatUtilBase.SHOW_TYPE);
createElementLink(sb, element, StringUtil.escapeXml(str));
}
return CodeInsightBundle.message("javadoc.candiates", text, sb);
}
return CodeInsightBundle.message("javadoc.candidates.not.found", text);
}
private static void createElementLink(@NonNls final StringBuilder sb, final PsiElement element, final String str) {
sb.append("&nbsp;&nbsp;<a href=\"" + DocumentationManager.PSI_ELEMENT_PROTOCOL);
sb.append(JavaDocUtil.getReferenceText(element.getProject(), element));
sb.append("\">");
sb.append(str);
sb.append("</a>");
sb.append("<br>");
}
@Nullable
public static List<String> getExternalJavaDocUrl(final PsiElement element) {
List<String> urls = null;
if (element instanceof PsiClass) {
urls = findUrlForClass((PsiClass)element);
}
else if (element instanceof PsiField) {
PsiField field = (PsiField)element;
PsiClass aClass = field.getContainingClass();
if (aClass != null) {
urls = findUrlForClass(aClass);
if (urls != null) {
for (int i = 0; i < urls.size(); i++) {
urls.set(i, urls.get(i) + "#" + field.getName());
}
}
}
}
else if (element instanceof PsiMethod) {
PsiMethod method = (PsiMethod)element;
PsiClass aClass = method.getContainingClass();
if (aClass != null) {
final List<String> classUrls = findUrlForClass(aClass);
if (classUrls != null) {
urls = new ArrayList<String>();
String signature = formatMethodSignature(method);
for (String classUrl : classUrls) {
urls.add(classUrl + "#" + signature);
}
signature = PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY,
PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS,
PsiFormatUtilBase.SHOW_TYPE | PsiFormatUtilBase.SHOW_FQ_CLASS_NAMES, 999);
for (String classUrl : classUrls) {
urls.add(classUrl + "#" + signature);
}
}
}
}
else if (element instanceof PsiPackage) {
urls = findUrlForPackage((PsiPackage)element);
}
else if (element instanceof PsiDirectory) {
PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
if (aPackage != null) {
urls = findUrlForPackage(aPackage);
}
}
if (urls == null) {
return null;
}
else {
for (int i = 0; i < urls.size(); i++) {
urls.set(i, FileUtil.toSystemIndependentName(urls.get(i)));
}
return urls;
}
}
public static String formatMethodSignature(PsiMethod method) {
return PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY,
PsiFormatUtilBase.SHOW_NAME |
PsiFormatUtilBase.SHOW_PARAMETERS |
PsiFormatUtilBase.SHOW_RAW_NON_TOP_TYPE,
PsiFormatUtilBase.SHOW_TYPE |
PsiFormatUtilBase.SHOW_FQ_CLASS_NAMES |
PsiFormatUtilBase.SHOW_RAW_NON_TOP_TYPE,
999);
}
@Nullable
public static List<String> findUrlForClass(PsiClass aClass) {
String qName = aClass.getQualifiedName();
if (qName == null) return null;
PsiFile file = aClass.getContainingFile();
if (!(file instanceof PsiJavaFile)) return null;
String packageName = ((PsiJavaFile)file).getPackageName();
String relPath;
if (packageName.length() > 0) {
relPath = packageName.replace('.', '/') + '/' + qName.substring(packageName.length() + 1) + HTML_EXTENSION;
}
else {
relPath = qName + HTML_EXTENSION;
}
final PsiFile containingFile = aClass.getContainingFile();
if (containingFile == null) return null;
final VirtualFile virtualFile = containingFile.getVirtualFile();
if (virtualFile == null) return null;
return findUrlForVirtualFile(containingFile.getProject(), virtualFile, relPath);
}
@Nullable
public static List<String> findUrlForVirtualFile(final Project project, final VirtualFile virtualFile, final String relPath) {
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
Module module = fileIndex.getModuleForFile(virtualFile);
if (module == null) {
final VirtualFileSystem fs = virtualFile.getFileSystem();
if (fs instanceof JarFileSystem) {
final VirtualFile jar = ((JarFileSystem)fs).getVirtualFileForJar(virtualFile);
if (jar != null) {
module = fileIndex.getModuleForFile(jar);
}
}
}
if (module != null) {
String[] javadocPaths = JavaModuleExternalPaths.getInstance(module).getJavadocUrls();
final List<String> httpRoots = PlatformDocumentationUtil.getHttpRoots(javadocPaths, relPath);
// if found nothing and the file is from library classes, fall back to order entries
if (httpRoots != null || !fileIndex.isInLibraryClasses(virtualFile)) {
return httpRoots;
}
}
final List<OrderEntry> orderEntries = fileIndex.getOrderEntriesForFile(virtualFile);
for (OrderEntry orderEntry : orderEntries) {
final String[] files = JavadocOrderRootType.getUrls(orderEntry);
final List<String> httpRoot = PlatformDocumentationUtil.getHttpRoots(files, relPath);
if (httpRoot != null) return httpRoot;
}
return null;
}
@Nullable
public static List<String> findUrlForPackage(PsiPackage aPackage) {
String qName = aPackage.getQualifiedName();
qName = qName.replace('.', '/') + '/' + PACKAGE_SUMMARY_FILE;
for (PsiDirectory directory : aPackage.getDirectories()) {
List<String> url = findUrlForVirtualFile(aPackage.getProject(), directory.getVirtualFile(), qName);
if (url != null) {
return url;
}
}
return null;
}
@Override
public PsiElement getDocumentationElementForLink(final PsiManager psiManager, final String link, final PsiElement context) {
return JavaDocUtil.findReferenceTarget(psiManager, link, context);
@@ -18,7 +18,7 @@ package com.intellij.codeInsight.javadoc;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.codeInsight.documentation.DocumentationManagerUtil;
import com.intellij.lang.ASTNode;
import com.intellij.lang.LangBundle;
import com.intellij.openapi.diagnostic.Logger;
@@ -1474,7 +1474,7 @@ public class JavaDocInfoGenerator {
private void generateLink(StringBuilder buffer, PsiElement element, String label) {
String refText = JavaDocUtil.getReferenceText(myProject, element);
if (refText != null) {
DocumentationManager.createHyperlink(buffer, refText,label,false);
DocumentationManagerUtil.createHyperlink(buffer, refText,label,false);
//return generateLink(buffer, refText, label, context, false);
}
}
@@ -1501,7 +1501,7 @@ public class JavaDocInfoGenerator {
}
DocumentationManager.createHyperlink(buffer, JavaDocUtil.getReferenceText(context.getProject(), target), label, plainLink);
DocumentationManagerUtil.createHyperlink(buffer, JavaDocUtil.getReferenceText(context.getProject(), target), label, plainLink);
return label.length();
}
@@ -1,8 +1,11 @@
package com.intellij.codeInsight.javadoc;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator;
import com.intellij.codeInsight.documentation.DocumentationManagerProtocol;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.PsiFormatUtil;
@@ -10,24 +13,130 @@ import com.intellij.psi.util.PsiFormatUtilBase;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class JavaDocumentationProviderBase {
@NonNls public static final String HTML_EXTENSION = ".html";
@NonNls public static final String PACKAGE_SUMMARY_FILE = "package-summary.html";
public String generateDoc(final PsiElement element, final PsiElement originalElement) {
if (element instanceof PsiMethodCallExpression) {
return getMethodCandidateInfo((PsiMethodCallExpression)element);
}
//external documentation finder
return generateExternalJavadoc(element);
}
@Nullable
public static String generateExternalJavadoc(final PsiElement element) {
public List<String> getExternalJavaDocUrl(final PsiElement element) {
List<String> urls = null;
if (element instanceof PsiClass) {
urls = findUrlForClass((PsiClass)element);
}
else if (element instanceof PsiField) {
PsiField field = (PsiField)element;
PsiClass aClass = field.getContainingClass();
if (aClass != null) {
urls = findUrlForClass(aClass);
if (urls != null) {
for (int i = 0; i < urls.size(); i++) {
urls.set(i, urls.get(i) + "#" + field.getName());
}
}
}
}
else if (element instanceof PsiMethod) {
PsiMethod method = (PsiMethod)element;
PsiClass aClass = method.getContainingClass();
if (aClass != null) {
final List<String> classUrls = findUrlForClass(aClass);
if (classUrls != null) {
urls = new ArrayList<String>();
String signature = formatMethodSignature(method);
for (String classUrl : classUrls) {
urls.add(classUrl + "#" + signature);
}
signature = PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY,
PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS,
PsiFormatUtilBase.SHOW_TYPE | PsiFormatUtilBase.SHOW_FQ_CLASS_NAMES, 999);
for (String classUrl : classUrls) {
urls.add(classUrl + "#" + signature);
}
}
}
}
else if (element instanceof PsiPackage) {
urls = findUrlForPackage((PsiPackage)element);
}
else if (element instanceof PsiDirectory) {
PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
if (aPackage != null) {
urls = findUrlForPackage(aPackage);
}
}
if (urls == null) {
return null;
}
else {
for (int i = 0; i < urls.size(); i++) {
urls.set(i, FileUtil.toSystemIndependentName(urls.get(i)));
}
return urls;
}
}
@Nullable
public List<String> findUrlForClass(PsiClass aClass) {
String qName = aClass.getQualifiedName();
if (qName == null) return null;
PsiFile file = aClass.getContainingFile();
if (!(file instanceof PsiJavaFile)) return null;
String packageName = ((PsiJavaFile)file).getPackageName();
String relPath;
if (packageName.length() > 0) {
relPath = packageName.replace('.', '/') + '/' + qName.substring(packageName.length() + 1) + HTML_EXTENSION;
}
else {
relPath = qName + HTML_EXTENSION;
}
final PsiFile containingFile = aClass.getContainingFile();
if (containingFile == null) return null;
final VirtualFile virtualFile = containingFile.getVirtualFile();
if (virtualFile == null) return null;
return findUrlForVirtualFile(containingFile.getProject(), virtualFile, relPath);
}
@Nullable
public List<String> findUrlForVirtualFile(final Project project, final VirtualFile virtualFile, final String relPath) {
return null;
}
@Nullable
public List<String> findUrlForPackage(PsiPackage aPackage) {
String qName = aPackage.getQualifiedName();
qName = qName.replace('.', '/') + '/' + PACKAGE_SUMMARY_FILE;
for (PsiDirectory directory : aPackage.getDirectories()) {
List<String> url = findUrlForVirtualFile(aPackage.getProject(), directory.getVirtualFile(), qName);
if (url != null) {
return url;
}
}
return null;
}
@Nullable
public String generateExternalJavadoc(final PsiElement element) {
final JavaDocInfoGenerator javaDocInfoGenerator = new JavaDocInfoGenerator(element.getProject(), element);
final List<String> docURLs = getExternalJavaDocUrl(element);
return JavaDocExternalFilter.filterInternalDocInfo(javaDocInfoGenerator.generateDocInfo(docURLs));
return javaDocInfoGenerator.generateDocInfo(docURLs);
}
private String getMethodCandidateInfo(PsiMethodCallExpression expr) {
@@ -58,11 +167,23 @@ public class JavaDocumentationProviderBase {
}
private static void createElementLink(@NonNls final StringBuilder sb, final PsiElement element, final String str) {
sb.append("&nbsp;&nbsp;<a href=\"" + DocumentationManager.PSI_ELEMENT_PROTOCOL);
sb.append("&nbsp;&nbsp;<a href=\"" + DocumentationManagerProtocol.PSI_ELEMENT_PROTOCOL);
sb.append(JavaDocUtil.getReferenceText(element.getProject(), element));
sb.append("\">");
sb.append(str);
sb.append("</a>");
sb.append("<br>");
}
public static String formatMethodSignature(PsiMethod method) {
return PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY,
PsiFormatUtilBase.SHOW_NAME |
PsiFormatUtilBase.SHOW_PARAMETERS |
PsiFormatUtilBase.SHOW_RAW_NON_TOP_TYPE,
PsiFormatUtilBase.SHOW_TYPE |
PsiFormatUtilBase.SHOW_FQ_CLASS_NAMES |
PsiFormatUtilBase.SHOW_RAW_NON_TOP_TYPE,
999);
}
}
@@ -1,4 +1,8 @@
package com.intellij.codeInsight.documentation;
import org.jetbrains.annotations.NonNls;
public interface DocumentationManagerProtocol {
@NonNls public static final String PSI_ELEMENT_PROTOCOL = "psi_element://";
@NonNls public static final String DOC_ELEMENT_PROTOCOL = "doc_element://";
}
@@ -1,4 +1,19 @@
package com.intellij.codeInsight.documentation;
public class DocumentationManagerUtil {
@SuppressWarnings({"HardCodedStringLiteral"})
public static void createHyperlink(StringBuilder buffer, String refText,String label,boolean plainLink) {
buffer.append("<a href=\"");
buffer.append(DocumentationManagerProtocol.PSI_ELEMENT_PROTOCOL); // :-)
buffer.append(refText);
buffer.append("\">");
if (!plainLink) {
buffer.append("<code>");
}
buffer.append(label);
if (!plainLink) {
buffer.append("</code>");
}
buffer.append("</a>");
}
}
@@ -74,7 +74,7 @@ import java.lang.ref.WeakReference;
import java.util.*;
import java.util.List;
public class DocumentationManager extends DockablePopupManager<DocumentationComponent> {
public class DocumentationManager extends DockablePopupManager<DocumentationComponent> implements DocumentationManagerProtocol {
@NonNls public static final String JAVADOC_LOCATION_AND_SIZE = "javadoc.popup";
public static final DataKey<String> SELECTED_QUICK_DOC_TEXT = DataKey.create("QUICK_DOC.SELECTED_TEXT");
@@ -89,8 +89,6 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
private WeakReference<JBPopup> myDocInfoHintRef;
private Component myPreviouslyFocused = null;
public static final Key<SmartPsiElementPointer> ORIGINAL_ELEMENT_KEY = Key.create("Original element");
@NonNls public static final String PSI_ELEMENT_PROTOCOL = "psi_element://";
@NonNls public static final String DOC_ELEMENT_PROTOCOL = "doc_element://";
private final ActionManagerEx myActionManagerEx;
@@ -961,20 +959,8 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
return element;
}
@SuppressWarnings({"HardCodedStringLiteral"})
public static void createHyperlink(StringBuilder buffer, String refText,String label,boolean plainLink) {
buffer.append("<a href=\"");
buffer.append(PSI_ELEMENT_PROTOCOL); // :-)
buffer.append(refText);
buffer.append("\">");
if (!plainLink) {
buffer.append("<code>");
}
buffer.append(label);
if (!plainLink) {
buffer.append("</code>");
}
buffer.append("</a>");
DocumentationManagerUtil.createHyperlink(buffer, refText, label, plainLink);
}
@Override