PY-18522 Always try to infer expected indent when pasting into empty definition

Use indent based on caret position only when we're pasting neither
inside existing statement list (e.g. in the middle of a function), nor
inside empty statement list
This commit is contained in:
Mikhail Golubev
2016-03-31 16:05:11 +03:00
parent 511fabfcf6
commit 40f9d95817
11 changed files with 136 additions and 18 deletions

View File

@@ -30,6 +30,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ObjectUtils;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.PythonLanguage;
@@ -39,6 +40,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import static com.jetbrains.python.psi.PyUtil.as;
/**
* User : catherine
*/
@@ -84,7 +87,7 @@ public class PythonCopyPasteProcessor implements CopyPastePreProcessor {
text = addLeadingSpaces(text, NOT_INDENT_FILTER, indentSize, indentChar);
int firstLineIndent = StringUtil.findFirst(text, NOT_INDENT_FILTER);
final String indentText = getIndentText(file, document, caretOffset, lineNumber, firstLineIndent);
final String indentText = getIndentText(file, document, caretOffset, lineNumber);
int toRemove = calculateIndentToRemove(text, NOT_INDENT_FILTER);
@@ -135,7 +138,7 @@ public class PythonCopyPasteProcessor implements CopyPastePreProcessor {
private static String getIndentText(@NotNull final PsiFile file,
@NotNull final Document document,
int caretOffset,
int lineNumber, int firstLineIndent) {
int lineNumber) {
PsiElement nonWS = PyUtil.findNextAtOffset(file, caretOffset, PsiWhiteSpace.class);
if (nonWS != null) {
@@ -147,27 +150,28 @@ public class PythonCopyPasteProcessor implements CopyPastePreProcessor {
}
}
int lineStartOffset = getLineStartSafeOffset(document, lineNumber);
String indentText = document.getText(TextRange.create(lineStartOffset, caretOffset));
if (nonWS != null && document.getLineNumber(nonWS.getTextOffset()) == lineNumber) {
indentText = document.getText(TextRange.create(lineStartOffset, nonWS.getTextOffset()));
return PyIndentUtil.getLineIndent(document, lineNumber);
}
else if (caretOffset == lineStartOffset) {
final PsiElement ws = file.findElementAt(lineStartOffset);
if (ws != null) {
final String wsText = ws.getText();
final List<String> strings = StringUtil.split(wsText, "\n");
if (strings.size() >= 1) {
indentText = strings.get(0);
}
int lineStartOffset = getLineStartSafeOffset(document, lineNumber);
final PsiElement ws = file.findElementAt(lineStartOffset);
if (ws != null) {
// Beginning of empty definition, e.g. class or function header without the actual body
PyStatementList statementList = ObjectUtils.chooseNotNull(as(ws.getNextSibling(), PyStatementList.class),
as(ws.getPrevSibling(), PyStatementList.class));
if (statementList != null && statementList.getStatements().length == 0) {
return PyIndentUtil.getExpectedElementIndent(statementList);
}
// Top-level, there should be no indentation
if (PsiTreeUtil.getParentOfType(ws, PyStatementList.class) == null) {
return "";
final PyStatementListContainer container = PsiTreeUtil.getParentOfType(ws, PyStatementListContainer.class);
if (container != null) {
return PyIndentUtil.getElementIndent(container.getStatementList());
}
}
return indentText;
return document.getText(TextRange.create(lineStartOffset, caretOffset));
}
private static int calculateIndentToRemove(@NotNull String text, @NotNull final CharFilter filter) {

View File

@@ -0,0 +1,14 @@
class C:
def empty(self):
"""
line 1
line 2
"""
pass
def another(self):
"""
line 1
line 2
"""
pass

View File

@@ -0,0 +1,9 @@
class C:
def empty(self):
<caret>
def another(self):
"""
line 1
line 2
"""
pass

View File

@@ -0,0 +1,10 @@
class C:
def empty(self):
def another(self):
<selection> """
line 1
line 2
"""
pass
</selection>

View File

@@ -0,0 +1,14 @@
class C:
def empty(self):
"""
line 1
line 2
"""
pass
def another(self):
"""
line 1
line 2
"""
pass

View File

@@ -0,0 +1,9 @@
class C:
def empty(self):
<caret>
def another(self):
"""
line 1
line 2
"""
pass

View File

@@ -0,0 +1,10 @@
class C:
def empty(self):
def another(self):
<selection> """
line 1
line 2
"""
pass
</selection>

View File

@@ -0,0 +1,14 @@
class C:
def empty(self):
"""
line 1
line 2
"""
pass
def another(self):
"""
line 1
line 2
"""
pass

View File

@@ -0,0 +1,9 @@
class C:
def empty(self):
<caret>
def another(self):
"""
line 1
line 2
"""
pass

View File

@@ -0,0 +1,10 @@
class C:
def empty(self):
def another(self):
<selection> """
line 1
line 2
"""
pass
</selection>

View File

@@ -376,4 +376,19 @@ public class PyCopyPasteTest extends PyTestCase {
public void testSameIndentPreserved() {
doTest();
}
// PY-18522
public void testEmptyFunctionCaretAtNoneIndent() {
doTest();
}
// PY-18522
public void testEmptyFunctionCaretAtDefIndent() {
doTest();
}
// PY-18522
public void testEmptyFunctionCaretAtBodyIndent() {
doTest();
}
}