From 516ca8f264d3fc3fbb83cc596b81d1ea0dfa9b90 Mon Sep 17 00:00:00 2001 From: Patrick Scheibe Date: Mon, 14 Jun 2021 23:52:13 +0200 Subject: [PATCH] Add article and tutorial about Documentation Provider (#413) * Initial version of a simple DocumentationProvider * Correct usage of DocumentationMarkup, fix quick navigation * Include Yann's suggestions. Not finished yet. * Fix issues Yann pointed out --- .../language/SimpleDocumentationProvider.java | 96 +++++++++++++++++++ .../org/intellij/sdk/language/SimpleUtil.java | 27 +++++- .../src/main/resources/META-INF/plugin.xml | 1 + 3 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 simple_language_plugin/src/main/java/org/intellij/sdk/language/SimpleDocumentationProvider.java diff --git a/simple_language_plugin/src/main/java/org/intellij/sdk/language/SimpleDocumentationProvider.java b/simple_language_plugin/src/main/java/org/intellij/sdk/language/SimpleDocumentationProvider.java new file mode 100644 index 000000000..30aeed817 --- /dev/null +++ b/simple_language_plugin/src/main/java/org/intellij/sdk/language/SimpleDocumentationProvider.java @@ -0,0 +1,96 @@ +package org.intellij.sdk.language; + +import com.intellij.lang.documentation.AbstractDocumentationProvider; +import com.intellij.lang.documentation.DocumentationMarkup; +import com.intellij.psi.PsiElement; +import com.intellij.psi.presentation.java.SymbolPresentationUtil; +import org.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class SimpleDocumentationProvider extends AbstractDocumentationProvider { + + /** + * For the Simple Language, we don't have online documentation. However, if your language provides + * references pages online, URLs for the element can be returned here. + */ + @Override + public @Nullable List getUrlFor(PsiElement element, PsiElement originalElement) { + return null; + } + + /** + * Extracts the key, value, file and documentation comment of a Simple key/value entry and returns + * a formatted representation of the information. + */ + @Override + public @Nullable String generateDoc(PsiElement element, @Nullable PsiElement originalElement) { + if (element instanceof SimpleProperty) { + final String key = ((SimpleProperty) element).getKey(); + final String value = ((SimpleProperty) element).getValue(); + final String file = SymbolPresentationUtil.getFilePathPresentation(element.getContainingFile()); + final String docComment = SimpleUtil.findDocumentationComment((SimpleProperty) element); + + return renderFullDoc(key, value, file, docComment); + } + return null; + } + + /** + * Provides the information in which file the Simple language key/value is defined. + */ + @Override + public @Nullable String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { + if (element instanceof SimpleProperty) { + final String key = ((SimpleProperty) element).getKey(); + final String file = SymbolPresentationUtil.getFilePathPresentation(element.getContainingFile()); + return "\"" + key + "\" in " + file; + } + return null; + } + + /** + * Provides documentation when a Simple Language element is hovered with the mouse. + */ + @Override + public @Nullable String generateHoverDoc(@NotNull PsiElement element, @Nullable PsiElement originalElement) { + return generateDoc(element, originalElement); + } + + /** + * Creates a key/value row for the rendered documentation. + */ + private void addKeyValueSection(String key, String value, StringBuilder sb) { + sb.append(DocumentationMarkup.SECTION_HEADER_START); + sb.append(key); + sb.append(DocumentationMarkup.SECTION_SEPARATOR); + sb.append("

"); + sb.append(value); + sb.append(DocumentationMarkup.SECTION_END); + } + + /** + * Creates the formatted documentation using {@link DocumentationMarkup}. See the Java doc of + * {@link com.intellij.lang.documentation.DocumentationProvider#generateDoc(PsiElement, PsiElement)} for more + * information about building the layout. + */ + private String renderFullDoc(String key, String value, String file, String docComment) { + StringBuilder sb = new StringBuilder(); + sb.append(DocumentationMarkup.DEFINITION_START); + sb.append("Simple Property"); + sb.append(DocumentationMarkup.DEFINITION_END); + sb.append(DocumentationMarkup.CONTENT_START); + sb.append(value); + sb.append(DocumentationMarkup.CONTENT_END); + sb.append(DocumentationMarkup.SECTIONS_START); + addKeyValueSection("Key:", key, sb); + addKeyValueSection("Value:", value, sb); + addKeyValueSection("File:", file, sb); + addKeyValueSection("Comment:", docComment, sb); + sb.append(DocumentationMarkup.SECTIONS_END); + return sb.toString(); + } + +} diff --git a/simple_language_plugin/src/main/java/org/intellij/sdk/language/SimpleUtil.java b/simple_language_plugin/src/main/java/org/intellij/sdk/language/SimpleUtil.java index 8341323d7..f3edbb94a 100644 --- a/simple_language_plugin/src/main/java/org/intellij/sdk/language/SimpleUtil.java +++ b/simple_language_plugin/src/main/java/org/intellij/sdk/language/SimpleUtil.java @@ -2,19 +2,22 @@ package org.intellij.sdk.language; +import com.google.common.collect.Lists; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.search.FileTypeIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import org.intellij.sdk.language.psi.SimpleFile; import org.intellij.sdk.language.psi.SimpleProperty; +import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; public class SimpleUtil { @@ -61,4 +64,20 @@ public class SimpleUtil { return result; } + /** + * Attempts to collect any comment elements above the Simple key/value pair. + */ + public static @NotNull String findDocumentationComment(SimpleProperty property) { + List result = new LinkedList<>(); + PsiElement element = property.getPrevSibling(); + while (element instanceof PsiComment || element instanceof PsiWhiteSpace) { + if (element instanceof PsiComment) { + String commentText = element.getText().replaceFirst("[!# ]+", ""); + result.add(commentText); + } + element = element.getPrevSibling(); + } + return StringUtil.join(Lists.reverse(result),"\n "); + } + } diff --git a/simple_language_plugin/src/main/resources/META-INF/plugin.xml b/simple_language_plugin/src/main/resources/META-INF/plugin.xml index 7f552ab28..701b4f976 100644 --- a/simple_language_plugin/src/main/resources/META-INF/plugin.xml +++ b/simple_language_plugin/src/main/resources/META-INF/plugin.xml @@ -66,6 +66,7 @@ +