mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Smart copy-paste
fixed PY-6410 Adding/Pasting text at the end of a class method causes the next class method to be moved outside the class
This commit is contained in:
@@ -10,6 +10,6 @@ import com.intellij.openapi.options.UnnamedConfigurable;
|
||||
public class PySmartKeysOptions extends BeanConfigurable<CodeInsightSettings> implements UnnamedConfigurable {
|
||||
public PySmartKeysOptions() {
|
||||
super(CodeInsightSettings.getInstance());
|
||||
checkBox("INDENT_TO_CARET_ON_PASTE", "Indent pasted lines relative to caret location");
|
||||
checkBox("INDENT_TO_CARET_ON_PASTE", "Smart indent pasted lines");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.editor;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.editorActions.CopyPastePreProcessor;
|
||||
import com.intellij.openapi.editor.CaretModel;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
@@ -13,6 +14,8 @@ import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User : catherine
|
||||
*/
|
||||
@@ -29,23 +32,40 @@ public class PythonCopyPasteProcessor implements CopyPastePreProcessor {
|
||||
Editor editor,
|
||||
String text,
|
||||
RawText rawText) {
|
||||
if (!CodeInsightSettings.getInstance().INDENT_TO_CARET_ON_PASTE) {
|
||||
return text;
|
||||
}
|
||||
|
||||
final CaretModel caretModel = editor.getCaretModel();
|
||||
final Document document = editor.getDocument();
|
||||
String newText = text;
|
||||
|
||||
if (file instanceof PyFile && StringUtil.startsWithWhitespace(text) && StringUtil.endsWithLineBreak(text)) {
|
||||
if (file instanceof PyFile && (StringUtil.startsWithWhitespace(text) || StringUtil.endsWithLineBreak(text) ||
|
||||
StringUtil.splitByLines(text).length > 1)) {
|
||||
if (text.endsWith("\n")) text = text.substring(0, text.length() - 1);
|
||||
final int caretOffset = caretModel.getOffset();
|
||||
final PsiElement element = PsiUtilCore.getElementAtOffset(file, caretOffset-1);
|
||||
final int lineNumber = document.getLineNumber(caretOffset);
|
||||
final int offset = getLineStartSafeOffset(document, lineNumber);
|
||||
final PsiElement element1 = PsiUtilCore.getElementAtOffset(file, offset);
|
||||
if (element instanceof PsiWhiteSpace && element == element1) {
|
||||
caretModel.moveToOffset(offset);
|
||||
final List<String> strings = StringUtil.split(element.getText(), "\n");
|
||||
//user already prepared place to paste to and we just want to indent right
|
||||
if (StringUtil.countChars(element.getText(), '\n') > 2) {
|
||||
newText = text + " ";
|
||||
}
|
||||
else {
|
||||
newText = text + "\n" + strings.get(strings.size()-1);
|
||||
//pasted text'll be the only one statement in block
|
||||
if (!element.getText().endsWith("\n"))
|
||||
caretModel.moveToOffset(element.getTextRange().getEndOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
return text;
|
||||
return newText;
|
||||
}
|
||||
|
||||
public int getLineStartSafeOffset(final Document document, int line) {
|
||||
public static int getLineStartSafeOffset(final Document document, int line) {
|
||||
if (line == document.getLineCount()) return document.getTextLength();
|
||||
return document.getLineStartOffset(line);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
def bar():
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
|
||||
var = "string"
|
||||
@@ -1,2 +1,4 @@
|
||||
def bar():
|
||||
<caret>
|
||||
<caret>
|
||||
|
||||
var = "string"
|
||||
@@ -1,3 +1,5 @@
|
||||
def bar():
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
|
||||
var = "string"
|
||||
@@ -1,2 +1,3 @@
|
||||
def bar():
|
||||
<caret>
|
||||
<caret>
|
||||
var = "string"
|
||||
@@ -0,0 +1,7 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
|
||||
def bar(self):
|
||||
pass
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
<caret>def bar(self):
|
||||
pass
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
<selection> def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
</selection>
|
||||
@@ -0,0 +1,7 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
<selection>def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
y = 2</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
y = 2</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
y = 2</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
y = 2</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
y = 2</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
y = 2</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
y = 2
|
||||
</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
y = 2
|
||||
</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
y = 2
|
||||
</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
y = 2
|
||||
</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
y = 2
|
||||
</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
y = 2
|
||||
</selection>
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1</selection>
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1 y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1</selection>
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1 y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1</selection>
|
||||
y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1</selection>
|
||||
y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1</selection>
|
||||
y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1</selection>
|
||||
y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
</selection> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
</selection> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection> x = 1
|
||||
</selection> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret>y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
</selection> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
</selection> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<caret> y = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>x = 1
|
||||
</selection> y = 2
|
||||
@@ -2,7 +2,6 @@ package com.jetbrains.python;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
|
||||
/**
|
||||
@@ -44,18 +43,137 @@ public class PyCopyPasteTest extends PyTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testMethodInClass() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIndent11() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent12() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent13() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent21() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent22() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent23() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent31() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent32() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent33() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent41() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent42() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndent43() {
|
||||
doTestSingleLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti11() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti12() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti13() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti21() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti22() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti23() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti31() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti32() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti33() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti41() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti42() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentMulti43() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
public void testIndentInnerFunction() {
|
||||
doTestMultiLine();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
String name = getTestName(false);
|
||||
|
||||
if (!SystemInfo.isWindows) {
|
||||
System.out.println("PyCopyPasteTest." + name + ": system is not windows. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
myFixture.configureByFile("copyPaste/" + name + ".src.py");
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_COPY);
|
||||
myFixture.configureByFile("copyPaste/" + name + ".dst.py");
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE);
|
||||
myFixture.checkResultByFile("copyPaste/" + name + ".after.py");
|
||||
}
|
||||
|
||||
private void doTestSingleLine() {
|
||||
String name = getTestName(false);
|
||||
|
||||
myFixture.configureByFile("copyPaste/singleLine/" + name + ".src.py");
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_COPY);
|
||||
myFixture.configureByFile("copyPaste/singleLine/" + name + ".dst.py");
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE);
|
||||
myFixture.checkResultByFile("copyPaste/singleLine/" + name + ".after.py");
|
||||
}
|
||||
|
||||
private void doTestMultiLine() {
|
||||
String name = getTestName(false);
|
||||
|
||||
myFixture.configureByFile("copyPaste/multiLine/" + name + ".src.py");
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_COPY);
|
||||
myFixture.configureByFile("copyPaste/multiLine/" + name + ".dst.py");
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE);
|
||||
myFixture.checkResultByFile("copyPaste/multiLine/" + name + ".after.py");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user