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:
Ekaterina Tuzova
2012-07-02 15:45:20 +04:00
parent f66a60ccef
commit a67f912cc5
85 changed files with 469 additions and 15 deletions

View File

@@ -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");
}
}

View File

@@ -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);
}

View File

@@ -1,3 +1,5 @@
def bar():
x = 1
y = 2
y = 2
var = "string"

View File

@@ -1,2 +1,4 @@
def bar():
<caret>
<caret>
var = "string"

View File

@@ -1,3 +1,5 @@
def bar():
x = 1
y = 2
y = 2
var = "string"

View File

@@ -1,2 +1,3 @@
def bar():
<caret>
<caret>
var = "string"

View File

@@ -0,0 +1,7 @@
class C:
def foo(self):
x = 1
y = 2
def bar(self):
pass

View File

@@ -0,0 +1,3 @@
class C:
<caret>def bar(self):
pass

View File

@@ -0,0 +1,5 @@
class C:
<selection> def foo(self):
x = 1
y = 2
</selection>

View File

@@ -0,0 +1,7 @@
class C:
def foo(self):
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,5 @@
class C:
<selection>def foo(self):
x = 1
y = 2
</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1
y = 2</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1
y = 2</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1
y = 2</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1
y = 2</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1
y = 2</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1
y = 2</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
<selection> x = 1
y = 2
</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
<selection> x = 1
y = 2
</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
<selection> x = 1
y = 2
</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
<selection>x = 1
y = 2
</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
<selection>x = 1
y = 2
</selection>

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
x = 1
y = 2
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,5 @@
class C:
def foo(self):
<selection>x = 1
y = 2
</selection>

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
x = 1y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1</selection>
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
x = 1 y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1</selection>
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
x = 1 y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1</selection>
y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1</selection>
y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1</selection>
y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1</selection>
y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1
</selection> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1
</selection> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection> x = 1
</selection> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret>y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1
</selection> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1
</selection> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
x = 1
y = 2

View File

@@ -0,0 +1,3 @@
class C:
def foo(self):
<caret> y = 2

View File

@@ -0,0 +1,4 @@
class C:
def foo(self):
<selection>x = 1
</selection> y = 2

View File

@@ -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");
}
}