split string literal if Enter is pressed in the middle
#KT-6308 Fixed
This commit is contained in:
@@ -16,24 +16,26 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.editor
|
package org.jetbrains.kotlin.idea.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.codeInsight.CodeInsightSettings
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate
|
||||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
import com.intellij.util.IncorrectOperationException
|
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
|
||||||
import org.jetbrains.kotlin.psi.JetFunctionLiteral
|
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.psi.tree.TokenSet
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.editor.actionSystem.EditorActionHandler
|
||||||
|
import com.intellij.openapi.util.Ref
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiWhiteSpace
|
import com.intellij.psi.PsiWhiteSpace
|
||||||
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
|
import com.intellij.psi.tree.TokenSet
|
||||||
|
import com.intellij.util.IncorrectOperationException
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isSingleQuoted
|
||||||
|
|
||||||
public class KotlinEnterHandler: EnterHandlerDelegateAdapter() {
|
public class KotlinEnterHandler: EnterHandlerDelegateAdapter() {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -50,6 +52,11 @@ public class KotlinEnterHandler: EnterHandlerDelegateAdapter() {
|
|||||||
originalHandler: EditorActionHandler?
|
originalHandler: EditorActionHandler?
|
||||||
): EnterHandlerDelegate.Result? {
|
): EnterHandlerDelegate.Result? {
|
||||||
if (file !is JetFile) return EnterHandlerDelegate.Result.Continue
|
if (file !is JetFile) return EnterHandlerDelegate.Result.Continue
|
||||||
|
|
||||||
|
if (preprocessEnterInStringLiteral(file, editor, caretOffsetRef, caretAdvance)) {
|
||||||
|
return EnterHandlerDelegate.Result.DefaultForceIndent
|
||||||
|
}
|
||||||
|
|
||||||
if (!CodeInsightSettings.getInstance()!!.SMART_INDENT_ON_ENTER) return EnterHandlerDelegate.Result.Continue
|
if (!CodeInsightSettings.getInstance()!!.SMART_INDENT_ON_ENTER) return EnterHandlerDelegate.Result.Continue
|
||||||
|
|
||||||
val document = editor.getDocument()
|
val document = editor.getDocument()
|
||||||
@@ -84,4 +91,36 @@ public class KotlinEnterHandler: EnterHandlerDelegateAdapter() {
|
|||||||
|
|
||||||
return EnterHandlerDelegate.Result.Continue
|
return EnterHandlerDelegate.Result.Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can't use the core platform logic (EnterInStringLiteralHandler) because it assumes that the string
|
||||||
|
// is a single token and the first character of the token is an opening quote. In the case of Kotlin,
|
||||||
|
// the opening quote is a separate token and the first character of the string token is just a random letter.
|
||||||
|
private fun preprocessEnterInStringLiteral(psiFile: PsiFile,
|
||||||
|
editor: Editor,
|
||||||
|
caretOffsetRef: Ref<Int>,
|
||||||
|
caretAdvanceRef: Ref<Int>): Boolean {
|
||||||
|
var caretOffset = caretOffsetRef.get()
|
||||||
|
val psiAtOffset = psiFile.findElementAt(caretOffset) ?: return false
|
||||||
|
val stringTemplate = psiAtOffset.getStrictParentOfType<JetStringTemplateExpression>() ?: return false
|
||||||
|
if (!stringTemplate.isSingleQuoted()) return false
|
||||||
|
val tokenType = psiAtOffset.getNode().getElementType()
|
||||||
|
when (tokenType) {
|
||||||
|
JetTokens.CLOSING_QUOTE, JetTokens.REGULAR_STRING_PART, JetTokens.ESCAPE_SEQUENCE,
|
||||||
|
JetTokens.SHORT_TEMPLATE_ENTRY_START, JetTokens.LONG_TEMPLATE_ENTRY_START -> {
|
||||||
|
val doc = editor.getDocument()
|
||||||
|
var caretAdvance = 1
|
||||||
|
if (stringTemplate.getParent() is JetDotQualifiedExpression) {
|
||||||
|
doc.insertString(stringTemplate.getTextRange().getEndOffset(), ")")
|
||||||
|
doc.insertString(stringTemplate.getTextRange().getStartOffset(), "(")
|
||||||
|
caretOffset++
|
||||||
|
caretAdvance++
|
||||||
|
}
|
||||||
|
doc.insertString(caretOffset, "\" + \"")
|
||||||
|
caretOffsetRef.set(caretOffset + 3)
|
||||||
|
caretAdvanceRef.set(caretAdvance)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,11 @@ public class KotlinQuoteHandler : QuoteHandler {
|
|||||||
|
|
||||||
override fun isInsideLiteral(iterator: HighlighterIterator): Boolean {
|
override fun isInsideLiteral(iterator: HighlighterIterator): Boolean {
|
||||||
val tokenType = iterator.getTokenType()
|
val tokenType = iterator.getTokenType()
|
||||||
return tokenType == JetTokens.REGULAR_STRING_PART || tokenType == JetTokens.OPEN_QUOTE || tokenType == JetTokens.CLOSING_QUOTE || tokenType == JetTokens.SHORT_TEMPLATE_ENTRY_START || tokenType == JetTokens.LONG_TEMPLATE_ENTRY_END || tokenType == JetTokens.LONG_TEMPLATE_ENTRY_START
|
return tokenType == JetTokens.REGULAR_STRING_PART ||
|
||||||
|
tokenType == JetTokens.OPEN_QUOTE ||
|
||||||
|
tokenType == JetTokens.CLOSING_QUOTE ||
|
||||||
|
tokenType == JetTokens.SHORT_TEMPLATE_ENTRY_START ||
|
||||||
|
tokenType == JetTokens.LONG_TEMPLATE_ENTRY_END ||
|
||||||
|
tokenType == JetTokens.LONG_TEMPLATE_ENTRY_START
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,6 +234,54 @@ public class TypedHandlerTest : LightCodeInsightTestCase() {
|
|||||||
"""fun f() { val a = f(<caret>) }"""
|
"""fun f() { val a = f(<caret>) }"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
public fun testSplitStringByEnter(): Unit = doCharTypeTest(
|
||||||
|
'\n',
|
||||||
|
"""val s = "foo<caret>bar"""",
|
||||||
|
"val s = \"foo\" +\n" +
|
||||||
|
" \"bar\""
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun testSplitStringByEnter_Empty(): Unit = doCharTypeTest(
|
||||||
|
'\n',
|
||||||
|
"""val s = "<caret>"""",
|
||||||
|
"val s = \"\" +\n" +
|
||||||
|
" \"\""
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun testSplitStringByEnter_BeforeEscapeSequence(): Unit = doCharTypeTest(
|
||||||
|
'\n',
|
||||||
|
"""val s = "foo<caret>\nbar"""",
|
||||||
|
"val s = \"foo\" +\n" +
|
||||||
|
" \"\\nbar\""
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun testSplitStringByEnter_BeforeSubstitution(): Unit = doCharTypeTest(
|
||||||
|
'\n',
|
||||||
|
"""val s = "foo<caret>${amp}bar"""",
|
||||||
|
"val s = \"foo\" +\n" +
|
||||||
|
" \"${amp}bar\""
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun testSplitStringByEnter_AddParentheses(): Unit = doCharTypeTest(
|
||||||
|
'\n',
|
||||||
|
"""val l = "foo<caret>bar".length()""",
|
||||||
|
"val l = (\"foo\" +\n" +
|
||||||
|
" \"bar\").length()"
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun testSplitStringByEnter_ExistingParentheses(): Unit = doCharTypeTest(
|
||||||
|
'\n',
|
||||||
|
"""val l = ("asdf" + "foo<caret>bar").length()""",
|
||||||
|
"val l = (\"asdf\" + \"foo\" +\n" +
|
||||||
|
" \"bar\").length()"
|
||||||
|
)
|
||||||
|
|
||||||
|
public fun testSplitStringByEnter_TripleQuotedString(): Unit = doCharTypeTest(
|
||||||
|
'\n',
|
||||||
|
"val l = \"\"\"foo<caret>bar\"\"\"",
|
||||||
|
"val l = \"\"\"foo\nbar\"\"\""
|
||||||
|
)
|
||||||
|
|
||||||
public fun testTypeLtInFunDeclaration() {
|
public fun testTypeLtInFunDeclaration() {
|
||||||
doLtGtTest("fun <caret>")
|
doLtGtTest("fun <caret>")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user