diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index e18df4974244..084e536a71a2 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -55,7 +55,7 @@ serviceImplementation="com.jetbrains.python.psi.impl.PyBuiltinCache"/> - + diff --git a/python/src/com/jetbrains/python/PyLineMarkerNavigator.java b/python/src/com/jetbrains/python/PyLineMarkerNavigator.java deleted file mode 100644 index e25f31123074..000000000000 --- a/python/src/com/jetbrains/python/PyLineMarkerNavigator.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.jetbrains.python; - -import com.intellij.codeInsight.daemon.impl.GutterIconNavigationHandler; -import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator; -import com.intellij.ide.util.DefaultPsiElementCellRenderer; -import com.intellij.psi.NavigatablePsiElement; -import com.intellij.psi.PsiElement; -import com.intellij.util.Processor; -import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.search.PySuperMethodsSearch; - -import java.awt.event.MouseEvent; -import java.util.List; -import java.util.ArrayList; - -/** - * @author yole - */ -public class PyLineMarkerNavigator implements GutterIconNavigationHandler { - public void navigate(final MouseEvent e, final PsiElement elt) { - if (elt.getParent() instanceof PyFunction) { - final PyFunction function = (PyFunction)elt.getParent(); - final List navElements = new ArrayList(); - PySuperMethodsSearch.search(function).forEach(new Processor() { - public boolean process(final PsiElement psiElement) { - if (psiElement instanceof NavigatablePsiElement) { - navElements.add((NavigatablePsiElement) psiElement); - } - return true; - } - }); - final NavigatablePsiElement[] methods = navElements.toArray(new NavigatablePsiElement[navElements.size()]); - PsiElementListNavigator.openTargets(e, methods, "Choose Super Method of " + function.getName(), - new DefaultPsiElementCellRenderer()); - } - } -} diff --git a/python/src/com/jetbrains/python/PyLineMarkerProvider.java b/python/src/com/jetbrains/python/PyLineMarkerProvider.java deleted file mode 100644 index d805884b8957..000000000000 --- a/python/src/com/jetbrains/python/PyLineMarkerProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.jetbrains.python; - -import com.intellij.codeHighlighting.Pass; -import com.intellij.codeInsight.daemon.impl.LineMarkerInfo; -import com.intellij.codeInsight.daemon.impl.LineMarkerProvider; -import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.IconLoader; -import com.intellij.psi.PsiElement; -import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.search.PySuperMethodsSearch; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.util.List; -import java.util.Collection; - -/** - * @author yole - */ -public class PyLineMarkerProvider implements LineMarkerProvider { - private static final Icon OVERRIDING_METHOD_ICON = IconLoader.getIcon("/gutter/overridingMethod.png"); - - public LineMarkerInfo getLineMarkerInfo(final PsiElement element) { - final ASTNode node = element.getNode(); - if (node != null && node.getElementType() == PyTokenTypes.IDENTIFIER && element.getParent() instanceof PyFunction) { - final PyFunction function = (PyFunction)element.getParent(); - return getMethodMarker(element, function); - } - return null; - } - - @Nullable - private static LineMarkerInfo getMethodMarker(final PsiElement element, final PyFunction function) { - if (PySuperMethodsSearch.search(function).findFirst() != null) { - // TODO: show "implementing" instead of "overriding" icon for Python implementations of Java interface methods - LineMarkerInfo info = new LineMarkerInfo(element, element.getTextRange().getStartOffset(), - OVERRIDING_METHOD_ICON, Pass.UPDATE_ALL, null, new PyLineMarkerNavigator()); - return info; - } - return null; - } - - public void collectSlowLineMarkers(final List elements, final Collection result) { - } -} diff --git a/python/src/com/jetbrains/python/codeInsight/PyLineMarkerNavigator.java b/python/src/com/jetbrains/python/codeInsight/PyLineMarkerNavigator.java new file mode 100644 index 000000000000..7d63bbd6c253 --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/PyLineMarkerNavigator.java @@ -0,0 +1,40 @@ +package com.jetbrains.python.codeInsight; + +import com.intellij.codeInsight.daemon.impl.GutterIconNavigationHandler; +import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator; +import com.intellij.ide.util.DefaultPsiElementCellRenderer; +import com.intellij.psi.NavigatablePsiElement; +import com.intellij.psi.PsiElement; +import com.intellij.util.Processor; +import com.intellij.util.Query; +import org.jetbrains.annotations.Nullable; + +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; + +/** + * @author yole + */ +public abstract class PyLineMarkerNavigator implements GutterIconNavigationHandler { + public void navigate(final MouseEvent e, final PsiElement elt) { + final List navElements = new ArrayList(); + Query elementQuery = search(elt); + if (elementQuery == null) return; + elementQuery.forEach(new Processor() { + public boolean process(final T psiElement) { + if (psiElement instanceof NavigatablePsiElement) { + navElements.add((NavigatablePsiElement)psiElement); + } + return true; + } + }); + final NavigatablePsiElement[] methods = navElements.toArray(new NavigatablePsiElement[navElements.size()]); + PsiElementListNavigator.openTargets(e, methods, getTitle(elt), new DefaultPsiElementCellRenderer()); + } + + protected abstract String getTitle(PsiElement elt); + + @Nullable + protected abstract Query search(PsiElement elt); +} diff --git a/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java b/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java new file mode 100644 index 000000000000..a28eae9994c9 --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/PyLineMarkerProvider.java @@ -0,0 +1,81 @@ +package com.jetbrains.python.codeInsight; + +import com.intellij.codeHighlighting.Pass; +import com.intellij.codeInsight.daemon.impl.LineMarkerInfo; +import com.intellij.codeInsight.daemon.impl.LineMarkerProvider; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.IconLoader; +import com.intellij.psi.PsiElement; +import com.intellij.util.Query; +import com.jetbrains.python.PyTokenTypes; +import com.jetbrains.python.psi.PyClass; +import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.search.PyClassInheritorsSearch; +import com.jetbrains.python.psi.search.PySuperMethodsSearch; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.Collection; +import java.util.List; + +/** + * @author yole + */ +public class PyLineMarkerProvider implements LineMarkerProvider { + private static final Icon OVERRIDING_METHOD_ICON = IconLoader.getIcon("/gutter/overridingMethod.png"); + private static final Icon OVERRIDDEN_ICON = IconLoader.getIcon("/gutter/overridenMethod.png"); + + public LineMarkerInfo getLineMarkerInfo(final PsiElement element) { + final ASTNode node = element.getNode(); + if (node != null && node.getElementType() == PyTokenTypes.IDENTIFIER && element.getParent() instanceof PyFunction) { + final PyFunction function = (PyFunction)element.getParent(); + return getMethodMarker(element, function); + } + return null; + } + + @Nullable + private static LineMarkerInfo getMethodMarker(final PsiElement element, final PyFunction function) { + if (PySuperMethodsSearch.search(function).findFirst() != null) { + // TODO: show "implementing" instead of "overriding" icon for Python implementations of Java interface methods + PyLineMarkerNavigator markerNavigator = new PyLineMarkerNavigator() { + protected String getTitle(final PsiElement elt) { + return "Choose Super Method of " + ((PyFunction)elt.getParent()).getName(); + } + + @Nullable + protected Query search(final PsiElement elt) { + if (!(elt.getParent() instanceof PyFunction)) return null; + return PySuperMethodsSearch.search((PyFunction)elt.getParent()); + } + }; + return new LineMarkerInfo(element, element.getTextRange().getStartOffset(), OVERRIDING_METHOD_ICON, Pass.UPDATE_ALL, + null, markerNavigator); + } + return null; + } + + public void collectSlowLineMarkers(final List elements, final Collection result) { + for(PsiElement element: elements) { + if (element instanceof PyClass) { + collectInheritingClasses((PyClass) element, result); + } + } + } + + private static void collectInheritingClasses(final PyClass element, final Collection result) { + if (PyClassInheritorsSearch.search(element, false).findFirst() != null) { + PyLineMarkerNavigator navigator = new PyLineMarkerNavigator() { + protected String getTitle(final PsiElement elt) { + return "Choose Subclass of "+ ((PyClass) elt).getName(); + } + + protected Query search(final PsiElement elt) { + return PyClassInheritorsSearch.search((PyClass) elt, true); + } + }; + result.add(new LineMarkerInfo(element, element.getTextOffset(), OVERRIDDEN_ICON, Pass.UPDATE_OVERRIDEN_MARKERS, + null, navigator)); + } + } +}