support custom folding regions for Kotlin

#KT-5207 Fixed
This commit is contained in:
Dmitry Jemerov
2015-04-27 19:22:37 +02:00
parent cb553bc952
commit 3af20b5d45
3 changed files with 42 additions and 23 deletions
@@ -18,11 +18,12 @@ package org.jetbrains.kotlin.idea
import com.intellij.codeInsight.folding.JavaCodeFoldingSettings import com.intellij.codeInsight.folding.JavaCodeFoldingSettings
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import com.intellij.lang.folding.FoldingBuilderEx import com.intellij.lang.folding.CustomFoldingBuilder
import com.intellij.lang.folding.FoldingDescriptor import com.intellij.lang.folding.FoldingDescriptor
import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Document
import com.intellij.openapi.project.DumbAware import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.JetNodeTypes import org.jetbrains.kotlin.JetNodeTypes
@@ -31,15 +32,13 @@ import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetFunctionLiteral import org.jetbrains.kotlin.psi.JetFunctionLiteral
import org.jetbrains.kotlin.psi.JetImportList import org.jetbrains.kotlin.psi.JetImportList
import java.util.ArrayList
public class KotlinFoldingBuilder : FoldingBuilderEx(), DumbAware { public class KotlinFoldingBuilder : CustomFoldingBuilder(), DumbAware {
override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array<FoldingDescriptor> { override fun buildLanguageFoldRegions(descriptors: MutableList<FoldingDescriptor>,
root: PsiElement, document: Document, quick: Boolean) {
if (root !is JetFile) { if (root !is JetFile) {
return FoldingDescriptor.EMPTY return
} }
val descriptors = ArrayList<FoldingDescriptor>()
val imports = root.getImportDirectives() val imports = root.getImportDirectives()
if (imports.size() > 1) { if (imports.size() > 1) {
val importKeyword = imports.get(0).getFirstChild() val importKeyword = imports.get(0).getFirstChild()
@@ -55,7 +54,6 @@ public class KotlinFoldingBuilder : FoldingBuilderEx(), DumbAware {
} }
appendDescriptors(root.getNode(), document, descriptors) appendDescriptors(root.getNode(), document, descriptors)
return descriptors.copyToArray()
} }
private fun appendDescriptors(node: ASTNode, document: Document, descriptors: MutableList<FoldingDescriptor>) { private fun appendDescriptors(node: ASTNode, document: Document, descriptors: MutableList<FoldingDescriptor>) {
@@ -96,29 +94,23 @@ public class KotlinFoldingBuilder : FoldingBuilderEx(), DumbAware {
private fun isOneLine(textRange: TextRange, document: Document) = private fun isOneLine(textRange: TextRange, document: Document) =
document.getLineNumber(textRange.getStartOffset()) == document.getLineNumber(textRange.getEndOffset()) document.getLineNumber(textRange.getStartOffset()) == document.getLineNumber(textRange.getEndOffset())
override fun getPlaceholderText(node: ASTNode): String? { override fun getLanguagePlaceholderText(node: ASTNode, range: TextRange): String = when {
if (node.getElementType() == JetTokens.BLOCK_COMMENT) { node.getElementType() == JetTokens.BLOCK_COMMENT -> "/.../"
return "/.../" node.getElementType() == KDocTokens.KDOC -> "/**...*/"
} node.getPsi() is JetImportList -> "..."
if (node.getElementType() == KDocTokens.KDOC) { else -> "{...}"
return "/**...*/"
}
if (node.getPsi() is JetImportList) {
return "..."
}
return "{...}"
} }
override fun isCollapsedByDefault(astNode: ASTNode): Boolean { override fun isRegionCollapsedByDefault(node: ASTNode): Boolean {
val settings = JavaCodeFoldingSettings.getInstance() val settings = JavaCodeFoldingSettings.getInstance()
if (astNode.getPsi() is JetImportList) { if (node.getPsi() is JetImportList) {
return settings.isCollapseImports() return settings.isCollapseImports()
} }
val type = astNode.getElementType() val type = node.getElementType()
if (type == JetTokens.BLOCK_COMMENT || type == KDocTokens.KDOC) { if (type == JetTokens.BLOCK_COMMENT || type == KDocTokens.KDOC) {
if (isFirstElementInFile(astNode.getPsi())) { if (isFirstElementInFile(node.getPsi())) {
return settings.isCollapseFileHeader() return settings.isCollapseFileHeader()
} }
} }
@@ -126,6 +118,9 @@ public class KotlinFoldingBuilder : FoldingBuilderEx(), DumbAware {
return false return false
} }
override fun isCustomFoldingRoot(node: ASTNode)
= node.getElementType() == JetNodeTypes.BLOCK || node.getElementType() == JetNodeTypes.CLASS_BODY
private fun isFirstElementInFile(element: PsiElement): Boolean { private fun isFirstElementInFile(element: PsiElement): Boolean {
val parent = element.getParent() val parent = element.getParent()
if (parent is JetFile) { if (parent is JetFile) {
@@ -0,0 +1,18 @@
class Foo <fold text='{...}' expand='true'>{
<fold text='Methods' expand='true'>// <editor-fold desc="Methods">
fun foo() {}
fun bar() <fold text='{...}' expand='true'>{
}</fold>
// </editor-fold></fold>
fun xyzzy() <fold text='{...}' expand='true'>{
<fold text='Body' expand='true'>// <editor-fold desc="Body">
printn("Xyzzy")
printn("Xyzzy")
printn("Xyzzy")
// </editor-fold></fold>
}</fold>
}</fold>
@@ -88,6 +88,12 @@ public class KotlinFoldingTestGenerated extends AbstractKotlinFoldingTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/folding/checkCollapse"), Pattern.compile("^(.+)\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/folding/checkCollapse"), Pattern.compile("^(.+)\\.kt$"), true);
} }
@TestMetadata("customRegions.kt")
public void testCustomRegions() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/folding/checkCollapse/customRegions.kt");
doSettingsFoldingTest(fileName);
}
@TestMetadata("functionLiteral.kt") @TestMetadata("functionLiteral.kt")
public void testFunctionLiteral() throws Exception { public void testFunctionLiteral() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/folding/checkCollapse/functionLiteral.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/folding/checkCollapse/functionLiteral.kt");