diff options
author | Ignat Beresnev <ignat@beresnev.me> | 2021-12-14 10:09:10 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-14 10:09:10 +0300 |
commit | ed5d582b1a0f667c21443d1a493ff46bc5860865 (patch) | |
tree | 1733fe31493f742584763895f443f1874a4693ab | |
parent | bf9d62a7a2bb510d8099bb2bba225b95c2c064f1 (diff) | |
parent | 19b2a2d5d0986fca3cf6766a05d09d7e458aa370 (diff) | |
download | dokka-ed5d582b1a0f667c21443d1a493ff46bc5860865.tar.gz dokka-ed5d582b1a0f667c21443d1a493ff46bc5860865.tar.bz2 dokka-ed5d582b1a0f667c21443d1a493ff46bc5860865.zip |
Merge pull request #2259 from Kotlin/2213-description-list-support
Description list support for JavaDocs (#2213)
12 files changed, 304 insertions, 15 deletions
diff --git a/core/api/core.api b/core/api/core.api index 96fe317a..46a4c3a5 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -3913,6 +3913,14 @@ public final class org/jetbrains/dokka/pages/HtmlContent : org/jetbrains/dokka/m public abstract interface class org/jetbrains/dokka/pages/Kind { } +public final class org/jetbrains/dokka/pages/ListStyle : java/lang/Enum, org/jetbrains/dokka/pages/Style { + public static final field DescriptionDetails Lorg/jetbrains/dokka/pages/ListStyle; + public static final field DescriptionList Lorg/jetbrains/dokka/pages/ListStyle; + public static final field DescriptionTerm Lorg/jetbrains/dokka/pages/ListStyle; + public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/pages/ListStyle; + public static fun values ()[Lorg/jetbrains/dokka/pages/ListStyle; +} + public abstract interface class org/jetbrains/dokka/pages/MemberPage : org/jetbrains/dokka/pages/ContentPage { } diff --git a/core/src/main/kotlin/pages/ContentNodes.kt b/core/src/main/kotlin/pages/ContentNodes.kt index 0c262937..c1bb3b8c 100644 --- a/core/src/main/kotlin/pages/ContentNodes.kt +++ b/core/src/main/kotlin/pages/ContentNodes.kt @@ -350,6 +350,28 @@ enum class ContentStyle : Style { RowTitle, TabbedContent, WithExtraAttributes, RunnableSample, InDocumentationAnchor, Caption } +enum class ListStyle : Style { + /** + * Represents a list of groups of [DescriptionTerm] and [DescriptionDetails]. + * Common uses for this element are to implement a glossary or to display + * metadata (a list of key-value pairs). Formatting example: see `<dl>` html tag. + */ + DescriptionList, + + /** + * If used within [DescriptionList] context, specifies a term in a description + * or definition list, usually followed by [DescriptionDetails] for one or more + * terms. Formatting example: see `<dt>` html tag + */ + DescriptionTerm, + + /** + * If used within [DescriptionList] context, provides the definition or other + * related text associated with [DescriptionTerm]. Formatting example: see `<dd>` html tag + */ + DescriptionDetails +} + object CommentTable : Style object MultimoduleTable : Style diff --git a/plugins/base/api/base.api b/plugins/base/api/base.api index 5a7573ee..9450476b 100644 --- a/plugins/base/api/base.api +++ b/plugins/base/api/base.api @@ -1398,6 +1398,8 @@ public class org/jetbrains/dokka/base/translators/documentables/PageContentBuild public final fun cover (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;Lkotlin/jvm/functions/Function1;)V public static synthetic fun cover$default (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V protected final fun createText (Ljava/lang/String;Lorg/jetbrains/dokka/pages/Kind;Ljava/util/Set;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;)Lorg/jetbrains/dokka/pages/ContentText; + public final fun descriptionList (Lorg/jetbrains/dokka/pages/Kind;Ljava/util/Set;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;Lkotlin/jvm/functions/Function1;)V + public static synthetic fun descriptionList$default (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/pages/Kind;Ljava/util/Set;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public final fun divergentGroup (Lorg/jetbrains/dokka/pages/ContentDivergentGroup$GroupID;Ljava/util/Set;Lorg/jetbrains/dokka/pages/Kind;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;ZLkotlin/jvm/functions/Function1;)V public static synthetic fun divergentGroup$default (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/pages/ContentDivergentGroup$GroupID;Ljava/util/Set;Lorg/jetbrains/dokka/pages/Kind;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public final fun firstParagraphComment (Lorg/jetbrains/dokka/model/doc/DocTag;Lorg/jetbrains/dokka/pages/Kind;Ljava/util/Set;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;)V diff --git a/plugins/base/base-test-utils/api/base-test-utils.api b/plugins/base/base-test-utils/api/base-test-utils.api index c822d16b..d3db4866 100644 --- a/plugins/base/base-test-utils/api/base-test-utils.api +++ b/plugins/base/base-test-utils/api/base-test-utils.api @@ -108,10 +108,22 @@ public final class utils/Br : utils/Tag { public static final field INSTANCE Lutils/Br; } +public final class utils/Dd : utils/Tag { + public fun <init> ([Ljava/lang/Object;)V +} + public final class utils/Div : utils/Tag { public fun <init> ([Ljava/lang/Object;)V } +public final class utils/Dl : utils/Tag { + public fun <init> ([Ljava/lang/Object;)V +} + +public final class utils/Dt : utils/Tag { + public fun <init> ([Ljava/lang/Object;)V +} + public final class utils/I : utils/Tag { public fun <init> ([Ljava/lang/Object;)V } diff --git a/plugins/base/base-test-utils/src/main/kotlin/renderers/JsoupUtils.kt b/plugins/base/base-test-utils/src/main/kotlin/renderers/JsoupUtils.kt index 47c9608a..a4dadca4 100644 --- a/plugins/base/base-test-utils/src/main/kotlin/renderers/JsoupUtils.kt +++ b/plugins/base/base-test-utils/src/main/kotlin/renderers/JsoupUtils.kt @@ -29,6 +29,9 @@ class A(vararg matchers: Any) : Tag("a", *matchers) class B(vararg matchers: Any) : Tag("b", *matchers) class I(vararg matchers: Any) : Tag("i", *matchers) class STRIKE(vararg matchers: Any) : Tag("strike", *matchers) +class Dl(vararg matchers: Any) : Tag("dl", *matchers) +class Dt(vararg matchers: Any) : Tag("dt", *matchers) +class Dd(vararg matchers: Any) : Tag("dd", *matchers) object Wbr : Tag("wbr") object Br : Tag("br") private fun Any.accepts(n: Node, ignoreSpan:Boolean = true) { diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index b61d513a..c3b15738 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -8,7 +8,6 @@ import org.jetbrains.dokka.base.DokkaBaseConfiguration import org.jetbrains.dokka.base.DokkaBaseConfiguration.Companion.defaultFooterMessage import org.jetbrains.dokka.base.renderers.* import org.jetbrains.dokka.base.renderers.html.command.consumers.ImmediateResolutionTagConsumer -import org.jetbrains.dokka.base.renderers.pageId import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint import org.jetbrains.dokka.base.resolvers.local.DokkaBaseLocationProvider import org.jetbrains.dokka.base.templating.* @@ -112,6 +111,12 @@ open class HtmlRenderer( ) { childrenCallback() } node.extra[InsertTemplateExtra] != null -> node.extra[InsertTemplateExtra]?.let { templateCommand(it.command) } ?: Unit + node.hasStyle(ListStyle.DescriptionTerm) -> DT(emptyMap(), consumer).visit { + this@wrapGroup.childrenCallback() + } + node.hasStyle(ListStyle.DescriptionDetails) -> DD(emptyMap(), consumer).visit { + this@wrapGroup.childrenCallback() + } else -> childrenCallback() } } @@ -295,8 +300,17 @@ open class HtmlRenderer( node: ContentList, pageContext: ContentPage, sourceSetRestriction: Set<DisplaySourceSet>? - ) = if (node.ordered) ol { buildListItems(node.children, pageContext, sourceSetRestriction) } - else ul { buildListItems(node.children, pageContext, sourceSetRestriction) } + ) = when { + node.ordered -> { + ol { buildListItems(node.children, pageContext, sourceSetRestriction) } + } + node.hasStyle(ListStyle.DescriptionList) -> { + dl { node.children.forEach { it.build(this, pageContext, sourceSetRestriction) } } + } + else -> { + ul { buildListItems(node.children, pageContext, sourceSetRestriction) } + } + } open fun OL.buildListItems( items: List<ContentNode>, diff --git a/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt b/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt index 8c2e1c99..c38edea8 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt @@ -4,10 +4,10 @@ import org.intellij.markdown.MarkdownElementTypes import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.properties.PropertyContainer +import org.jetbrains.dokka.model.properties.plus import org.jetbrains.dokka.model.toDisplaySourceSets import org.jetbrains.dokka.pages.* import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull -import org.jetbrains.dokka.model.properties.plus open class DocTagToContentConverter : CommentsToContentConverter { override fun buildContent( @@ -39,14 +39,14 @@ open class DocTagToContentConverter : CommentsToContentConverter { ) ) - fun buildList(ordered: Boolean, start: Int = 1) = + fun buildList(ordered: Boolean, newStyles: Set<Style> = emptySet(), start: Int = 1) = listOf( ContentList( buildChildren(docTag), ordered, dci, sourceSets.toDisplaySourceSets(), - styles, + styles + newStyles, ((PropertyContainer.empty<ContentNode>()) + SimpleAttr("start", start.toString())) ) ) @@ -68,10 +68,27 @@ open class DocTagToContentConverter : CommentsToContentConverter { is H5 -> buildHeader(5) is H6 -> buildHeader(6) is Ul -> buildList(false) - is Ol -> buildList(true, docTag.params["start"]?.toInt() ?: 1) + is Ol -> buildList(true, start = docTag.params["start"]?.toInt() ?: 1) is Li -> listOf( ContentGroup(buildChildren(docTag), dci, sourceSets.toDisplaySourceSets(), styles, extra) ) + is Dl -> buildList(false, newStyles = setOf(ListStyle.DescriptionList)) + is Dt -> listOf( + ContentGroup( + buildChildren(docTag), + dci, + sourceSets.toDisplaySourceSets(), + styles + ListStyle.DescriptionTerm + ) + ) + is Dd -> listOf( + ContentGroup( + buildChildren(docTag), + dci, + sourceSets.toDisplaySourceSets(), + styles + ListStyle.DescriptionDetails + ) + ) is Br -> buildNewLine() is B -> buildChildren(docTag, setOf(TextStyle.Strong)) is I -> buildChildren(docTag, setOf(TextStyle.Italic)) diff --git a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt index 7d4f5c05..8c3fcd84 100644 --- a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt +++ b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt @@ -173,6 +173,18 @@ open class PageContentBuilder( contents += ListBuilder(true, mainDRI, sourceSets, kind, styles, extra).apply(operation).build() } + fun descriptionList( + kind: Kind = ContentKind.Main, + sourceSets: Set<DokkaSourceSet> = mainSourcesetData, + styles: Set<Style> = mainStyles, + extra: PropertyContainer<ContentNode> = mainExtra, + operation: ListBuilder.() -> Unit = {} + ) { + contents += ListBuilder(false, mainDRI, sourceSets, kind, styles + ListStyle.DescriptionList, extra) + .apply(operation) + .build() + } + internal fun headers(vararg label: String) = contentFor(mainDRI, mainSourcesetData) { label.forEach { text(it) } } diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt index d74a1ca4..f9f591b2 100644 --- a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt +++ b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt @@ -14,17 +14,21 @@ import org.jetbrains.dokka.base.parsers.MarkdownParser import org.jetbrains.dokka.base.translators.parseHtmlEncodedWithNormalisedSpaces import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.* +import org.jetbrains.dokka.model.doc.Deprecated import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.dokka.utilities.enumValueOrNull +import org.jetbrains.dokka.utilities.htmlEscape import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.idea.util.CommentSaver.Companion.tokenType import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespace import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jsoup.Jsoup -import org.jsoup.nodes.* +import org.jsoup.nodes.Comment +import org.jsoup.nodes.Element +import org.jsoup.nodes.Node +import org.jsoup.nodes.TextNode import java.util.* -import org.jetbrains.dokka.utilities.htmlEscape interface JavaDocumentationParser { fun parseDocumentation(element: PsiNamedElement): DocumentationNode @@ -396,6 +400,9 @@ class JavadocParser( "ul" -> ifChildrenPresent { Ul(children) } "ol" -> ifChildrenPresent { Ol(children) } "li" -> listOf(Li(children)) + "dl" -> ifChildrenPresent { Dl(children) } + "dt" -> listOf(Dt(children)) + "dd" -> listOf(Dd(children)) "a" -> listOf(createLink(element, children)) "table" -> ifChildrenPresent { Table(children) } "tr" -> ifChildrenPresent { Tr(children) } diff --git a/plugins/base/src/test/kotlin/parsers/JavadocParserTest.kt b/plugins/base/src/test/kotlin/parsers/JavadocParserTest.kt index e6e1e105..c066075a 100644 --- a/plugins/base/src/test/kotlin/parsers/JavadocParserTest.kt +++ b/plugins/base/src/test/kotlin/parsers/JavadocParserTest.kt @@ -5,10 +5,9 @@ import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.DEnum import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.model.doc.P import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test -import utils.* +import utils.text class JavadocParserTest : BaseAbstractTest() { @@ -249,4 +248,105 @@ class JavadocParserTest : BaseAbstractTest() { } } } + + @Test + fun `description list tag`() { + val source = """ + |/src/main/kotlin/test/Test.java + |package example + | + | /** + | * <dl> + | * <dt> + | * <code>name="<i>name</i>"</code> + | * </dt> + | * <dd> + | * A URI path segment. The subdirectory name for this value is contained in the + | * <code>path</code> attribute. + | * </dd> + | * <dt> + | * <code>path="<i>path</i>"</code> + | * </dt> + | * <dd> + | * The subdirectory you're sharing. While the <i>name</i> attribute is a URI path + | * segment, the <i>path</i> value is an actual subdirectory name. + | * </dd> + | * </dl> + | */ + | public class Test {} + """.trimIndent() + + val expected = listOf( + Dl( + listOf( + Dt( + listOf( + CodeInline( + listOf( + Text("name=\""), + I( + listOf( + Text("name") + ) + ), + Text("\"") + ) + ), + ) + ), + Dd( + listOf( + Text(" A URI path segment. The subdirectory name for this value is contained in the "), + CodeInline( + listOf( + Text("path") + ) + ), + Text(" attribute. ") + ) + ), + + Dt( + listOf( + CodeInline( + listOf( + Text("path=\""), + I( + listOf( + Text("path") + ) + ), + Text("\"") + ) + ) + ) + ), + Dd( + listOf( + Text(" The subdirectory you're sharing. While the "), + I( + listOf( + Text("name") + ) + ), + Text(" attribute is a URI path segment, the "), + I( + listOf( + Text("path") + ) + ), + Text(" value is an actual subdirectory name. ") + ) + ) + ) + ) + ) + + testInline(source, configuration) { + documentablesCreationStage = { modules -> + val docs = modules.first().packages.first().classlikes.single().documentation.first().value + assertEquals(expected, docs.children.first().root.children) + } + } + } } diff --git a/plugins/base/src/test/kotlin/renderers/html/ListStylesTest.kt b/plugins/base/src/test/kotlin/renderers/html/ListStylesTest.kt new file mode 100644 index 00000000..8b11dad1 --- /dev/null +++ b/plugins/base/src/test/kotlin/renderers/html/ListStylesTest.kt @@ -0,0 +1,41 @@ +package renderers.html + +import org.jetbrains.dokka.base.renderers.html.HtmlRenderer +import org.jetbrains.dokka.pages.ListStyle +import org.junit.jupiter.api.Test +import renderers.testPage +import utils.Dd +import utils.Dl +import utils.Dt +import utils.match + + +class ListStylesTest : HtmlRenderingOnlyTestBase() { + + @Test + fun `description list render`() { + val page = testPage { + descriptionList { + item(styles = setOf(ListStyle.DescriptionTerm)) { + text("Description term #1") + } + item(styles = setOf(ListStyle.DescriptionTerm)) { + text("Description term #2") + } + item(styles = setOf(ListStyle.DescriptionDetails)) { + text("Description details describing terms #1 and #2") + } + } + } + + + HtmlRenderer(context).render(page) + renderedContent.match( + Dl( + Dt("Description term #1"), + Dt("Description term #2"), + Dd("Description details describing terms #1 and #2") + ) + ) + } +} diff --git a/plugins/base/src/test/kotlin/transformers/CommentsToContentConverterTest.kt b/plugins/base/src/test/kotlin/transformers/CommentsToContentConverterTest.kt index 8703a4a9..9a77172b 100644 --- a/plugins/base/src/test/kotlin/transformers/CommentsToContentConverterTest.kt +++ b/plugins/base/src/test/kotlin/transformers/CommentsToContentConverterTest.kt @@ -1,13 +1,14 @@ package transformers +import matchers.content.* import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.* -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import matchers.content.* import org.jetbrains.dokka.pages.* import org.jetbrains.kotlin.utils.addToStdlib.assertedCast +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test class CommentsToContentConverterTest { private val converter = DocTagToContentConverter() @@ -422,4 +423,54 @@ class CommentsToContentConverterTest { } } } -}
\ No newline at end of file + + @Test + fun `description list`() { + val docTag = + Dl( + listOf( + Dt( + listOf( + Text("description list can have...") + ) + ), + Dt( + listOf( + Text("... two consecutive description terms") + ) + ), + Dd( + listOf( + Text("and usually has some sort of a description, like this one") + ) + ) + ) + ) + + executeTest(docTag) { + composite<ContentList> { + check { + assertTrue(style.contains(ListStyle.DescriptionList)) { "Expected DL style" } + } + group { + check { + assertTrue(style.contains(ListStyle.DescriptionTerm)) { "Expected DT style" } + } + +"description list can have..." + } + group { + check { + assertTrue(style.contains(ListStyle.DescriptionTerm)) { "Expected DT style" } + } + +"... two consecutive description terms" + } + group { + check { + assertTrue(style.contains(ListStyle.DescriptionDetails)) { "Expected DD style" } + } + +"and usually has some sort of a description, like this one" + } + } + } + } +} |