Permalink
Browse files

Add "Copy concatenation text to clipboard" intention #KT-13744 Fixed

  • Loading branch information...
shiraji authored and mglukhikh committed Sep 22, 2016
1 parent 023c02d commit 391a0fdde5788ad7c8e854e7eba03a4e186256b5
Showing with 297 additions and 0 deletions.
  1. +5 −0 generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
  2. +2 −0 idea/resources/intentionDescriptions/CopyConcatenatedStringToClipboardIntention/after.kt.template
  3. +3 −0 idea/resources/intentionDescriptions/CopyConcatenatedStringToClipboardIntention/before.kt.template
  4. +7 −0 idea/resources/intentionDescriptions/CopyConcatenatedStringToClipboardIntention/description.html
  5. +5 −0 idea/src/META-INF/plugin.xml
  6. +54 −0 ...jetbrains/kotlin/idea/intentions/copyConcatenatedStringToClipboard/ConcatenatedStringGenerator.kt
  7. +41 −0 ...n/idea/intentions/copyConcatenatedStringToClipboard/CopyConcatenatedStringToClipboardIntention.kt
  8. +1 −0 idea/testData/concatenatedStringGenerator/constants.kt
  9. +1 −0 idea/testData/concatenatedStringGenerator/constants.kt.result
  10. +1 −0 idea/testData/concatenatedStringGenerator/simple.kt
  11. +1 −0 idea/testData/concatenatedStringGenerator/simple.kt.result
  12. +1 −0 idea/testData/concatenatedStringGenerator/stringtemplate.kt
  13. +1 −0 idea/testData/concatenatedStringGenerator/stringtemplate.kt.result
  14. +1 −0 idea/testData/concatenatedStringGenerator/variables.kt
  15. +1 −0 idea/testData/concatenatedStringGenerator/variables.kt.result
  16. +1 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/.intention
  17. +4 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/constants.kt
  18. +4 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/constants.kt.after
  19. +3 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/numbers.kt
  20. +4 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/simple.kt
  21. +4 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/simple.kt.after
  22. +3 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/simpleString.kt
  23. +5 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/variables.kt
  24. +5 −0 idea/testData/intentions/copyConcatenatedStringToClipboard/variables.kt.after
  25. +39 −0 idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractConcatenatedStringGeneratorTest.kt
  26. +61 −0 idea/tests/org/jetbrains/kotlin/idea/intentions/ConcatenatedStringGeneratorTestGenerated.java
  27. +39 −0 idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
@@ -90,6 +90,7 @@ import org.jetbrains.kotlin.idea.imports.AbstractOptimizeImportsTest
import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest
import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest2
import org.jetbrains.kotlin.idea.intentions.AbstractMultiFileIntentionTest
+import org.jetbrains.kotlin.idea.intentions.AbstractConcatenatedStringGeneratorTest
import org.jetbrains.kotlin.idea.intentions.declarations.AbstractJoinLinesTest
import org.jetbrains.kotlin.idea.internal.AbstractBytecodeToolWindowTest
import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest
@@ -529,6 +530,10 @@ fun main(args: Array<String>) {
model("intentions/loopToCallChain", pattern = "^([\\w\\-_]+)\\.kt$")
}
+ testClass<AbstractConcatenatedStringGeneratorTest> {
+ model("concatenatedStringGenerator", pattern = "^([\\w\\-_]+)\\.kt$")
+ }
+
testClass<AbstractInspectionTest>() {
model("intentions", pattern = "^(inspections\\.test)$", singleClass = true)
model("inspections", pattern = "^(inspections\\.test)$", singleClass = true)
@@ -0,0 +1,2 @@
+the following text is copied to the clipboard:
+s: ? t: ?
@@ -0,0 +1,3 @@
+fun p(s: String, t: String) {
+ println(<spot>"s: $s t: $t"</spot>)
+}
@@ -0,0 +1,7 @@
+<html>
+<body>
+This intention copies the text of a <b>String</b> concatenation
+to the system clipboard. This can be useful for example when you have a multi-line SQL query in
+your code, split into concatenated lines which you need to copy to an external application.
+</body>
+</html>
@@ -1354,6 +1354,11 @@
<category>Kotlin</category>
</intentionAction>
+ <intentionAction>
+ <className>org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.CopyConcatenatedStringToClipboardIntention</className>
+ <category>Kotlin</category>
+ </intentionAction>
+
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupName="Kotlin"
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard
+
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
+
+class ConcatenatedStringGenerator {
+ fun create(element: KtBinaryExpression): String {
+ val binaryExpression = KtPsiUtil.getTopmostParentOfTypes(element, KtBinaryExpression::class.java) as? KtBinaryExpression ?: element
+ val stringBuilder = StringBuilder()
+ binaryExpression.appendTo(stringBuilder)
+ return stringBuilder.toString()
+ }
+
+ private fun KtBinaryExpression.appendTo(sb: StringBuilder) {
+ left?.appendTo(sb)
+ right?.appendTo(sb)
+ }
+
+ private fun KtExpression.appendTo(sb: StringBuilder) {
+ when (this) {
+ is KtBinaryExpression -> this.appendTo(sb)
+ is KtConstantExpression -> sb.append(text)
+ is KtStringTemplateExpression -> this.appendTo(sb)
+ else -> sb.append("?")
+ }
+ }
+
+ private fun KtStringTemplateExpression.appendTo(sb: StringBuilder) {
+ collectDescendantsOfType<KtStringTemplateEntry>().forEach {
+ stringTemplate ->
+ when (stringTemplate) {
+ is KtLiteralStringTemplateEntry -> sb.append(stringTemplate.text)
+ is KtEscapeStringTemplateEntry -> sb.append(stringTemplate.unescapedValue)
+ else -> sb.append("?")
+ }
+ }
+ }
+}
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard
+
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.ide.CopyPasteManager
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.intentions.SelfTargetingOffsetIndependentIntention
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtBinaryExpression
+import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
+import java.awt.datatransfer.StringSelection
+
+class CopyConcatenatedStringToClipboardIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(
+ KtBinaryExpression::class.java, "Copy concatenation text to clipboard") {
+ override fun applyTo(element: KtBinaryExpression, editor: Editor?) {
+ val text = ConcatenatedStringGenerator().create(element)
+ CopyPasteManager.getInstance().setContents(StringSelection(text))
+ }
+
+ override fun isApplicableTo(element: KtBinaryExpression): Boolean {
+ if (element.operationToken != KtTokens.PLUS) return false
+ val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false
+ return KotlinBuiltIns.isString(resolvedCall.candidateDescriptor.returnType)
+ }
+}
@@ -0,0 +1 @@
+"" + 1 + 1.1 + "foo"
@@ -0,0 +1 @@
+"foo" + "bar"
@@ -0,0 +1 @@
+"foo$foo$bar" + "${bar}${bar2()}bar"
@@ -0,0 +1 @@
+"" + b<caret> + "foo"
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.CopyConcatenatedStringToClipboardIntention
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: true
+// INTENTION_TEXT: Copy concatenation text to clipboard
+
+val s = "" + 1<caret> + 1.1 + "foo"
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: true
+// INTENTION_TEXT: Copy concatenation text to clipboard
+
+val s = "" + 1 + 1.1 + "foo"
@@ -0,0 +1,3 @@
+// IS_APPLICABLE: false
+
+val foo = 1 + <caret>1
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: true
+// INTENTION_TEXT: Copy concatenation text to clipboard
+
+val foo = "foo"<caret> + "bar"
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: true
+// INTENTION_TEXT: Copy concatenation text to clipboard
+
+val foo = "foo" + "bar"
@@ -0,0 +1,3 @@
+// IS_APPLICABLE: false
+
+val foo = "foo"<caret>
@@ -0,0 +1,5 @@
+// IS_APPLICABLE: true
+// INTENTION_TEXT: Copy concatenation text to clipboard
+
+val b = 100
+val s = "" + b<caret> + "foo"
@@ -0,0 +1,5 @@
+// IS_APPLICABLE: true
+// INTENTION_TEXT: Copy concatenation text to clipboard
+
+val b = 100
+val s = "" + b + "foo"
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.intentions
+
+import junit.framework.TestCase
+import org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.ConcatenatedStringGenerator
+import org.jetbrains.kotlin.idea.test.KotlinCodeInsightTestCase
+import org.jetbrains.kotlin.psi.KtBinaryExpression
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import java.io.File
+
+abstract class AbstractConcatenatedStringGeneratorTest : KotlinCodeInsightTestCase() {
+
+ @Throws(Exception::class)
+ protected fun doTest(path: String) {
+ val mainFile = File(path)
+ val readText = mainFile.readText()
+ val resultFile = File("$path.result")
+ val expectedText = resultFile.readText()
+ val expression = KtPsiFactory(project).createExpression(readText) as? KtBinaryExpression
+ TestCase.assertNotNull("Invalid expression: $readText", expression)
+ val generatedString = ConcatenatedStringGenerator().create(expression!!)
+ TestCase.assertEquals("mismatch '$expectedText' - '$generatedString'", expectedText, generatedString)
+ }
+}
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.intentions;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
+import org.jetbrains.kotlin.test.KotlinTestUtils;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
+@SuppressWarnings("all")
+@TestMetadata("idea/testData/concatenatedStringGenerator")
+@TestDataPath("$PROJECT_ROOT")
+@RunWith(JUnit3RunnerWithInners.class)
+public class ConcatenatedStringGeneratorTestGenerated extends AbstractConcatenatedStringGeneratorTest {
+ public void testAllFilesPresentInConcatenatedStringGenerator() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/concatenatedStringGenerator"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
+ }
+
+ @TestMetadata("constants.kt")
+ public void testConstants() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/concatenatedStringGenerator/constants.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/concatenatedStringGenerator/simple.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("stringtemplate.kt")
+ public void testStringtemplate() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/concatenatedStringGenerator/stringtemplate.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("variables.kt")
+ public void testVariables() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/concatenatedStringGenerator/variables.kt");
+ doTest(fileName);
+ }
+}
@@ -5490,6 +5490,45 @@ public void testUnescapeSingleQuote() throws Exception {
}
+ @TestMetadata("idea/testData/intentions/copyConcatenatedStringToClipboard")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class CopyConcatenatedStringToClipboard extends AbstractIntentionTest {
+ public void testAllFilesPresentInCopyConcatenatedStringToClipboard() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/copyConcatenatedStringToClipboard"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
+ }
+
+ @TestMetadata("constants.kt")
+ public void testConstants() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/copyConcatenatedStringToClipboard/constants.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("numbers.kt")
+ public void testNumbers() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/copyConcatenatedStringToClipboard/numbers.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/copyConcatenatedStringToClipboard/simple.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("simpleString.kt")
+ public void testSimpleString() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/copyConcatenatedStringToClipboard/simpleString.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("variables.kt")
+ public void testVariables() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/copyConcatenatedStringToClipboard/variables.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/intentions/declarations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

0 comments on commit 391a0fd

Please sign in to comment.