diff options
Diffstat (limited to 'python/src')
48 files changed, 892 insertions, 353 deletions
diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index 88280cc2cf10..a27eb44ae3af 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -528,6 +528,12 @@ <!-- Packaging --> <moduleService serviceInterface="com.jetbrains.python.packaging.PyPackageRequirementsSettings" serviceImplementation="com.jetbrains.python.packaging.PyPackageRequirementsSettings"/> + + <!-- Console --> + <toolWindow id="Python Console" anchor="bottom" icon="" + factoryClass="com.jetbrains.python.console.PythonConsoleToolWindowFactory" secondary="false"/> + + </extensions> <extensionPoints> @@ -615,6 +621,12 @@ </component> </project-components> + <project-components> + <component> + <implementation-class>com.jetbrains.python.console.PythonConsoleToolWindow</implementation-class> + </component> + </project-components> + <actions> <group id="PyTypeHierarchyPopupMenu"> <reference ref="TypeHierarchyBase.BaseOnThisType"/> diff --git a/python/src/com/jetbrains/python/PyAddImportFix.java b/python/src/com/jetbrains/python/PyAddImportFix.java new file mode 100644 index 000000000000..c13fed13fdcb --- /dev/null +++ b/python/src/com/jetbrains/python/PyAddImportFix.java @@ -0,0 +1,55 @@ +package com.jetbrains.python; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.jetbrains.python.codeInsight.imports.AddImportHelper; +import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.psi.PyElementGenerator; +import com.jetbrains.python.psi.PyFile; +import com.jetbrains.python.psi.PyImportStatementBase; +import org.jetbrains.annotations.NotNull; + +/** + * Quick fix that adds import to file + * + * @author Ilya.Kazakevich + */ +public class PyAddImportFix implements LocalQuickFix { + @NotNull + private final String myImportToAdd; + @NotNull + private final PyFile myFile; + + /** + * @param importToAdd string representing what to add (i.e. "from foo import bar") + * @param file where to add + */ + public PyAddImportFix(@NotNull final String importToAdd, @NotNull final PyFile file) { + myImportToAdd = importToAdd; + myFile = file; + } + + @NotNull + @Override + public String getName() { + return PyBundle.message("QFIX.add.import", myImportToAdd); + } + + @NotNull + @Override + public String getFamilyName() { + return getName(); + } + + @Override + public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + final PyElementGenerator generator = PyElementGenerator.getInstance(project); + final PyImportStatementBase statement = + generator.createFromText(LanguageLevel.forElement(myFile), PyImportStatementBase.class, myImportToAdd); + final PsiElement recommendedPosition = AddImportHelper.getFileInsertPosition(myFile); + myFile.addAfter(statement, recommendedPosition); + } +} + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index 5d29d3f79d50..482daa88b66c 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -32,6 +32,8 @@ QFIX.create.property=Create property QFIX.add.encoding=Add encoding declaration +QFIX.add.import=Add "''{0}''" + QFIX.NAME.parameters=Parameters of functions and methods QFIX.rename.parameter.to.$0=Rename to ''{0}'' diff --git a/python/src/com/jetbrains/python/actions/ExecuteInConsoleAction.java b/python/src/com/jetbrains/python/actions/ExecuteInConsoleAction.java index 58b35fe5f591..cb90d498e663 100644 --- a/python/src/com/jetbrains/python/actions/ExecuteInConsoleAction.java +++ b/python/src/com/jetbrains/python/actions/ExecuteInConsoleAction.java @@ -17,7 +17,6 @@ package com.jetbrains.python.actions; import com.intellij.execution.ExecutionHelper; import com.intellij.execution.console.LanguageConsoleView; -import com.intellij.execution.console.LanguageConsoleViewImpl; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.openapi.actionSystem.*; @@ -215,7 +214,7 @@ public class ExecuteInConsoleAction extends AnAction { private static void startConsole(final Project project, final Consumer<PyCodeExecutor> consumer, Module context) { - PydevConsoleRunner runner = RunPythonConsoleAction.runPythonConsole(project, context); + PydevConsoleRunner runner = RunPythonConsoleAction.runPythonConsole(project, context, null); runner.addConsoleListener(new PydevConsoleRunner.ConsoleListener() { @Override public void handleConsoleInitialized(LanguageConsoleView consoleView) { diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/PySmartEnterProcessor.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/PySmartEnterProcessor.java index e27f2a638899..2785b23afc56 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/PySmartEnterProcessor.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/PySmartEnterProcessor.java @@ -79,7 +79,7 @@ public class PySmartEnterProcessor extends SmartEnterProcessor { } final PsiElement[] children = element.getChildren(); - for (PsiElement child : children) { + for (final PsiElement child : children) { if (element instanceof PyStatement && child instanceof PyStatement) { continue; } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyPlainEnterProcessor.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyPlainEnterProcessor.java index ac2e31252dcf..ccdcf1b93f2a 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyPlainEnterProcessor.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/enterProcessors/PyPlainEnterProcessor.java @@ -20,7 +20,9 @@ import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.codeInsight.editorActions.smartEnter.SmartEnterUtil; -import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.PyStatementList; +import com.jetbrains.python.psi.PyStatementListContainer; +import com.jetbrains.python.psi.PyStatementPart; import org.jetbrains.annotations.Nullable; /** @@ -32,17 +34,8 @@ import org.jetbrains.annotations.Nullable; public class PyPlainEnterProcessor implements EnterProcessor { @Nullable private static PyStatementList getStatementList(PsiElement psiElement, Editor editor) { - if (psiElement instanceof PyStatementPart) { - return ((PyStatementPart)psiElement).getStatementList(); - } - else if (psiElement instanceof PyFunction) { - return ((PyFunction)psiElement).getStatementList(); - } - else if (psiElement instanceof PyClass) { - return ((PyClass)psiElement).getStatementList(); - } - else if (psiElement instanceof PyWithStatement) { - return PsiTreeUtil.getChildOfType(psiElement, PyStatementList.class); + if (psiElement instanceof PyStatementListContainer) { + return ((PyStatementListContainer)psiElement).getStatementList(); } else { final CaretModel caretModel = editor.getCaretModel(); diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyArgumentListFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyArgumentListFixer.java index f7d877e5bb5b..de90fa158bab 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyArgumentListFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyArgumentListFixer.java @@ -25,26 +25,30 @@ import com.jetbrains.python.psi.PyArgumentList; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyDecorator; import com.jetbrains.python.psi.PyUtil; +import org.jetbrains.annotations.NotNull; /** * @author Alexey.Ivanov */ -public class PyArgumentListFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyArgumentList) { - final PsiElement rBrace = PyUtil.getChildByFilter(psiElement, PyTokenTypes.CLOSE_BRACES, 0); - if (psiElement.getParent() instanceof PyClass || psiElement.getParent() instanceof PyDecorator) { - final PsiElement lBrace = PyUtil.getChildByFilter(psiElement, PyTokenTypes.OPEN_BRACES, 0); - if (lBrace != null && rBrace == null) { - final Document document = editor.getDocument(); - document.insertString(psiElement.getTextRange().getEndOffset(), ")"); - } +public class PyArgumentListFixer extends PyFixer<PyArgumentList> { + public PyArgumentListFixer() { + super(PyArgumentList.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyArgumentList arguments) throws IncorrectOperationException { + final PsiElement rBrace = PyUtil.getChildByFilter(arguments, PyTokenTypes.CLOSE_BRACES, 0); + if (arguments.getParent() instanceof PyClass || arguments.getParent() instanceof PyDecorator) { + final PsiElement lBrace = PyUtil.getChildByFilter(arguments, PyTokenTypes.OPEN_BRACES, 0); + if (lBrace != null && rBrace == null) { + final Document document = editor.getDocument(); + document.insertString(arguments.getTextRange().getEndOffset(), ")"); } - else { - if (rBrace == null) { - final Document document = editor.getDocument(); - document.insertString(psiElement.getTextRange().getEndOffset(), ")"); - } + } + else { + if (rBrace == null) { + final Document document = editor.getDocument(); + document.insertString(arguments.getTextRange().getEndOffset(), ")"); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyClassFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyClassFixer.java index b9846e1cb894..ce51d6d46824 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyClassFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyClassFixer.java @@ -17,7 +17,6 @@ package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; -import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyTokenTypes; @@ -25,6 +24,9 @@ import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterPro import com.jetbrains.python.psi.PyArgumentList; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyUtil; +import org.jetbrains.annotations.NotNull; + +import static com.jetbrains.python.psi.PyUtil.sure; /** * Created by IntelliJ IDEA. @@ -32,21 +34,22 @@ import com.jetbrains.python.psi.PyUtil; * Date: 16.04.2010 * Time: 18:41:08 */ -public class PyClassFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyClass) { - final PsiElement colon = PyUtil.getChildByFilter(psiElement, TokenSet.create(PyTokenTypes.COLON), 0); - if (colon == null) { - final PyClass aClass = (PyClass)psiElement; - final PyArgumentList argList = PsiTreeUtil.getChildOfType(aClass, PyArgumentList.class); - int offset = argList.getTextRange().getEndOffset(); - String textToInsert = ":"; - if (aClass.getNameNode() == null) { - processor.registerUnresolvedError(argList.getTextRange().getEndOffset() + 1); - textToInsert = " :"; - } - editor.getDocument().insertString(offset, textToInsert); +public class PyClassFixer extends PyFixer<PyClass> { + public PyClassFixer() { + super(PyClass.class); + } + + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyClass pyClass) throws IncorrectOperationException { + final PsiElement colon = PyUtil.getFirstChildOfType(pyClass, PyTokenTypes.COLON); + if (colon == null) { + final PyArgumentList argList = PsiTreeUtil.getChildOfType(pyClass, PyArgumentList.class); + final int offset = sure(argList).getTextRange().getEndOffset(); + String textToInsert = ":"; + if (pyClass.getNameNode() == null) { + processor.registerUnresolvedError(argList.getTextRange().getEndOffset() + 1); + textToInsert = " :"; } + editor.getDocument().insertString(offset, textToInsert); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyConditionalStatementPartFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyConditionalStatementPartFixer.java index 2885c63f6345..f71c61261103 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyConditionalStatementPartFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyConditionalStatementPartFixer.java @@ -25,6 +25,9 @@ import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterPro import com.jetbrains.python.psi.PyConditionalStatementPart; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyUtil; +import org.jetbrains.annotations.NotNull; + +import static com.jetbrains.python.psi.PyUtil.sure; /** * Created by IntelliJ IDEA. @@ -32,31 +35,35 @@ import com.jetbrains.python.psi.PyUtil; * Date: 15.04.2010 * Time: 19:33:14 */ -public class PyConditionalStatementPartFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyConditionalStatementPart) { - final PyConditionalStatementPart conditionalStatementPart = (PyConditionalStatementPart)psiElement; - final PyExpression condition = conditionalStatementPart.getCondition(); - final Document document = editor.getDocument(); - final PsiElement colon = PyUtil.getChildByFilter(conditionalStatementPart, TokenSet.create(PyTokenTypes.COLON), 0); - if (colon == null) { - if (condition != null) { - final PsiElement firstNonComment = PyUtil.getFirstNonCommentAfter(condition.getNextSibling()); - if (firstNonComment != null && !":".equals(firstNonComment.getNode().getText())) { - document.insertString(firstNonComment.getTextRange().getEndOffset(), ":"); - } - } - else { - final PsiElement keywordToken = PyUtil.getChildByFilter(conditionalStatementPart, - TokenSet.create(PyTokenTypes.IF_KEYWORD, PyTokenTypes.ELIF_KEYWORD, - PyTokenTypes.WHILE_KEYWORD), 0); - final int offset = keywordToken.getTextRange().getEndOffset(); - document.insertString(offset, " :"); - processor.registerUnresolvedError(offset + 1); +public class PyConditionalStatementPartFixer extends PyFixer<PyConditionalStatementPart> { + public PyConditionalStatementPartFixer() { + super(PyConditionalStatementPart.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyConditionalStatementPart statementPart) + throws IncorrectOperationException { + final PyExpression condition = statementPart.getCondition(); + final Document document = editor.getDocument(); + final PsiElement colon = PyUtil.getFirstChildOfType(statementPart, PyTokenTypes.COLON); + if (colon == null) { + if (condition != null) { + final PsiElement firstNonComment = PyUtil.getFirstNonCommentAfter(condition.getNextSibling()); + if (firstNonComment != null && !":".equals(firstNonComment.getNode().getText())) { + document.insertString(firstNonComment.getTextRange().getEndOffset(), ":"); } - } else if (condition == null) { - processor.registerUnresolvedError(colon.getTextRange().getStartOffset()); } + else { + final TokenSet keywords = TokenSet.create(PyTokenTypes.IF_KEYWORD, PyTokenTypes.ELIF_KEYWORD, PyTokenTypes.WHILE_KEYWORD); + final PsiElement keywordToken = PyUtil.getChildByFilter(statementPart, + keywords, 0); + final int offset = sure(keywordToken).getTextRange().getEndOffset(); + document.insertString(offset, " :"); + processor.registerUnresolvedError(offset + 1); + } + } + else if (condition == null) { + processor.registerUnresolvedError(colon.getTextRange().getStartOffset()); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyExceptFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyExceptFixer.java index 8e3532cb49b3..67d5ff5c9ee5 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyExceptFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyExceptFixer.java @@ -17,13 +17,15 @@ package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; -import com.intellij.psi.tree.TokenSet; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; import com.jetbrains.python.psi.PyExceptPart; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyUtil; +import org.jetbrains.annotations.NotNull; + +import static com.jetbrains.python.psi.PyUtil.sure; /** * Created by IntelliJ IDEA. @@ -31,24 +33,26 @@ import com.jetbrains.python.psi.PyUtil; * Date: 22.04.2010 * Time: 18:13:34 */ -public class PyExceptFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyExceptPart) { - PyExceptPart exceptPart = (PyExceptPart)psiElement; - final PsiElement colon = PyUtil.getChildByFilter(exceptPart, TokenSet.create(PyTokenTypes.COLON), 0); - if (colon == null) { - int offset = PyUtil.getChildByFilter(exceptPart, - TokenSet.create(PyTokenTypes.EXCEPT_KEYWORD), 0).getTextRange().getEndOffset(); - final PyExpression exceptClass = exceptPart.getExceptClass(); - if (exceptClass != null) { - offset = exceptClass.getTextRange().getEndOffset(); - } - final PyExpression target = exceptPart.getTarget(); - if (target != null) { - offset = target.getTextRange().getEndOffset(); - } - editor.getDocument().insertString(offset, ":"); +public class PyExceptFixer extends PyFixer<PyExceptPart> { + public PyExceptFixer() { + super(PyExceptPart.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyExceptPart exceptPart) throws IncorrectOperationException { + final PsiElement colon = PyUtil.getFirstChildOfType(exceptPart, PyTokenTypes.COLON); + if (colon == null) { + final PsiElement exceptToken = PyUtil.getFirstChildOfType(exceptPart, PyTokenTypes.EXCEPT_KEYWORD); + int offset = sure(exceptToken).getTextRange().getEndOffset(); + final PyExpression exceptClass = exceptPart.getExceptClass(); + if (exceptClass != null) { + offset = exceptClass.getTextRange().getEndOffset(); + } + final PyExpression target = exceptPart.getTarget(); + if (target != null) { + offset = target.getTextRange().getEndOffset(); } + editor.getDocument().insertString(offset, ":"); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFixer.java index f02831d92d36..0ebdceb20e37 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFixer.java @@ -19,6 +19,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; +import com.jetbrains.python.psi.PyElement; +import org.jetbrains.annotations.NotNull; /** * Created by IntelliJ IDEA. @@ -26,6 +28,20 @@ import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterPro * Date: 15.04.2010 * Time: 17:10:33 */ -public interface PyFixer { - void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException; +public abstract class PyFixer<T extends PyElement> { + private final Class<T> myClass; + + public PyFixer(@NotNull Class<T> aClass) { + myClass = aClass; + } + + public final void apply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PsiElement element) + throws IncorrectOperationException { + if (myClass.isInstance(element)) { + //noinspection unchecked + doApply(editor, processor, (T)element); + } + } + + public abstract void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull T element); } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyForPartFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyForPartFixer.java index 1b8b438c68fd..eefe5cd1fc3e 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyForPartFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyForPartFixer.java @@ -18,12 +18,13 @@ package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; -import com.intellij.psi.tree.TokenSet; -import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; import com.jetbrains.python.psi.PyForPart; import com.jetbrains.python.psi.PyUtil; +import org.jetbrains.annotations.NotNull; + +import static com.jetbrains.python.psi.PyUtil.sure; /** * Created by IntelliJ IDEA. @@ -31,41 +32,42 @@ import com.jetbrains.python.psi.PyUtil; * Date: 16.04.2010 * Time: 16:03:43 */ -public class PyForPartFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyForPart) { - final PyForPart forPart = (PyForPart)psiElement; - final PsiElement colon = PyUtil.getChildByFilter(psiElement, TokenSet.create(PyTokenTypes.COLON), 0); - final Document document = editor.getDocument(); - final PsiElement forToken = PyUtil.getChildByFilter(forPart, - TokenSet.create(PyTokenTypes.FOR_KEYWORD), 0); - if (colon == null) { - String textToInsert = ":"; - PsiElement sourceOrTarget = forPart.getSource(); - PsiElement positionToInsert = sourceOrTarget; - if (sourceOrTarget == null) { - sourceOrTarget = forPart.getTarget(); - final PsiElement inToken = PyUtil.getChildByFilter(forPart, TokenSet.create(PyTokenTypes.IN_KEYWORD), 0); - if (inToken == null) { - if (sourceOrTarget == null) { - positionToInsert = forToken; - textToInsert = " in :"; - processor.registerUnresolvedError(positionToInsert.getTextRange().getEndOffset() + 1); - } - else { - positionToInsert = sourceOrTarget; - textToInsert = " in :"; - processor.registerUnresolvedError(positionToInsert.getTextRange().getEndOffset() + 4); - } +public class PyForPartFixer extends PyFixer<PyForPart> { + public PyForPartFixer() { + super(PyForPart.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyForPart forPart) { + final PsiElement colon = PyUtil.getFirstChildOfType(forPart, PyTokenTypes.COLON); + final Document document = editor.getDocument(); + final PsiElement forToken = PyUtil.getFirstChildOfType(forPart, PyTokenTypes.FOR_KEYWORD); + if (colon == null) { + String textToInsert = ":"; + PsiElement sourceOrTarget = forPart.getSource(); + PsiElement positionToInsert = sourceOrTarget; + if (sourceOrTarget == null) { + sourceOrTarget = forPart.getTarget(); + final PsiElement inToken = PyUtil.getFirstChildOfType(forPart, PyTokenTypes.IN_KEYWORD); + if (inToken == null) { + if (sourceOrTarget == null) { + positionToInsert = sure(forToken); + textToInsert = " in :"; + processor.registerUnresolvedError(positionToInsert.getTextRange().getEndOffset() + 1); } else { - positionToInsert = inToken; - textToInsert = " :"; - processor.registerUnresolvedError(positionToInsert.getTextRange().getEndOffset() + 1); + positionToInsert = sourceOrTarget; + textToInsert = " in :"; + processor.registerUnresolvedError(positionToInsert.getTextRange().getEndOffset() + 4); } } - document.insertString(positionToInsert.getTextRange().getEndOffset(), textToInsert); + else { + positionToInsert = inToken; + textToInsert = " :"; + processor.registerUnresolvedError(positionToInsert.getTextRange().getEndOffset() + 1); + } } + document.insertString(positionToInsert.getTextRange().getEndOffset(), textToInsert); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFunctionFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFunctionFixer.java index f1988e13f57a..ad959f80ccae 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFunctionFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyFunctionFixer.java @@ -18,13 +18,13 @@ package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; -import com.intellij.psi.tree.TokenSet; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyParameterList; import com.jetbrains.python.psi.PyUtil; +import org.jetbrains.annotations.NotNull; /** * Created by IntelliJ IDEA. @@ -32,16 +32,19 @@ import com.jetbrains.python.psi.PyUtil; * Date: 16.04.2010 * Time: 16:59:07 */ -public class PyFunctionFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyFunction) { - final PsiElement colon = PyUtil.getChildByFilter(psiElement, TokenSet.create(PyTokenTypes.COLON), 0); - if (colon == null) { - final PyFunction function = (PyFunction)psiElement; - final PyParameterList parameterList = function.getParameterList(); - final Document document = editor.getDocument(); - document.insertString(parameterList.getTextRange().getEndOffset(), ":"); - } +public class PyFunctionFixer extends PyFixer<PyFunction> { + public PyFunctionFixer() { + super(PyFunction.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyFunction function) + throws IncorrectOperationException { + final PsiElement colon = PyUtil.getFirstChildOfType(function, PyTokenTypes.COLON); + if (colon == null) { + final PyParameterList parameterList = function.getParameterList(); + final Document document = editor.getDocument(); + document.insertString(parameterList.getTextRange().getEndOffset(), ":"); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyMissingBracesFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyMissingBracesFixer.java index 0d8565d6960d..eb97d2bdb372 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyMissingBracesFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyMissingBracesFixer.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NotNull; /** * Created by IntelliJ IDEA. @@ -27,10 +28,16 @@ import com.jetbrains.python.psi.*; * Date: 15.04.2010 * Time: 17:55:46 */ -public class PyMissingBracesFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { +public class PyMissingBracesFixer extends PyFixer<PyElement> { + public PyMissingBracesFixer() { + super(PyElement.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyElement psiElement) + throws IncorrectOperationException { if (psiElement instanceof PySetLiteralExpression || psiElement instanceof PyDictLiteralExpression) { - PsiElement lastChild = PyUtil.getFirstNonCommentBefore(psiElement.getLastChild()); + final PsiElement lastChild = PyUtil.getFirstNonCommentBefore(psiElement.getLastChild()); if (lastChild != null && !"}".equals(lastChild.getText())) { editor.getDocument().insertString(lastChild.getTextRange().getEndOffset(), "}"); } @@ -38,7 +45,7 @@ public class PyMissingBracesFixer implements PyFixer { else if (psiElement instanceof PyListLiteralExpression || psiElement instanceof PySliceExpression || psiElement instanceof PySubscriptionExpression) { - PsiElement lastChild = PyUtil.getFirstNonCommentBefore(psiElement.getLastChild()); + final PsiElement lastChild = PyUtil.getFirstNonCommentBefore(psiElement.getLastChild()); if (lastChild != null && !"]".equals(lastChild.getText())) { editor.getDocument().insertString(lastChild.getTextRange().getEndOffset(), "]"); } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParameterListFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParameterListFixer.java index 7b5970d7baf2..69a06b8b7c48 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParameterListFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParameterListFixer.java @@ -23,6 +23,7 @@ import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; import com.jetbrains.python.psi.PyParameterList; import com.jetbrains.python.psi.PyUtil; +import org.jetbrains.annotations.NotNull; /** * Created by IntelliJ IDEA. @@ -30,19 +31,22 @@ import com.jetbrains.python.psi.PyUtil; * Date: 16.04.2010 * Time: 17:25:46 */ -public class PyParameterListFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyParameterList) { - final PsiElement lBrace = PyUtil.getChildByFilter(psiElement, PyTokenTypes.OPEN_BRACES, 0); - final PsiElement rBrace = PyUtil.getChildByFilter(psiElement, PyTokenTypes.CLOSE_BRACES, 0); - if (lBrace == null || rBrace == null) { - final Document document = editor.getDocument(); - if (lBrace == null) { - document.insertString(psiElement.getTextRange().getStartOffset(), "("); - } - else { - document.insertString(psiElement.getTextRange().getEndOffset(), ")"); - } +public class PyParameterListFixer extends PyFixer<PyParameterList> { + public PyParameterListFixer() { + super(PyParameterList.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyParameterList psiElement) throws IncorrectOperationException { + final PsiElement lBrace = PyUtil.getChildByFilter(psiElement, PyTokenTypes.OPEN_BRACES, 0); + final PsiElement rBrace = PyUtil.getChildByFilter(psiElement, PyTokenTypes.CLOSE_BRACES, 0); + if (lBrace == null || rBrace == null) { + final Document document = editor.getDocument(); + if (lBrace == null) { + document.insertString(psiElement.getTextRange().getStartOffset(), "("); + } + else { + document.insertString(psiElement.getTextRange().getEndOffset(), ")"); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParenthesizedFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParenthesizedFixer.java index a055375bc040..582e034c5603 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParenthesizedFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyParenthesizedFixer.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; import com.jetbrains.python.psi.PyParenthesizedExpression; +import org.jetbrains.annotations.NotNull; /** * Created by IntelliJ IDEA. @@ -27,13 +28,17 @@ import com.jetbrains.python.psi.PyParenthesizedExpression; * Date: 15.04.2010 * Time: 17:42:08 */ -public class PyParenthesizedFixer implements PyFixer { - public void apply(final Editor editor, final PySmartEnterProcessor processor, final PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyParenthesizedExpression) { - final PsiElement lastChild = psiElement.getLastChild(); - if (lastChild != null && !")".equals(lastChild.getText())) { - editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), ")"); - } +public class PyParenthesizedFixer extends PyFixer<PyParenthesizedExpression> { + public PyParenthesizedFixer() { + super(PyParenthesizedExpression.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyParenthesizedExpression expression) + throws IncorrectOperationException { + final PsiElement lastChild = expression.getLastChild(); + if (lastChild != null && !")".equals(lastChild.getText())) { + editor.getDocument().insertString(expression.getTextRange().getEndOffset(), ")"); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyStringLiteralFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyStringLiteralFixer.java index 906aecd9c757..3e9925a86131 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyStringLiteralFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyStringLiteralFixer.java @@ -17,10 +17,10 @@ package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; import com.jetbrains.python.psi.PyStringLiteralExpression; +import org.jetbrains.annotations.NotNull; /** * Created by IntelliJ IDEA. @@ -28,31 +28,35 @@ import com.jetbrains.python.psi.PyStringLiteralExpression; * Date: 15.04.2010 * Time: 17:17:14 */ -public class PyStringLiteralFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyStringLiteralExpression) { - final String text = psiElement.getText(); - if (StringUtil.startsWith(text, "\"\"\"")) { - final int suffixLength = StringUtil.commonSuffixLength(text, "\"\"\""); - if (suffixLength != 3) { - editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\"\"\"".substring(suffixLength)); - } +public class PyStringLiteralFixer extends PyFixer<PyStringLiteralExpression> { + public PyStringLiteralFixer() { + super(PyStringLiteralExpression.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyStringLiteralExpression psiElement) + throws IncorrectOperationException { + final String text = psiElement.getText(); + if (StringUtil.startsWith(text, "\"\"\"")) { + final int suffixLength = StringUtil.commonSuffixLength(text, "\"\"\""); + if (suffixLength != 3) { + editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\"\"\"".substring(suffixLength)); } - else if (StringUtil.startsWith(text, "\'\'\'")) { - final int suffixLength = StringUtil.commonSuffixLength(text, "\'\'\'"); - if (suffixLength != 3) { - editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\'\'\'".substring(suffixLength)); - } + } + else if (StringUtil.startsWith(text, "\'\'\'")) { + final int suffixLength = StringUtil.commonSuffixLength(text, "\'\'\'"); + if (suffixLength != 3) { + editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\'\'\'".substring(suffixLength)); } - else if (StringUtil.startsWith(text, "\"")) { - if (!StringUtil.endsWith(text, "\"")) { - editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\""); - } + } + else if (StringUtil.startsWith(text, "\"")) { + if (!StringUtil.endsWith(text, "\"")) { + editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\""); } - else if (StringUtil.startsWith(text, "\'")) { - if (!StringUtil.endsWith(text, "\'")) { - editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\'"); - } + } + else if (StringUtil.startsWith(text, "\'")) { + if (!StringUtil.endsWith(text, "\'")) { + editor.getDocument().insertString(psiElement.getTextRange().getEndOffset(), "\'"); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyUnconditionalStatementPartFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyUnconditionalStatementPartFixer.java index 57bfd39f4f85..6aace3972a1b 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyUnconditionalStatementPartFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyUnconditionalStatementPartFixer.java @@ -21,10 +21,10 @@ import com.intellij.psi.tree.TokenSet; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; -import com.jetbrains.python.psi.PyElsePart; -import com.jetbrains.python.psi.PyFinallyPart; -import com.jetbrains.python.psi.PyTryPart; -import com.jetbrains.python.psi.PyUtil; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NotNull; + +import static com.jetbrains.python.psi.PyUtil.sure; /** * Created by IntelliJ IDEA. @@ -32,16 +32,20 @@ import com.jetbrains.python.psi.PyUtil; * Date: 16.04.2010 * Time: 14:25:20 */ -public class PyUnconditionalStatementPartFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { +public class PyUnconditionalStatementPartFixer extends PyFixer<PyElement> { + public PyUnconditionalStatementPartFixer() { + super(PyElement.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyElement psiElement) + throws IncorrectOperationException { if (PyUtil.instanceOf(psiElement, PyElsePart.class, PyTryPart.class, PyFinallyPart.class)) { - final PsiElement colon = PyUtil.getChildByFilter(psiElement, TokenSet.create(PyTokenTypes.COLON), 0); + final PsiElement colon = PyUtil.getFirstChildOfType(psiElement, PyTokenTypes.COLON); if (colon == null) { - final PsiElement keywordToken = PyUtil.getChildByFilter(psiElement, - TokenSet.create(PyTokenTypes.ELSE_KEYWORD, PyTokenTypes.TRY_KEYWORD, - PyTokenTypes.FINALLY_KEYWORD), - 0); - editor.getDocument().insertString(keywordToken.getTextRange().getEndOffset(), ":"); + final TokenSet keywords = TokenSet.create(PyTokenTypes.ELSE_KEYWORD, PyTokenTypes.TRY_KEYWORD, PyTokenTypes.FINALLY_KEYWORD); + final PsiElement keywordToken = PyUtil.getChildByFilter(psiElement, keywords, 0); + editor.getDocument().insertString(sure(keywordToken).getTextRange().getEndOffset(), ":"); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java index b6d099ef7cb5..ec236d9242f5 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java @@ -15,65 +15,59 @@ */ package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers; -import com.intellij.lang.ASTNode; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor; -import com.jetbrains.python.psi.PyElementType; import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.PyUtil; import com.jetbrains.python.psi.PyWithItem; import com.jetbrains.python.psi.PyWithStatement; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import static com.jetbrains.python.psi.PyUtil.sure; /** * @author Mikhail Golubev */ -public class PyWithFixer implements PyFixer { - public void apply(Editor editor, PySmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException { - if (psiElement instanceof PyWithStatement) { - final PyWithStatement withStatement = (PyWithStatement)psiElement; - final PsiElement colonToken = getFirstChildOfType(psiElement, PyTokenTypes.COLON); - final PsiElement withToken = getFirstChildOfType(withStatement, PyTokenTypes.WITH_KEYWORD); - final Document document = editor.getDocument(); - if (colonToken == null) { - int insertAt = sure(withToken).getTextRange().getEndOffset(); - String textToInsert = ":"; - final PyWithItem[] withItems = withStatement.getWithItems(); - final PyWithItem lastItem = withItems.length != 0 ? withItems[withItems.length - 1] : null; - if (lastItem == null || lastItem.getExpression() == null) { - textToInsert = " :"; - processor.registerUnresolvedError(insertAt + 1); - } - else { - final PyExpression expression = lastItem.getExpression(); - insertAt = expression.getTextRange().getEndOffset(); - final PsiElement asToken = getFirstChildOfType(lastItem, PyTokenTypes.AS_KEYWORD); - if (asToken != null) { - insertAt = asToken.getTextRange().getEndOffset(); - final PyExpression target = lastItem.getTarget(); - if (target != null) { - insertAt = target.getTextRange().getEndOffset(); - } - else { - textToInsert = " :"; - processor.registerUnresolvedError(insertAt + 1); - } +public class PyWithFixer extends PyFixer<PyWithStatement> { + public PyWithFixer() { + super(PyWithStatement.class); + } + + @Override + public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyWithStatement withStatement) throws IncorrectOperationException { + final PsiElement colonToken = PyUtil.getFirstChildOfType(withStatement, PyTokenTypes.COLON); + final PsiElement withToken = PyUtil.getFirstChildOfType(withStatement, PyTokenTypes.WITH_KEYWORD); + final Document document = editor.getDocument(); + if (colonToken == null) { + int insertAt = sure(withToken).getTextRange().getEndOffset(); + String textToInsert = ":"; + final PyWithItem[] withItems = withStatement.getWithItems(); + final PyWithItem lastItem = withItems.length != 0 ? withItems[withItems.length - 1] : null; + if (lastItem == null || lastItem.getExpression() == null) { + textToInsert = " :"; + processor.registerUnresolvedError(insertAt + 1); + } + else { + final PyExpression expression = lastItem.getExpression(); + insertAt = expression.getTextRange().getEndOffset(); + final PsiElement asToken = PyUtil.getFirstChildOfType(lastItem, PyTokenTypes.AS_KEYWORD); + if (asToken != null) { + insertAt = asToken.getTextRange().getEndOffset(); + final PyExpression target = lastItem.getTarget(); + if (target != null) { + insertAt = target.getTextRange().getEndOffset(); + } + else { + textToInsert = " :"; + processor.registerUnresolvedError(insertAt + 1); } } - document.insertString(insertAt, textToInsert); } + document.insertString(insertAt, textToInsert); } } - - @Nullable - private static PsiElement getFirstChildOfType(@NotNull final PsiElement element, @NotNull PyElementType type) { - final ASTNode child = element.getNode().findChildByType(type); - return child != null ? child.getPsi() : null; - } } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java index 3d77ac4f62b1..848818b95e27 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java @@ -16,6 +16,10 @@ package com.jetbrains.python.console; import com.google.common.base.CharMatcher; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionHelper; @@ -59,11 +63,14 @@ import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.tree.FileElement; import com.intellij.remote.RemoteSshProcess; import com.intellij.testFramework.LightVirtualFile; +import com.intellij.ui.content.Content; import com.intellij.util.ArrayUtil; import com.intellij.util.IJSwingUtilities; import com.intellij.util.PathMappingSettings; @@ -132,6 +139,9 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC private static final long APPROPRIATE_TO_WAIT = 60000; private PyRemoteSdkCredentials myRemoteCredentials; + private ToolWindow myToolWindow; + + private String myConsoleTitle = null; protected PydevConsoleRunner(@NotNull final Project project, @NotNull Sdk sdk, @NotNull final PyConsoleType consoleType, @@ -192,8 +202,10 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC @NotNull final PyConsoleType consoleType, @Nullable final String workingDirectory, @NotNull final Map<String, String> environmentVariables, + @Nullable final ToolWindow toolWindow, final String... statements2execute) { final PydevConsoleRunner consoleRunner = create(project, sdk, consoleType, workingDirectory, environmentVariables); + consoleRunner.setToolWindow(toolWindow); consoleRunner.setStatementsToExecute(statements2execute); consoleRunner.run(); return consoleRunner; @@ -481,6 +493,20 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC } } + @Override + protected String constructConsoleTitle(@NotNull String consoleTitle) { + if (myConsoleTitle == null) { + myConsoleTitle = super.constructConsoleTitle(consoleTitle); + } + return myConsoleTitle; + } + + @Override + protected void showConsole(Executor defaultExecutor, RunContentDescriptor contentDescriptor) { + PythonConsoleToolWindow terminalView = PythonConsoleToolWindow.getInstance(getProject()); + terminalView.init(getToolWindow(), contentDescriptor); + } + protected AnAction createRerunAction() { return new RestartAction(this); } @@ -583,9 +609,32 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC } @Override - protected AnAction createCloseAction(Executor defaultExecutor, RunContentDescriptor myDescriptor) { - final AnAction generalCloseAction = super.createCloseAction(defaultExecutor, myDescriptor); - return createConsoleStoppingAction(generalCloseAction); + protected AnAction createCloseAction(Executor defaultExecutor, final RunContentDescriptor descriptor) { + final AnAction generalCloseAction = super.createCloseAction(defaultExecutor, descriptor); + + final AnAction stopAction = new DumbAwareAction() { + @Override + public void update(AnActionEvent e) { + generalCloseAction.update(e); + } + + @Override + public void actionPerformed(AnActionEvent e) { + e = stopConsole(e); + + clearContent(descriptor); + + generalCloseAction.actionPerformed(e); + } + }; + stopAction.copyFrom(generalCloseAction); + return stopAction; + } + + private void clearContent(RunContentDescriptor descriptor) { + Content content = getToolWindow().getContentManager().findContent(descriptor.getDisplayName()); + assert content != null; + getToolWindow().getContentManager().removeContent(content, true); } private AnAction createConsoleStoppingAction(final AnAction generalStopAction) { @@ -597,26 +646,31 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC @Override public void actionPerformed(AnActionEvent e) { - if (myPydevConsoleCommunication != null) { - final AnActionEvent furtherActionEvent = - new AnActionEvent(e.getInputEvent(), e.getDataContext(), e.getPlace(), - e.getPresentation(), e.getActionManager(), e.getModifiers()); - try { - closeCommunication(); - // waiting for REPL communication before destroying process handler - Thread.sleep(300); - } - catch (Exception ignored) { - // Ignore - } - generalStopAction.actionPerformed(furtherActionEvent); - } + e = stopConsole(e); + + generalStopAction.actionPerformed(e); } }; stopAction.copyFrom(generalStopAction); return stopAction; } + private AnActionEvent stopConsole(AnActionEvent e) { + if (myPydevConsoleCommunication != null) { + e = new AnActionEvent(e.getInputEvent(), e.getDataContext(), e.getPlace(), + e.getPresentation(), e.getActionManager(), e.getModifiers()); + try { + closeCommunication(); + // waiting for REPL communication before destroying process handler + Thread.sleep(300); + } + catch (Exception ignored) { + // Ignore + } + } + return e; + } + protected AnAction createSplitLineAction() { class ConsoleSplitLineAction extends EditorAction { @@ -738,6 +792,17 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC } } + public ToolWindow getToolWindow() { + if (myToolWindow == null) { + myToolWindow = ToolWindowManager.getInstance(getProject()).getToolWindow(PythonConsoleToolWindowFactory.ID); + } + return myToolWindow; + } + + public void setToolWindow(ToolWindow toolWindow) { + myToolWindow = toolWindow; + } + public interface ConsoleListener { void handleConsoleInitialized(LanguageConsoleView consoleView); } @@ -889,4 +954,21 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory<PythonC return session; } + + @Override + protected List<String> getActiveConsoleNames(final String consoleTitle) { + return FluentIterable.from( + Lists.newArrayList(PythonConsoleToolWindow.getInstance(getProject()).getToolWindow().getContentManager().getContents())).transform( + new Function<Content, String>() { + @Override + public String apply(Content input) { + return input.getDisplayName(); + } + }).filter(new Predicate<String>() { + @Override + public boolean apply(String input) { + return input.contains(consoleTitle); + } + }).toList(); + } } diff --git a/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java b/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java new file mode 100644 index 000000000000..e8c50e49280a --- /dev/null +++ b/python/src/com/jetbrains/python/console/PythonConsoleToolWindow.java @@ -0,0 +1,127 @@ +package com.jetbrains.python.console; + +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.SimpleToolWindowPanel; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.openapi.wm.ex.ToolWindowManagerEx; +import com.intellij.openapi.wm.ex.ToolWindowManagerListener; +import com.intellij.openapi.wm.impl.content.ToolWindowContentUi; +import com.intellij.ui.content.Content; +import com.intellij.ui.content.ContentFactory; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +/** + * @author traff + */ +public class PythonConsoleToolWindow { + + private final Project myProject; + + private boolean myInitialized = false; + + public PythonConsoleToolWindow(Project project) { + myProject = project; + } + + public static PythonConsoleToolWindow getInstance(@NotNull Project project) { + return project.getComponent(PythonConsoleToolWindow.class); + } + + + public void init(final @NotNull ToolWindow toolWindow, final @NotNull RunContentDescriptor contentDescriptor) { + addContent(toolWindow, contentDescriptor); + + if (!myInitialized) { + doInit(toolWindow); + } + } + + private void doInit(final ToolWindow toolWindow) { + myInitialized = true; + + toolWindow.setToHideOnEmptyContent(true); + + ((ToolWindowManagerEx)ToolWindowManager.getInstance(myProject)).addToolWindowManagerListener(new ToolWindowManagerListener() { + @Override + public void toolWindowRegistered(@NotNull String id) { + } + + @Override + public void stateChanged() { + ToolWindow window = getToolWindow(); + if (window != null) { + boolean visible = window.isVisible(); + if (visible && toolWindow.getContentManager().getContentCount() == 0) { + RunPythonConsoleAction.runPythonConsole(myProject, null, toolWindow); + } + } + } + }); + } + + private static void addContent(ToolWindow toolWindow, RunContentDescriptor contentDescriptor) { + toolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true"); + + Content content = toolWindow.getContentManager().findContent(contentDescriptor.getDisplayName()); + if (content == null) { + content = createContent(contentDescriptor); + toolWindow.getContentManager().addContent(content); + } + else { + SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true); + resetContent(contentDescriptor, panel, content); + } + + toolWindow.getContentManager().setSelectedContent(content); + } + + public ToolWindow getToolWindow() { + return ToolWindowManager.getInstance(myProject).getToolWindow(PythonConsoleToolWindowFactory.ID); + } + + private static Content createContent(final @NotNull RunContentDescriptor contentDescriptor) { + SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true); + + final Content content = ContentFactory.SERVICE.getInstance().createContent(panel, contentDescriptor.getDisplayName(), false); + content.setCloseable(true); + + resetContent(contentDescriptor, panel, content); + + return content; + } + + private static void resetContent(RunContentDescriptor contentDescriptor, SimpleToolWindowPanel panel, Content content) { + panel.setContent(contentDescriptor.getComponent()); + //panel.addFocusListener(createFocusListener(toolWindow)); + + content.setComponent(panel); + content.setPreferredFocusableComponent(contentDescriptor.getComponent()); + } + + private static FocusListener createFocusListener(final ToolWindow toolWindow) { + return new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + JComponent component = getComponentToFocus(toolWindow); + if (component != null) { + component.requestFocusInWindow(); + } + } + + @Override + public void focusLost(FocusEvent e) { + + } + }; + } + + private static JComponent getComponentToFocus(ToolWindow window) { + return window.getContentManager().getComponent(); + } +} diff --git a/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.java b/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.java new file mode 100644 index 000000000000..f042a539bc22 --- /dev/null +++ b/python/src/com/jetbrains/python/console/PythonConsoleToolWindowFactory.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.console; + +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowFactory; + +/** + * @author traff + */ +public class PythonConsoleToolWindowFactory implements ToolWindowFactory, DumbAware { + public static final String ID = "Python Console"; + + @Override + public void createToolWindowContent(Project project, ToolWindow toolWindow) { + RunPythonConsoleAction.runPythonConsole(project, null, toolWindow); + } +} diff --git a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java index 02a153f7a016..566adea43c87 100644 --- a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java +++ b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java @@ -32,6 +32,7 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindow; import com.intellij.util.PathMappingSettings; import com.jetbrains.python.buildout.BuildoutFacet; import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase; @@ -42,6 +43,7 @@ import com.jetbrains.python.sdk.PythonEnvUtil; import com.jetbrains.python.sdk.PythonSdkType; import icons.PythonIcons; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; @@ -77,11 +79,11 @@ public class RunPythonConsoleAction extends AnAction implements DumbAware { public void actionPerformed(final AnActionEvent e) { final Project project = e.getData(CommonDataKeys.PROJECT); - runPythonConsole(project, e.getData(LangDataKeys.MODULE)); + runPythonConsole(project, e.getData(LangDataKeys.MODULE), null); } @NotNull - public static PydevConsoleRunner runPythonConsole(Project project, Module contextModule) { + public static PydevConsoleRunner runPythonConsole(Project project, Module contextModule, @Nullable ToolWindow toolWindow) { assert project != null : "Project is null"; Pair<Sdk, Module> sdkAndModule = findPythonSdkAndModule(project, contextModule); @@ -152,7 +154,7 @@ public class RunPythonConsoleAction extends AnAction implements DumbAware { envs.put(PythonEnvUtil.IPYTHONENABLE, ipythonEnabled); return PydevConsoleRunner - .createAndRun(project, sdk, PyConsoleType.PYTHON, workingDir, envs, setupFragment); + .createAndRun(project, sdk, PyConsoleType.PYTHON, workingDir, envs, toolWindow, setupFragment); } public static PathMappingSettings getMappings(Project project, Sdk sdk) { diff --git a/python/src/com/jetbrains/python/documentation/EpydocString.java b/python/src/com/jetbrains/python/documentation/EpydocString.java index 132ef4924b5c..3d0fc3e89d9e 100644 --- a/python/src/com/jetbrains/python/documentation/EpydocString.java +++ b/python/src/com/jetbrains/python/documentation/EpydocString.java @@ -44,6 +44,13 @@ public class EpydocString extends StructuredDocStringBase { "precondition", "postcondition", "invariant", "author", "organization", "copyright", "license", "contact", "summary", "see" }; + /** + * Empty doc (for {@link #createParameterType(String, String)} probably) + */ + public EpydocString() { + this(""); + } + public EpydocString(@NotNull String docstringText) { super(docstringText, "@"); } diff --git a/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java b/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java index d09af58f4fc3..c05069098ea6 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java +++ b/python/src/com/jetbrains/python/documentation/PyDocstringGenerator.java @@ -87,8 +87,6 @@ public class PyDocstringGenerator { for (PyParameter functionParam : function.getParameterList().getParameters()) { String paramName = functionParam.getName(); if (!functionParam.isSelf() && !StringUtil.isEmpty(paramName)) { - assert paramName != null; - String type = signature != null ? signature.getArgTypeQualifiedName(paramName) : null; if (type != null) { @@ -140,12 +138,9 @@ public class PyDocstringGenerator { final VirtualFile virtualFile = myFile.getVirtualFile(); if (virtualFile == null) return; - OpenFileDescriptor descriptor = new OpenFileDescriptor( - myProject, virtualFile, myDocStringOwner.getTextOffset() + myDocStringOwner.getTextLength() - ); + OpenFileDescriptor descriptor = new OpenFileDescriptor(myProject, virtualFile, myDocStringExpression.getTextOffset()); Editor targetEditor = FileEditorManager.getInstance(myProject).openTextEditor(descriptor, true); if (targetEditor != null) { - targetEditor.getCaretModel().moveToOffset(myDocStringExpression.getTextOffset()); TemplateManager.getInstance(myProject).startTemplate(targetEditor, template); } } @@ -298,7 +293,7 @@ public class PyDocstringGenerator { if (myDocStringOwner instanceof PyFunction) { final PyStatementList statementList = ((PyFunction)myDocStringOwner).getStatementList(); final Document document = PsiDocumentManager.getInstance(myProject).getDocument(getFile()); - if (document != null && statementList != null && myFunction != null && statementList.getStatements().length != 0 + if (document != null && myFunction != null && statementList.getStatements().length != 0 && document.getLineNumber(statementList.getTextOffset()) != document.getLineNumber(myFunction.getTextOffset())) { whitespace = PsiTreeUtil.getPrevSiblingOfType(statementList, PsiWhiteSpace.class); } @@ -411,7 +406,7 @@ public class PyDocstringGenerator { final PyStatementList list = myFunction.getStatementList(); final Document document = PsiDocumentManager.getInstance(myProject).getDocument(getFile()); - if (document != null && list != null) { + if (document != null) { if (document.getLineNumber(list.getTextOffset()) == document.getLineNumber(myFunction.getTextOffset()) || list.getStatements().length == 0) { PyFunction func = elementGenerator.createFromText(LanguageLevel.forElement(myFunction), diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationSettings.java b/python/src/com/jetbrains/python/documentation/PyDocumentationSettings.java index 6ea65405ba1a..49a17efd28a6 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationSettings.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationSettings.java @@ -15,7 +15,9 @@ */ package com.jetbrains.python.documentation; -import com.intellij.openapi.components.*; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleServiceManager; import com.intellij.openapi.util.text.StringUtil; @@ -27,6 +29,7 @@ import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyTargetExpression; import com.jetbrains.python.psi.impl.PyPsiUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -54,7 +57,7 @@ public class PyDocumentationSettings implements PersistentStateComponent<PyDocum private boolean isFormat(PsiFile file, final String format) { if (file instanceof PyFile) { - PyTargetExpression expr = ((PyFile) file).findTopLevelAttribute(PyNames.DOCFORMAT); + PyTargetExpression expr = ((PyFile)file).findTopLevelAttribute(PyNames.DOCFORMAT); if (expr != null) { String docformat = PyPsiUtils.strValue(expr.findAssignedValue()); if (docformat != null) { @@ -88,4 +91,21 @@ public class PyDocumentationSettings implements PersistentStateComponent<PyDocum public void loadState(PyDocumentationSettings state) { XmlSerializerUtil.copyBean(state, this); } + + /** + * TODO: Use this factory for the whole document infrastructure to simplify new documentation engine support + * Factory that returns appropriate instance of {@link StructuredDocStringBase} if specificed + * + * @return instance or null if no doctype os set + */ + @Nullable + public StructuredDocStringBase getDocString() { + if (myDocStringFormat.equals(DocStringFormat.EPYTEXT)) { + return new EpydocString(); + } + if (myDocStringFormat.equals(DocStringFormat.REST)) { + return new SphinxDocString(); + } + return null; + } } diff --git a/python/src/com/jetbrains/python/documentation/SphinxDocString.java b/python/src/com/jetbrains/python/documentation/SphinxDocString.java index ae5c7056a90b..c04e1c9471cf 100644 --- a/python/src/com/jetbrains/python/documentation/SphinxDocString.java +++ b/python/src/com/jetbrains/python/documentation/SphinxDocString.java @@ -31,7 +31,14 @@ public class SphinxDocString extends StructuredDocStringBase { ":type", ":raise", ":raises", ":var", ":cvar", ":ivar", ":return", ":returns", ":rtype", ":except", ":exception" }; - public SphinxDocString(@NotNull String docstringText) { + /** + * Empty doc (for {@link #createParameterType(String, String)} probably) + */ + public SphinxDocString() { + this(""); + } + + public SphinxDocString(@NotNull final String docstringText) { super(docstringText, ":"); } diff --git a/python/src/com/jetbrains/python/documentation/StructuredDocStringBase.java b/python/src/com/jetbrains/python/documentation/StructuredDocStringBase.java index 9f6cecba7a84..36b70ec0f76a 100644 --- a/python/src/com/jetbrains/python/documentation/StructuredDocStringBase.java +++ b/python/src/com/jetbrains/python/documentation/StructuredDocStringBase.java @@ -43,18 +43,21 @@ public abstract class StructuredDocStringBase implements StructuredDocString { private static final Pattern RE_LOOSE_TAG_LINE = Pattern.compile("([a-z]+) ([a-zA-Z_0-9]*):?([^:]*)"); private static final Pattern RE_ARG_TYPE = Pattern.compile("(.*) ([a-zA-Z_0-9]+)"); - public static String[] PARAM_TAGS = new String[] { "param", "parameter", "arg", "argument" }; - public static String[] PARAM_TYPE_TAGS = new String[] { "type" }; - public static String[] VARIABLE_TAGS = new String[] { "ivar", "cvar", "var" }; + public static String[] PARAM_TAGS = new String[]{"param", "parameter", "arg", "argument"}; + public static String[] PARAM_TYPE_TAGS = new String[]{"type"}; + public static String[] VARIABLE_TAGS = new String[]{"ivar", "cvar", "var"}; - public static String[] RAISES_TAGS = new String[] { "raises", "raise", "except", "exception" }; - public static String[] RETURN_TAGS = new String[] { "return", "returns" }; + public static String[] RAISES_TAGS = new String[]{"raises", "raise", "except", "exception"}; + public static String[] RETURN_TAGS = new String[]{"return", "returns"}; + @NotNull + private final String myTagPrefix; public enum ReferenceType {PARAMETER, PARAMETER_TYPE, KEYWORD, VARIABLE, CLASS_VARIABLE, INSTANCE_VARIABLE} public static String TYPE = "type"; protected StructuredDocStringBase(@NotNull String docStringText, String tagPrefix) { + myTagPrefix = tagPrefix; final Substring docString = new Substring(docStringText); final List<Substring> lines = docString.splitLines(); final int nlines = lines.size(); @@ -74,6 +77,12 @@ public abstract class StructuredDocStringBase implements StructuredDocString { } @Override + @NotNull + public String createParameterType(@NotNull final String name, @NotNull final String type) { + return myTagPrefix + TYPE + String.format(" %s %s", name, type); + } + + @Override public String getDescription() { return myDescription; } @@ -82,8 +91,9 @@ public abstract class StructuredDocStringBase implements StructuredDocString { public String getSummary() { final List<String> strings = StringUtil.split(StringUtil.trimLeading(myDescription), "\n", true, false); if (strings.size() > 1) { - if (strings.get(1).isEmpty()) + if (strings.get(1).isEmpty()) { return strings.get(0); + } } return ""; } @@ -216,8 +226,8 @@ public abstract class StructuredDocStringBase implements StructuredDocString { @Override @Nullable - public Substring getParamByNameAndKind(@NotNull String name, String kind) { - for (Substring s: getTagArguments(kind)) { + public Substring getParamByNameAndKind(@NotNull String name, String kind) { + for (Substring s : getTagArguments(kind)) { if (name.equals(s.getValue())) { return s; } diff --git a/python/src/com/jetbrains/python/inspections/PyInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyInspectionVisitor.java index 4584f06ae8d9..6c86e72b1bcd 100644 --- a/python/src/com/jetbrains/python/inspections/PyInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyInspectionVisitor.java @@ -78,12 +78,12 @@ public abstract class PyInspectionVisitor extends PyElementVisitor { protected final void registerProblem(@Nullable final PsiElement element, @NotNull final String message, - @NotNull final LocalQuickFix quickFix) { + @NotNull final LocalQuickFix... quickFixes) { if (element == null || element.getTextLength() == 0) { return; } if (myHolder != null) { - myHolder.registerProblem(element, message, quickFix); + myHolder.registerProblem(element, message, quickFixes); } } diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java index 8b6143ffe092..b2ad485c24f8 100644 --- a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java @@ -99,7 +99,7 @@ public class PyShadowingNamesInspection extends PyInspection { final ScopeOwner nextOwner = ScopeUtil.getScopeOwner(owner); if (nextOwner != null) { final ResolveProcessor processor = new ResolveProcessor(name); - PyResolveUtil.scopeCrawlUp(processor, nextOwner, null, name, null); + PyResolveUtil.scopeCrawlUp(processor, nextOwner, null, name, null, null); final PsiElement resolved = processor.getResult(); if (resolved != null) { final PyComprehensionElement comprehension = PsiTreeUtil.getParentOfType(resolved, PyComprehensionElement.class); diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveArgumentQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveArgumentQuickFix.java index 0ae7ac1c7812..708e91743730 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveArgumentQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveArgumentQuickFix.java @@ -27,6 +27,7 @@ import com.jetbrains.python.psi.PyExpression; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +//TODO: Remove pydoc aswell public class PyRemoveArgumentQuickFix implements LocalQuickFix { @NotNull diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 877da8df6dd9..cd4e582bb6f2 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -901,6 +901,20 @@ public class PyUtil { } /** + * Returns first child psi element with specified element type or {@code null} if no such element exists. + * Semantically it's the same as {@code getChildByFilter(element, TokenSet.create(type), 0)}. + * + * @param element tree parent node + * @param type element type expected + * @return child element described + */ + @Nullable + public static PsiElement getFirstChildOfType(@NotNull final PsiElement element, @NotNull PyElementType type) { + final ASTNode child = element.getNode().findChildByType(type); + return child != null ? child.getPsi() : null; + } + + /** * If argument is a PsiDirectory, turn it into a PsiFile that points to __init__.py in that directory. * If there's no __init__.py there, null is returned, there's no point to resolve to a dir which is not a package. * Alas, resolve() and multiResolve() can't return anything but a PyFile or PsiFileImpl.isPsiUpToDate() would fail. @@ -1645,6 +1659,11 @@ public class PyUtil { return Collections2.filter(pyMemberInfos, new ObjectPredicate(false)); } + public static boolean isStarImportableFrom(@NotNull String name, @NotNull PyFile file) { + final List<String> dunderAll = file.getDunderAll(); + return dunderAll != null ? dunderAll.contains(name) : !name.startsWith("_"); + } + /** * Filters only pyclass object (new class) */ diff --git a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java index 744dc9731b41..bb0e29f800a7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java @@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.impl.PsiFileFactoryImpl; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.tree.TokenSet; @@ -86,8 +87,9 @@ public class PyElementGeneratorImpl extends PyElementGenerator { } + @Override public PyStringLiteralExpression createStringLiteralFromString(@NotNull String unescaped) { - return createStringLiteralFromString(null, unescaped); + return createStringLiteralFromString(null, unescaped, true); } public PyStringLiteralExpression createStringLiteral(@NotNull PyStringLiteralExpression oldElement, @NotNull String unescaped) { @@ -100,7 +102,11 @@ public class PyElementGeneratorImpl extends PyElementGenerator { } } - public PyStringLiteralExpression createStringLiteralFromString(@Nullable PsiFile destination, @NotNull String unescaped) { + + @Override + public PyStringLiteralExpression createStringLiteralFromString(@Nullable PsiFile destination, + @NotNull String unescaped, + final boolean preferUTF8) { boolean useDouble = !unescaped.contains("\""); boolean useMulti = unescaped.matches(".*(\r|\n).*"); String quotes; @@ -115,7 +121,7 @@ public class PyElementGeneratorImpl extends PyElementGenerator { VirtualFile vfile = destination == null ? null : destination.getVirtualFile(); Charset charset; if (vfile == null) { - charset = Charset.forName("US-ASCII"); + charset = (preferUTF8 ? Charset.forName("UTF-8") : Charset.forName("US-ASCII")); } else { charset = vfile.getCharset(); @@ -191,7 +197,7 @@ public class PyElementGeneratorImpl extends PyElementGenerator { final LeafPsiElement[] leafs = PsiTreeUtil.getChildrenOfType(list, LeafPsiElement.class); if (leafs != null) { final Deque<LeafPsiElement> commas = Queues.newArrayDeque(Collections2.filter(Arrays.asList(leafs), COMMAS_ONLY)); - if (! commas.isEmpty()) { + if (!commas.isEmpty()) { final LeafPsiElement lastComma = commas.getLast(); if (PsiTreeUtil.getNextSiblingOfType(lastComma, PyExpression.class) == null) { //Comma has no expression after it lastComma.delete(); @@ -297,7 +303,7 @@ public class PyElementGeneratorImpl extends PyElementGenerator { AccessDirection accessDirection) { String propertyText; if (accessDirection == AccessDirection.DELETE) { - propertyText = "@" + propertyName +".deleter\ndef " + propertyName + "(self):\n del self." + fieldName; + propertyText = "@" + propertyName + ".deleter\ndef " + propertyName + "(self):\n del self." + fieldName; } else if (accessDirection == AccessDirection.WRITE) { propertyText = "@" + propertyName + ".setter\ndef " + propertyName + "(self, value):\n self." + fieldName + " = value"; @@ -415,6 +421,12 @@ public class PyElementGeneratorImpl extends PyElementGenerator { PyExpressionStatement.class, content + "\n"); } + @NotNull + @Override + public PsiElement createNewLine() { + return createFromText(LanguageLevel.getDefault(), PsiWhiteSpace.class, " \n\n "); + } + private static class CommasOnly extends NotNullPredicate<LeafPsiElement> { @Override protected boolean applyNotNull(@NotNull final LeafPsiElement input) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyElsePartImpl.java b/python/src/com/jetbrains/python/psi/impl/PyElsePartImpl.java index ddd02d5310a3..8c69893c62a8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyElsePartImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyElsePartImpl.java @@ -15,26 +15,16 @@ */ package com.jetbrains.python.psi.impl; -import com.jetbrains.python.psi.PyElsePart; -import com.jetbrains.python.psi.PyStatementList; -import com.jetbrains.python.PyElementTypes; import com.intellij.lang.ASTNode; +import com.jetbrains.python.psi.PyElsePart; /** * User: dcheryasov * Date: Mar 15, 2009 9:40:35 PM */ -public class PyElsePartImpl extends PyElementImpl implements PyElsePart { +public class PyElsePartImpl extends PyStatementPartImpl implements PyElsePart { public PyElsePartImpl(ASTNode astNode) { super(astNode); } - - public PyStatementList getStatementList() { - ASTNode n = getNode().findChildByType(PyElementTypes.STATEMENT_LISTS); - if (n != null) { - return (PyStatementList)n.getPsi(); - } - return null; - } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java index 030fcfe3d7e5..02b790622fe7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -477,8 +477,9 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { if (starImportSource != null) { starImportSource = PyUtil.turnDirIntoInit(starImportSource); if (starImportSource instanceof PyFile) { - final PsiElement result = ((PyFile)starImportSource).getElementNamed(name); - if (result != null) { + final PyFile file = (PyFile)starImportSource; + final PsiElement result = file.getElementNamed(name); + if (result != null && PyUtil.isStarImportableFrom(name, file)) { return result; } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java index e0cdf87b2aab..9d2be0f62205 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionBuilder.java @@ -23,6 +23,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.util.ArrayUtil; import com.jetbrains.python.PyNames; import com.jetbrains.python.PythonFileType; +import com.jetbrains.python.documentation.StructuredDocStringBase; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; @@ -82,14 +83,21 @@ public class PyFunctionBuilder { /** * Adds docstring to function. Provide doc with out of comment blocks. * + * * @param docString doc */ public void docString(@NotNull final String docString) { - myDocStringLines = StringUtil.splitByLines(removeIndent(docString)); + final String[] stringsToAdd = StringUtil.splitByLines(removeIndent(docString)); + if (myDocStringLines == null) { + myDocStringLines = stringsToAdd; + } + else { + myDocStringLines = ArrayUtil.mergeArrays(myDocStringLines, stringsToAdd); + } } @NotNull - private String removeIndent(@NotNull final String string) { + private static String removeIndent(@NotNull final String string) { return INDENT_REMOVE_PATTERN.matcher(string).replaceAll(""); } @@ -97,6 +105,21 @@ public class PyFunctionBuilder { myName = name; } + /** + * Adds param and its type to doc + * @param name param name + * @param type param type + * @param docStyle what docstyle to use to doc param type + */ + @NotNull + public PyFunctionBuilder parameterWithType(@NotNull final String name, + @NotNull final String type, + @NotNull final StructuredDocStringBase docStyle) { + parameter(name); + docString(docStyle.createParameterType(name, type)); + return this; + } + public PyFunctionBuilder parameter(String baseName) { String name = baseName; int uniqueIndex = 0; @@ -173,8 +196,9 @@ public class PyFunctionBuilder { /** * Adds decorator with argument + * * @param decoratorName decorator name - * @param value its argument + * @param value its argument */ public void decorate(@NotNull final String decoratorName, @NotNull final String value) { decorate(decoratorName); diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java index 4011c233e38d..88c3134481a8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java @@ -52,11 +52,8 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo for (PsiElement importedFile : new HashSet<PsiElement>(importedFiles)) { // resolver gives lots of duplicates final PsiElement source = PyUtil.turnDirIntoInit(importedFile); if (source instanceof PyFile) { - Iterable<PyElement> declaredNames = ((PyFile)source).iterateNames(); - if (((PyFile)source).getDunderAll() == null) { - declaredNames = excludeUnderscoredNames(declaredNames); - } - chain.add(declaredNames); + final PyFile sourceFile = (PyFile)source; + chain.add(filterStarImportableNames(sourceFile.iterateNames(), sourceFile)); } } return chain; @@ -64,15 +61,13 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo return Collections.emptyList(); } - private static Iterable<PyElement> excludeUnderscoredNames(Iterable<PyElement> declaredNames) { + @NotNull + private static Iterable<PyElement> filterStarImportableNames(@NotNull Iterable<PyElement> declaredNames, @NotNull final PyFile file) { return Iterables.filter(declaredNames, new Predicate<PyElement>() { @Override public boolean apply(@Nullable PyElement input) { final String name = input != null ? input.getName() : null; - if (name != null && name.startsWith("_")) { - return false; - } - return true; + return name != null && PyUtil.isStarImportableFrom(name, file); } }); } @@ -93,11 +88,7 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo final List<? extends RatedResolveResult> results = moduleType.resolveMember(name, null, AccessDirection.READ, PyResolveContext.defaultContext()); final PsiElement result = results != null && !results.isEmpty() ? results.get(0).getElement() : null; - if (result != null) { - final List<String> all = sourceFile.getDunderAll(); - if (all != null ? !all.contains(name) : name.startsWith("_")) { - continue; - } + if (result != null && PyUtil.isStarImportableFrom(name, sourceFile) ) { return result; } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyStatementPartImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStatementPartImpl.java index 46e9a785a9d4..7454d6741382 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyStatementPartImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyStatementPartImpl.java @@ -15,10 +15,11 @@ */ package com.jetbrains.python.psi.impl; -import com.jetbrains.python.psi.PyStatementPart; -import com.jetbrains.python.psi.PyStatementList; -import com.jetbrains.python.PyElementTypes; import com.intellij.lang.ASTNode; +import com.jetbrains.python.PyElementTypes; +import com.jetbrains.python.psi.PyStatementList; +import com.jetbrains.python.psi.PyStatementPart; +import org.jetbrains.annotations.NotNull; /** * Abstract statement part implementation; extracts the statements list. @@ -30,11 +31,8 @@ public abstract class PyStatementPartImpl extends PyElementImpl implements PySta super(astNode); } + @NotNull public PyStatementList getStatementList() { - ASTNode n = getNode().findChildByType(PyElementTypes.STATEMENT_LISTS); - if (n != null) { - return (PyStatementList)n.getPsi(); - } - return null; + return childToPsiNotNull(PyElementTypes.STATEMENT_LIST); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyWithStatementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyWithStatementImpl.java index 98cd8e5703d5..3af3771e8ecd 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyWithStatementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyWithStatementImpl.java @@ -63,6 +63,14 @@ public class PyWithStatementImpl extends PyElementImpl implements PyWithStatemen } public PyWithItem[] getWithItems() { - return childrenToPsi(WITH_ITEM, PyWithItem.EMPTY_ARRAY); + return childrenToPsi(WITH_ITEM, PyWithItem.EMPTY_ARRAY); + } + + @Override + @NotNull + public PyStatementList getStatementList() { + final PyStatementList statementList = childToPsi(PyElementTypes.STATEMENT_LIST); + assert statementList != null : "Statement list missing for with statement " + getText(); + return statementList; } } diff --git a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java index da8c0d618a8b..838a4dbcc75a 100644 --- a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java @@ -38,6 +38,11 @@ import com.jetbrains.python.psi.impl.PyPsiUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + /** * Ref resolution routines. * User: dcheryasov @@ -106,16 +111,17 @@ public class PyResolveUtil { owner = outerScopeOwner; } } - scopeCrawlUp(processor, owner, originalOwner, name, roof); + scopeCrawlUp(processor, owner, originalOwner, name, roof, realContext); } public static void scopeCrawlUp(@NotNull PsiScopeProcessor processor, @NotNull ScopeOwner scopeOwner, @Nullable String name, @Nullable PsiElement roof) { - scopeCrawlUp(processor, scopeOwner, scopeOwner, name, roof); + scopeCrawlUp(processor, scopeOwner, scopeOwner, name, roof, null); } public static void scopeCrawlUp(@NotNull PsiScopeProcessor processor, @Nullable ScopeOwner scopeOwner, - @Nullable ScopeOwner originalScopeOwner, @Nullable String name, @Nullable PsiElement roof) { + @Nullable ScopeOwner originalScopeOwner, @Nullable String name, @Nullable PsiElement roof, + @Nullable final PsiElement anchor) { while (scopeOwner != null) { if (!(scopeOwner instanceof PyClass) || scopeOwner == originalScopeOwner) { final Scope scope = ControlFlowCache.getScope(scopeOwner); @@ -136,7 +142,31 @@ public class PyResolveUtil { } } } - for (NameDefiner definer : scope.getImportedNameDefiners()) { + List<NameDefiner> definers = new ArrayList<NameDefiner>(scope.getImportedNameDefiners()); + if (anchor != null && ScopeUtil.getScopeOwner(anchor) == scopeOwner) { + final Comparator<NameDefiner> nearestDefinerComparator = new Comparator<NameDefiner>() { + @Override + public int compare(NameDefiner a, NameDefiner b) { + final boolean aIsBefore = PyPsiUtils.isBefore(a, anchor); + final boolean bIsBefore = PyPsiUtils.isBefore(b, anchor); + final int diff = a.getTextOffset() - b.getTextOffset(); + if (aIsBefore && bIsBefore) { + return -diff; + } + else if (aIsBefore) { + return -1; + } + else if (bIsBefore) { + return 1; + } + else { + return diff; + } + } + }; + Collections.sort(definers, nearestDefinerComparator); + } + for (NameDefiner definer : definers) { if (!processor.execute(definer, ResolveState.initial())) { found = true; break; diff --git a/python/src/com/jetbrains/python/run/PyRemoteTracebackFilter.java b/python/src/com/jetbrains/python/run/PyRemoteTracebackFilter.java new file mode 100644 index 000000000000..2af1a641de83 --- /dev/null +++ b/python/src/com/jetbrains/python/run/PyRemoteTracebackFilter.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.run; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.remote.RemoteProcessHandlerBase; +import com.intellij.util.PathMappingSettings; +import org.jetbrains.annotations.Nullable; + +/** + * @author traff + */ +public class PyRemoteTracebackFilter extends PythonTracebackFilter { + private final RemoteProcessHandlerBase myHandler; + + public PyRemoteTracebackFilter(Project project, String workingDirectory, RemoteProcessHandlerBase remoteProcessHandler) { + super(project, workingDirectory); + + myHandler = remoteProcessHandler; + } + + @Override + @Nullable + protected VirtualFile findFileByName(String fileName) { + VirtualFile vFile = super.findFileByName(fileName); + if (vFile != null) { + return vFile; + } + for (PathMappingSettings.PathMapping m : myHandler.getMappingSettings().getPathMappings()) { + if (m.canReplaceRemote(fileName)) { + VirtualFile file = LocalFileSystem.getInstance().findFileByPath(m.mapToLocal(fileName)); + if (file != null && file.exists()) { + return file; + } + } + } + + + + return null; + } +} diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java index 216e68c58e1d..a4d1718bb006 100644 --- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java @@ -47,6 +47,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.remote.RemoteProcessHandlerBase; import com.intellij.util.PlatformUtils; import com.intellij.util.containers.HashMap; import com.jetbrains.python.PythonHelpersLocator; @@ -80,7 +81,9 @@ public abstract class PythonCommandLineState extends CommandLineState { public static final String GROUP_DEBUGGER = "Debugger"; public static final String GROUP_SCRIPT = "Script"; private final AbstractPythonRunConfiguration myConfig; - private final List<Filter> myFilters; + + private final List<Filter> myFilters = Lists.<Filter>newArrayList(new UrlFilter()); + private Boolean myMultiprocessDebug = null; public boolean isDebug() { @@ -99,15 +102,9 @@ public abstract class PythonCommandLineState extends CommandLineState { return serverSocket; } - public PythonCommandLineState(AbstractPythonRunConfiguration runConfiguration, ExecutionEnvironment env, List<Filter> filters) { + public PythonCommandLineState(AbstractPythonRunConfiguration runConfiguration, ExecutionEnvironment env) { super(env); myConfig = runConfiguration; - myFilters = Lists.newArrayList(filters); - addDefaultFilters(); - } - - protected void addDefaultFilters() { - myFilters.add(new UrlFilter()); } @Nullable @@ -134,10 +131,23 @@ public abstract class PythonCommandLineState extends CommandLineState { protected ConsoleView createAndAttachConsole(Project project, ProcessHandler processHandler, Executor executor) throws ExecutionException { final ConsoleView consoleView = createConsoleBuilder(project).filters(myFilters).getConsole(); + + addTracebackFilter(project, consoleView, processHandler); + consoleView.attachToProcess(processHandler); return consoleView; } + protected void addTracebackFilter(Project project, ConsoleView consoleView, ProcessHandler processHandler) { + if (PySdkUtil.isRemote(myConfig.getSdk())) { + assert processHandler instanceof RemoteProcessHandlerBase; + consoleView.addMessageFilter(new PyRemoteTracebackFilter(project, myConfig.getWorkingDirectory(), (RemoteProcessHandlerBase) processHandler)); + } + else { + consoleView.addMessageFilter(new PythonTracebackFilter(project, myConfig.getWorkingDirectory())); + } + } + private TextConsoleBuilder createConsoleBuilder(Project project) { if (isDebug()) { return new PyDebugConsoleBuilder(project, PythonSdkType.findSdkByPath(myConfig.getInterpreterPath())); diff --git a/python/src/com/jetbrains/python/run/PythonRunConfiguration.java b/python/src/com/jetbrains/python/run/PythonRunConfiguration.java index bbba44441227..118c27beb548 100644 --- a/python/src/com/jetbrains/python/run/PythonRunConfiguration.java +++ b/python/src/com/jetbrains/python/run/PythonRunConfiguration.java @@ -15,11 +15,9 @@ */ package com.jetbrains.python.run; -import com.google.common.collect.Lists; import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.configurations.*; -import com.intellij.execution.filters.Filter; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.options.SettingsEditor; @@ -40,7 +38,6 @@ import org.jdom.Element; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.util.List; /** * @author yole @@ -64,10 +61,7 @@ public class PythonRunConfiguration extends AbstractPythonRunConfiguration } public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException { - List<Filter> filters = Lists.newArrayList(); - filters.add(new PythonTracebackFilter(getProject(), getWorkingDirectory())); - - return new PythonScriptCommandLineState(this, env, filters); + return new PythonScriptCommandLineState(this, env); } public void checkConfiguration() throws RuntimeConfigurationException { diff --git a/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java b/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java index 53ef554838ae..81d2daaee3d0 100644 --- a/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java @@ -18,20 +18,17 @@ package com.jetbrains.python.run; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.ParametersList; import com.intellij.execution.configurations.ParamsGroup; -import com.intellij.execution.filters.Filter; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.openapi.util.text.StringUtil; -import java.util.List; - /** * @author yole */ public class PythonScriptCommandLineState extends PythonCommandLineState { private final PythonRunConfiguration myConfig; - public PythonScriptCommandLineState(PythonRunConfiguration runConfiguration, ExecutionEnvironment env, List<Filter> filters) { - super(runConfiguration, env, filters); + public PythonScriptCommandLineState(PythonRunConfiguration runConfiguration, ExecutionEnvironment env) { + super(runConfiguration, env); myConfig = runConfiguration; } diff --git a/python/src/com/jetbrains/python/run/PythonTracebackFilter.java b/python/src/com/jetbrains/python/run/PythonTracebackFilter.java index e3bd879cfe81..73a3abd222b1 100644 --- a/python/src/com/jetbrains/python/run/PythonTracebackFilter.java +++ b/python/src/com/jetbrains/python/run/PythonTracebackFilter.java @@ -51,10 +51,7 @@ public class PythonTracebackFilter implements Filter { if (matcher.find()) { String fileName = matcher.group(1).replace('\\', '/'); int lineNumber = Integer.parseInt(matcher.group(2)); - VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fileName); - if (vFile == null && !StringUtil.isEmptyOrSpaces(myWorkingDirectory)) { - vFile = LocalFileSystem.getInstance().findFileByIoFile(new File(myWorkingDirectory, fileName)); - } + VirtualFile vFile = findFileByName(fileName); if (vFile != null) { OpenFileHyperlinkInfo hyperlink = new OpenFileHyperlinkInfo(myProject, vFile, lineNumber - 1); @@ -66,4 +63,13 @@ public class PythonTracebackFilter implements Filter { } return null; } + + @Nullable + protected VirtualFile findFileByName(String fileName) { + VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fileName); + if (vFile == null && !StringUtil.isEmptyOrSpaces(myWorkingDirectory)) { + vFile = LocalFileSystem.getInstance().findFileByIoFile(new File(myWorkingDirectory, fileName)); + } + return vFile; + } } diff --git a/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java b/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java index 098462ef44fb..f288bd99ce3b 100644 --- a/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java +++ b/python/src/com/jetbrains/python/sdk/PyDetectedSdk.java @@ -8,4 +8,8 @@ public class PyDetectedSdk extends ProjectJdkImpl { setHomePath(name); } + @Override + public String getVersionString() { + return ""; + } } diff --git a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java index 39e4e96b836b..1a5aafe59051 100644 --- a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java +++ b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java @@ -22,7 +22,6 @@ import com.intellij.execution.ExecutionResult; import com.intellij.execution.Executor; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.ParamsGroup; -import com.intellij.execution.filters.Filter; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.testframework.TestFrameworkRunningModel; @@ -42,12 +41,10 @@ import com.jetbrains.python.console.PythonDebugLanguageConsoleView; import com.jetbrains.python.run.AbstractPythonRunConfiguration; import com.jetbrains.python.run.CommandLinePatcher; import com.jetbrains.python.run.PythonCommandLineState; -import com.jetbrains.python.run.PythonTracebackFilter; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -62,7 +59,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt } public PythonTestCommandLineStateBase(AbstractPythonRunConfiguration configuration, ExecutionEnvironment env) { - super(configuration, env, Collections.<Filter>emptyList()); + super(configuration, env); myConfiguration = configuration; } @@ -77,7 +74,6 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt consoleProperties, getEnvironment()); final ConsoleView consoleView = new PythonDebugLanguageConsoleView(project, PythonSdkType.findSdkByPath(myConfiguration.getInterpreterPath()), testsOutputConsoleView); - consoleView.addMessageFilter(new PythonTracebackFilter(project, myConfiguration.getWorkingDirectory())); consoleView.attachToProcess(processHandler); return consoleView; } @@ -85,7 +81,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt processHandler, consoleProperties, getEnvironment()); - consoleView.addMessageFilter(new PythonTracebackFilter(project, myConfiguration.getWorkingDirectory())); + addTracebackFilter(project, consoleView, processHandler); return consoleView; } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java b/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java index 3637f37ca91c..581e688de1d5 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java @@ -81,7 +81,7 @@ public class PyTestCommandLineState extends PythonTestCommandLineStateBase { protected ConsoleView createAndAttachConsole(Project project, ProcessHandler processHandler, Executor executor) throws ExecutionException { final ConsoleView consoleView = super.createAndAttachConsole(project, processHandler, executor); - consoleView.addMessageFilter(new PyTestTracebackFilter(project, myConfiguration.getWorkingDirectory())); + addTracebackFilter(project, consoleView, processHandler); return consoleView; } } |