diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 65a362ba0c68..457088cb3e30 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -324,6 +324,7 @@ + @@ -354,6 +355,7 @@ + diff --git a/python/src/com/jetbrains/python/codeInsight/PyDynamicMember.java b/python/src/com/jetbrains/python/codeInsight/PyDynamicMember.java index 2a895618e65b..8c63c06b7d0f 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyDynamicMember.java +++ b/python/src/com/jetbrains/python/codeInsight/PyDynamicMember.java @@ -74,7 +74,10 @@ public class PyDynamicMember { return myName; } - public static Icon getIcon() { + public Icon getIcon() { + if (myTarget != null) { + return myTarget.getIcon(0); + } return IconLoader.getIcon("/nodes/method.png"); } diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleMembersProvider.java b/python/src/com/jetbrains/python/psi/types/PyModuleMembersProvider.java new file mode 100644 index 000000000000..12b7f55b5415 --- /dev/null +++ b/python/src/com/jetbrains/python/psi/types/PyModuleMembersProvider.java @@ -0,0 +1,28 @@ +package com.jetbrains.python.psi.types; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.jetbrains.python.codeInsight.PyDynamicMember; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * @author yole + */ +public abstract class PyModuleMembersProvider { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyModuleMembersProvider"); + + public abstract Collection getMembers(PsiFile module); + + @Nullable + public PsiElement resolveMember(PsiFile module, String name) { + for (PyDynamicMember o : getMembers(module)) { + if (o.getName().equals(name)) { + return o.resolve(module); + } + } + return null; + } +} diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index e66bcd01d760..bc9bf3568395 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -3,12 +3,14 @@ package com.jetbrains.python.psi.types; import com.google.common.collect.ImmutableSet; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.psi.*; import com.intellij.util.ProcessingContext; import com.intellij.util.SmartList; import com.jetbrains.python.PyNames; +import com.jetbrains.python.codeInsight.PyDynamicMember; import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyFile; @@ -46,6 +48,13 @@ public class PyModuleType implements PyType { // Modules don't descend from obje @Nullable public List resolveMember(final String name, AccessDirection direction, PyResolveContext resolveContext) { + for(PyModuleMembersProvider provider: Extensions.getExtensions(PyModuleMembersProvider.EP_NAME)) { + final PsiElement element = provider.resolveMember(myModule, name); + if (element != null) { + return new SmartList(element); + } + } + //return PyResolveUtil.treeWalkUp(new PyResolveUtil.ResolveProcessor(name), myModule, null, null); final PsiElement result = ResolveImportUtil.resolveChild(myModule, name, myModule, null, false); if (result != null) return new SmartList(result); @@ -94,6 +103,14 @@ public class PyModuleType implements PyType { // Modules don't descend from obje public Object[] getCompletionVariants(String completionPrefix, PyExpression location, ProcessingContext context) { Set names_already = context.get(CTX_NAMES); List result = new ArrayList(); + + for (PyModuleMembersProvider provider : Extensions.getExtensions(PyModuleMembersProvider.EP_NAME)) { + for (PyDynamicMember member : provider.getMembers(myModule)) { + final String name = member.getName(); + result.add(LookupElementBuilder.create(name).setIcon(member.getIcon()).setTypeText(member.getShortType())); + } + } + ResolveImportUtil.PointInImport point = ResolveImportUtil.getPointInImport(location); if (point.role == NONE || point.role == AS_NAME) { // when not imported from, add regular attributes final VariantsProcessor processor = new VariantsProcessor(location);