Make auto-indent work for multiline string with injection (KT-17942)

#KT-17942 Fixed
This commit is contained in:
Nikolay Krasko
2017-05-17 14:23:59 +03:00
parent e5822c76fb
commit 251a0270a4
5 changed files with 63 additions and 1 deletions
@@ -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<Int>, caretAdvance: Ref<Int>, 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)
}
}
}
@@ -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)
@@ -0,0 +1,12 @@
// language=HTML
val a =
"""
<html><caret>
</html>"""
//-----
// language=HTML
val a =
"""
<html>
<caret>
</html>"""
@@ -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')
@@ -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");