python subclass navigation

This commit is contained in:
Dmitry Jemerov
2008-03-26 13:35:51 +03:00
parent 1f483e4af3
commit b5e4019dbf
5 changed files with 122 additions and 83 deletions
+1 -1
View File
@@ -55,7 +55,7 @@
serviceImplementation="com.jetbrains.python.psi.impl.PyBuiltinCache"/>
<referenceImporter implementation="com.jetbrains.python.validation.PythonReferenceImporter"/>
<codeInsight.lineMarkerProvider language="Python" implementationClass="com.jetbrains.python.PyLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="Python" implementationClass="com.jetbrains.python.codeInsight.PyLineMarkerProvider"/>
<definitionsSearch implementation="com.jetbrains.python.psi.search.PyDefinitionsSearch"/>
<gotoImplementationRendererProvider implementation="com.jetbrains.python.codeInsight.PyGotoImplementationRendererProvider"/>
</extensions>
@@ -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<NavigatablePsiElement> navElements = new ArrayList<NavigatablePsiElement>();
PySuperMethodsSearch.search(function).forEach(new Processor<PsiElement>() {
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());
}
}
}
@@ -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<PsiElement> elements, final Collection<LineMarkerInfo> result) {
}
}
@@ -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<T extends PsiElement> implements GutterIconNavigationHandler {
public void navigate(final MouseEvent e, final PsiElement elt) {
final List<NavigatablePsiElement> navElements = new ArrayList<NavigatablePsiElement>();
Query<T> elementQuery = search(elt);
if (elementQuery == null) return;
elementQuery.forEach(new Processor<T>() {
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<T> search(PsiElement elt);
}
@@ -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<PsiElement>() {
protected String getTitle(final PsiElement elt) {
return "Choose Super Method of " + ((PyFunction)elt.getParent()).getName();
}
@Nullable
protected Query<PsiElement> 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<PsiElement> elements, final Collection<LineMarkerInfo> result) {
for(PsiElement element: elements) {
if (element instanceof PyClass) {
collectInheritingClasses((PyClass) element, result);
}
}
}
private static void collectInheritingClasses(final PyClass element, final Collection<LineMarkerInfo> result) {
if (PyClassInheritorsSearch.search(element, false).findFirst() != null) {
PyLineMarkerNavigator navigator = new PyLineMarkerNavigator<PyClass>() {
protected String getTitle(final PsiElement elt) {
return "Choose Subclass of "+ ((PyClass) elt).getName();
}
protected Query<PyClass> 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));
}
}
}