Add "Copy concatenation text to clipboard" intention #KT-13744 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
023c02deb3
commit
391a0fdde5
@@ -90,6 +90,7 @@ import org.jetbrains.kotlin.idea.imports.AbstractOptimizeImportsTest
|
|||||||
import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest
|
import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest
|
||||||
import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest2
|
import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest2
|
||||||
import org.jetbrains.kotlin.idea.intentions.AbstractMultiFileIntentionTest
|
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.intentions.declarations.AbstractJoinLinesTest
|
||||||
import org.jetbrains.kotlin.idea.internal.AbstractBytecodeToolWindowTest
|
import org.jetbrains.kotlin.idea.internal.AbstractBytecodeToolWindowTest
|
||||||
import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest
|
import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest
|
||||||
@@ -529,6 +530,10 @@ fun main(args: Array<String>) {
|
|||||||
model("intentions/loopToCallChain", pattern = "^([\\w\\-_]+)\\.kt$")
|
model("intentions/loopToCallChain", pattern = "^([\\w\\-_]+)\\.kt$")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testClass<AbstractConcatenatedStringGeneratorTest> {
|
||||||
|
model("concatenatedStringGenerator", pattern = "^([\\w\\-_]+)\\.kt$")
|
||||||
|
}
|
||||||
|
|
||||||
testClass<AbstractInspectionTest>() {
|
testClass<AbstractInspectionTest>() {
|
||||||
model("intentions", pattern = "^(inspections\\.test)$", singleClass = true)
|
model("intentions", pattern = "^(inspections\\.test)$", singleClass = true)
|
||||||
model("inspections", pattern = "^(inspections\\.test)$", singleClass = true)
|
model("inspections", pattern = "^(inspections\\.test)$", singleClass = true)
|
||||||
|
|||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
the following text is copied to the clipboard:
|
||||||
|
s: ? t: ?
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun p(s: String, t: String) {
|
||||||
|
println(<spot>"s: $s t: $t"</spot>)
|
||||||
|
}
|
||||||
+7
@@ -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>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
|
<intentionAction>
|
||||||
|
<className>org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.CopyConcatenatedStringToClipboardIntention</className>
|
||||||
|
<category>Kotlin</category>
|
||||||
|
</intentionAction>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
|
||||||
displayName="Object literal can be converted to lambda"
|
displayName="Object literal can be converted to lambda"
|
||||||
groupName="Kotlin"
|
groupName="Kotlin"
|
||||||
|
|||||||
+54
@@ -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("?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -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
|
||||||
@@ -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"
|
||||||
+39
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+61
@@ -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")
|
@TestMetadata("idea/testData/intentions/declarations")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user