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

This commit is contained in:
shiraji
2016-09-22 17:28:42 +09:00
committed by Mikhail Glukhikh
parent 023c02deb3
commit 391a0fdde5
27 changed files with 297 additions and 0 deletions
@@ -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>
+5
View File
@@ -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 @@
11.1foo
+1
View File
@@ -0,0 +1 @@
"foo" + "bar"
@@ -0,0 +1 @@
foobar
@@ -0,0 +1 @@
"foo$foo$bar" + "${bar}${bar2()}bar"
@@ -0,0 +1 @@
foo????bar
@@ -0,0 +1 @@
"" + b<caret> + "foo"
@@ -0,0 +1 @@
?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 class IntentionTestGenerated extends AbstractIntentionTest {
}
@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)