diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 1b02cfd7d813..7cd53851f868 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -148,6 +148,11 @@ Python + + com.jetbrains.python.codeInsight.intentions.PyConvertLambdaToFunctionIntention + Python + + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index f7d2a8834a2f..a4a812658721 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -130,7 +130,9 @@ INTN.convert.dict.literal.to.dict.constructor=Convert dict literal to dict const INTN.quoted.string=Convert between single-quoted and double-quoted strings INTN.quoted.string.single.to.double=Convert single-quoted string to double-quoted string -INTN.quoted.string.double.to.single=Convert double-quoted string to sungle-quoted string +INTN.quoted.string.double.to.single=Convert double-quoted string to single-quoted string + +INTN.convert.lambda.to.function=Convert lambda to function # Conflict checker CONFLICT.name.$0.obscured=Name ''{0}'' obscured by local definitions diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java new file mode 100644 index 000000000000..ce0726cd99fd --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java @@ -0,0 +1,100 @@ +package com.jetbrains.python.codeInsight.intentions; + +import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +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.psi.*; +import org.jetbrains.annotations.NotNull; + +/** + * User: catherine + * Intention to convert lambda to function + */ +public class PyConvertLambdaToFunctionIntention extends BaseIntentionAction { + + @NotNull + public String getFamilyName() { + return PyBundle.message("INTN.convert.lambda.to.function"); + } + + @NotNull + public String getText() { + return PyBundle.message("INTN.convert.lambda.to.function"); + } + + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + PyLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyLambdaExpression.class); + if (lambdaExpression != null) { + if (lambdaExpression.getBody() != null) + return true; + } + return false; + } + + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + PyLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyLambdaExpression.class); + PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); + if (lambdaExpression != null) { + String name; + PsiElement parent = lambdaExpression.getParent(); + if (parent instanceof PyAssignmentStatement) { + name = ((PyAssignmentStatement)parent).getLeftHandSideExpression().getText(); + } + else { + Application application = ApplicationManager.getApplication(); + if (application != null && !application.isUnitTestMode()) { + AskNameDialog dialog = new AskNameDialog(project); + dialog.setTitle("Enter function name"); + dialog.show(); + if (!dialog.isOK()) return; // 'Cancel' button cancels everything + name = dialog.getAlias(); + if (name.isEmpty()) return; + } + else + name = "function"; + } + + PyExpression body = lambdaExpression.getBody(); + PyParameter[] parameters = lambdaExpression.getParameterList().getParameters(); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("def "); + stringBuilder.append(name); + stringBuilder.append("("); + int size = parameters.length; + for (int i = 0; i != size; ++i) { + PyParameter parameter = parameters[i]; + stringBuilder.append(parameter.getName()); + if ( i != size - 1) + stringBuilder.append(","); + } + stringBuilder.append("):\n return "); + stringBuilder.append(body.getText()); + + PyFunction function = elementGenerator.createFromText(LanguageLevel.forElement(lambdaExpression), + PyFunction.class, stringBuilder.toString()); + + PyFunction pyFunction = PsiTreeUtil.getParentOfType(lambdaExpression, PyFunction.class); + if (pyFunction != null) { + pyFunction.getStatementList().addBefore(function, pyFunction.getStatementList().getStatements()[0]); + } + else { + PyStatement statement = PsiTreeUtil.getParentOfType(lambdaExpression, PyStatement.class); + file.addBefore(function, statement); + } + if (parent instanceof PyAssignmentStatement) { + parent.delete(); + } + else { + lambdaExpression.replace(elementGenerator.createFromText(LanguageLevel.forElement(lambdaExpression), PyExpression.class, + name)); + } + } + } +} diff --git a/python/testData/intentions/afterConvertLambdaToFunction.py b/python/testData/intentions/afterConvertLambdaToFunction.py new file mode 100644 index 000000000000..619b1e392e9c --- /dev/null +++ b/python/testData/intentions/afterConvertLambdaToFunction.py @@ -0,0 +1,6 @@ +def func(seq): + def function(x, y): + return (x + y) / y + + newlist = reduce(function + , seq) \ No newline at end of file diff --git a/python/testData/intentions/beforeConvertLambdaToFunction.py b/python/testData/intentions/beforeConvertLambdaToFunction.py new file mode 100644 index 000000000000..eaa151a875ac --- /dev/null +++ b/python/testData/intentions/beforeConvertLambdaToFunction.py @@ -0,0 +1,2 @@ +def func(seq): + newlist = reduce(lambda x, y: (x+y)/y, seq) \ 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 c5a4a0112bc3..5799c1ffb6f1 100644 --- a/python/testSrc/com/jetbrains/python/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/PyIntentionTest.java @@ -124,4 +124,8 @@ public class PyIntentionTest extends PyLightFixtureTestCase { public void testQuotedString() { doTest(PyBundle.message("INTN.quoted.string.double.to.single")); } + + public void testConvertLambdaToFunction() { + doTest(PyBundle.message("INTN.convert.lambda.to.function")); + } }