correctly check if we need to insert a backslash when wrapping (PY-7039)

This commit is contained in:
Dmitry Jemerov
2012-08-22 16:24:04 +02:00
parent 3490280116
commit d358309fcc
3 changed files with 26 additions and 14 deletions
@@ -8,6 +8,7 @@ import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.Stack;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.editor.PythonEnterHandler;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
@@ -30,13 +31,12 @@ public class RemoveUnnecessaryBackslashQuickFix implements LocalQuickFix {
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement problemElement = descriptor.getPsiElement();
if (problemElement != null) {
PyElement parent = PsiTreeUtil.getParentOfType(problemElement, PySequenceExpression.class, PyDictLiteralExpression.class,
PyParenthesizedExpression.class, PyArgumentList.class, PyParameterList.class);
PsiElement parent = PsiTreeUtil.getParentOfType(problemElement, PythonEnterHandler.IMPLICIT_WRAP_CLASSES);
removeBackSlash(parent);
}
}
private static void removeBackSlash(PyElement parent) {
private static void removeBackSlash(PsiElement parent) {
if (parent != null) {
Stack<PsiElement> stack = new Stack<PsiElement>();
if (parent instanceof PyParenthesizedExpression)
@@ -29,7 +29,15 @@ import org.jetbrains.annotations.Nullable;
public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
private boolean needPostProcess = false;
private static final Class[] IMPLICIT_WRAP_CLASSES = new Class[]{
public static final Class[] IMPLICIT_WRAP_CLASSES = new Class[] {
PySequenceExpression.class,
PyDictLiteralExpression.class,
PyParenthesizedExpression.class,
PyArgumentList.class,
PyParameterList.class
};
private static final Class[] WRAPPABLE_CLASSES = new Class[]{
PsiComment.class,
PyParenthesizedExpression.class,
PyListCompExpression.class,
@@ -116,13 +124,11 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
final boolean isEscapedBackslash = "\\".equals(doc.getText(TextRange.create(offset-2, offset - 1))) && nextIsBackslash;
if (nextIsBackslash && !isEscapedQuote && !isEscapedBackslash) return Result.Continue;
final PsiElement parent = string.getParent();
final StringBuilder replacementString = new StringBuilder();
needPostProcess = true;
if (parent instanceof PySequenceExpression || parent instanceof PyParenthesizedExpression ||
parent instanceof PyBinaryExpression || parent instanceof PyKeyValueExpression ||
parent instanceof PyNamedParameter || parent instanceof PyArgumentList) {
replacementString.append(quote + pref + quote);
if (PsiTreeUtil.getParentOfType(string, IMPLICIT_WRAP_CLASSES) != null) {
replacementString.append(quote).append(pref).append(quote);
doc.insertString(offset, replacementString);
caretOffset.set(caretOffset.get() + 1);
return Result.Continue;
@@ -132,7 +138,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
replacementString.append(quote);
caretOffset.set(caretOffset.get() + 1);
}
replacementString.append(quote + " \\" + pref);
replacementString.append(quote).append(" \\").append(pref);
if (!isEscapedQuote)
replacementString.append(quote);
doc.insertString(offset, replacementString.toString());
@@ -187,7 +193,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
PsiElement wrappableAfter = findWrappable(file, offset, false);
if (!(wrappableBefore instanceof PsiComment)) {
while (wrappableBefore != null) {
PsiElement next = PsiTreeUtil.getParentOfType(wrappableBefore, IMPLICIT_WRAP_CLASSES);
PsiElement next = PsiTreeUtil.getParentOfType(wrappableBefore, WRAPPABLE_CLASSES);
if (next == null) {
break;
}
@@ -196,7 +202,7 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
}
if (!(wrappableAfter instanceof PsiComment)) {
while (wrappableAfter != null) {
PsiElement next = PsiTreeUtil.getParentOfType(wrappableAfter, IMPLICIT_WRAP_CLASSES);
PsiElement next = PsiTreeUtil.getParentOfType(wrappableAfter, WRAPPABLE_CLASSES);
if (next == null) {
break;
}
@@ -234,8 +240,8 @@ public class PythonEnterHandler extends EnterHandlerDelegateAdapter {
@Nullable
private static PsiElement findWrappable(PsiFile file, int offset, boolean before) {
PsiElement wrappable = before
? findBeforeCaret(file, offset, IMPLICIT_WRAP_CLASSES)
: findAfterCaret(file, offset, IMPLICIT_WRAP_CLASSES);
? findBeforeCaret(file, offset, WRAPPABLE_CLASSES)
: findAfterCaret(file, offset, WRAPPABLE_CLASSES);
if (wrappable == null) {
PsiElement emptyTuple = before
? findBeforeCaret(file, offset, PyTupleExpression.class)
@@ -111,6 +111,12 @@ public class PyEditingTest extends PyTestCase {
" r'string'");
}
public void testEnterInStringFormatting() { // PY-7039
doTestEnter("foo += \"fooba<caret>r\" % foo\n",
"foo += \"fooba\" \\\n" +
" \"r\" % foo\n");
}
public void testEnterInStatement() {
doTestEnter("if a <caret>and b: pass", "if a \\\nand b: pass");
}