Support namespaces in descriptor documentation provider

GitOrigin-RevId: 4b8a598529ebb50b2200ddbb707ed03b926dfd7f
This commit is contained in:
Karol Lewandowski
2025-04-08 15:08:04 +00:00
committed by intellij-monorepo-bot
parent e98051b16d
commit 29ceaa2edd
6 changed files with 75 additions and 2 deletions
@@ -44,6 +44,10 @@
"type": "string"
}
},
"namespace": {
"type": "string",
"description": "Element namespace."
},
"since": {
"type": "string",
"description": "Version since the element is available."
@@ -60,8 +60,8 @@ internal abstract class AbstractXmlDescriptorDocumentationTargetProvider : PsiDo
private fun getIsAttributeAndPath(element: PsiElement, originalElement: PsiElement): Pair<Boolean, List<String>>? {
val context = findContextElement(originalElement) ?: return null
val elementName = (element as? PsiNamedElement)?.name ?: return null
if (elementName == (context as? PsiNamedElement)?.name) { // assume no parent and child with the same name
val elementName = getElementName(element) ?: return null
if (elementName == getContextElementName (context)) { // assume no parent and child with the same name
return (context is XmlAttribute) to getXmlElementPath(context)
}
// handle lookup element
@@ -72,6 +72,18 @@ internal abstract class AbstractXmlDescriptorDocumentationTargetProvider : PsiDo
return isAttribute to (parentPath + elementName)
}
private fun getElementName(element: PsiElement): String? {
// because in case of elements defined with XSD:
if (element is XmlTag && element.containingFile.virtualFile.extension == "xsd") {
return element.getAttribute("name")?.value
}
return (element as? PsiNamedElement)?.name
}
private fun getContextElementName(context: PsiElement): String? {
return (context as? XmlTag)?.localName ?: (context as? PsiNamedElement)?.name
}
private fun findContextElement(context: PsiElement): XmlElement? {
if (context is PsiWhiteSpace) {
val prevXmlElement = context.siblings(forward = false, withSelf = false)
@@ -68,6 +68,7 @@ internal data class Element(
var name: String? = null,
var descriptiveName: String? = null,
var sdkDocsFixedPath: List<String> = emptyList(),
var namespace: String? = null,
var since: String? = null,
var until: String? = null,
var deprecatedSince: String? = null,
@@ -171,6 +171,7 @@ internal class DocumentationRenderer(private val project: Project) {
appendDeprecation(element.deprecatedSince, element.deprecationNote)
appendSinceUntil(element.since, element.until)
element.description?.trim()?.let { appendLine("$it\n") }
appendNamespace(element.namespace)
appendRequirement(element.requirement)
appendDefaultValue(element.defaultValue)
appendAttributes(element.attributes)
@@ -250,6 +251,12 @@ internal class DocumentationRenderer(private val project: Project) {
}
}
private fun StringBuilder.appendNamespace(namespace: String?) {
if (namespace == null) return
appendLine("$HEADER_LEVEL Namespace")
appendLine("`$namespace`")
}
private fun StringBuilder.appendRequirement(requirement: Requirement?) {
if (requirement == null) return
val requiredText = when (requirement.required) {
@@ -284,6 +284,22 @@ elements:
name: internalChildElement
#language=Markdown
description: Description of `internalChildElement`.
- element:
name: xi:include
namespace: xmlns:xi="http://www.w3.org/2001/XInclude"
#language=Markdown
description: Description of `xi:include`.
attributes:
- attribute:
name: href
#language=Markdown
description: Description of `xi:include@href`.
children:
- element:
name: xi:fallback
namespace: xmlns:xi="http://www.w3.org/2001/XInclude"
#language=Markdown
description: Description of `xi:fallback`.
- element:
name: "*"
attributes:
@@ -46,6 +46,7 @@ class XmlDescriptorDocumentationProviderTest : CodeInsightFixtureTestCase<Module
"<li><a href=\"psi_element://#element:root__elementWithChildrenDescription\"><code>&lt;elementWithChildrenDescription&gt;</code></a></li>" +
"<li><a href=\"psi_element://#element:root__internalElement\"><code>&lt;internalElement&gt;</code></a> <i>internal</i></li>" +
"<li><a href=\"psi_element://#element:root__elementWithInternalLinks\"><code>&lt;elementWithInternalLinks&gt;</code></a> <i>internal</i></li>" +
"<li><a href=\"psi_element://#element:root__xi:include\"><code>&lt;xi:include&gt;</code></a></li>" +
"</ul>"
)
}
@@ -434,6 +435,38 @@ class XmlDescriptorDocumentationProviderTest : CodeInsightFixtureTestCase<Module
)
}
fun `test element with namespace`() {
doTestDocContains(
"""
<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:inc<caret>lude href="any"/>
</root>
""".trimIndent(),
"<p><a href=\"psi_element://#element:root\"><code>&lt;root&gt;</code></a> / <b><code>&lt;xi:include&gt;</code></b><hr/>\n" +
"Description of <code>xi:include</code>.<h5>Namespace</h5><p><code>xmlns:xi=&quot;http://www.w3.org/2001/XInclude&quot;</code>" +
"<h5>Attributes</h5>" +
"<ul>" +
"<li><a href=\"psi_element://#attribute:root__xi:include__href\"><code>href</code></a></li>" +
"</ul>" +
"<h5>Children</h5>" +
"<ul>" +
"<li><a href=\"psi_element://#element:root__xi:include__xi:fallback\"><code>&lt;xi:fallback&gt;</code></a></li>" +
"</ul>"
)
}
fun `test attribute of element with namespace`() {
doTestDocContains(
"""
<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include hr<caret>ef="any"/>
</root>
""".trimIndent(),
"<p><a href=\"psi_element://#element:root\"><code>&lt;root&gt;</code></a> / <a href=\"psi_element://#element:root__xi:include\"><code>&lt;xi:include&gt;</code></a> / <b><code>@href</code></b><hr/>\n" +
"Description of <code>xi:include@href</code>."
)
}
fun `test element not included in the doc_provider context should not be documented`() {
doTestDoesNotProvideDoc(
"""