LineIndentProvider: support inside block body between { and first statement/expression

Part of #KT-22211
This commit is contained in:
Dmitry Gridin
2020-06-10 17:40:45 +07:00
parent 63a0b5bfde
commit da5b2cfb64
3 changed files with 71 additions and 24 deletions
@@ -71,6 +71,9 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
before.isAt(BlockOpeningBrace) && after.isAt(BlockClosingBrace) && !currentPosition.hasLineBreaksAfter(offset) -> before.isAt(BlockOpeningBrace) && after.isAt(BlockClosingBrace) && !currentPosition.hasLineBreaksAfter(offset) ->
return factory.createIndentCalculator(Indent.getNoneIndent(), before.startOffset) return factory.createIndentCalculator(Indent.getNoneIndent(), before.startOffset)
before.isAt(BlockOpeningBrace) && before.beforeIgnoringWhiteSpaceOrComment().isFunctionDeclaration() ->
return factory.createIndentCalculator(Indent.getNormalIndent(), before.startOffset)
after.isAt(Quest) && after.after().isAt(Colon) -> { after.isAt(Quest) && after.after().isAt(Colon) -> {
val indent = if (settings.continuationIndentInElvis) val indent = if (settings.continuationIndentInElvis)
Indent.getContinuationIndent() Indent.getContinuationIndent()
@@ -102,7 +105,7 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
} }
before.isAt(Eq) -> { before.isAt(Eq) -> {
val declaration = findFunctionOrPropertyDeclarationBefore(before.copyAnd { it.moveBeforeIgnoringWhiteSpaceOrComment() }) val declaration = findFunctionOrPropertyOrMultiDeclarationBefore(before.beforeIgnoringWhiteSpaceOrComment())
if (declaration != null) { if (declaration != null) {
val indent = if (settings.continuationIndentForExpressionBodies) val indent = if (settings.continuationIndentForExpressionBodies)
Indent.getContinuationIndent() Indent.getContinuationIndent()
@@ -117,7 +120,7 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
factory.createIndentCalculatorForParenthesis(before, currentPosition, after, offset, settings)?.let { return it } factory.createIndentCalculatorForParenthesis(before, currentPosition, after, offset, settings)?.let { return it }
} }
findFunctionOrPropertyDeclarationBefore(before)?.let { findFunctionOrPropertyOrMultiDeclarationBefore(before)?.let {
return factory.createIndentCalculator(Indent.getNoneIndent(), it.startOffset) return factory.createIndentCalculator(Indent.getNoneIndent(), it.startOffset)
} }
@@ -149,7 +152,7 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
if (settings.alignWhenMultilineFunctionParentheses) createAlignMultilineIndent(leftParenthesis) else Indent.getNoneIndent() if (settings.alignWhenMultilineFunctionParentheses) createAlignMultilineIndent(leftParenthesis) else Indent.getNoneIndent()
} }
findFunctionKeywordBeforeIdentifier(leftParenthesis.copyAnd { it.moveBeforeIgnoringWhiteSpaceOrComment() })?.let { findFunctionKeywordBeforeIdentifier(leftParenthesis.beforeIgnoringWhiteSpaceOrComment())?.let {
return createIndentCalculator(indentForParentheses, it.startOffset) return createIndentCalculator(indentForParentheses, it.startOffset)
} }
@@ -162,7 +165,7 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
return createIndentCalculator(Indent.getNoneIndent(), leftParenthesis.startOffset) return createIndentCalculator(Indent.getNoneIndent(), leftParenthesis.startOffset)
} }
leftParenthesis.copyAnd { it.moveBeforeIgnoringWhiteSpaceOrComment() }.let { keyword -> leftParenthesis.beforeIgnoringWhiteSpaceOrComment().let { keyword ->
if (keyword.isControlFlowKeyword()) { if (keyword.isControlFlowKeyword()) {
return createIndentCalculator(Indent.getNoneIndent(), keyword.startOffset) return createIndentCalculator(Indent.getNoneIndent(), keyword.startOffset)
} }
@@ -180,36 +183,76 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
} }
/** /**
* @param declarationPosition is position before '=' for expression body or '{' * @receiver is position before '=' for expression body or '{' for block body
*/ */
private fun findFunctionOrPropertyDeclarationBefore(declarationPosition: SemanticEditorPosition): SemanticEditorPosition? { private fun SemanticEditorPosition.isFunctionDeclaration(): Boolean = findFunctionDeclarationBeforeBody(this) != null
/**
* @param endOfDeclaration is position before '=' for expression body or '{' for block body
*/
private fun findFunctionOrPropertyOrMultiDeclarationBefore(endOfDeclaration: SemanticEditorPosition): SemanticEditorPosition? =
findFunctionDeclarationBeforeBody(endOfDeclaration)
?: findPropertyDeclarationBeforeAssignment(endOfDeclaration)
?: findMultiDeclarationBeforeAssignment(endOfDeclaration)
/**
* `val (a, b) = 1 to 2`
* ^
*/
private fun findMultiDeclarationBeforeAssignment(rightParenthesis: SemanticEditorPosition): SemanticEditorPosition? {
if (!rightParenthesis.isAt(RightParenthesis)) return null
return with(rightParenthesis.copy()) {
if (!moveBeforeParenthesesIfPossible()) return null
takeIf { isVarOrVal() }
}
}
/**
* `val a = 5`
* `val a: Int = 5`
* `val List<Int>.a: Int = 5`
* `val <T> List<Int>.a: Int = 5`
*/
private fun findPropertyDeclarationBeforeAssignment(endOfDeclaration: SemanticEditorPosition): SemanticEditorPosition? {
// `val a = 5` // `val a = 5`
// this is false positive for declaration with explicit return type // this is a false positive for a declaration with explicit return type
if (declarationPosition.isAt(Identifier)) { if (endOfDeclaration.isAt(Identifier)) {
findPropertyKeywordBeforeIdentifier(declarationPosition)?.let { return it } findPropertyKeywordBeforeIdentifier(endOfDeclaration)?.let { return it }
} }
return with(declarationPosition.copy()) { return with(endOfDeclaration.copy()) {
// explicit type `fun a(): String` or `val a: String` // explicit type `fun a(): String` or `val a: String`
if (moveBeforeTypeQualifierIfPossible(true)) { if (moveBeforeTypeQualifierIfPossible(true)) {
if (!isAt(Colon)) return null if (!isAt(Colon)) return null
moveBeforeIgnoringWhiteSpaceOrComment() moveBeforeIgnoringWhiteSpaceOrComment()
} }
if (isAt(RightParenthesis)) { findPropertyKeywordBeforeIdentifier(this)
if (!moveBeforeParenthesesIfPossible()) return null
// destructuring declaration `val (a, b)`
if (isVarOrVal())
this
else
findFunctionKeywordBeforeIdentifier(this)
} else {
findPropertyKeywordBeforeIdentifier(this)
}
} }
} }
/**
* `val a = fun() { }`
* `val a = fun String.Companion????.() { }`
* `fun a() = 4`
* `fun a(): Int = 4`
* `fun Int.a(): Int = 4`
* `fun <T> T.a(): Int = 4`
*/
private fun findFunctionDeclarationBeforeBody(endOfDeclaration: SemanticEditorPosition): SemanticEditorPosition? =
with(endOfDeclaration.copy()) {
// explicit type `fun a(): String`
// ^
if (moveBeforeTypeQualifierIfPossible(true)) {
if (!isAt(Colon)) return null
moveBeforeIgnoringWhiteSpaceOrComment()
}
if (!moveBeforeParenthesesIfPossible()) return null
findFunctionKeywordBeforeIdentifier(this)
}
private fun findPropertyKeywordBeforeIdentifier(identifierPosition: SemanticEditorPosition): SemanticEditorPosition? { private fun findPropertyKeywordBeforeIdentifier(identifierPosition: SemanticEditorPosition): SemanticEditorPosition? {
if (!identifierPosition.isAt(Identifier)) return null if (!identifierPosition.isAt(Identifier)) return null
return with(identifierPosition.copy()) { return with(identifierPosition.copy()) {
@@ -226,12 +269,14 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
*/ */
private fun findFunctionKeywordBeforeIdentifier(identifierPosition: SemanticEditorPosition): SemanticEditorPosition? { private fun findFunctionKeywordBeforeIdentifier(identifierPosition: SemanticEditorPosition): SemanticEditorPosition? {
// anonymous function `val a = fun() { }` // anonymous function `val a = fun() { }`
// ^
if (identifierPosition.isAt(FunctionKeyword)) return identifierPosition if (identifierPosition.isAt(FunctionKeyword)) return identifierPosition
return with(identifierPosition.copy()) { return with(identifierPosition.copy()) {
moveBeforeWhileThisIsWhiteSpaceOrComment() moveBeforeWhileThisIsWhiteSpaceOrComment()
// anonymous function with receiver `val a = fun String.Companion????.() { }` // anonymous function with receiver `val a = fun String.Companion????.() { }`
// ^
if (isAt(Dot)) { if (isAt(Dot)) {
moveBeforeIgnoringWhiteSpaceOrComment() moveBeforeIgnoringWhiteSpaceOrComment()
if (!moveBeforeTypeQualifierIfPossible(true)) return null if (!moveBeforeTypeQualifierIfPossible(true)) return null
@@ -453,6 +498,8 @@ abstract class KotlinLikeLangLineIndentProvider : JavaLikeLangLineIndentProvider
moveBeforeWhileThisIsWhiteSpaceOrComment() moveBeforeWhileThisIsWhiteSpaceOrComment()
} }
private fun SemanticEditorPosition.beforeIgnoringWhiteSpaceOrComment() = copyAnd { it.moveBeforeIgnoringWhiteSpaceOrComment() }
private enum class KotlinElement : SemanticEditorPosition.SyntaxElement { private enum class KotlinElement : SemanticEditorPosition.SyntaxElement {
TemplateEntryOpen, TemplateEntryOpen,
TemplateEntryClose, TemplateEntryClose,
+2 -2
View File
@@ -1,8 +1,8 @@
object Test { // TODO restore correct behavior object Test { // TODO restore correct behavior
// some // some
fun test() { fun test() {
<caret> <caret>
} }
} }
// WITHOUT_CUSTOM_LINE_INDENT_PROVIDER // IGNORE_FORMATTER
+1 -1
View File
@@ -4,4 +4,4 @@ object Test { // TODO restore correct behavior
} }
} }
// WITHOUT_CUSTOM_LINE_INDENT_PROVIDER // IGNORE_FORMATTER