Conversion on copy paste:

Only convert elements that are wholly selected
This commit is contained in:
Pavel V. Talanov
2013-12-19 21:42:27 +04:00
parent da3b43fbf3
commit ab19669c43
15 changed files with 135 additions and 34 deletions
@@ -17,7 +17,7 @@
package org.jetbrains.jet.plugin.conversion.copy;
import com.intellij.codeInsight.editorActions.TextBlockTransferableData;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,11 +26,11 @@ import java.awt.datatransfer.DataFlavor;
class CopiedCode implements TextBlockTransferableData {
@NotNull
public static final DataFlavor DATA_FLAVOR = new DataFlavor(JavaCopyPastePostProcessor.class, "class: JavaCopyPastePostProcessor");
private final PsiFile file;
private final PsiJavaFile file;
private final int[] startOffsets;
private final int[] endOffsets;
public CopiedCode(@Nullable PsiFile file, @NotNull int[] startOffsets, @NotNull int[] endOffsets) {
public CopiedCode(@Nullable PsiJavaFile file, @NotNull int[] startOffsets, @NotNull int[] endOffsets) {
this.file = file;
this.startOffsets = startOffsets;
this.endOffsets = endOffsets;
@@ -58,7 +58,7 @@ class CopiedCode implements TextBlockTransferableData {
}
@Nullable
public PsiFile getFile() {
public PsiJavaFile getFile() {
return file;
}
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.plugin.editor.JetEditorOptions
import java.awt.datatransfer.Transferable
import java.util.ArrayList
import com.intellij.openapi.util.TextRange
public class JavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBlockTransferableData> {
@@ -52,7 +53,7 @@ public class JavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBlockTran
}
val lightFile = PsiFileFactory.getInstance(file.getProject())!!.createFileFromText(file.getText()!!, file)
return CopiedCode(lightFile, startOffsets!!, endOffsets!!)
return CopiedCode(lightFile as? PsiJavaFile, startOffsets!!, endOffsets!!)
}
public override fun processTransferableData(project: Project?, editor: Editor?, bounds: RangeMarker?,
@@ -60,6 +61,9 @@ public class JavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBlockTran
if (value !is CopiedCode)
return
if (value.getFile() == null)
return
val file = PsiDocumentManager.getInstance(project!!).getPsiFile(editor!!.getDocument())
if (file !is JetFile)
return
@@ -67,8 +71,8 @@ public class JavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBlockTran
val jetEditorOptions = JetEditorOptions.getInstance()!!
val needConvert = jetEditorOptions.isEnableJavaToKotlinConversion() && (jetEditorOptions.isDonTShowConversionDialog() || okFromDialog(project))
if (needConvert) {
val text = convertCopiedCodeToKotlin((value as CopiedCode), file)
if (text.isNotEmpty() ) {
val text = convertCopiedCodeToKotlin(value, file)
if (text.isNotEmpty()) {
ApplicationManager.getApplication()!!.runWriteAction {
editor.getDocument().replaceString(bounds!!.getStartOffset(), bounds.getEndOffset(), text)
editor.getCaretModel().moveToOffset(bounds.getStartOffset() + text.length())
@@ -78,38 +82,68 @@ public class JavaCopyPastePostProcessor() : CopyPastePostProcessor<TextBlockTran
}
}
private fun convertCopiedCodeToKotlin(code: CopiedCode, file: PsiFile): String {
val buffer = getSelectedElements(code.getFile()!!, code.getStartOffsets(), code.getEndOffsets())
val project = file.getProject()
val converter = Converter(project, PluginSettings)
val result = buffer.map { converter.elementToKotlin(it) }.makeString("")
return StringUtil.convertLineSeparators(result.toString())
}
private fun getSelectedElements(file: PsiFile, startOffsets: IntArray, endOffsets: IntArray): MutableList<PsiElement> {
val buffer = ArrayList<PsiElement>()
private fun convertCopiedCodeToKotlin(code: CopiedCode, fileToPaste: PsiFile): String {
val converter = Converter(fileToPaste.getProject(), PluginSettings)
val startOffsets = code.getStartOffsets()
val endOffsets = code.getEndOffsets()
assert(startOffsets.size == endOffsets.size) { "Must have the same size" }
val result = StringBuilder()
for (i in 0..startOffsets.size - 1) {
val startOffset = startOffsets[i]
val endOffset = endOffsets[i]
var elem = file.findElementAt(startOffset)
while (elem != null &&
elem!!.getParent() != null &&
!(elem!!.getParent() is PsiFile) &&
elem!!.getParent()!!.getTextRange()!!.getEndOffset() <= endOffset) {
elem = elem!!.getParent()
}
if (elem != null) {
buffer.add(elem!!)
}
while (elem != null && elem!!.getTextRange()!!.getEndOffset() < endOffset) {
elem = elem!!.getNextSibling()
if (elem != null) {
buffer.add(elem!!)
}
}
result.append(convertRangeToKotlin(code.getFile()!!, TextRange(startOffset, endOffset), converter))
}
return buffer
return StringUtil.convertLineSeparators(result.toString())
}
private fun convertRangeToKotlin(file: PsiJavaFile,
range: TextRange,
converter: Converter): String {
val result = StringBuilder()
var currentRange = range
while (!currentRange.isEmpty()) {
val leafElement = findFirstLeafElementWhollyInRange(file, currentRange)
if (leafElement == null) {
break;
}
val elementToConvert = findTopMostParentWhollyInRange(currentRange, leafElement)
result.append(converter.elementToKotlin(elementToConvert))
val endOfConverted = elementToConvert.getTextRange()!!.getEndOffset()
currentRange = TextRange(endOfConverted, currentRange.getEndOffset())
}
return result.toString()
}
private fun findFirstLeafElementWhollyInRange(file: PsiJavaFile, range: TextRange): PsiElement? {
var i = range.getStartOffset()
while (i < range.getEndOffset()) {
var element = file.findElementAt(i)
if (element == null) {
++i
continue
}
val elemRange = element!!.getTextRange()!!
if (elemRange !in range) {
i = elemRange.getEndOffset()
continue
}
return element
}
return null
}
private fun findTopMostParentWhollyInRange(range: TextRange,
base: PsiElement): PsiElement {
var elem = base
var parent = elem.getParent()
while (elem.getTextRange()!! in range &&
parent != null &&
parent !is PsiJavaFile &&
parent!!.getTextRange()!! in range) {
elem = parent!!
parent = elem.getParent()
}
return elem
}
private fun okFromDialog(project: Project): Boolean {
@@ -0,0 +1,5 @@
import g.e.v
fun main(args: Array<String>) {
}
@@ -0,0 +1,4 @@
import java.util.List;
import a.b.c;
import java.util.Set;
<selection>import g.e.v;</selection>
@@ -0,0 +1,5 @@
<caret>
fun main(args: Array<String>) {
}
@@ -0,0 +1,4 @@
fun main(args: Array<String>) {
reference(arg)
somethingElse()
}
@@ -0,0 +1,5 @@
class A {
public static void main(String[] args) {
qualifier.<selection>reference(arg)</selection>;
}
}
@@ -0,0 +1,4 @@
fun main(args: Array<String>) {
<caret>
somethingElse()
}
@@ -0,0 +1 @@
}
@@ -0,0 +1,5 @@
class A {
public static void main(String[] args) {
//sdasd
}
<selection>}</selection>
@@ -0,0 +1 @@
<caret>
@@ -0,0 +1,4 @@
fun main(args: Array<String>) {
qualifier
somethingElse()
}
@@ -0,0 +1,5 @@
class A {
public static void main(String[] args) {
<selection>qualifier</selection>.reference(arg);
}
}
@@ -0,0 +1,4 @@
fun main(args: Array<String>) {
<caret>
somethingElse()
}
@@ -51,6 +51,26 @@ public class JavaToKotlinCopyPasteConversionTestGenerated extends AbstractJavaTo
doTest("idea/testData/copyPaste/conversion/Imports2.java");
}
@TestMetadata("Imports3.java")
public void testImports3() throws Exception {
doTest("idea/testData/copyPaste/conversion/Imports3.java");
}
@TestMetadata("MethodReferenceWithoutQualifier.java")
public void testMethodReferenceWithoutQualifier() throws Exception {
doTest("idea/testData/copyPaste/conversion/MethodReferenceWithoutQualifier.java");
}
@TestMetadata("OnlyClosingBrace.java")
public void testOnlyClosingBrace() throws Exception {
doTest("idea/testData/copyPaste/conversion/OnlyClosingBrace.java");
}
@TestMetadata("OnlyQualifier.java")
public void testOnlyQualifier() throws Exception {
doTest("idea/testData/copyPaste/conversion/OnlyQualifier.java");
}
@TestMetadata("SampleBlock.java")
public void testSampleBlock() throws Exception {
doTest("idea/testData/copyPaste/conversion/SampleBlock.java");