Can an IntelliJ plugin fold one-line javadoc comments?
I am writing an IntelliJ Plugin to help with coding standards and conventions at my company.
We have some requirements concerning where Javadoc should be used, and I'm creating code inspections and quick fixes for helping with that. Unfortunately, it will lead to a lot of /** {@inheritDoc} */
about the codebase, which I find ugly. I want to create some functionality in the plugin to replace this text visually in the editor with just "Inherits Javadoc". I know the editor has this functionality because it's what IntelliJ does natively with @SuppressWarning
annotations and // language=sql
comments, but I'm unsure on how to implement it in a plugin. I tried a FoldingBuilder, but it doesn't seem to do anything when the FoldingDescriptor only covers a single line. See below.
import com.intellij.lang.ASTNode
import com.intellij.lang.folding.FoldingBuilder
import com.intellij.lang.folding.FoldingDescriptor
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.FoldingGroup
import com.intellij.openapi.project.DumbAware
import com.intellij.psi.javadoc.PsiDocComment
import com.intellij.psi.util.PsiTreeUtil
class InheritDocFoldingBuilder : FoldingBuilder, DumbAware {
private val text = "{@inheritDoc}"
private val foldingGroup = FoldingGroup.newGroup("inheritDoc")
override fun buildFoldRegions(node: ASTNode, document: Document): Array<FoldingDescriptor> {
val descriptors = mutableListOf<FoldingDescriptor>()
val docComments = PsiTreeUtil.findChildrenOfType(node.psi, PsiDocComment::class.java)
for (docComment in docComments) {
if (docComment.text.contains(text)) {
descriptors.add(FoldingDescriptor(docComment.node, docComment.textRange, foldingGroup))
}
}
return descriptors.toTypedArray()
}
override fun getPlaceholderText(node: ASTNode): String? = if (isInheritDoc(node)) "Inherits Javadoc" else null
override fun isCollapsedByDefault(node: ASTNode): Boolean = isInheritDoc(node)
private fun isInheritDoc(node: ASTNode): Boolean {
return node.psi is PsiDocComment && node.text.contains(text)
}
}
If I change this so that the FoldingDescriptor
's range includes either the whitespace before or after the javadoc comment, then it works fine, except it looks weird because it appears on either the line above or below (depending on which whitespace I've included)
I also tried an InlayHintsProvider
where I custom-implemented the InlayPresentation
and tried to just draw the hint over top of the javadoc comment with a filled rectangle and a string, but it looks like the actual text of the document gets painted after everything else so it can't be covered up like that. See below
override fun collect(element: PsiElement, editor: Editor, sink: InlayHintsSink): Boolean {
if (element is PsiDocComment && element.text.contains("{@inheritDoc}")) {
val hintText = "Inherits Javadoc from parent"
val inlayPresentation = object : InlayPresentation {
override val height: Int
get() = editor.lineHeight
override val width: Int
get() = editor.component.getFontMetrics(editor.colorsScheme.getFont(EditorFontType.PLAIN))
.stringWidth(hintText)
override fun addListener(listener: PresentationListener) {}
override fun fireContentChanged(area: Rectangle) {}
override fun fireSizeChanged(previous: Dimension, current: Dimension) {}
override fun mouseClicked(event: MouseEvent, translated: Point) {}
override fun mouseMoved(event: MouseEvent, translated: Point) {}
override fun paint(g: Graphics2D, attributes: TextAttributes) {
g.color = JBColor.GRAY
g.drawString(hintText, 0, editor.ascent)
}
override fun removeListener(listener: PresentationListener) {}
override fun toString(): String = super.toString()
}
sink.addInlineElement(element.textRange.endOffset, false, inlayPresentation, true)
}
return true
}
Is there any way what I want can be done?
Thanks.
Please sign in to leave a comment.
Hi,
I think that folding builder is the right solution here, but keep in mind that Javadoc content is rendered for {@inheritDoc} in Reader mode: https://www.jetbrains.com/help/idea/reader-mode.html, so maybe there is no need for that.
Regarding the issue, please try adding order="first" to your folding builder registration in plugin.xml. Currently, probably the out-of-the-box Java folding builder for Javadoc comments takes precedence over the one you have implemented.
Karol Lewandowski Thank you! The order="first" did make it work properly if I manually right-click → fold the selection.
It's still not respecting the `isCollapsedByDefault` method though. I've changed that method to just `= true` to make sure I wasn't overlooking any code issues, but it still isn't honoring it. Any ideas there?
It should work. Maybe you expanded it manually and this editor state is reproduced after IDE restart. Verify it with other files you didn't open before.
Yep, that was it. Thanks!