diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index 9ab0ab8b7c08..95f122b0928b 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; import com.intellij.util.ObjectUtils; @@ -309,6 +310,16 @@ public class PyDocumentationBuilder { myContent.add(formatDocString(myElement, docStringExpression.getStringValue())); } + if (PyUtil.isTopLevel(elementDefinition)) { + final PsiFile containing = elementDefinition.getContainingFile(); + if (containing instanceof PyFile) { + final String link = getLinkToModule((PyFile)containing); + if (link != null) { + myProlog.addItem(link); + } + } + } + if (elementDefinition instanceof PyClass) { pyClass = (PyClass)elementDefinition; myBody.add(PythonDocumentationProvider.describeDecorators(pyClass, WRAP_IN_ITALIC, ESCAPE_AND_SAVE_NEW_LINES_AND_SPACES, BR, BR)); @@ -502,12 +513,22 @@ public class PyDocumentationBuilder { .addWith(TagBold, $(ObjectUtils.chooseNotNull(QualifiedNameFinder.canonizeQualifiedName(name, null), name).toString())); } else { - String path = file.getPath(); - myProlog.addWith(TagSpan.withAttribute("path", path), $("").addWith(TagSmall, $(path))); + final String path = file.getPath(); + myProlog.addWith(TagSpan.withAttribute("path", path), $(path)); } } } + @Nullable + private String getLinkToModule(@NotNull PyFile module) { + final QualifiedName name = QualifiedNameFinder.findCanonicalImportPath(module, null); + if (name != null) { + return PyDocumentationLink.toModule(name.toString(), name.toString()); + } + final VirtualFile vFile = module.getVirtualFile(); + return vFile != null ? vFile.getPath() : null; + } + @Nullable private String getLinkToClass(@NotNull PyClass pyClass, boolean preferQualifiedName) { final String qualifiedName = pyClass.getQualifiedName(); diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationLink.kt b/python/src/com/jetbrains/python/documentation/PyDocumentationLink.kt index 5e451765020d..bce81b356e05 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationLink.kt +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationLink.kt @@ -17,12 +17,10 @@ package com.jetbrains.python.documentation import com.intellij.codeInsight.documentation.DocumentationManagerProtocol import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFileSystemItem import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.QualifiedName -import com.jetbrains.python.psi.PyClass -import com.jetbrains.python.psi.PyFunction -import com.jetbrains.python.psi.PyNamedParameter -import com.jetbrains.python.psi.PyPsiFacade +import com.jetbrains.python.psi.* import com.jetbrains.python.psi.types.PyClassType import com.jetbrains.python.psi.types.PyTypeParser import com.jetbrains.python.psi.types.TypeEvalContext @@ -33,6 +31,7 @@ object PyDocumentationLink { private const val LINK_TYPE_PARAM = "#param#" private const val LINK_TYPE_TYPENAME = "#typename#" private const val LINK_TYPE_FUNC = "#func#" + private const val LINK_TYPE_MODULE = "#module#" @JvmStatic fun toContainingClass(content: String?): String { @@ -72,6 +71,11 @@ object PyDocumentationLink { } } + @JvmStatic + fun toModule(content: String, qualifiedName: String): String { + return "$content" + } + @JvmStatic fun elementForLink(link: String, element: PsiElement, context: TypeEvalContext): PsiElement? { return when { @@ -79,10 +83,23 @@ object PyDocumentationLink { link == LINK_TYPE_PARAM -> parameterPossibleClass(element, context) link.startsWith(LINK_TYPE_TYPENAME) -> possibleClass(link.substring(LINK_TYPE_TYPENAME.length), element, context) link.startsWith(LINK_TYPE_FUNC) -> possibleFunction(link.substring(LINK_TYPE_FUNC.length), element) + link.startsWith(LINK_TYPE_MODULE) -> possibleModule(link.substring(LINK_TYPE_MODULE.length), element) else -> null } } + private fun possibleModule(qualifiedName: String, element: PsiElement): PyFile? { + val facade = PyPsiFacade.getInstance(element.project) + val qName = QualifiedName.fromDottedString(qualifiedName) + + val resolveContext = facade.createResolveContextFromFoothold(element) + return facade.resolveQualifiedName(qName, resolveContext) + .filterIsInstance() + .map { PyUtil.turnDirIntoInit(it) } + .filterIsInstance() + .firstOrNull() + } + @JvmStatic private fun possibleFunction(qualifiedName: String, element: PsiElement): PyFunction? { // TODO a better, more general way to resolve qualified names of function diff --git a/python/testData/quickdoc/ArgumentList.html b/python/testData/quickdoc/ArgumentList.html index 0cab4184ae8d..9da52ac20344 100644 --- a/python/testData/quickdoc/ArgumentList.html +++ b/python/testData/quickdoc/ArgumentList.html @@ -1 +1 @@ -
def foo() -> None
Doc of foo.
\ No newline at end of file +
ArgumentList
def foo() -> None
Doc of foo.
\ No newline at end of file diff --git a/python/testData/quickdoc/BuiltinLen.html b/python/testData/quickdoc/BuiltinLen.html index 1d9e08d99275..c7630466e143 100644 --- a/python/testData/quickdoc/BuiltinLen.html +++ b/python/testData/quickdoc/BuiltinLen.html @@ -1 +1 @@ -
def len(o: Sized) -> int
len(object) -> integer

Return the number of items of a sequence or collection.
\ No newline at end of file +
__builtin__
def len(o: Sized) -> int
len(object) -> integer

Return the number of items of a sequence or collection.
\ No newline at end of file diff --git a/python/testData/quickdoc/CallFunc.html b/python/testData/quickdoc/CallFunc.html index 0cab4184ae8d..0015974164f8 100644 --- a/python/testData/quickdoc/CallFunc.html +++ b/python/testData/quickdoc/CallFunc.html @@ -1 +1 @@ -
def foo() -> None
Doc of foo.
\ No newline at end of file +
CallFunc
def foo() -> None
Doc of foo.
\ No newline at end of file diff --git a/python/testData/quickdoc/ClassConstructor.html b/python/testData/quickdoc/ClassConstructor.html index 0328d0789102..bff1f2803de5 100644 --- a/python/testData/quickdoc/ClassConstructor.html +++ b/python/testData/quickdoc/ClassConstructor.html @@ -1 +1 @@ -
class Foo(object)
Doc of Foo.
\ No newline at end of file +
Doc of Foo.
\ No newline at end of file diff --git a/python/testData/quickdoc/ClassWithAllKindSuperClassExpressions.html b/python/testData/quickdoc/ClassWithAllKindSuperClassExpressions.html index f97619dbbb65..ac6fd2d6d566 100644 --- a/python/testData/quickdoc/ClassWithAllKindSuperClassExpressions.html +++ b/python/testData/quickdoc/ClassWithAllKindSuperClassExpressions.html @@ -1 +1 @@ -
class A(metaclass=Meta1, six.with_metaclass(Meta2, Base1), Base2[int], Base3, Base4)
\ No newline at end of file +
ClassWithAllKindSuperClassExpressions
class A(metaclass=Meta1, six.with_metaclass(Meta2, Base1), Base2[int], Base3, Base4)
\ No newline at end of file diff --git a/python/testData/quickdoc/DirectClass.html b/python/testData/quickdoc/DirectClass.html index 0328d0789102..f3eb028be433 100644 --- a/python/testData/quickdoc/DirectClass.html +++ b/python/testData/quickdoc/DirectClass.html @@ -1 +1 @@ -
class Foo(object)
Doc of Foo.
\ No newline at end of file +
DirectClass
class Foo(object)
Doc of Foo.
\ No newline at end of file diff --git a/python/testData/quickdoc/DirectFunc.html b/python/testData/quickdoc/DirectFunc.html index 0cab4184ae8d..19199851b3c8 100644 --- a/python/testData/quickdoc/DirectFunc.html +++ b/python/testData/quickdoc/DirectFunc.html @@ -1 +1 @@ -
def foo() -> None
Doc of foo.
\ No newline at end of file +
DirectFunc
def foo() -> None
Doc of foo.
\ No newline at end of file diff --git a/python/testData/quickdoc/DocOnImplementationWithOverloads.html b/python/testData/quickdoc/DocOnImplementationWithOverloads.html index 54f92d4102e9..83a059288f6b 100644 --- a/python/testData/quickdoc/DocOnImplementationWithOverloads.html +++ b/python/testData/quickdoc/DocOnImplementationWithOverloads.html @@ -1 +1 @@ -
def foo(param: bool) -> bool
Possible types:
• (param: str) -> str
• (param: int) -> int
\ No newline at end of file +
DocOnImplementationWithOverloads
def foo(param: bool) -> bool
Possible types:
• (param: str) -> str
• (param: int) -> int
\ No newline at end of file diff --git a/python/testData/quickdoc/Docstring.html b/python/testData/quickdoc/Docstring.html index 0cab4184ae8d..434246889527 100644 --- a/python/testData/quickdoc/Docstring.html +++ b/python/testData/quickdoc/Docstring.html @@ -1 +1 @@ -
def foo() -> None
Doc of foo.
\ No newline at end of file +
Docstring
def foo() -> None
Doc of foo.
\ No newline at end of file diff --git a/python/testData/quickdoc/EmptyTupleType.html b/python/testData/quickdoc/EmptyTupleType.html index bfa7591fa97f..9038ecf00d4e 100644 --- a/python/testData/quickdoc/EmptyTupleType.html +++ b/python/testData/quickdoc/EmptyTupleType.html @@ -1 +1 @@ -
def func() -> Tuple
\ No newline at end of file +
EmptyTupleType
def func() -> Tuple
\ No newline at end of file diff --git a/python/testData/quickdoc/HeterogeneousTuple.html b/python/testData/quickdoc/HeterogeneousTuple.html index cd610f2d59ac..a64e2246e222 100644 --- a/python/testData/quickdoc/HeterogeneousTuple.html +++ b/python/testData/quickdoc/HeterogeneousTuple.html @@ -1 +1 @@ -
def get_tuple() -> Tuple[int, int, str]
\ No newline at end of file +
HeterogeneousTuple
def get_tuple() -> Tuple[int, int, str]
\ No newline at end of file diff --git a/python/testData/quickdoc/HomogeneousTuple.html b/python/testData/quickdoc/HomogeneousTuple.html index 942809d9eba8..f09f9ae6b84a 100644 --- a/python/testData/quickdoc/HomogeneousTuple.html +++ b/python/testData/quickdoc/HomogeneousTuple.html @@ -1 +1 @@ -
def get_tuple() -> Tuple[str, ...]
\ No newline at end of file +
HomogeneousTuple
def get_tuple() -> Tuple[str, ...]
\ No newline at end of file diff --git a/python/testData/quickdoc/Indented.html b/python/testData/quickdoc/Indented.html index 3e019e5b9629..de9f0074b45d 100644 --- a/python/testData/quickdoc/Indented.html +++ b/python/testData/quickdoc/Indented.html @@ -1 +1 @@ -
def foo() -> None
Doc of foo.
It has two lines.
\ No newline at end of file +
Indented
def foo() -> None
Doc of foo.
It has two lines.
\ No newline at end of file diff --git a/python/testData/quickdoc/ManyDecoratorsClass.html b/python/testData/quickdoc/ManyDecoratorsClass.html index 0b53ad3847b4..734a3ef14b70 100644 --- a/python/testData/quickdoc/ManyDecoratorsClass.html +++ b/python/testData/quickdoc/ManyDecoratorsClass.html @@ -1 +1 @@ -
@decorator1
@decorator2
class A
Doc of A
\ No newline at end of file +
ManyDecoratorsClass
@decorator1
@decorator2
class A
Doc of A
\ No newline at end of file diff --git a/python/testData/quickdoc/ManyDecoratorsFunction.html b/python/testData/quickdoc/ManyDecoratorsFunction.html index 2c24aedab6bf..0def677c737d 100644 --- a/python/testData/quickdoc/ManyDecoratorsFunction.html +++ b/python/testData/quickdoc/ManyDecoratorsFunction.html @@ -1 +1 @@ -
@decorator1
@decorator2
def foo(param: Any) -> Optional[Any]
\ No newline at end of file +
ManyDecoratorsFunction
@decorator1
@decorator2
def foo(param: Any) -> Optional[Any]
\ No newline at end of file diff --git a/python/testData/quickdoc/MultilineAssignedValueForTarget.html b/python/testData/quickdoc/MultilineAssignedValueForTarget.html index 60bdfc08b7bd..87289da3d7a1 100644 --- a/python/testData/quickdoc/MultilineAssignedValueForTarget.html +++ b/python/testData/quickdoc/MultilineAssignedValueForTarget.html @@ -1 +1 @@ -
var: List[int] = [1,...
\ No newline at end of file + \ No newline at end of file diff --git a/python/testData/quickdoc/OneDecoratorClass.html b/python/testData/quickdoc/OneDecoratorClass.html index 473d009fa9b6..8a409b28d88b 100644 --- a/python/testData/quickdoc/OneDecoratorClass.html +++ b/python/testData/quickdoc/OneDecoratorClass.html @@ -1 +1 @@ -
@decorator
class A
Doc of A
\ No newline at end of file +
OneDecoratorClass
@decorator
class A
Doc of A
\ No newline at end of file diff --git a/python/testData/quickdoc/OneDecoratorFunction.html b/python/testData/quickdoc/OneDecoratorFunction.html index e80a94e55a00..4a8bbc472700 100644 --- a/python/testData/quickdoc/OneDecoratorFunction.html +++ b/python/testData/quickdoc/OneDecoratorFunction.html @@ -1 +1 @@ -
@decorator
def foo(param: Any) -> Optional[Any]
\ No newline at end of file +
OneDecoratorFunction
@decorator
def foo(param: Any) -> Optional[Any]
\ No newline at end of file diff --git a/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.html b/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.html index d32cc0ade4e8..66b6ffd68a28 100644 --- a/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.html +++ b/python/testData/quickdoc/OptionalAndUnionTypesContainingTypeVars.html @@ -1 +1 @@ -
def f(x1: Optional[T], x2: Union[T, Tuple[Any, Any]]) -> None
\ No newline at end of file +
OptionalAndUnionTypesContainingTypeVars
def f(x1: Optional[T], x2: Union[T, Tuple[Any, Any]]) -> None
\ No newline at end of file diff --git a/python/testData/quickdoc/OptionalParameterType.html b/python/testData/quickdoc/OptionalParameterType.html index fc10aa66d8ac..36f45d777cce 100644 --- a/python/testData/quickdoc/OptionalParameterType.html +++ b/python/testData/quickdoc/OptionalParameterType.html @@ -1 +1 @@ -
def open(encoding: Optional[str], errors: Optional[str]) -> None
\ No newline at end of file +
OptionalParameterType
def open(encoding: Optional[str], errors: Optional[str]) -> None
\ No newline at end of file diff --git a/python/testData/quickdoc/Overloads.html b/python/testData/quickdoc/Overloads.html index 21f42bcbf063..6c7398e1ea7b 100644 --- a/python/testData/quickdoc/Overloads.html +++ b/python/testData/quickdoc/Overloads.html @@ -1 +1 @@ -
@typing.overload
def foo(p: str) -> str
\ No newline at end of file +
Overloads
@typing.overload
def foo(p: str) -> str
\ No newline at end of file diff --git a/python/testData/quickdoc/OverloadsAndImplementation.html b/python/testData/quickdoc/OverloadsAndImplementation.html index 54f92d4102e9..7d8486578711 100644 --- a/python/testData/quickdoc/OverloadsAndImplementation.html +++ b/python/testData/quickdoc/OverloadsAndImplementation.html @@ -1 +1 @@ -
def foo(param: bool) -> bool
Possible types:
• (param: str) -> str
• (param: int) -> int
\ No newline at end of file +
OverloadsAndImplementation
def foo(param: bool) -> bool
Possible types:
• (param: str) -> str
• (param: int) -> int
\ No newline at end of file diff --git a/python/testData/quickdoc/PlainTextDocstringsQuotesPlacementDoesntAffectFormatting.html b/python/testData/quickdoc/PlainTextDocstringsQuotesPlacementDoesntAffectFormatting.html index 99eeba9d2dc2..52a6adc41bbd 100644 --- a/python/testData/quickdoc/PlainTextDocstringsQuotesPlacementDoesntAffectFormatting.html +++ b/python/testData/quickdoc/PlainTextDocstringsQuotesPlacementDoesntAffectFormatting.html @@ -1 +1 @@ -
def func() -> None
Docstring.
\ No newline at end of file +
Docstring.
\ No newline at end of file diff --git a/python/testData/quickdoc/SingleLineAssignedValueForTarget.html b/python/testData/quickdoc/SingleLineAssignedValueForTarget.html index 08e07b91f19f..9bd22d1b599b 100644 --- a/python/testData/quickdoc/SingleLineAssignedValueForTarget.html +++ b/python/testData/quickdoc/SingleLineAssignedValueForTarget.html @@ -1 +1 @@ -
var: int = 42
\ No newline at end of file + \ No newline at end of file diff --git a/python/testData/quickdoc/TypeVars.html b/python/testData/quickdoc/TypeVars.html index ef819546415b..58687c159326 100644 --- a/python/testData/quickdoc/TypeVars.html +++ b/python/testData/quickdoc/TypeVars.html @@ -1 +1 @@ -
def f(p1: T1, p2: T2, p3: T3) -> None
\ No newline at end of file +
TypeVars
def f(p1: T1, p2: T2, p3: T3) -> None
\ No newline at end of file diff --git a/python/testData/quickdoc/UnknownTuple.html b/python/testData/quickdoc/UnknownTuple.html index 6573c1b60ca8..c27a1366e5a8 100644 --- a/python/testData/quickdoc/UnknownTuple.html +++ b/python/testData/quickdoc/UnknownTuple.html @@ -1 +1 @@ -
def get_tuple() -> tuple
\ No newline at end of file +
UnknownTuple
def get_tuple() -> tuple
\ No newline at end of file diff --git a/python/testData/quickdoc/UnmatchedAssignedValueForTarget.html b/python/testData/quickdoc/UnmatchedAssignedValueForTarget.html index b8a92b8ebb92..506a46732b59 100644 --- a/python/testData/quickdoc/UnmatchedAssignedValueForTarget.html +++ b/python/testData/quickdoc/UnmatchedAssignedValueForTarget.html @@ -1 +1 @@ -
var: Any = func()[0]
\ No newline at end of file + \ No newline at end of file