PY-29717 Display qualified name/path of a module for a top-level definition

This commit is contained in:
Mikhail Golubev
2018-06-09 15:59:38 +03:00
parent 530c7d2d74
commit f94e80c996
29 changed files with 71 additions and 33 deletions
@@ -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();
@@ -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 "<a href=\"${DocumentationManagerProtocol.PSI_ELEMENT_PROTOCOL}$LINK_TYPE_MODULE$qualifiedName\">$content</a>"
}
@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<PsiFileSystemItem>()
.map { PyUtil.turnDirIntoInit(it) }
.filterIsInstance<PyFile>()
.firstOrNull()
}
@JvmStatic
private fun possibleFunction(qualifiedName: String, element: PsiElement): PyFunction? {
// TODO a better, more general way to resolve qualified names of function
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#ArgumentList">ArgumentList</a><br>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.</div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>len</b>(o:&nbsp;Sized)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a></pre></div><div class='content'>len(object)&nbsp;-&gt;&nbsp;integer<br><br>Return&nbsp;the&nbsp;number&nbsp;of&nbsp;items&nbsp;of&nbsp;a&nbsp;sequence&nbsp;or&nbsp;collection.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#__builtin__">__builtin__</a><br>def&nbsp;<b>len</b>(o:&nbsp;Sized)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a></pre></div><div class='content'>len(object)&nbsp;-&gt;&nbsp;integer<br><br>Return&nbsp;the&nbsp;number&nbsp;of&nbsp;items&nbsp;of&nbsp;a&nbsp;sequence&nbsp;or&nbsp;collection.</div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#CallFunc">CallFunc</a><br>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.</div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>class&nbsp;<b>Foo</b>(<a href="psi_element://#typename#object">object</a>)</pre></div><div class='content'>Doc&nbsp;of&nbsp;Foo.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#ClassConstructor">ClassConstructor</a><br>class&nbsp;<b>Foo</b>(<a href="psi_element://#typename#object">object</a>)</pre></div><div class='content'>Doc&nbsp;of&nbsp;Foo.</div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>class&nbsp;<b>A</b>(metaclass=<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Meta1">Meta1</a>,&nbsp;six.with_metaclass(<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Meta2">Meta2</a>,&nbsp;<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Base1">Base1</a>),&nbsp;<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Base2">Base2</a>[<a href="psi_element://#typename#int">int</a>],&nbsp;<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Base3">Base3</a>,&nbsp;Base4)</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#ClassWithAllKindSuperClassExpressions">ClassWithAllKindSuperClassExpressions</a><br>class&nbsp;<b>A</b>(metaclass=<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Meta1">Meta1</a>,&nbsp;six.with_metaclass(<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Meta2">Meta2</a>,&nbsp;<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Base1">Base1</a>),&nbsp;<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Base2">Base2</a>[<a href="psi_element://#typename#int">int</a>],&nbsp;<a href="psi_element://#typename#ClassWithAllKindSuperClassExpressions.Base3">Base3</a>,&nbsp;Base4)</pre></div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>class&nbsp;<b>Foo</b>(<a href="psi_element://#typename#object">object</a>)</pre></div><div class='content'>Doc&nbsp;of&nbsp;Foo.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#DirectClass">DirectClass</a><br>class&nbsp;<b>Foo</b>(<a href="psi_element://#typename#object">object</a>)</pre></div><div class='content'>Doc&nbsp;of&nbsp;Foo.</div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#DirectFunc">DirectFunc</a><br>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.</div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>foo</b>(param:&nbsp;<a href="psi_element://#typename#bool">bool</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#bool">bool</a><br>Possible&nbsp;types:<br>•&nbsp;(param:&nbsp;<a href="psi_element://#typename#str">str</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#str">str</a><br>•&nbsp;(param:&nbsp;<a href="psi_element://#typename#int">int</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a></pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#DocOnImplementationWithOverloads">DocOnImplementationWithOverloads</a><br>def&nbsp;<b>foo</b>(param:&nbsp;<a href="psi_element://#typename#bool">bool</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#bool">bool</a><br>Possible&nbsp;types:<br>•&nbsp;(param:&nbsp;<a href="psi_element://#typename#str">str</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#str">str</a><br>•&nbsp;(param:&nbsp;<a href="psi_element://#typename#int">int</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a></pre></div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#Docstring">Docstring</a><br>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.</div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>func</b>()&nbsp;-&gt;&nbsp;Tuple</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#EmptyTupleType">EmptyTupleType</a><br>def&nbsp;<b>func</b>()&nbsp;-&gt;&nbsp;Tuple</pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>get_tuple</b>()&nbsp;-&gt;&nbsp;Tuple[<a href="psi_element://#typename#int">int</a>,&nbsp;<a href="psi_element://#typename#int">int</a>,&nbsp;<a href="psi_element://#typename#str">str</a>]</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#HeterogeneousTuple">HeterogeneousTuple</a><br>def&nbsp;<b>get_tuple</b>()&nbsp;-&gt;&nbsp;Tuple[<a href="psi_element://#typename#int">int</a>,&nbsp;<a href="psi_element://#typename#int">int</a>,&nbsp;<a href="psi_element://#typename#str">str</a>]</pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>get_tuple</b>()&nbsp;-&gt;&nbsp;Tuple[<a href="psi_element://#typename#str">str</a>,&nbsp;...]</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#HomogeneousTuple">HomogeneousTuple</a><br>def&nbsp;<b>get_tuple</b>()&nbsp;-&gt;&nbsp;Tuple[<a href="psi_element://#typename#str">str</a>,&nbsp;...]</pre></div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.<br>It&nbsp;has&nbsp;two&nbsp;lines.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#Indented">Indented</a><br>def&nbsp;<b>foo</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Doc&nbsp;of&nbsp;foo.<br>It&nbsp;has&nbsp;two&nbsp;lines.</div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>@<i>decorator1</i><br>@<i>decorator2</i><br>class&nbsp;<b>A</b></pre></div><div class='content'>Doc&nbsp;of&nbsp;A</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#ManyDecoratorsClass">ManyDecoratorsClass</a><br>@<i>decorator1</i><br>@<i>decorator2</i><br>class&nbsp;<b>A</b></pre></div><div class='content'>Doc&nbsp;of&nbsp;A</div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>@<i>decorator1</i><br>@<i>decorator2</i><br>def&nbsp;<b>foo</b>(param:&nbsp;Any)&nbsp;-&gt;&nbsp;Optional[Any]</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#ManyDecoratorsFunction">ManyDecoratorsFunction</a><br>@<i>decorator1</i><br>@<i>decorator2</i><br>def&nbsp;<b>foo</b>(param:&nbsp;Any)&nbsp;-&gt;&nbsp;Optional[Any]</pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>var: List[<a href="psi_element://#typename#int">int</a>] = [1,...</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#MultilineAssignedValueForTarget">MultilineAssignedValueForTarget</a><br>var: List[<a href="psi_element://#typename#int">int</a>] = [1,...</pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>@<i>decorator</i><br>class&nbsp;<b>A</b></pre></div><div class='content'>Doc&nbsp;of&nbsp;A</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#OneDecoratorClass">OneDecoratorClass</a><br>@<i>decorator</i><br>class&nbsp;<b>A</b></pre></div><div class='content'>Doc&nbsp;of&nbsp;A</div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>@<i>decorator</i><br>def&nbsp;<b>foo</b>(param:&nbsp;Any)&nbsp;-&gt;&nbsp;Optional[Any]</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#OneDecoratorFunction">OneDecoratorFunction</a><br>@<i>decorator</i><br>def&nbsp;<b>foo</b>(param:&nbsp;Any)&nbsp;-&gt;&nbsp;Optional[Any]</pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>f</b>(x1:&nbsp;Optional[T],&nbsp;x2:&nbsp;Union[T,&nbsp;Tuple[Any,&nbsp;Any]])&nbsp;-&gt;&nbsp;None</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#OptionalAndUnionTypesContainingTypeVars">OptionalAndUnionTypesContainingTypeVars</a><br>def&nbsp;<b>f</b>(x1:&nbsp;Optional[T],&nbsp;x2:&nbsp;Union[T,&nbsp;Tuple[Any,&nbsp;Any]])&nbsp;-&gt;&nbsp;None</pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>open</b>(encoding:&nbsp;Optional[<a href="psi_element://#typename#str">str</a>],&nbsp;errors:&nbsp;Optional[<a href="psi_element://#typename#str">str</a>])&nbsp;-&gt;&nbsp;None</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#OptionalParameterType">OptionalParameterType</a><br>def&nbsp;<b>open</b>(encoding:&nbsp;Optional[<a href="psi_element://#typename#str">str</a>],&nbsp;errors:&nbsp;Optional[<a href="psi_element://#typename#str">str</a>])&nbsp;-&gt;&nbsp;None</pre></div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>@<i>typing.overload</i><br>def&nbsp;<b>foo</b>(p:&nbsp;<a href="psi_element://#typename#str">str</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#str">str</a></pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#Overloads">Overloads</a><br>@<i>typing.overload</i><br>def&nbsp;<b>foo</b>(p:&nbsp;<a href="psi_element://#typename#str">str</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#str">str</a></pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>foo</b>(param:&nbsp;<a href="psi_element://#typename#bool">bool</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#bool">bool</a><br>Possible&nbsp;types:<br>•&nbsp;(param:&nbsp;<a href="psi_element://#typename#str">str</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#str">str</a><br>•&nbsp;(param:&nbsp;<a href="psi_element://#typename#int">int</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a></pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#OverloadsAndImplementation">OverloadsAndImplementation</a><br>def&nbsp;<b>foo</b>(param:&nbsp;<a href="psi_element://#typename#bool">bool</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#bool">bool</a><br>Possible&nbsp;types:<br>•&nbsp;(param:&nbsp;<a href="psi_element://#typename#str">str</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#str">str</a><br>•&nbsp;(param:&nbsp;<a href="psi_element://#typename#int">int</a>)&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#int">int</a></pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>func</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Docstring.</div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#PlainTextDocstringsQuotesPlacementDoesntAffectFormatting">PlainTextDocstringsQuotesPlacementDoesntAffectFormatting</a><br>def&nbsp;<b>func</b>()&nbsp;-&gt;&nbsp;None</pre></div><div class='content'>Docstring.</div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>var: <a href="psi_element://#typename#int">int</a> = 42</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#SingleLineAssignedValueForTarget">SingleLineAssignedValueForTarget</a><br>var: <a href="psi_element://#typename#int">int</a> = 42</pre></div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>f</b>(p1:&nbsp;T1,&nbsp;p2:&nbsp;T2,&nbsp;p3:&nbsp;T3)&nbsp;-&gt;&nbsp;None</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#TypeVars">TypeVars</a><br>def&nbsp;<b>f</b>(p1:&nbsp;T1,&nbsp;p2:&nbsp;T2,&nbsp;p3:&nbsp;T3)&nbsp;-&gt;&nbsp;None</pre></div></body></html>
+1 -1
View File
@@ -1 +1 @@
<html><body><div class='definition'><pre>def&nbsp;<b>get_tuple</b>()&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#tuple">tuple</a></pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#UnknownTuple">UnknownTuple</a><br>def&nbsp;<b>get_tuple</b>()&nbsp;-&gt;&nbsp;<a href="psi_element://#typename#tuple">tuple</a></pre></div></body></html>
@@ -1 +1 @@
<html><body><div class='definition'><pre>var: Any = func()[0]</pre></div></body></html>
<html><body><div class='definition'><pre><a href="psi_element://#module#UnmatchedAssignedValueForTarget">UnmatchedAssignedValueForTarget</a><br>var: Any = func()[0]</pre></div></body></html>