@@ -2,12 +2,15 @@ package space.whitememory.pythoninlayparams.types
22
33import com.intellij.codeInsight.hints.FactoryInlayHintsCollector
44import com.intellij.codeInsight.hints.InlayHintsSink
5+ import com.intellij.codeInsight.hints.presentation.InlayPresentation
56import com.intellij.openapi.editor.Editor
67import com.intellij.psi.PsiElement
78import com.jetbrains.python.psi.PyElement
89import com.jetbrains.python.psi.types.TypeEvalContext
910import space.whitememory.pythoninlayparams.types.hints.HintGenerator
1011import space.whitememory.pythoninlayparams.types.hints.HintResolver
12+ import space.whitememory.pythoninlayparams.types.hints.InlayInfoDetails
13+ import space.whitememory.pythoninlayparams.types.hints.PsiInlayInfoDetail
1114
1215@Suppress(" UnstableApiUsage" )
1316abstract class AbstractPythonInlayTypeHintsCollector (editor : Editor , open val settings : Any ) :
@@ -24,10 +27,93 @@ abstract class AbstractPythonInlayTypeHintsCollector(editor: Editor, open val se
2427 val typeAnnotation = HintResolver .getExpressionAnnotationType(element, typeEvalContext)
2528 val hintName = HintGenerator .generateTypeHintText(element, typeAnnotation, typeEvalContext)
2629
27- displayTypeHint(element, sink, hintName)
30+ if (hintName.isEmpty()) {
31+ return
32+ }
33+
34+ val resolvedHintName = resolveInlayPresentation(hintName)
35+
36+ displayTypeHint(element, sink, resolvedHintName)
37+ }
38+
39+ private fun resolveInlayPresentation (
40+ infoDetails : List <InlayInfoDetails >,
41+ separator : String = " | ",
42+ limit : Int? = 3
43+ ): InlayPresentation {
44+ val convertedInlayInfoDetails = infoDetails.map { getInlayPresentationForInlayInfoDetails(it) }
45+
46+ return factory.seq(* separatePresentation(convertedInlayInfoDetails, separator, limit).toTypedArray())
47+ }
48+
49+ private fun getInlayPresentationForInlayInfoDetails (infoDetail : InlayInfoDetails ): InlayPresentation {
50+ if (infoDetail.rootInlayInfo == null ) {
51+ return resolveInlayPresentation(infoDetail.details, separator = infoDetail.separator, limit = infoDetail.limit)
52+ }
53+
54+ val textPresentation = factory.smallText(infoDetail.rootInlayInfo.text)
55+ val navigationElementProvider: (() -> PsiElement ? )? = when (infoDetail.rootInlayInfo) {
56+ is PsiInlayInfoDetail -> {{ infoDetail.rootInlayInfo.element }}
57+ else -> null
58+ }
59+
60+ val basePresentation = navigationElementProvider?.let {
61+ factory.psiSingleReference(textPresentation, it)
62+ } ? : textPresentation
63+
64+ if (infoDetail.details.isEmpty()) {
65+ return basePresentation
66+ }
67+
68+ val childDetails = infoDetail.details.map { getInlayPresentationForInlayInfoDetails(it) }
69+
70+ return factory.seq(
71+ basePresentation,
72+ factory.smallText(" [" ),
73+ * separatePresentation(
74+ childDetails,
75+ separator = infoDetail.separator,
76+ limit = infoDetail.limit
77+ ).toTypedArray(),
78+ factory.smallText(" ]" )
79+ )
80+ }
81+
82+ private fun separatePresentation (
83+ presentations : List <InlayPresentation >,
84+ separator : String ,
85+ limit : Int?
86+ ): List <InlayPresentation > {
87+ if (presentations.size <= 1 ) {
88+ return presentations
89+ }
90+
91+ val separatedInlayPresentation = mutableListOf<InlayPresentation >()
92+
93+ val iterator = presentations.iterator()
94+ var count = 0
95+
96+ while (iterator.hasNext()) {
97+ if (limit != null && count == limit) {
98+ if (iterator.hasNext()) {
99+ separatedInlayPresentation.add(factory.smallText(" ..." ))
100+ }
101+ break
102+ }
103+
104+ separatedInlayPresentation.add(iterator.next())
105+
106+ count = count.inc()
107+
108+ if (iterator.hasNext() && (limit != null && count != limit)) {
109+ separatedInlayPresentation.add(factory.smallText(separator))
110+ }
111+ }
112+
113+ return separatedInlayPresentation
28114 }
29115
30- abstract fun displayTypeHint (element : PyElement , sink : InlayHintsSink , hintName : String )
116+ abstract fun displayTypeHint (element : PyElement , sink : InlayHintsSink , hintName : InlayPresentation )
31117
32118 override fun collect (element : PsiElement , editor : Editor , sink : InlayHintsSink ): Boolean {
33119 if (! element.isValid || element.project.isDefault) {
0 commit comments