diff --git a/build.gradle.kts b/build.gradle.kts
index 6ce33aa..2e3eab6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -68,7 +68,7 @@ intellij {
.mapNotNull { fromToolbox(root, it) }.firstOrNull()
pycharmPath?.absolutePath?.let { alternativeIdePath = it }
- setPlugins("PsiViewer:192-SNAPSHOT")
+ setPlugins("PsiViewer:191.4212")
}
java {
diff --git a/res/META-INF/change-notes.html b/res/META-INF/change-notes.html
index a215a99..c33e0fc 100644
--- a/res/META-INF/change-notes.html
+++ b/res/META-INF/change-notes.html
@@ -2,6 +2,7 @@
- IntelliJ Platform 2019.2 compatibility
- Tons of internal refactorings: generate more codes
+ - CubicalTT folding
0.4.2
diff --git a/res/META-INF/description.html b/res/META-INF/description.html
index 9bc36e8..aec923f 100644
--- a/res/META-INF/description.html
+++ b/res/META-INF/description.html
@@ -84,6 +84,7 @@ Features (listed for each supported language):
- Running (type checking) your code
- Live template contexts
- Executable (cubical) management
+ - Folding code blocks and imports
- Syntax highlighter, color settings page
- Completion/find usages/goto declaration
- Stub indices, goto symbol (search everywhere)
diff --git a/res/META-INF/plugin.xml b/res/META-INF/plugin.xml
index 08cf761..ba894d9 100644
--- a/res/META-INF/plugin.xml
+++ b/res/META-INF/plugin.xml
@@ -64,6 +64,7 @@
+
diff --git a/src/org/ice1000/tt/editing/cubicaltt/folding.kt b/src/org/ice1000/tt/editing/cubicaltt/folding.kt
new file mode 100644
index 0000000..ba2164f
--- /dev/null
+++ b/src/org/ice1000/tt/editing/cubicaltt/folding.kt
@@ -0,0 +1,75 @@
+package org.ice1000.tt.editing.cubicaltt
+
+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.openapi.project.DumbAware
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiComment
+import com.intellij.psi.PsiElement
+import com.intellij.psi.TokenType
+import org.ice1000.tt.FOLDING_PLACEHOLDER
+import org.ice1000.tt.editing.collectFoldRegions
+import org.ice1000.tt.psi.*
+import org.ice1000.tt.psi.cubicaltt.*
+
+class CubicalTTFoldingBuilder : FoldingBuilderEx(), DumbAware {
+ override fun getPlaceholderText(node: ASTNode) = when (node.elementType) {
+ CubicalTTTokenType.BLOCK_COMMENT -> "{---}"
+ CubicalTTTypes.SYSTEM -> "[$FOLDING_PLACEHOLDER]"
+ else -> FOLDING_PLACEHOLDER
+ }
+
+ override fun isCollapsedByDefault(node: ASTNode) = false
+
+ override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array {
+ if (root !is CubicalTTFileImpl) return emptyArray()
+ return collectFoldRegions(root) { FoldingVisitor(it, document) }
+ }
+}
+
+private class FoldingVisitor(
+ private val descriptors: MutableList,
+ private val document: Document
+) : CubicalTTVisitor() {
+ override fun visitData(o: CubicalTTData) {
+ val labels = o.labelList.takeIf { it.size > 1 } ?: return
+ descriptors += FoldingDescriptor(o, TextRange(labels.first().startOffset, labels.last().endOffset))
+ }
+
+ override fun visitSystem(o: CubicalTTSystem) {
+ val startLine = document.getLineNumber(o.startOffset)
+ val endLine = document.getLineNumber(o.endOffset)
+ if (startLine != endLine) descriptors.add(FoldingDescriptor(o, o.textRange))
+ }
+
+ override fun visitComment(comment: PsiComment?) {
+ if (comment?.elementType == CubicalTTTokenType.BLOCK_COMMENT)
+ descriptors += FoldingDescriptor(comment, comment.textRange)
+ }
+
+ override fun visitSplitBody(o: CubicalTTSplitBody) = layout(o)
+ override fun visitExpWhere(o: CubicalTTExpWhere) = layout(o)
+ override fun visitMutual(o: CubicalTTMutual) = layout(o)
+ override fun visitLetExp(o: CubicalTTLetExp) {
+ val layoutStart = o.childrenWithLeaves.firstOrNull { it.elementType == CubicalTTTypes.LAYOUT_START } ?: return
+ val layoutEnd = layoutStart.rightSiblings.firstOrNull {
+ it.elementType == CubicalTTTypes.KW_IN
+ }?.prevSiblingIgnoring(TokenType.WHITE_SPACE) ?: return
+ descriptors += FoldingDescriptor(o, TextRange(layoutStart.startOffset, layoutEnd.endOffset))
+ }
+
+ private fun layout(o: PsiElement) {
+ val layoutStart = o.childrenWithLeaves.firstOrNull { it.elementType == CubicalTTTypes.LAYOUT_START } ?: return
+ val layoutEnd = layoutStart.rightSiblings.firstOrNull { it.elementType == CubicalTTTypes.LAYOUT_END } ?: o.lastChild
+ ?: return
+ descriptors += FoldingDescriptor(o, TextRange(layoutStart.startOffset, layoutEnd.endOffset))
+ }
+
+ override fun visitModule(o: CubicalTTModule) {
+ val imports = o.importList.takeIf { it.size > 1 } ?: return
+ val startOffset = imports.first().moduleUsage?.startOffset ?: return
+ descriptors += FoldingDescriptor(o, TextRange(startOffset, imports.last().endOffset))
+ }
+}
diff --git a/src/org/ice1000/tt/editing/redprl/folding.kt b/src/org/ice1000/tt/editing/redprl/folding.kt
index 931aefe..2bedb39 100644
--- a/src/org/ice1000/tt/editing/redprl/folding.kt
+++ b/src/org/ice1000/tt/editing/redprl/folding.kt
@@ -37,7 +37,6 @@ private class FoldingVisitor(
private val document: Document
) : RedPrlVisitor() {
-
override fun visitComment(comment: PsiComment?) {
if (comment?.elementType == RedPrlTokenType.BLOCK_COMMENT)
descriptors += FoldingDescriptor(comment, comment.textRange)