Conversion on copy paste:
Only convert elements that are wholly selected
This commit is contained in:
@@ -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()
|
||||
}
|
||||
+20
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user