Implement EnterBetweenBracesAndBracketsNoCommitDelegate

Part of #KT-22211
Part of #KT-39353
This commit is contained in:
Dmitry Gridin
2020-06-03 21:58:24 +07:00
parent e72fb755a0
commit 7a58a59114
15 changed files with 118 additions and 46 deletions
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.editor
import com.intellij.codeInsight.editorActions.enter.EnterBetweenBracesNoCommitDelegate
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.lexer.KtTokens
class EnterBetweenBracesAndBracketsNoCommitDelegate : EnterBetweenBracesNoCommitDelegate() {
override fun isCommentType(type: IElementType?): Boolean = type in KtTokens.COMMENTS
override fun isBracePair(lBrace: Char, rBrace: Char): Boolean = super.isBracePair(lBrace, rBrace) || (lBrace == '[' && rBrace == ']')
}
@@ -63,11 +63,17 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
// println(debugInfo(currentPosition)) // println(debugInfo(currentPosition))
// ~~~ TESTING ~~~ // ~~~ TESTING ~~~
val before = currentPosition.beforeWhitespacesAndComments() val before = currentPosition.beforeOptionalMix(*WHITE_SPACE_OR_COMMENT_BIT_SET)
val after = currentPosition.afterOptionalMix(*WHITE_SPACE_OR_COMMENT_BIT_SET)
when { when {
before.isAt(TemplateEntryOpen) -> { before.isAt(TemplateEntryOpen) -> {
val baseLineOffset = before.startOffset val baseLineOffset = before.startOffset
return factory.createIndentCalculator(Indent.getNormalIndent()) { baseLineOffset } val indent = if (!currentPosition.hasEmptyLineAfter(offset) && after.isAt(TemplateEntryClose))
Indent.getNoneIndent()
else
Indent.getNormalIndent()
return factory.createIndentCalculator(indent) { baseLineOffset }
} }
before.isAtAnyOf(TryKeyword, FinallyKeyword) -> return factory.createIndentCalculator( before.isAtAnyOf(TryKeyword, FinallyKeyword) -> return factory.createIndentCalculator(
@@ -75,20 +81,17 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
IndentCalculator.LINE_BEFORE, IndentCalculator.LINE_BEFORE,
) )
before.isInControlFlowStatement() -> { before.isInControlFlowStatement() -> return factory.createIndentCalculator(
val afterWhitespacesAndComments = currentPosition.afterWhitespacesAndComments() when {
return factory.createIndentCalculator( after.isAt(LeftParenthesis) -> Indent.getContinuationIndent()
when { after.isAtAnyOf(BlockOpeningBrace, Arrow) -> Indent.getNoneIndent()
afterWhitespacesAndComments.isAt(LeftParenthesis) -> Indent.getContinuationIndent() else -> Indent.getNormalIndent()
afterWhitespacesAndComments.isAtAnyOf(BlockOpeningBrace, Arrow) -> Indent.getNoneIndent() },
else -> Indent.getNormalIndent() IndentCalculator.LINE_BEFORE,
}, )
IndentCalculator.LINE_BEFORE,
)
}
} }
currentPosition.afterWhitespacesAndComments() after
.takeIf { it.isAt(TemplateEntryClose) } .takeIf { it.isAt(TemplateEntryClose) }
?.let { templateEntryPosition -> ?.let { templateEntryPosition ->
val indent = if (currentPosition.hasEmptyLineAfter(offset)) Indent.getNormalIndent() else Indent.getNoneIndent() val indent = if (currentPosition.hasEmptyLineAfter(offset)) Indent.getNormalIndent() else Indent.getNoneIndent()
@@ -100,34 +103,18 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
return null return null
} }
private fun SemanticEditorPosition.beforeWhitespacesAndComments(): SemanticEditorPosition = beforeOptionalMix(
Whitespace,
LineComment,
BlockComment,
)
private fun SemanticEditorPosition.afterWhitespacesAndComments(): SemanticEditorPosition = afterOptionalMix(
Whitespace,
LineComment,
BlockComment,
)
private fun SemanticEditorPosition.moveBeforeWhitespacesAndComments(): SemanticEditorPosition = apply {
moveBeforeOptionalMix(Whitespace, LineComment, BlockComment)
}
private fun SemanticEditorPosition.isInControlFlowStatement(): Boolean = with(copy()) { private fun SemanticEditorPosition.isInControlFlowStatement(): Boolean = with(copy()) {
if (isAt(BlockOpeningBrace)) { if (isAt(BlockOpeningBrace)) {
moveBefore() moveBefore()
moveBeforeParentheses(LeftParenthesis, RightParenthesis) moveBeforeParentheses(LeftParenthesis, RightParenthesis)
moveBeforeWhitespacesAndComments() moveBeforeOptionalMix(*WHITE_SPACE_OR_COMMENT_BIT_SET)
} }
if (currElement in CONTROL_FLOW_CONSTRUCTIONS) return true if (currElement in CONTROL_FLOW_CONSTRUCTIONS) return true
if (!isAt(RightParenthesis)) return false if (!isAt(RightParenthesis)) return false
moveBeforeParentheses(LeftParenthesis, RightParenthesis) moveBeforeParentheses(LeftParenthesis, RightParenthesis)
moveBeforeWhitespacesAndComments() moveBeforeOptionalMix(*WHITE_SPACE_OR_COMMENT_BIT_SET)
return currElement in CONTROL_FLOW_CONSTRUCTIONS return currElement in CONTROL_FLOW_CONSTRUCTIONS
} }
@@ -141,6 +128,7 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
FinallyKeyword, FinallyKeyword,
WhileKeyword, WhileKeyword,
RegularStringPart, RegularStringPart,
KDoc,
} }
companion object { companion object {
@@ -150,6 +138,7 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
KtTokens.LONG_TEMPLATE_ENTRY_END to TemplateEntryClose, KtTokens.LONG_TEMPLATE_ENTRY_END to TemplateEntryClose,
KtTokens.EOL_COMMENT to LineComment, KtTokens.EOL_COMMENT to LineComment,
KtTokens.BLOCK_COMMENT to BlockComment, KtTokens.BLOCK_COMMENT to BlockComment,
KtTokens.DOC_COMMENT to KDoc,
KtTokens.ARROW to Arrow, KtTokens.ARROW to Arrow,
KtTokens.LBRACE to BlockOpeningBrace, KtTokens.LBRACE to BlockOpeningBrace,
KtTokens.RBRACE to BlockClosingBrace, KtTokens.RBRACE to BlockClosingBrace,
@@ -165,6 +154,8 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
KtTokens.DO_KEYWORD to DoKeyword, KtTokens.DO_KEYWORD to DoKeyword,
KtTokens.FOR_KEYWORD to ForKeyword, KtTokens.FOR_KEYWORD to ForKeyword,
KtTokens.REGULAR_STRING_PART to RegularStringPart, KtTokens.REGULAR_STRING_PART to RegularStringPart,
KtTokens.LBRACKET to ArrayOpeningBracket,
KtTokens.RBRACKET to ArrayClosingBracket,
) )
private val CONTROL_FLOW_CONSTRUCTIONS: HashSet<SemanticEditorPosition.SyntaxElement> = hashSetOf( private val CONTROL_FLOW_CONSTRUCTIONS: HashSet<SemanticEditorPosition.SyntaxElement> = hashSetOf(
@@ -178,5 +169,11 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
CatchKeyword, CatchKeyword,
FinallyKeyword, FinallyKeyword,
) )
private val WHITE_SPACE_OR_COMMENT_BIT_SET: Array<SemanticEditorPosition.SyntaxElement> = arrayOf(
Whitespace,
LineComment,
BlockComment,
)
} }
} }
@@ -308,6 +308,21 @@ public class PerformanceTypingIndentationTestGenerated extends AbstractPerforman
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses.kt"); runTest("idea/testData/indentationOnNewline/InExpressionsParentheses.kt");
} }
@TestMetadata("InExpressionsParentheses2.kt")
public void testInExpressionsParentheses2() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses2.kt");
}
@TestMetadata("InExpressionsParentheses3.kt")
public void testInExpressionsParentheses3() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses3.kt");
}
@TestMetadata("InExpressionsParentheses4.kt")
public void testInExpressionsParentheses4() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses4.kt");
}
@TestMetadata("InExpressionsParenthesesBeforeOperand.kt") @TestMetadata("InExpressionsParenthesesBeforeOperand.kt")
public void testInExpressionsParenthesesBeforeOperand() throws Exception { public void testInExpressionsParenthesesBeforeOperand() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.kt"); runTest("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.kt");
+2
View File
@@ -81,6 +81,8 @@
id="KotlinEnterHandler" order="before EnterBetweenBracesHandler"/> id="KotlinEnterHandler" order="before EnterBetweenBracesHandler"/>
<enterHandlerDelegate implementation="org.jetbrains.kotlin.idea.editor.KotlinMultilineStringEnterHandler" <enterHandlerDelegate implementation="org.jetbrains.kotlin.idea.editor.KotlinMultilineStringEnterHandler"
id="KotlinMultilineStringEnterHandler" order="before EnterBetweenBracesHandler"/> id="KotlinMultilineStringEnterHandler" order="before EnterBetweenBracesHandler"/>
<enterBetweenBracesDelegate language="kotlin"
implementationClass="org.jetbrains.kotlin.idea.editor.EnterBetweenBracesAndBracketsNoCommitDelegate"/>
<lang.smartEnterProcessor language="kotlin" implementationClass="org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler"/> <lang.smartEnterProcessor language="kotlin" implementationClass="org.jetbrains.kotlin.idea.editor.KotlinSmartEnterHandler"/>
<backspaceHandlerDelegate implementation="org.jetbrains.kotlin.idea.editor.KotlinBackspaceHandler"/> <backspaceHandlerDelegate implementation="org.jetbrains.kotlin.idea.editor.KotlinBackspaceHandler"/>
<backspaceHandlerDelegate implementation="org.jetbrains.kotlin.idea.editor.KotlinStringTemplateBackspaceHandler"/> <backspaceHandlerDelegate implementation="org.jetbrains.kotlin.idea.editor.KotlinStringTemplateBackspaceHandler"/>
@@ -1,6 +0,0 @@
val somelong = 3 + 4 - (
<caret>
)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// WITHOUT_CUSTOM_LINE_INDENT_PROVIDER
@@ -3,4 +3,4 @@ val somelong = 3 + 4 - (
) )
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION // SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// WITHOUT_CUSTOM_LINE_INDENT_PROVIDER // IGNORE_FORMATTER
@@ -1,4 +1,4 @@
val somelong = 3 + 4 - (<caret>) val somelong = 3 + 4 - (<caret>)
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION // SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// WITHOUT_CUSTOM_LINE_INDENT_PROVIDER // IGNORE_FORMATTER
@@ -0,0 +1,6 @@
val somelong = 3 + 4 - (
<caret>
)
// SET_FALSE: ALIGN_MULTILINE_BINARY_OPERATION
// IGNORE_FORMATTER
@@ -0,0 +1,4 @@
val somelong = 3 + 4 - (<caret>)
// SET_FALSE: ALIGN_MULTILINE_BINARY_OPERATION
// IGNORE_FORMATTER
@@ -0,0 +1,8 @@
fun a() {
val somelong = 3 + 4 - (
<caret>
)
}
// SET_FALSE: ALIGN_MULTILINE_BINARY_OPERATION
// IGNORE_FORMATTER
@@ -0,0 +1,6 @@
fun a() {
val somelong = 3 + 4 - (<caret>)
}
// SET_FALSE: ALIGN_MULTILINE_BINARY_OPERATION
// IGNORE_FORMATTER
@@ -0,0 +1,8 @@
fun a() {
val somelong = 3 + 4 - (
<caret>
)
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// IGNORE_FORMATTER
@@ -0,0 +1,6 @@
fun a() {
val somelong = 3 + 4 - (<caret>)
}
// SET_TRUE: ALIGN_MULTILINE_BINARY_OPERATION
// IGNORE_FORMATTER
@@ -4,7 +4,7 @@ fun a() {
select select
${ ${
<caret> <caret>
} }
from T from T
""" """
} }
@@ -310,6 +310,21 @@ public class TypingIndentationTestBaseGenerated extends AbstractTypingIndentatio
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses.after.kt"); runTest("idea/testData/indentationOnNewline/InExpressionsParentheses.after.kt");
} }
@TestMetadata("InExpressionsParentheses2.after.kt")
public void testInExpressionsParentheses2() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses2.after.kt");
}
@TestMetadata("InExpressionsParentheses3.after.kt")
public void testInExpressionsParentheses3() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses3.after.kt");
}
@TestMetadata("InExpressionsParentheses4.after.kt")
public void testInExpressionsParentheses4() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses4.after.kt");
}
@TestMetadata("InExpressionsParenthesesBeforeOperand.after.kt") @TestMetadata("InExpressionsParenthesesBeforeOperand.after.kt")
public void testInExpressionsParenthesesBeforeOperand() throws Exception { public void testInExpressionsParenthesesBeforeOperand() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.after.kt"); runTest("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.after.kt");
@@ -706,11 +721,6 @@ public class TypingIndentationTestBaseGenerated extends AbstractTypingIndentatio
runTest("idea/testData/indentationOnNewline/InEnumInitializerListNotEmpty.after.inv.kt"); runTest("idea/testData/indentationOnNewline/InEnumInitializerListNotEmpty.after.inv.kt");
} }
@TestMetadata("InExpressionsParentheses.after.inv.kt")
public void testInExpressionsParentheses() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParentheses.after.inv.kt");
}
@TestMetadata("InExpressionsParenthesesBeforeOperand.after.inv.kt") @TestMetadata("InExpressionsParenthesesBeforeOperand.after.inv.kt")
public void testInExpressionsParenthesesBeforeOperand() throws Exception { public void testInExpressionsParenthesesBeforeOperand() throws Exception {
runTest("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.after.inv.kt"); runTest("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.after.inv.kt");