diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 820f4166470..5f774da7aeb 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -73,6 +73,8 @@ import org.jetbrains.kotlin.idea.completion.test.handlers.AbstractSmartCompletio import org.jetbrains.kotlin.idea.completion.test.weighers.AbstractBasicCompletionWeigherTest import org.jetbrains.kotlin.idea.completion.test.weighers.AbstractSmartCompletionWeigherTest import org.jetbrains.kotlin.idea.conversion.copy.AbstractJavaToKotlinCopyPasteConversionTest +import org.jetbrains.kotlin.idea.conversion.copy.AbstractLiteralKotlinToKotlinCopyPasteTest +import org.jetbrains.kotlin.idea.conversion.copy.AbstractLiteralTextToKotlinCopyPasteTest import org.jetbrains.kotlin.idea.conversion.copy.AbstractTextJavaToKotlinCopyPasteConversionTest import org.jetbrains.kotlin.idea.coverage.AbstractKotlinCoverageOutputFilesTest import org.jetbrains.kotlin.idea.debugger.AbstractBeforeExtractFunctionInsertionTest @@ -799,6 +801,14 @@ fun main(args: Array) { model("copyPaste/plainTextConversion", pattern = """^([^\.]+)\.txt$""") } + testClass { + model("copyPaste/plainTextLiteral", pattern = """^([^\.]+)\.txt$""") + } + + testClass { + model("copyPaste/literal", pattern = """^([^\.]+)\.kt$""") + } + testClass { model("copyPaste/imports", pattern = KT_WITHOUT_DOTS_IN_NAME, testMethod = "doTestCopy", testClassName = "Copy", recursive = false) model("copyPaste/imports", pattern = KT_WITHOUT_DOTS_IN_NAME, testMethod = "doTestCut", testClassName = "Cut", recursive = false) diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 71f57ed11e3..ccea1824973 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -565,6 +565,7 @@ + diff --git a/idea/src/org/jetbrains/kotlin/idea/editor/KotlinLiteralCopyPasteProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinLiteralCopyPasteProcessor.kt new file mode 100644 index 00000000000..eb77ab057b9 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/editor/KotlinLiteralCopyPasteProcessor.kt @@ -0,0 +1,263 @@ +/* + * Copyright 2010-2017 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.editor + +import com.intellij.codeInsight.editorActions.CopyPastePreProcessor +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.RawText +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.util.text.LineTokenizer +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.editor.fixers.range +import org.jetbrains.kotlin.lexer.KotlinLexer +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtEscapeStringTemplateEntry +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtStringTemplateEntry +import org.jetbrains.kotlin.psi.KtStringTemplateExpression +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.isSingleQuoted +import org.jetbrains.kotlin.psi.psiUtil.startOffset +import kotlin.coroutines.experimental.SequenceBuilder +import kotlin.coroutines.experimental.buildIterator + +private fun PsiElement.findContainingTemplate(): PsiElement { + val parent = this.parent + @Suppress("IfThenToElvis") return if (parent is KtStringTemplateEntry) parent.parent else parent +} + +private fun PsiFile.getTemplateIfAtLiteral(offset: Int): KtStringTemplateExpression? { + val at = this.findElementAt(offset) ?: return null + 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.CLOSING_QUOTE -> if (offset == at.startOffset) at.parent as? KtStringTemplateExpression else null + else -> null + } +} + + +//Copied from StringLiteralCopyPasteProcessor to avoid erroneous inheritance +private fun deduceBlockSelectionWidth(startOffsets: IntArray, endOffsets: IntArray, text: String): Int { + val fragmentCount = startOffsets.size + assert(fragmentCount > 0) + var totalLength = fragmentCount - 1 // number of line breaks inserted between fragments + for (i in 0..fragmentCount - 1) { + totalLength += endOffsets[i] - startOffsets[i] + } + if (totalLength < text.length && (text.length + 1) % fragmentCount == 0) { + return (text.length + 1) / fragmentCount - 1 + } + else { + return -1 + } +} + +class KotlinLiteralCopyPasteProcessor : CopyPastePreProcessor { + override fun preprocessOnCopy(file: PsiFile, startOffsets: IntArray, endOffsets: IntArray, text: String): String? { + if (file !is KtFile) { + return null + } + val buffer = StringBuilder() + var changed = false + val fileText = file.text + val deducedBlockSelectionWidth = deduceBlockSelectionWidth(startOffsets, endOffsets, text) + + for (i in startOffsets.indices) { + if (i > 0) { + buffer.append('\n') // LF is added for block selection + } + val fileRange = TextRange(startOffsets[i], endOffsets[i]) + var givenTextOffset = fileRange.startOffset + while (givenTextOffset < fileRange.endOffset) { + val element: PsiElement? = file.findElementAt(givenTextOffset) + if (element == null) { + buffer.append(fileText.substring(givenTextOffset, fileRange.endOffset)) + break + } + val elTp = element.node.elementType + if (elTp == KtTokens.ESCAPE_SEQUENCE && fileRange.contains(element.range) && !fileRange.contains(element.findContainingTemplate().range)) { + val tpEntry = element.parent as KtEscapeStringTemplateEntry + changed = true + buffer.append(tpEntry.unescapedValue) + givenTextOffset = element.endOffset + } + else if (elTp == KtTokens.SHORT_TEMPLATE_ENTRY_START || elTp == KtTokens.LONG_TEMPLATE_ENTRY_START) { + //Process inner templates without escaping + val tpEntry = element.parent + val inter = fileRange.intersection(tpEntry.range)!! + buffer.append(fileText.substring(inter.startOffset, inter.endOffset)) + givenTextOffset = inter.endOffset + } + else { + val inter = fileRange.intersection(element.range)!! + buffer.append(fileText.substring(inter.startOffset, inter.endOffset)) + givenTextOffset = inter.endOffset + } + } + val blockSelectionPadding = deducedBlockSelectionWidth - fileRange.length + for (j in 0..blockSelectionPadding - 1) { + buffer.append(' ') + } + } + + return if (changed) buffer.toString() else null + } + + override fun preprocessOnPaste(project: Project, file: PsiFile, editor: Editor, text: String, rawText: RawText?): String { + if (file !is KtFile) { + return text + } + PsiDocumentManager.getInstance(project).commitDocument(editor.document) + val selectionModel = editor.selectionModel + val beginTp = file.getTemplateIfAtLiteral(selectionModel.selectionStart) ?: return text + val endTp = file.getTemplateIfAtLiteral(selectionModel.selectionEnd) ?: return text + if (beginTp.isSingleQuoted() != endTp.isSingleQuoted()) { + return text + } + + return if (beginTp.isSingleQuoted()) { + val res = StringBuilder() + TemplateTokenSequence(text).forEach { + when (it) { + is LiteralChunk -> StringUtil.escapeStringCharacters(it.text.length, it.text, "\$\"", res) + is EntryChunk -> res.append(it.text) + is NewLineChunk -> res.append("\\n\"+\n \"") + } + } + res.toString() + } + else { + val tripleQuoteRe = Regex("[\"]{3,}") + TemplateTokenSequence(text).map { chunk -> + when (chunk) { + is LiteralChunk -> chunk.text.replace("\$", "\${'$'}").let { escapedDollar -> + tripleQuoteRe.replace(escapedDollar) { "\"\"" + "\${'\"'}".repeat(it.value.count() - 2) } + } + is EntryChunk -> chunk.text + is NewLineChunk -> "\n" + } + }.joinToString(separator = "") + } + } +} + +private sealed class TemplateChunk +private data class LiteralChunk(val text: String) : TemplateChunk() +private data class EntryChunk(val text: String) : TemplateChunk() +private object NewLineChunk : TemplateChunk() + +private class TemplateTokenSequence(private val inputString: String) : Sequence { + private fun String.guessIsTemplateEntryStart(): Boolean = if (this.startsWith("\${")) { + true + } + else if (this.length > 1 && this[0] == '$') { + val guessedIdentifier = substring(1) + KotlinLexer().apply { start(guessedIdentifier) }.tokenType == KtTokens.IDENTIFIER + } + else { + false + } + + private fun findTemplateEntryEnd(input: String, from: Int): Int { + val wrapped = '"' + input.substring(from) + '"' + val lexer = KotlinLexer().apply { start(wrapped) }.apply { advance() } + + if (lexer.tokenType == KtTokens.SHORT_TEMPLATE_ENTRY_START) { + lexer.advance() + return if (lexer.tokenType == KtTokens.IDENTIFIER) { + from + lexer.tokenEnd - 1 + } + else { + -1 + } + } + else if (lexer.tokenType == KtTokens.LONG_TEMPLATE_ENTRY_START) { + var depth = 0 + while (lexer.tokenType != null) { + if (lexer.tokenType == KtTokens.LONG_TEMPLATE_ENTRY_START) { + depth++ + } + else if (lexer.tokenType == KtTokens.LONG_TEMPLATE_ENTRY_END) { + depth-- + if (depth == 0) { + return from + lexer.currentPosition.offset - 1 + } + } + lexer.advance() + } + return -1 + } + else { + return -1 + } + } + + private suspend fun SequenceBuilder.yieldLiteral(chunk: String) { + val splitLines = LineTokenizer.tokenize(chunk, false, true) + for (i in 0..splitLines.size - 1) { + if (i != 0) { + yield(NewLineChunk) + } + splitLines[i].takeIf { !it.isEmpty() }?.let { yield(LiteralChunk(it)) } + } + } + + private fun iterTemplateChunks(): Iterator { + if (inputString.isEmpty()) { + return emptySequence().iterator() + } + return buildIterator { + var from = 0 + var to = 0 + while (to < inputString.length) { + val c = inputString[to] + if (c == '\\') { + to += 1 + if (to < inputString.length) to += 1 + continue + } + else if (c == '$') { + if (inputString.substring(to).guessIsTemplateEntryStart()) { + if (from < to) yieldLiteral(inputString.substring(from until to)) + from = to + to = findTemplateEntryEnd(inputString, from) + if (to != -1) { + yield(EntryChunk(inputString.substring(from until to))) + } + else { + to = inputString.length + yieldLiteral(inputString.substring(from until to)) + } + from = to + continue + } + } + to++ + } + if (from < to) { + yieldLiteral(inputString.substring(from until to)) + } + } + } + + override fun iterator(): Iterator = iterTemplateChunks() +} + diff --git a/idea/testData/copyPaste/literal/DontEscapeEntries.expected.kt b/idea/testData/copyPaste/literal/DontEscapeEntries.expected.kt new file mode 100644 index 00000000000..93eabb47317 --- /dev/null +++ b/idea/testData/copyPaste/literal/DontEscapeEntries.expected.kt @@ -0,0 +1 @@ +val a = "begin $a else end" \ No newline at end of file diff --git a/idea/testData/copyPaste/literal/DontEscapeEntries.kt b/idea/testData/copyPaste/literal/DontEscapeEntries.kt new file mode 100644 index 00000000000..8292abc0bc7 --- /dev/null +++ b/idea/testData/copyPaste/literal/DontEscapeEntries.kt @@ -0,0 +1,2 @@ +val a = "something" +val b = "something $a else" \ No newline at end of file diff --git a/idea/testData/copyPaste/literal/DontEscapeEntries.to.kt b/idea/testData/copyPaste/literal/DontEscapeEntries.to.kt new file mode 100644 index 00000000000..c35958ebed5 --- /dev/null +++ b/idea/testData/copyPaste/literal/DontEscapeEntries.to.kt @@ -0,0 +1 @@ +val a = "begin end" \ No newline at end of file diff --git a/idea/testData/copyPaste/literal/DontEscapeEntries2.expected.kt b/idea/testData/copyPaste/literal/DontEscapeEntries2.expected.kt new file mode 100644 index 00000000000..1070320c63b --- /dev/null +++ b/idea/testData/copyPaste/literal/DontEscapeEntries2.expected.kt @@ -0,0 +1 @@ +val a = "begin ${a.length} else end" \ No newline at end of file diff --git a/idea/testData/copyPaste/literal/DontEscapeEntries2.kt b/idea/testData/copyPaste/literal/DontEscapeEntries2.kt new file mode 100644 index 00000000000..4b2af580ccb --- /dev/null +++ b/idea/testData/copyPaste/literal/DontEscapeEntries2.kt @@ -0,0 +1,2 @@ +val a = "something" +val b = "something ${a.length} else" \ No newline at end of file diff --git a/idea/testData/copyPaste/literal/DontEscapeEntries2.to.kt b/idea/testData/copyPaste/literal/DontEscapeEntries2.to.kt new file mode 100644 index 00000000000..c35958ebed5 --- /dev/null +++ b/idea/testData/copyPaste/literal/DontEscapeEntries2.to.kt @@ -0,0 +1 @@ +val a = "begin end" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.expected.kt b/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.expected.kt new file mode 100644 index 00000000000..85d81547fb1 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.expected.kt @@ -0,0 +1,2 @@ +val a = """asomething ${'$'}{dsadas +somethingelse""" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.kt b/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.kt new file mode 100644 index 00000000000..e9deafe333d --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.kt @@ -0,0 +1 @@ +val a = """a""" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.txt b/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.txt new file mode 100644 index 00000000000..7b3e605f9c4 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/BrokenEntries.txt @@ -0,0 +1,2 @@ +something ${dsadas +somethingelse \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiLine.expected.kt b/idea/testData/copyPaste/plainTextLiteral/MultiLine.expected.kt new file mode 100644 index 00000000000..a9e08358f16 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiLine.expected.kt @@ -0,0 +1,2 @@ +val a = "somethinga/b\n" + + "c/d" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiLine.kt b/idea/testData/copyPaste/plainTextLiteral/MultiLine.kt new file mode 100644 index 00000000000..3eeed86b7fa --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiLine.kt @@ -0,0 +1 @@ +val a = "something" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiLine.txt b/idea/testData/copyPaste/plainTextLiteral/MultiLine.txt new file mode 100644 index 00000000000..60a57f61443 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiLine.txt @@ -0,0 +1,2 @@ +a/b +c/d \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiLineToTripleQuote.expected.kt b/idea/testData/copyPaste/plainTextLiteral/MultiLineToTripleQuote.expected.kt new file mode 100644 index 00000000000..c3305c0ccf4 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiLineToTripleQuote.expected.kt @@ -0,0 +1,2 @@ +val a = """something a/b +c/d""" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiLineToTripleQuote.kt b/idea/testData/copyPaste/plainTextLiteral/MultiLineToTripleQuote.kt new file mode 100644 index 00000000000..12c294b19cf --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiLineToTripleQuote.kt @@ -0,0 +1 @@ +val a = """something """ \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiLinetoTripleQuote.txt b/idea/testData/copyPaste/plainTextLiteral/MultiLinetoTripleQuote.txt new file mode 100644 index 00000000000..60a57f61443 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiLinetoTripleQuote.txt @@ -0,0 +1,2 @@ +a/b +c/d \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.expected.kt b/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.expected.kt new file mode 100644 index 00000000000..448b28ccc8c --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.expected.kt @@ -0,0 +1 @@ +val a ="""literal ""${'"'}${'"'}${'"'} foo ""${'"'}${'"'}${'"'} literal""" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.kt b/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.kt new file mode 100644 index 00000000000..8d0fa4c52ab --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.kt @@ -0,0 +1 @@ +val a ="""literal literal""" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.txt b/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.txt new file mode 100644 index 00000000000..c38de2860e6 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.txt @@ -0,0 +1 @@ +""""" foo """"" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.expected.kt b/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.expected.kt new file mode 100644 index 00000000000..44cd1f85224 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.expected.kt @@ -0,0 +1 @@ +val fo ="some plain string" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.kt b/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.kt new file mode 100644 index 00000000000..07635bd168a --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.kt @@ -0,0 +1 @@ +val fo ="" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.txt b/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.txt new file mode 100644 index 00000000000..c3b7fb1d0ba --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.txt @@ -0,0 +1 @@ +some plain string \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.expected.kt b/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.expected.kt new file mode 100644 index 00000000000..51028983696 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.expected.kt @@ -0,0 +1 @@ +val pattern = "iframe=\"(\\w)\"" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.kt b/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.kt new file mode 100644 index 00000000000..2352f646ec4 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.kt @@ -0,0 +1 @@ +val pattern = "" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.txt b/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.txt new file mode 100644 index 00000000000..9d9eda7d046 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithBackslashes.txt @@ -0,0 +1 @@ +iframe="(\w)" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.expected.kt b/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.expected.kt new file mode 100644 index 00000000000..7a4d2f7a881 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.expected.kt @@ -0,0 +1 @@ +val a ="""literal hello ${'$'}${'$'}${'$'} hello literal""" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.kt b/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.kt new file mode 100644 index 00000000000..8d0fa4c52ab --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.kt @@ -0,0 +1 @@ +val a ="""literal literal""" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.txt b/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.txt new file mode 100644 index 00000000000..5a04cdfad22 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.txt @@ -0,0 +1 @@ +hello $$$ hello \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithEntries.expected.kt b/idea/testData/copyPaste/plainTextLiteral/WithEntries.expected.kt new file mode 100644 index 00000000000..bba833840ac --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithEntries.expected.kt @@ -0,0 +1 @@ +val a="Hello, ${a.substring("a${'c'}".length)}.length)}" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithEntries.kt b/idea/testData/copyPaste/plainTextLiteral/WithEntries.kt new file mode 100644 index 00000000000..74dcc268797 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithEntries.kt @@ -0,0 +1 @@ +val a="" \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithEntries.txt b/idea/testData/copyPaste/plainTextLiteral/WithEntries.txt new file mode 100644 index 00000000000..707099998d0 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithEntries.txt @@ -0,0 +1 @@ +Hello, ${a.substring("a${'c'}".length)}.length)} \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithQuotes.expected.kt b/idea/testData/copyPaste/plainTextLiteral/WithQuotes.expected.kt new file mode 100644 index 00000000000..5a646aca20d --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithQuotes.expected.kt @@ -0,0 +1,3 @@ +fun file(){ + println("Hello, \"Mary\"") +} \ No newline at end of file diff --git a/idea/testData/copyPaste/plainTextLiteral/WithQuotes.kt b/idea/testData/copyPaste/plainTextLiteral/WithQuotes.kt new file mode 100644 index 00000000000..8ac92ad48c9 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithQuotes.kt @@ -0,0 +1,3 @@ +fun file(){ + println("Hello, ") +} diff --git a/idea/testData/copyPaste/plainTextLiteral/WithQuotes.txt b/idea/testData/copyPaste/plainTextLiteral/WithQuotes.txt new file mode 100644 index 00000000000..592266b99e7 --- /dev/null +++ b/idea/testData/copyPaste/plainTextLiteral/WithQuotes.txt @@ -0,0 +1 @@ +"Mary" \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/conversion/copy/LiteralKotlinToKotlinCopyPasteTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/conversion/copy/LiteralKotlinToKotlinCopyPasteTestGenerated.java new file mode 100644 index 00000000000..9801960a079 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/conversion/copy/LiteralKotlinToKotlinCopyPasteTestGenerated.java @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2017 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.conversion.copy; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +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/copyPaste/literal") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class LiteralKotlinToKotlinCopyPasteTestGenerated extends AbstractLiteralKotlinToKotlinCopyPasteTest { + public void testAllFilesPresentInLiteral() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/copyPaste/literal"), Pattern.compile("^([^\\.]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("DontEscapeEntries.kt") + public void testDontEscapeEntries() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/literal/DontEscapeEntries.kt"); + doTest(fileName); + } + + @TestMetadata("DontEscapeEntries2.kt") + public void testDontEscapeEntries2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/literal/DontEscapeEntries2.kt"); + doTest(fileName); + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/conversion/copy/LiteralTextToKotlinCopyPasteTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/conversion/copy/LiteralTextToKotlinCopyPasteTestGenerated.java new file mode 100644 index 00000000000..4dcc40f54c9 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/conversion/copy/LiteralTextToKotlinCopyPasteTestGenerated.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010-2017 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.conversion.copy; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +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/copyPaste/plainTextLiteral") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class LiteralTextToKotlinCopyPasteTestGenerated extends AbstractLiteralTextToKotlinCopyPasteTest { + public void testAllFilesPresentInPlainTextLiteral() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/copyPaste/plainTextLiteral"), Pattern.compile("^([^\\.]+)\\.txt$"), TargetBackend.ANY, true); + } + + @TestMetadata("BrokenEntries.txt") + public void testBrokenEntries() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/BrokenEntries.txt"); + doTest(fileName); + } + + @TestMetadata("MultiLine.txt") + public void testMultiLine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/MultiLine.txt"); + doTest(fileName); + } + + @TestMetadata("MultiLinetoTripleQuote.txt") + public void testMultiLinetoTripleQuote() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/MultiLinetoTripleQuote.txt"); + doTest(fileName); + } + + @TestMetadata("MultiQuotesToTripleQuotes.txt") + public void testMultiQuotesToTripleQuotes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/MultiQuotesToTripleQuotes.txt"); + doTest(fileName); + } + + @TestMetadata("NoSpecialCharsToSingleQuote.txt") + public void testNoSpecialCharsToSingleQuote() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/NoSpecialCharsToSingleQuote.txt"); + doTest(fileName); + } + + @TestMetadata("WithBackslashes.txt") + public void testWithBackslashes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/WithBackslashes.txt"); + doTest(fileName); + } + + @TestMetadata("WithDollarSignToTripleQuotes.txt") + public void testWithDollarSignToTripleQuotes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/WithDollarSignToTripleQuotes.txt"); + doTest(fileName); + } + + @TestMetadata("WithEntries.txt") + public void testWithEntries() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/WithEntries.txt"); + doTest(fileName); + } + + @TestMetadata("WithQuotes.txt") + public void testWithQuotes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/copyPaste/plainTextLiteral/WithQuotes.txt"); + doTest(fileName); + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractLiteralKotlinToKotlinCopyPasteTest.kt b/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractLiteralKotlinToKotlinCopyPasteTest.kt new file mode 100644 index 00000000000..2175d770017 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractLiteralKotlinToKotlinCopyPasteTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2017 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.conversion.copy + +import com.intellij.openapi.actionSystem.IdeActions +import org.jetbrains.kotlin.idea.AbstractCopyPasteTest +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File + +abstract class AbstractLiteralKotlinToKotlinCopyPasteTest : AbstractCopyPasteTest() { + private val BASE_PATH = PluginTestCaseBase.getTestDataPathBase() + "/copyPaste/literal" + + + override fun getTestDataPath() = BASE_PATH + + override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + + + + + + fun doTest(path: String) { + myFixture.testDataPath = BASE_PATH + val testName = getTestName(false) + myFixture.configureByFiles(testName + ".kt") + + myFixture.performEditorAction(IdeActions.ACTION_COPY) + + configureTargetFile(testName + ".to.kt") + + myFixture.performEditorAction(IdeActions.ACTION_PASTE) + KotlinTestUtils.assertEqualsToFile(File(path.replace(".kt", ".expected.kt")), myFixture.file.text) + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractLiteralTextToKotlinCopyPasteTest.kt b/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractLiteralTextToKotlinCopyPasteTest.kt new file mode 100644 index 00000000000..ddd2f4ac820 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/editor/AbstractLiteralTextToKotlinCopyPasteTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2017 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.conversion.copy + +import com.intellij.openapi.actionSystem.IdeActions +import org.jetbrains.kotlin.idea.AbstractCopyPasteTest +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File + +abstract class AbstractLiteralTextToKotlinCopyPasteTest : AbstractCopyPasteTest() { + private val BASE_PATH = PluginTestCaseBase.getTestDataPathBase() + "/copyPaste/plainTextLiteral" + + + override fun getTestDataPath() = BASE_PATH + + override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + + + + + + fun doTest(path: String) { + myFixture.testDataPath = BASE_PATH + val testName = getTestName(false) + myFixture.configureByFiles(testName + ".txt") + + val fileText = myFixture.editor.document.text + + myFixture.editor.selectionModel.setSelection(0, fileText.length) + myFixture.performEditorAction(IdeActions.ACTION_COPY) + + configureTargetFile(testName + ".kt") + + myFixture.performEditorAction(IdeActions.ACTION_PASTE) + KotlinTestUtils.assertEqualsToFile(File(path.replace(".txt", ".expected.kt")), myFixture.file.text) + } +}