Better indententation on enter in lambdas

This commit is contained in:
Nikolay Krasko
2014-05-08 19:52:35 +04:00
parent 109f7992b4
commit 3f96b4775f
21 changed files with 228 additions and 2 deletions
+1
View File
@@ -6,6 +6,7 @@
<w>kdoc</w>
<w>memoized</w>
<w>multiline</w>
<w>preprocess</w>
<w>redeclarations</w>
<w>subclassed</w>
<w>subgraph</w>
+3
View File
@@ -268,7 +268,10 @@
<extendWordSelectionHandler implementation="org.jetbrains.jet.plugin.editor.wordSelection.JetStatementGroupSelectioner"/>
<extendWordSelectionHandler implementation="org.jetbrains.jet.plugin.editor.wordSelection.JetCodeBlockSelectioner"/>
<extendWordSelectionHandler implementation="org.jetbrains.jet.plugin.editor.wordSelection.JetListSelectioner"/>
<typedHandler implementation="org.jetbrains.jet.plugin.editor.KotlinTypedHandler"/>
<enterHandlerDelegate implementation="org.jetbrains.jet.plugin.editor.KotlinEnterHandler"
id="KotlinEnterHandler" order="before EnterBetweenBracesHandler"/>
<backspaceHandlerDelegate implementation="org.jetbrains.jet.plugin.editor.KotlinBackspaceHandler"/>
<copyPastePostProcessor implementation="org.jetbrains.jet.plugin.conversion.copy.ConvertJavaCopyPastePostProcessor"/>
@@ -134,7 +134,7 @@ public class CodeInsightUtils {
}
@Nullable
private static PsiElement getElementAtOffsetIgnoreWhitespaceBefore(@NotNull PsiFile file, int offset) {
public static PsiElement getElementAtOffsetIgnoreWhitespaceBefore(@NotNull PsiFile file, int offset) {
PsiElement element = file.findElementAt(offset);
if (element instanceof PsiWhiteSpace) {
return file.findElementAt(element.getTextRange().getEndOffset());
@@ -143,7 +143,7 @@ public class CodeInsightUtils {
}
@Nullable
private static PsiElement getElementAtOffsetIgnoreWhitespaceAfter(@NotNull PsiFile file, int offset) {
public static PsiElement getElementAtOffsetIgnoreWhitespaceAfter(@NotNull PsiFile file, int offset) {
PsiElement element = file.findElementAt(offset - 1);
if (element instanceof PsiWhiteSpace) {
return file.findElementAt(element.getTextRange().getStartOffset() - 1);
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.editor
import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter
import com.intellij.psi.PsiFile
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.Ref
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.actionSystem.EditorActionHandler
import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate
import com.intellij.codeInsight.CodeInsightSettings
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.jet.lang.psi.JetFile
import com.intellij.util.IncorrectOperationException
import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.lang.psi.JetFunctionLiteral
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.PsiWhiteSpace
public class KotlinEnterHandler: EnterHandlerDelegateAdapter() {
class object {
private val LOG = Logger.getInstance(javaClass<KotlinEnterHandler>())
private val FORCE_INDENT_IN_LAMBDA_AFTER = TokenSet.create(JetTokens.ARROW, JetTokens.LBRACE)
}
override fun preprocessEnter(
file: PsiFile,
editor: Editor,
caretOffsetRef: Ref<Int>,
caretAdvance: Ref<Int>,
dataContext: DataContext,
originalHandler: EditorActionHandler?
): EnterHandlerDelegate.Result? {
if (file !is JetFile) return EnterHandlerDelegate.Result.Continue
if (!CodeInsightSettings.getInstance()!!.SMART_INDENT_ON_ENTER) return EnterHandlerDelegate.Result.Continue
val document = editor.getDocument()
val text = document.getCharsSequence()
val caretOffset = caretOffsetRef.get()!!.toInt()
if (caretOffset !in 0..text.length()) return EnterHandlerDelegate.Result.Continue
val elementAt = file.findElementAt(caretOffset)
if (elementAt is PsiWhiteSpace && ("\n" in elementAt.getText()!!)) return EnterHandlerDelegate.Result.Continue
// Indent for LBRACE can be removed after fixing IDEA-124917
val elementBefore = CodeInsightUtils.getElementAtOffsetIgnoreWhitespaceAfter(file, caretOffset);
val elementAfter = CodeInsightUtils.getElementAtOffsetIgnoreWhitespaceBefore(file, caretOffset);
val isAfterLBraceOrArrow = elementBefore != null && elementBefore.getNode()!!.getElementType() in FORCE_INDENT_IN_LAMBDA_AFTER
val isBeforeRBrace = elementAfter == null || elementAfter.getNode()!!.getElementType() == JetTokens.RBRACE
if (isAfterLBraceOrArrow && isBeforeRBrace && (elementBefore!!.getParent() is JetFunctionLiteral)) {
originalHandler?.execute(editor, dataContext)
PsiDocumentManager.getInstance(file.getProject()).commitDocument(document)
try {
CodeStyleManager.getInstance(file.getProject())!!.adjustLineIndent(file, editor.getCaretModel().getOffset())
}
catch (e: IncorrectOperationException) {
LOG.error(e);
}
return EnterHandlerDelegate.Result.DefaultForceIndent
}
return EnterHandlerDelegate.Result.Continue
}
}
@@ -0,0 +1,3 @@
val a: (String) -> String = { some ->
<caret>
}
@@ -0,0 +1 @@
val a: (String) -> String = { some -><caret>}
@@ -0,0 +1,3 @@
val a: (String) -> String = { some ->
<caret>
}
@@ -0,0 +1 @@
val a: (String) -> String = { some -> <caret> }
@@ -0,0 +1,3 @@
val a: (String) -> String = {
<caret>some ->
}
@@ -0,0 +1,2 @@
val a: (String) -> String = { <caret>some ->
}
@@ -0,0 +1,10 @@
class Test {
fun foo(f: (String) -> String): Test = this
}
fun test() {
val abc = Test().foo()?.foo({ "str" }).foo {
<caret>
}
}
@@ -0,0 +1,8 @@
class Test {
fun foo(f: (String) -> String): Test = this
}
fun test() {
val abc = Test().foo()?.foo({ "str" }).foo {<caret>}
}
@@ -0,0 +1,9 @@
class Test {
fun foo(f: (String) -> String): Test = this
}
fun test() {
val abc = Test().foo()?.foo({ "str" }).foo {
<caret>
}
}
@@ -0,0 +1,8 @@
class Test {
fun foo(f: (String) -> String): Test = this
}
fun test() {
val abc = Test().foo()?.foo({ "str" }).foo { <caret> }
}
@@ -0,0 +1,11 @@
class Test {
fun foo(f: (String) -> String): Test = this
}
fun test() {
val abc = Test()
.foo { "Str" }
.foo {
<caret>
}
}
@@ -0,0 +1,9 @@
class Test {
fun foo(f: (String) -> String): Test = this
}
fun test() {
val abc = Test()
.foo { "Str" }
.foo {<caret>}
}
@@ -0,0 +1,11 @@
class Test {
fun foo(f: (String) -> String): Test = this
}
fun test() {
val abc = Test()
.foo { "Str" }
.foo {
<caret>
}
}
@@ -0,0 +1,9 @@
class Test {
fun foo(f: (String) -> String): Test = this
}
fun test() {
val abc = Test()
.foo { "Str" }
.foo { <caret> }
}
@@ -0,0 +1,4 @@
val a: (String) -> String = {
some ->
<caret>
}
@@ -0,0 +1,3 @@
val a: (String) -> String = {
some -><caret>
}
@@ -164,6 +164,46 @@ public class JetTypingIndentationTestBaseGenerated extends AbstractJetTypingInde
doNewlineTest("idea/testData/indentationOnNewline/InExpressionsParenthesesBeforeOperand.after.kt");
}
@TestMetadata("InLabmdaAfterArrow.after.kt")
public void testInLabmdaAfterArrow() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InLabmdaAfterArrow.after.kt");
}
@TestMetadata("InLambdaAfterArrowWithSpaces.after.kt")
public void testInLambdaAfterArrowWithSpaces() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InLambdaAfterArrowWithSpaces.after.kt");
}
@TestMetadata("InLambdaBeforeParams.after.kt")
public void testInLambdaBeforeParams() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InLambdaBeforeParams.after.kt");
}
@TestMetadata("InLambdaInsideChainCallSameLine.after.kt")
public void testInLambdaInsideChainCallSameLine() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InLambdaInsideChainCallSameLine.after.kt");
}
@TestMetadata("InLambdaInsideChainCallSameLineWithSpaces.after.kt")
public void testInLambdaInsideChainCallSameLineWithSpaces() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InLambdaInsideChainCallSameLineWithSpaces.after.kt");
}
@TestMetadata("InLambdaInsideChainCallWithNewLine.after.kt")
public void testInLambdaInsideChainCallWithNewLine() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InLambdaInsideChainCallWithNewLine.after.kt");
}
@TestMetadata("InLambdaInsideChainCallWithNewLineWithSpaces.after.kt")
public void testInLambdaInsideChainCallWithNewLineWithSpaces() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InLambdaInsideChainCallWithNewLineWithSpaces.after.kt");
}
@TestMetadata("InMultilineLambdaAfterArrow.after.kt")
public void testInMultilineLambdaAfterArrow() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/InMultilineLambdaAfterArrow.after.kt");
}
@TestMetadata("NotFirstParameter.after.kt")
public void testNotFirstParameter() throws Exception {
doNewlineTest("idea/testData/indentationOnNewline/NotFirstParameter.after.kt");