diff --git a/idea/resources/intentionDescriptions/IndentRawStringIntention/after.kt.template b/idea/resources/intentionDescriptions/IndentRawStringIntention/after.kt.template
new file mode 100644
index 00000000000..cf763d4ec4d
--- /dev/null
+++ b/idea/resources/intentionDescriptions/IndentRawStringIntention/after.kt.template
@@ -0,0 +1,7 @@
+fun test() {
+ val s = """
+ foo
+ bar
+ baz
+ """.trimIndent()
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/IndentRawStringIntention/before.kt.template b/idea/resources/intentionDescriptions/IndentRawStringIntention/before.kt.template
new file mode 100644
index 00000000000..6fc16cc2815
--- /dev/null
+++ b/idea/resources/intentionDescriptions/IndentRawStringIntention/before.kt.template
@@ -0,0 +1,5 @@
+fun test() {
+ val s = """foo
+bar
+baz"""
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/IndentRawStringIntention/description.html b/idea/resources/intentionDescriptions/IndentRawStringIntention/description.html
new file mode 100644
index 00000000000..d90c9b4d290
--- /dev/null
+++ b/idea/resources/intentionDescriptions/IndentRawStringIntention/description.html
@@ -0,0 +1,5 @@
+
+
+This intention indents a raw string.
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index b4850596d91..97e588ba599 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -1596,6 +1596,11 @@
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention
+ Kotlin
+
+
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention
+ Kotlin
+
+
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention
+ Kotlin
+
+
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention
+ Kotlin
+
+
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention
+ Kotlin
+
+
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention
+ Kotlin
+
+
(
+ KtStringTemplateExpression::class.java, "Indent raw string"
+) {
+
+ override fun isApplicableTo(element: KtStringTemplateExpression, caretOffset: Int): Boolean {
+ if (!element.text.startsWith("\"\"\"")) return false
+ if (element.getQualifiedExpressionForReceiver() != null) return false
+ val entries = element.entries
+ if (entries.size <= 1 || entries.any { it.text.startsWith(" ") || it.text.startsWith("\t") }) return false
+ return true
+ }
+
+ override fun applyTo(element: KtStringTemplateExpression, editor: Editor?) {
+ val file = element.containingKtFile
+ val project = file.project
+ val indentOptions = CodeStyleSettingsManager.getInstance(project).currentSettings.getIndentOptions(KotlinFileType.INSTANCE)
+ val parentIndent = CodeStyleManager.getInstance(project).getLineIndent(file, element.parent.startOffset) ?: ""
+ val indent = if (indentOptions.USE_TAB_CHARACTER) "$parentIndent\t" else "$parentIndent${" ".repeat(indentOptions.INDENT_SIZE)}"
+
+ val newString = buildString {
+ val maxIndex = element.entries.size - 1
+ element.entries.forEachIndexed { index, entry ->
+ if (index == 0) append("\n$indent")
+ append(entry.text)
+ if (entry.text == "\n") append(indent)
+ if (index == maxIndex) append("\n$indent")
+ }
+ }
+
+ element.replace(KtPsiFactory(element).createExpression("\"\"\"$newString\"\"\".trimIndent()"))
+ }
+
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/indentRawString/.intention b/idea/testData/intentions/indentRawString/.intention
new file mode 100644
index 00000000000..ae3461dfb83
--- /dev/null
+++ b/idea/testData/intentions/indentRawString/.intention
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.intentions.IndentRawStringIntention
diff --git a/idea/testData/intentions/indentRawString/hasIndent.kt b/idea/testData/intentions/indentRawString/hasIndent.kt
new file mode 100644
index 00000000000..e730ddcf1b4
--- /dev/null
+++ b/idea/testData/intentions/indentRawString/hasIndent.kt
@@ -0,0 +1,6 @@
+// IS_APPLICABLE: false
+fun test() {
+ val foo = """foo
+ bar
+baz"""
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/indentRawString/notRawString.kt b/idea/testData/intentions/indentRawString/notRawString.kt
new file mode 100644
index 00000000000..c8f55abeb88
--- /dev/null
+++ b/idea/testData/intentions/indentRawString/notRawString.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: false
+fun test() {
+ val foo = "foo"
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/indentRawString/receiver.kt b/idea/testData/intentions/indentRawString/receiver.kt
new file mode 100644
index 00000000000..87768deda0b
--- /dev/null
+++ b/idea/testData/intentions/indentRawString/receiver.kt
@@ -0,0 +1,7 @@
+// IS_APPLICABLE: false
+// WITH_RUNTIME
+fun test() {
+ val foo = """foo
+bar
+baz""".trimIndent()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/indentRawString/simple.kt b/idea/testData/intentions/indentRawString/simple.kt
new file mode 100644
index 00000000000..b0d800dd58e
--- /dev/null
+++ b/idea/testData/intentions/indentRawString/simple.kt
@@ -0,0 +1,6 @@
+// WITH_RUNTIME
+fun test() {
+ val foo = """foo
+bar
+baz"""
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/indentRawString/simple.kt.after b/idea/testData/intentions/indentRawString/simple.kt.after
new file mode 100644
index 00000000000..f302165ffac
--- /dev/null
+++ b/idea/testData/intentions/indentRawString/simple.kt.after
@@ -0,0 +1,8 @@
+// WITH_RUNTIME
+fun test() {
+ val foo = """
+ foo
+ bar
+ baz
+ """.trimIndent()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/indentRawString/singleLine.kt b/idea/testData/intentions/indentRawString/singleLine.kt
new file mode 100644
index 00000000000..e43ff1c4630
--- /dev/null
+++ b/idea/testData/intentions/indentRawString/singleLine.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: false
+fun test() {
+ val foo = """foo"""
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
index 6f5c52f6162..a656bbeb857 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
@@ -8387,6 +8387,45 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
+ @TestMetadata("idea/testData/intentions/indentRawString")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class IndentRawString extends AbstractIntentionTest {
+ public void testAllFilesPresentInIndentRawString() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/indentRawString"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("hasIndent.kt")
+ public void testHasIndent() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/indentRawString/hasIndent.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("notRawString.kt")
+ public void testNotRawString() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/indentRawString/notRawString.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("receiver.kt")
+ public void testReceiver() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/indentRawString/receiver.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/indentRawString/simple.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("singleLine.kt")
+ public void testSingleLine() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/indentRawString/singleLine.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/intentions/infixCallToOrdinary")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)