Paste inside indented .trimIndent() raw string: respect indentation (KT-31810)
#KT-31810 Fixed
This commit is contained in:
committed by
Nikolay Krasko
parent
d3b826c71d
commit
147f805c56
@@ -28,8 +28,11 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.idea.editor.fixers.range
|
import org.jetbrains.kotlin.idea.editor.fixers.range
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.collections.isCalling
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.callExpression
|
||||||
import org.jetbrains.kotlin.lexer.KotlinLexer
|
import org.jetbrains.kotlin.lexer.KotlinLexer
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtEscapeStringTemplateEntry
|
import org.jetbrains.kotlin.psi.KtEscapeStringTemplateEntry
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||||
@@ -41,8 +44,8 @@ private val PsiElement.templateContentRange: TextRange?
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun PsiFile.getTemplateIfAtLiteral(offset: Int): KtStringTemplateExpression? {
|
private fun PsiFile.getTemplateIfAtLiteral(offset: Int, at: PsiElement? = findElementAt(offset)): KtStringTemplateExpression? {
|
||||||
val at = this.findElementAt(offset) ?: return null
|
if (at == null) return null
|
||||||
return when (at.node?.elementType) {
|
return when (at.node?.elementType) {
|
||||||
KtTokens.REGULAR_STRING_PART, KtTokens.ESCAPE_SEQUENCE, KtTokens.LONG_TEMPLATE_ENTRY_START, KtTokens.SHORT_TEMPLATE_ENTRY_START -> at.parent.parent as? KtStringTemplateExpression
|
KtTokens.REGULAR_STRING_PART, KtTokens.ESCAPE_SEQUENCE, KtTokens.LONG_TEMPLATE_ENTRY_START, KtTokens.SHORT_TEMPLATE_ENTRY_START -> at.parent.parent as? KtStringTemplateExpression
|
||||||
KtTokens.CLOSING_QUOTE -> if (offset == at.startOffset) at.parent as? KtStringTemplateExpression else null
|
KtTokens.CLOSING_QUOTE -> if (offset == at.startOffset) at.parent as? KtStringTemplateExpression else null
|
||||||
@@ -123,7 +126,8 @@ class KotlinLiteralCopyPasteProcessor : CopyPastePreProcessor {
|
|||||||
}
|
}
|
||||||
PsiDocumentManager.getInstance(project).commitDocument(editor.document)
|
PsiDocumentManager.getInstance(project).commitDocument(editor.document)
|
||||||
val selectionModel = editor.selectionModel
|
val selectionModel = editor.selectionModel
|
||||||
val beginTp = file.getTemplateIfAtLiteral(selectionModel.selectionStart) ?: return text
|
val begin = file.findElementAt(selectionModel.selectionStart) ?: return text
|
||||||
|
val beginTp = file.getTemplateIfAtLiteral(selectionModel.selectionStart, begin) ?: return text
|
||||||
val endTp = file.getTemplateIfAtLiteral(selectionModel.selectionEnd) ?: return text
|
val endTp = file.getTemplateIfAtLiteral(selectionModel.selectionEnd) ?: return text
|
||||||
if (beginTp.isSingleQuoted() != endTp.isSingleQuoted()) {
|
if (beginTp.isSingleQuoted() != endTp.isSingleQuoted()) {
|
||||||
return text
|
return text
|
||||||
@@ -147,13 +151,23 @@ class KotlinLiteralCopyPasteProcessor : CopyPastePreProcessor {
|
|||||||
res.toString()
|
res.toString()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
val indent = if (beginTp.firstChild?.text == "\"\"\"" &&
|
||||||
|
beginTp.getQualifiedExpressionForReceiver()?.callExpression?.isCalling(FqName("kotlin.text.trimIndent")) == true
|
||||||
|
) {
|
||||||
|
begin.parent?.prevSibling?.takeIf { it.text != "\n" }?.text ?: ""
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
val tripleQuoteRe = Regex("[\"]{3,}")
|
val tripleQuoteRe = Regex("[\"]{3,}")
|
||||||
TemplateTokenSequence(text).map { chunk ->
|
TemplateTokenSequence(text).mapIndexed { index, chunk ->
|
||||||
when (chunk) {
|
when (chunk) {
|
||||||
is LiteralChunk -> chunk.text.replace("\$", "\${'$'}").let { escapedDollar ->
|
is LiteralChunk -> {
|
||||||
tripleQuoteRe.replace(escapedDollar) { "\"\"" + "\${'\"'}".repeat(it.value.count() - 2) }
|
val replaced = chunk.text.replace("\$", "\${'$'}").let { escapedDollar ->
|
||||||
|
tripleQuoteRe.replace(escapedDollar) { "\"\"" + "\${'\"'}".repeat(it.value.count() - 2) }
|
||||||
|
}
|
||||||
|
if (index == 0) replaced else indent + replaced
|
||||||
}
|
}
|
||||||
is EntryChunk -> chunk.text
|
is EntryChunk -> if (index == 0) chunk.text else indent + chunk.text
|
||||||
is NewLineChunk -> "\n"
|
is NewLineChunk -> "\n"
|
||||||
}
|
}
|
||||||
}.joinToString(separator = "")
|
}.joinToString(separator = "")
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fun test() = doTest("""
|
||||||
|
def foo(a)
|
||||||
|
a ? 0 : 1
|
||||||
|
end
|
||||||
|
""".trimIndent())
|
||||||
|
|
||||||
|
fun doTest(rubyCode: String) {
|
||||||
|
// some code here
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun test() = doTest("""
|
||||||
|
<caret>
|
||||||
|
""".trimIndent())
|
||||||
|
|
||||||
|
fun doTest(rubyCode: String) {
|
||||||
|
// some code here
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
def foo(a)
|
||||||
|
a ? 0 : 1
|
||||||
|
end
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fun test() = doTest("""
|
||||||
|
def foo(a)
|
||||||
|
a ? 0 : 1
|
||||||
|
end
|
||||||
|
""".trimIndent())
|
||||||
|
|
||||||
|
fun doTest(rubyCode: String) {
|
||||||
|
// some code here
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun test() = doTest("""
|
||||||
|
<caret>
|
||||||
|
""".trimIndent())
|
||||||
|
|
||||||
|
fun doTest(rubyCode: String) {
|
||||||
|
// some code here
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
def foo(a)
|
||||||
|
a ? 0 : 1
|
||||||
|
end
|
||||||
Generated
+10
@@ -59,6 +59,16 @@ public class LiteralTextToKotlinCopyPasteTestGenerated extends AbstractLiteralTe
|
|||||||
runTest("idea/testData/copyPaste/plainTextLiteral/TrailingLines.txt");
|
runTest("idea/testData/copyPaste/plainTextLiteral/TrailingLines.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TrimIndent.txt")
|
||||||
|
public void testTrimIndent() throws Exception {
|
||||||
|
runTest("idea/testData/copyPaste/plainTextLiteral/TrimIndent.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TrimIndent2.txt")
|
||||||
|
public void testTrimIndent2() throws Exception {
|
||||||
|
runTest("idea/testData/copyPaste/plainTextLiteral/TrimIndent2.txt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("WithBackslashes.txt")
|
@TestMetadata("WithBackslashes.txt")
|
||||||
public void testWithBackslashes() throws Exception {
|
public void testWithBackslashes() throws Exception {
|
||||||
runTest("idea/testData/copyPaste/plainTextLiteral/WithBackslashes.txt");
|
runTest("idea/testData/copyPaste/plainTextLiteral/WithBackslashes.txt");
|
||||||
|
|||||||
Reference in New Issue
Block a user