20. Documentation
A DocumentationProvider
helps users by showing documentation for symbols like method calls inside the editor. 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.
Implement a Documentation Provider and Register the EP
In the first step, we create an empty class that extends AbstractDocumentationProvider
and register it in the plugin.xml.
Make sure the extension is registered in the plugin.xml as shown below:
Ensure That the Correct PSI Element Is Used
For the Simple Language, we consider two use-cases:
A Simple key is used inside a Java string literal, and we would like to show documentation for the key/value right from the reference inside the Java file.
The cursor is already over a key/value definition inside a Simple file, in which case we would also like to show its documentation.
To ensure that the IntelliJ Platform chooses the correct element of type SimpleProperty
when is called, we create a dummy implementation of generateDoc()
:
Now, we set a breakpoint in our dummy implementation, debug the plugin, and call
for the Simple property both in the Java file and the Simple file. We do this by placing the cursor over the key and invoking to show the documentation.In both cases, we find that the element provided is SimplePropertyImpl
, which is exactly what we hoped for. However, there are two drawbacks: inside a Java string, your cursor needs to be directly over key
in the string "simple:key"
to make Quick Documentation work. Since the Simple Language only allows for one property per string, it would be nice if Quick Documentation worked no matter where your cursor was positioned in the string as long as the string contained a Simple property. Inside a Simple file, the situation is similar, and calling only works when the cursor is positioned on the key.
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
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. Since we would like to show this comment in the documentation as well, we need a small helper function that extracts the text from the comment. This function will reside in the SimpleUtil
class and will find, for instance, the comment preceding apikey
in the following short example:
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. 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.
Render the Documentation
With easy ways to access the key, the value, the file, and a possible documentation comment, we now have everything in place to provide a useful implementation of generateDoc()
.
The creation of the rendered documentation is done in a separate method for clarity. It uses DocumentationMarkup
to align and format the contents.
The addKeyValueSection()
method used is just a small helper function to reduce repetition.
After implementing all the steps above, the IDE will show the rendered documentation for a Simple key when called with
.Implement Additional Functionality
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. It's not necessary that this popup shows the exact same information as when calling Quick Documentation, but for the purpose of this tutorial, we'll do just that.
When the mouse hovers over code with Ctrl/Cmd pressed, the IDE shows navigation information of the symbol under the cursor, such as its namespace or package. The implementation below will show the Simple key and the file where it is defined.
Finally, SimpleProperty
and no additional work needs to be done. In other circumstances, you can override getDocumentationElementForLookupItem()
and return the correct PSI element.
Addendum: Choosing a Better Target Element
To be able to call
for Simple properties in all places of a Java string literal, two steps are required:The extension point needs to be changed from
lang.documentationProvider
todocumentationProvider
because only then the Simple DocumentationProvider is called for PSI elements with a different language.The
getCustomDocumentationElement()
method needs to be implemented to find the correct target PSI element for creating the documentation.
Therefore, the current version of the code could be extended to check whether PsiReference
functionalities to determine the correct target element. This allows getting documentation for a Simple property no matter where it was called inside a Java string literal or a Simple property definition.