From 251a0270a4954a1e18b90681d8cb57c43f249756 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 17 May 2017 14:23:59 +0300 Subject: [PATCH] Make auto-indent work for multiline string with injection (KT-17942) #KT-17942 Fixed --- .../KotlinMultilineStringEnterHandler.kt | 41 ++++++++++++++++++- .../idea/refactoring/dataContextUtils.kt | 4 ++ .../spaces/enterInInjectedFragment.kt | 12 ++++++ .../AbstractMultiLineStringIndentTest.kt | 1 + .../MultiLineStringIndentTestGenerated.java | 6 +++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 idea/testData/editor/enterHandler/multilineString/spaces/enterInInjectedFragment.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/editor/KotlinMultilineStringEnterHandler.kt b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinMultilineStringEnterHandler.kt index 2d18970a1c4..8e000bd094a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/editor/KotlinMultilineStringEnterHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinMultilineStringEnterHandler.kt @@ -20,10 +20,12 @@ import com.intellij.codeInsight.CodeInsightSettings import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate.Result import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter +import com.intellij.injected.editor.EditorWindow import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.actionSystem.EditorActionHandler +import com.intellij.openapi.editor.ex.EditorEx import com.intellij.openapi.project.Project import com.intellij.openapi.util.Ref import com.intellij.openapi.util.TextRange @@ -34,6 +36,9 @@ import com.intellij.psi.PsiFile import com.intellij.psi.codeStyle.CodeStyleSettingsManager import com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.idea.KotlinFileType +import org.jetbrains.kotlin.idea.refactoring.hostEditor +import org.jetbrains.kotlin.idea.refactoring.project +import org.jetbrains.kotlin.idea.refactoring.toPsiFile import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -50,11 +55,25 @@ class KotlinMultilineStringEnterHandler : EnterHandlerDelegateAdapter() { override fun preprocessEnter( file: PsiFile, editor: Editor, caretOffset: Ref, caretAdvance: Ref, dataContext: DataContext, originalHandler: EditorActionHandler?): EnterHandlerDelegate.Result { + val offset = caretOffset.get().toInt() + if (editor !is EditorWindow) { + return preprocessEnter(file, editor, offset, originalHandler, dataContext) + } + + val hostPosition = getHostPosition(dataContext) ?: return Result.Continue + return preprocessEnter(hostPosition, originalHandler, dataContext) + } + + private fun preprocessEnter(hostPosition: HostPosition, originalHandler: EditorActionHandler?, dataContext: DataContext): Result { + val (file, editor, offset) = hostPosition + return preprocessEnter(file, editor, offset, originalHandler, dataContext) + } + + private fun preprocessEnter(file: PsiFile, editor: Editor, offset: Int, originalHandler: EditorActionHandler?, dataContext: DataContext): Result { if (file !is KtFile) return Result.Continue val document = editor.document val text = document.text - val offset = caretOffset.get().toInt() if (offset == 0 || offset >= text.length) return Result.Continue @@ -81,6 +100,15 @@ class KotlinMultilineStringEnterHandler : EnterHandlerDelegateAdapter() { } override fun postProcessEnter(file: PsiFile, editor: Editor, dataContext: DataContext): Result { + if (editor !is EditorWindow) { + return postProcessEnter(file, editor) + } + + val hostPosition = getHostPosition(dataContext) ?: return Result.Continue + return postProcessEnter(hostPosition.file, hostPosition.editor) + } + + private fun postProcessEnter(file: PsiFile, editor: Editor): Result { if (file !is KtFile) return Result.Continue if (!wasInMultilineString) return Result.Continue @@ -344,5 +372,16 @@ class KotlinMultilineStringEnterHandler : EnterHandlerDelegateAdapter() { }) } } + + private data class HostPosition(val file: PsiFile, val editor: Editor, val offset: Int) + private fun getHostPosition(dataContext: DataContext): HostPosition? { + val editor = dataContext.hostEditor as? EditorEx ?: return null + val project = dataContext.project + + val virtualFile = editor.virtualFile ?: return null + val psiFile = virtualFile.toPsiFile(project) ?: return null + + return HostPosition(psiFile, editor, editor.caretModel.offset) + } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/dataContextUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/dataContextUtils.kt index 38246fd55b0..51a52610add 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/dataContextUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/dataContextUtils.kt @@ -18,7 +18,11 @@ package org.jetbrains.kotlin.idea.refactoring import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project val DataContext.project: Project get() = CommonDataKeys.PROJECT.getData(this)!! + +val DataContext.hostEditor: Editor? + get() = CommonDataKeys.HOST_EDITOR.getData(this) \ No newline at end of file diff --git a/idea/testData/editor/enterHandler/multilineString/spaces/enterInInjectedFragment.kt b/idea/testData/editor/enterHandler/multilineString/spaces/enterInInjectedFragment.kt new file mode 100644 index 00000000000..f0039cb8c44 --- /dev/null +++ b/idea/testData/editor/enterHandler/multilineString/spaces/enterInInjectedFragment.kt @@ -0,0 +1,12 @@ +// language=HTML +val a = + """ + + """ +//----- +// language=HTML +val a = + """ + + + """ \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractMultiLineStringIndentTest.kt b/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractMultiLineStringIndentTest.kt index 5d69f665fed..3268f33f1c7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractMultiLineStringIndentTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractMultiLineStringIndentTest.kt @@ -38,6 +38,7 @@ abstract class AbstractMultiLineStringIndentTest : KotlinLightCodeInsightFixture val beforeFile = multiFileText.substringBefore(FILE_SEPARATOR).trim() val afterFile = multiFileText.substringAfter(FILE_SEPARATOR).trim() + myFixture.setCaresAboutInjection(false) myFixture.configureByText(KotlinFileType.INSTANCE, beforeFile) myFixture.type('\n') diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/MultiLineStringIndentTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/editor/MultiLineStringIndentTestGenerated.java index 26e7b370e00..0a4b4eeea31 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/editor/MultiLineStringIndentTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/editor/MultiLineStringIndentTestGenerated.java @@ -116,6 +116,12 @@ public class MultiLineStringIndentTestGenerated extends AbstractMultiLineStringI doTest(fileName); } + @TestMetadata("enterInInjectedFragment.kt") + public void testEnterInInjectedFragment() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/enterHandler/multilineString/spaces/enterInInjectedFragment.kt"); + doTest(fileName); + } + @TestMetadata("enterInLineWithMarginOnNotMargedLine.kt") public void testEnterInLineWithMarginOnNotMargedLine() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/enterHandler/multilineString/spaces/enterInLineWithMarginOnNotMargedLine.kt");