documentation_provider.md: cleanup

This commit is contained in:
Karol Lewandowski 2022-03-11 14:33:28 +01:00
parent 968b2dabed
commit 8023d025e5

View File

@ -6,19 +6,17 @@
A [`DocumentationProvider`](upsource:///platform/analysis-api/src/com/intellij/lang/documentation/DocumentationProvider.java) A [`DocumentationProvider`](upsource:///platform/analysis-api/src/com/intellij/lang/documentation/DocumentationProvider.java)
helps users by showing documentation for symbols like method calls inside the editor. helps users by showing documentation for symbols like method calls inside the editor.
For the custom language tutorial, were implementing a version of this EP for the Simple Language that shows the key/value, For the custom language tutorial, we're implementing a version of this extension point (EP) for the Simple Language that shows the key/value,
the file where it is defined, and any related documentation comment. the file where it is defined, and any related documentation comment.
**Reference:** [](documentation.md) **Reference:** [](documentation.md)
## Implement DocumentationProvider and Register the EP ## Implement DocumentationProvider and Register the EP
In the first step, we create an empty class that extends In the first step, we create an empty class that extends
[`AbstractDocumentationProvider`](upsource:///platform/analysis-api/src/com/intellij/lang/documentation/AbstractDocumentationProvider.java) [`AbstractDocumentationProvider`](upsource:///platform/analysis-api/src/com/intellij/lang/documentation/AbstractDocumentationProvider.java)
and registers it in the <path>plugin.xml</path>. and registers it in the <path>plugin.xml</path>.
```java ```java
public class SimpleDocumentationProvider extends AbstractDocumentationProvider { } public class SimpleDocumentationProvider extends AbstractDocumentationProvider { }
``` ```
@ -29,11 +27,10 @@ Make sure the class is registered in the <path>plugin.xml</path> between the `ex
<extensions defaultExtensionNs="com.intellij"> <extensions defaultExtensionNs="com.intellij">
<!-- Other extensions… --> <!-- Other extensions… -->
<lang.documentationProvider language="Simple" <lang.documentationProvider language="Simple"
implementationClass="org.intellij.sdk.language.SimpleDocumentationProvider"/> implementationClass="org.intellij.sdk.language.SimpleDocumentationProvider"/>
</extensions> </extensions>
``` ```
## Ensure That the Correct PSI Element Is Used ## Ensure That the Correct PSI Element Is Used
For the Simple Language, we consider two use-cases: For the Simple Language, we consider two use-cases:
@ -47,8 +44,9 @@ we create a dummy implementation of `generateDoc()`:
```java ```java
@Override @Override
public @Nullable String generateDoc(PsiElement element, @Nullable PsiElement originalElement) { public @Nullable String generateDoc(PsiElement element,
return super.generateDoc(element, originalElement); @Nullable PsiElement originalElement) {
return super.generateDoc(element, originalElement);
} }
``` ```
@ -65,7 +63,6 @@ Inside a Simple file, the situation is similar, and calling <menupath>View | Qui
Please refer to the Addendum below, which explains how to improve on this situation by additionally overriding `getCustomDocumentationElement()` method. Please refer to the Addendum below, which explains how to improve on this situation by additionally overriding `getCustomDocumentationElement()` method.
## Extract Documentation Comments from Key/Value Definitions ## Extract Documentation Comments from Key/Value Definitions
While `SimpleProperty` elements will provide us with their key and value, we have no direct access to a possible comment that is preceding the key/value definition. While `SimpleProperty` elements will provide us with their key and value, we have no direct access to a possible comment that is preceding the key/value definition.
@ -73,14 +70,14 @@ Since we would like to show this comment in the documentation as well, we need a
This function will reside in the `SimpleUtil` class and will find for instance the comment preceding `apikey` in the following short example: This function will reside in the `SimpleUtil` class and will find for instance the comment preceding `apikey` in the following short example:
```text ```text
#An application programming interface key (API key) is a unique identifier used #An application programming interface key (API key) is a unique identifier
#to authenticate a user, developer, or calling program to an API. #used to authenticate a user, developer, or calling program to an API.
apikey=ph342m91337h4xX0r5k!11Zz! apikey=ph342m91337h4xX0r5k!11Zz!
``` ```
The following implementation will check if there is any comment preceding a `SimpleProperty`, and if there is, The following implementation will check if there is any comment preceding a `SimpleProperty`, and if there is,
it will collect all comment lines until it reaches either the previous key/value definition or the beginning of the file. it will collect all comment lines until it reaches either the previous key/value definition or the beginning of the file.
One caveat is that since were collecting the comment lines backwards, we need to reverse the list before joining them into a single string. One caveat is that since we're collecting the comment lines backwards, we need to reverse the list before joining them into a single string.
A simple regex is used to remove the leading hash characters and whitespaces from each line. A simple regex is used to remove the leading hash characters and whitespaces from each line.
```java ```java
@ -120,7 +117,7 @@ After implementing all the steps above, the IDE will show the rendered documenta
We can provide implementations for additional functionality that comes with a `DocumentationProvider`. We can provide implementations for additional functionality that comes with a `DocumentationProvider`.
For instance, when simply hovering the mouse over the code, it also shows documentation after a short delay. For instance, when simply hovering the mouse over the code, it also shows documentation after a short delay.
Its not necessary that this popup show the exact same information as when calling _Quick Documentation_, but for the purpose of this tutorial, well do just that. It's not necessary that this popup show the exact same information as when calling _Quick Documentation_, but for the purpose of this tutorial, we'll do just that.
```java ```java
``` ```
@ -141,7 +138,6 @@ In that case, language developers need to ensure that the correct PSI element fo
In the case of Simple Language, the lookup element is already a `SimpleProperty` and no additional work needs to be done. In the case of Simple Language, the lookup element is already a `SimpleProperty` and no additional work needs to be done.
In other circumstances, you can override `getDocumentationElementForLookupItem() `and return the correct PSI element. In other circumstances, you can override `getDocumentationElementForLookupItem() `and return the correct PSI element.
## Addendum: Choosing a Better Target Element ## Addendum: Choosing a Better Target Element
To be able to call <menupath>View | Quick Documentation</menupath> for Simple properties in all places of a Java string literal, two steps are required: To be able to call <menupath>View | Quick Documentation</menupath> for Simple properties in all places of a Java string literal, two steps are required:
@ -156,29 +152,37 @@ This allows getting documentation for a Simple property no matter where it was c
```java ```java
@Override @Override
public @Nullable PsiElement getCustomDocumentationElement(@NotNull Editor editor, @NotNull PsiFile file, @Nullable PsiElement contextElement, int targetOffset) { public @Nullable PsiElement getCustomDocumentationElement(@NotNull Editor editor,
if (contextElement != null) { @NotNull PsiFile file,
// In this part the SimpleProperty element is extracted from inside a Java string @Nullable PsiElement context,
if (contextElement instanceof PsiJavaToken && ((PsiJavaToken) contextElement).getTokenType().equals(JavaTokenType.STRING_LITERAL)) { int targetOffset) {
final PsiElement parent = contextElement.getParent(); if (context != null) {
final PsiReference[] references = parent.getReferences(); // In this part the SimpleProperty element
for (PsiReference ref : references) { // is extracted from inside a Java string
if (ref instanceof SimpleReference) { if (context instanceof PsiJavaToken &&
final PsiElement property = ref.resolve(); ((PsiJavaToken) context).getTokenType().equals(JavaTokenType.STRING_LITERAL)) {
if (property instanceof SimpleProperty) { PsiElement parent = context.getParent();
return property; PsiReference[] references = parent.getReferences();
} for (PsiReference ref : references) {
} if (ref instanceof SimpleReference) {
} PsiElement property = ref.resolve();
} if (property instanceof SimpleProperty) {
// In this part the SimpleProperty element is extracted when inside a .simple file return property;
else if (contextElement.getLanguage() == SimpleLanguage.INSTANCE) { }
final PsiElement property = PsiTreeUtil.getParentOfType(contextElement, SimpleProperty.class); }
if (property != null) { }
return property; }
} // In this part the SimpleProperty element is extracted
} // when inside of a .simple file
} else if (context.getLanguage() == SimpleLanguage.INSTANCE) {
return super.getCustomDocumentationElement(editor, file, contextElement, targetOffset); PsiElement property =
PsiTreeUtil.getParentOfType(context, SimpleProperty.class);
if (property != null) {
return property;
}
}
}
return super.getCustomDocumentationElement(
editor, file, context, targetOffset);
} }
``` ```