Skip to content

add folding builder #92

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions src/main/java/org/nixos/idea/lang/NixFoldingBuilder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package org.nixos.idea.lang

import com.intellij.lang.ASTNode
import com.intellij.lang.folding.FoldingBuilderEx
import com.intellij.lang.folding.FoldingDescriptor
import com.intellij.openapi.editor.Document
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.util.containers.toArray
import org.nixos.idea.psi.NixBindAttr
import org.nixos.idea.psi.NixElementType
import org.nixos.idea.psi.NixElementVisitor
import org.nixos.idea.psi.NixExprApp
import org.nixos.idea.psi.NixExprAssert
import org.nixos.idea.psi.NixExprAttrs
import org.nixos.idea.psi.NixExprIf
import org.nixos.idea.psi.NixExprLambda
import org.nixos.idea.psi.NixExprLet
import org.nixos.idea.psi.NixExprList
import org.nixos.idea.psi.NixExprOpConcat
import org.nixos.idea.psi.NixExprOpUpdate
import org.nixos.idea.psi.NixExprParens
import org.nixos.idea.psi.NixExprSelect
import org.nixos.idea.psi.NixExprWith
import org.nixos.idea.psi.NixFormal
import org.nixos.idea.psi.NixFormals
import org.nixos.idea.psi.NixIndString
import org.nixos.idea.psi.NixTypes

class NixFoldingBuilder : FoldingBuilderEx() {
override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array<FoldingDescriptor> {
val descriptors = mutableListOf<FoldingDescriptor>()

root.accept(object : NixElementVisitor<Unit>() {
override fun visitExprAttrs(o: NixExprAttrs) {
o.acceptChildren(this)
descriptors.add(FoldingDescriptor(o, o.textRange))
o.bindList.forEach { it.accept(this) }
}

override fun visitBindAttr(o: NixBindAttr) {
o.expr?.accept(this)
}

override fun visitExprParens(o: NixExprParens) {
descriptors.add(FoldingDescriptor(o, o.textRange))
o.expr?.accept(this)
}

override fun visitExprWith(o: NixExprWith) {
o.exprList.forEach { it.accept(this) }
}

override fun visitExprApp(o: NixExprApp) {
o.exprList.forEach { it.accept(this) }
}

override fun visitExprIf(o: NixExprIf) {
o.acceptChildren(this)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: You could override visitElement(PsiElement) with o.acceptChildren(this). Then you can remove all the other methods that do nothing but delegating to the children.

There are also various method which only delegate to children using element-specific code. Like visitExprWith, which just calls o.exprList.forEach { it.accept(this) }. Is there a good reason for that? Otherwise, you could just remove them after overriding visitElement.

}

override fun visitExprAssert(o: NixExprAssert) {
o.exprList.forEach { it.accept(this) }
}

override fun visitIndString(o: NixIndString) {
descriptors.add(FoldingDescriptor(o, o.textRange))
}

override fun visitExprOpUpdate(o: NixExprOpUpdate) {
o.acceptChildren(this)
}

override fun visitExprOpConcat(o: NixExprOpConcat) {
o.acceptChildren(this)
}

override fun visitExprList(o: NixExprList) {
descriptors.add(FoldingDescriptor(o, o.textRange))
o.items.forEach { it.accept(this) }
}

override fun visitExprSelect(o: NixExprSelect) {
o.acceptChildren(this)
}

override fun visitExprLet(o: NixExprLet) {
descriptors.add(FoldingDescriptor(o, o.textRange))
o.bindList.forEach { it.accept(this) }
o.expr?.accept(this)
}

override fun visitFormals(o: NixFormals) {
descriptors.add(FoldingDescriptor(o, o.textRange))
o.formalList.forEach { it.accept(this) }
}

override fun visitComment(comment: PsiComment) {
descriptors.add(FoldingDescriptor(comment, comment.textRange))
}

override fun visitFormal(o: NixFormal) {
o.expr?.accept(this)
}

override fun visitExprLambda(o: NixExprLambda) {
o.expr?.accept(this)
o.formals?.accept(this)
}

override fun visitFile(file: PsiFile) {
super.visitFile(file)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question (non-blocking): Why are you calling the super-method here, and only here? The super method doesn't seem to do anything important.

file.acceptChildren(this)
}
})

return descriptors.toArray(FoldingDescriptor.EMPTY_ARRAY)
}

override fun getPlaceholderText(node: ASTNode): String? =
Copy link
Contributor

@JojOatXGME JojOatXGME Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: Looks like you could provide the placeholder text and whether the region is collapsed by default to the constructor of FoldingDescriptor. It looks like in this case, getPlaceholderText and isCollapsedByDefault could just throw an UnsupportedOperationException or trigger an assertion.

when (node.elementType) {
NixTypes.EXPR_PARENS -> "(...)";
NixTypes.MCOMMENT -> "/* ... */";
NixTypes.EXPR_ATTRS -> "{ ... }";
NixTypes.EXPR_LIST -> "[ ... ]";
NixTypes.IND_STRING -> "'' ... ''";
NixTypes.FORMALS -> "{ ... }";
else -> null
}

override fun isCollapsedByDefault(node: ASTNode): Boolean {
return false
}
}
4 changes: 4 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
language="Nix"
implementationClass="org.nixos.idea.lang.NixCommenter"/>

<lang.foldingBuilder
language="Nix"
implementationClass="org.nixos.idea.lang.NixFoldingBuilder"/>

<moveLeftRightHandler
language="Nix"
implementationClass="org.nixos.idea.lang.NixMoveElementLeftRightHandler"/>
Expand Down