From 377f9fa25c6a7adbab75bda2601d68e511f8b83e Mon Sep 17 00:00:00 2001 From: "alexey.ivanov" Date: Fri, 12 Mar 2010 19:35:47 +0300 Subject: [PATCH] negate comparison intention --- python/src/META-INF/python-plugin-common.xml | 6 ++ .../com/jetbrains/python/PyBundle.properties | 3 + .../PyNegateComparisonIntention.java | 89 +++++++++++++++++++ .../intentions/afterNegateComparison.py | 2 + .../intentions/afterNegateComparison2.py | 2 + .../intentions/beforeNegateComparison.py | 2 + .../intentions/beforeNegateComparison2.py | 2 + .../com/jetbrains/python/PyIntentionTest.java | 10 ++- 8 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 python/src/com/jetbrains/python/codeInsight/intentions/PyNegateComparisonIntention.java create mode 100644 python/testData/intentions/afterNegateComparison.py create mode 100644 python/testData/intentions/afterNegateComparison2.py create mode 100644 python/testData/intentions/beforeNegateComparison.py create mode 100644 python/testData/intentions/beforeNegateComparison2.py diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 0109b367d34f..72b470087439 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -95,6 +95,12 @@ PySplitIfIntention + + com.jetbrains.python.codeInsight.intentions.PyNegateComparisonIntention + Python + PyNegateComparisonIntention + + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index 93f7ed1ab6df..f61ad5fb2df9 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -83,6 +83,9 @@ INTN.replace.method=Replace method which is not supported in current Python vers INTN.split.if=Split if INTN.split.if.text=Split into 2 if's +INTN.negate.comparison=Negate comparison +INTN.negate.$0.to.$1=Negate ''{0}'' to ''{1}'' + # Conflict checker CONFLICT.name.$0.obscured=Name ''{0}'' obscured by local definitions CONFLICT.name.$0.obscured.cannot.convert=Name ''{0}'' obscured. Cannot convert. diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyNegateComparisonIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyNegateComparisonIntention.java new file mode 100644 index 000000000000..e9fcdcee8c9e --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyNegateComparisonIntention.java @@ -0,0 +1,89 @@ +package com.jetbrains.python.codeInsight.intentions; + +import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.PyTokenTypes; +import com.jetbrains.python.PythonLanguage; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by IntelliJ IDEA. + * Author: Alexey.Ivanov + * Date: 12.03.2010 + * Time: 17:58:56 + */ +public class PyNegateComparisonIntention extends BaseIntentionAction { + private static final Map comparisonStrings = new HashMap(7); + private static final Map invertedComparasions = new HashMap(7); + + static { + comparisonStrings.put(PyTokenTypes.LT, "<"); + comparisonStrings.put(PyTokenTypes.GT, ">"); + comparisonStrings.put(PyTokenTypes.EQEQ, "=="); + comparisonStrings.put(PyTokenTypes.LE, "<="); + comparisonStrings.put(PyTokenTypes.GE, ">="); + comparisonStrings.put(PyTokenTypes.NE, "!="); + comparisonStrings.put(PyTokenTypes.NE_OLD, "<>"); + + invertedComparasions.put(PyTokenTypes.LT, PyTokenTypes.GE); + invertedComparasions.put(PyTokenTypes.GT, PyTokenTypes.LE); + invertedComparasions.put(PyTokenTypes.EQEQ, PyTokenTypes.NE); + invertedComparasions.put(PyTokenTypes.LE, PyTokenTypes.GT); + invertedComparasions.put(PyTokenTypes.GE, PyTokenTypes.LT); + invertedComparasions.put(PyTokenTypes.NE, PyTokenTypes.EQEQ); + invertedComparasions.put(PyTokenTypes.NE_OLD, PyTokenTypes.EQEQ); + } + + @NotNull + public String getFamilyName() { + return PyBundle.message("INTN.negate.comparison"); + } + + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + PsiElement element = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class, false); + if (element == null) { + return false; + } + + PyElementType operator = ((PyBinaryExpression)element).getOperator(); + if (!comparisonStrings.containsKey(operator)) { + return false; + } + setText(PyBundle.message("INTN.negate.$0.to.$1", + comparisonStrings.get(operator), + comparisonStrings.get(invertedComparasions.get(operator)))); + return true; + } + + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + PsiElement element = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class, false); + + PsiElement parent = element.getParent(); + while (parent instanceof PyParenthesizedExpression) { + parent = parent.getParent(); + } + PyBinaryExpression binaryExpression = (PyBinaryExpression)element; + final PyElementType invertedOperator = invertedComparasions.get(binaryExpression.getOperator()); + PyElementGenerator elementGenerator = PythonLanguage.getInstance().getElementGenerator(); + final PyBinaryExpression newElement = elementGenerator.createBinaryExpression(project, + comparisonStrings.get(invertedOperator), + binaryExpression.getLeftExpression(), + binaryExpression.getRightExpression()); + + if (parent instanceof PyPrefixExpression && ((PyPrefixExpression)parent).getOperationSign() == PyTokenTypes.NOT_KEYWORD) { + parent.replace(newElement); + } else { + element.replace(elementGenerator.createExpressionFromText(project, "not " + newElement.getText())); + } + } +} diff --git a/python/testData/intentions/afterNegateComparison.py b/python/testData/intentions/afterNegateComparison.py new file mode 100644 index 000000000000..648de97571d5 --- /dev/null +++ b/python/testData/intentions/afterNegateComparison.py @@ -0,0 +1,2 @@ +if b > 3 and a > b: + pass \ No newline at end of file diff --git a/python/testData/intentions/afterNegateComparison2.py b/python/testData/intentions/afterNegateComparison2.py new file mode 100644 index 000000000000..d095947dfd15 --- /dev/null +++ b/python/testData/intentions/afterNegateComparison2.py @@ -0,0 +1,2 @@ +if b < 3 or not a <= b: + pass \ No newline at end of file diff --git a/python/testData/intentions/beforeNegateComparison.py b/python/testData/intentions/beforeNegateComparison.py new file mode 100644 index 000000000000..f423358c334b --- /dev/null +++ b/python/testData/intentions/beforeNegateComparison.py @@ -0,0 +1,2 @@ +if b > 3 and not (a <= b): + pass \ No newline at end of file diff --git a/python/testData/intentions/beforeNegateComparison2.py b/python/testData/intentions/beforeNegateComparison2.py new file mode 100644 index 000000000000..a5bd4ac685ba --- /dev/null +++ b/python/testData/intentions/beforeNegateComparison2.py @@ -0,0 +1,2 @@ +if b < 3 or a > b: + pass \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/PyIntentionTest.java index a7b589e309f8..e621d33fa57c 100644 --- a/python/testSrc/com/jetbrains/python/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/PyIntentionTest.java @@ -82,7 +82,15 @@ public class PyIntentionTest extends PyLightFixtureTestCase { doTest(PyBundle.message("INTN.replace.method"), LanguageLevel.PYTHON30); } - public void testSplitIf()throws Exception { + public void testSplitIf() throws Exception { doTest(PyBundle.message("INTN.split.if.text")); } + + public void testNegateComparison() throws Exception { + doTest(PyBundle.message("INTN.negate.$0.to.$1", "<=", ">")); + } + + public void testNegateComparison2() throws Exception { + doTest(PyBundle.message("INTN.negate.$0.to.$1", ">", "<=")); + } }