diff options
author | Kamil Doległo <kamilok1965@interia.pl> | 2019-10-31 23:13:09 +0100 |
---|---|---|
committer | Kamil Doległo <kamilok1965@interia.pl> | 2019-10-31 23:13:36 +0100 |
commit | 41b9edd65e58735e69f29369942ef953baadeb3b (patch) | |
tree | 97979272908bc99fb38f1354e4de589b7b556e21 /core/src | |
parent | 5f36bdd75e32743f54193aa8eff8cd5185b3cf67 (diff) | |
download | dokka-41b9edd65e58735e69f29369942ef953baadeb3b.tar.gz dokka-41b9edd65e58735e69f29369942ef953baadeb3b.tar.bz2 dokka-41b9edd65e58735e69f29369942ef953baadeb3b.zip |
Add markdown content builder
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/main/kotlin/pages/ContentNodes.kt | 41 | ||||
-rw-r--r-- | core/src/main/kotlin/pages/NewContentBuilder.kt | 181 | ||||
-rw-r--r-- | core/src/test/kotlin/markdownParser/MarkdownParserTest.kt | 10 |
3 files changed, 139 insertions, 93 deletions
diff --git a/core/src/main/kotlin/pages/ContentNodes.kt b/core/src/main/kotlin/pages/ContentNodes.kt index afb81995..2dffbb17 100644 --- a/core/src/main/kotlin/pages/ContentNodes.kt +++ b/core/src/main/kotlin/pages/ContentNodes.kt @@ -9,8 +9,8 @@ interface ContentNode { /** Comment consisting of parts, eg. [ContentText]s, [ContentLink]s and so on */ data class ContentComment(val parts: List<ContentNode>, - override val platforms: List<PlatformData>, - override val annotations: List<Annotation> = emptyList() + override val platforms: List<PlatformData>, + override val annotations: List<Annotation> = emptyList() ): ContentNode /** Simple text */ @@ -20,24 +20,24 @@ data class ContentText(val text: String, ): ContentNode ///** Headers */ TODO for next iteration -data class ContentHeader(val text: String, +data class ContentHeader(val items: List<ContentNode>, val level: Int, - override val platforms: List<PlatformData>, - override val annotations: List<Annotation> = emptyList() + override val platforms: List<PlatformData>, + override val annotations: List<Annotation> = emptyList() ): ContentNode /** Lists */ data class ContentList(val items: List<ContentNode>, - val ordered: Boolean, - override val platforms: List<PlatformData>, - override val annotations: List<Annotation> = emptyList() + val ordered: Boolean, + override val platforms: List<PlatformData>, + override val annotations: List<Annotation> = emptyList() ): ContentNode /** Styled elements, eg. bold, strikethrough, emphasis and so on **/ data class ContentStyle(val items: List<ContentNode>, - val style: ContentNode, - override val platforms: List<PlatformData>, - override val annotations: List<Annotation> = emptyList() + val style: IStyle, + override val platforms: List<PlatformData>, + override val annotations: List<Annotation> = emptyList() ): ContentNode /** Code blocks */ @@ -53,13 +53,20 @@ data class ContentSymbol(val parts: List<ContentNode>, override val annotations: List<Annotation> = emptyList() ): ContentNode -/** All links that have te be resolved */ +/** All links to classes, packages, etc. that have te be resolved */ data class ContentLink(val text: String, val address: DRI, override val platforms: List<PlatformData>, override val annotations: List<Annotation> = emptyList() ): ContentNode +/** All links that do not need to be resolved */ +data class ContentResolvedLink(val text: String, + val address: String, + override val platforms: List<PlatformData>, + override val annotations: List<Annotation> = emptyList() +): ContentNode + /** Blocks of [ContentNode]s with name, eg. Functions, Types, Properties, etc. */ data class ContentBlock(val name: String, val children: List<ContentNode>, @@ -69,9 +76,15 @@ data class ContentBlock(val name: String, /** Logical grouping of [ContentNode]s, eg. [ContentLink], [ContentText] and [ContentSymbol] for one entity */ data class ContentGroup(val children: List<ContentNode>, - override val platforms: List<PlatformData>, - override val annotations: List<Annotation> = emptyList() + override val platforms: List<PlatformData>, + override val annotations: List<Annotation> = emptyList() ): ContentNode /** All annotations */ data class Annotation(val name: String) + +interface IStyle + +enum class Style: IStyle { + Emphasis, Strong, Paragraph +}
\ No newline at end of file diff --git a/core/src/main/kotlin/pages/NewContentBuilder.kt b/core/src/main/kotlin/pages/NewContentBuilder.kt index 05b649d1..89c509ea 100644 --- a/core/src/main/kotlin/pages/NewContentBuilder.kt +++ b/core/src/main/kotlin/pages/NewContentBuilder.kt @@ -4,24 +4,37 @@ import org.intellij.markdown.MarkdownElementTypes import org.intellij.markdown.MarkdownTokenTypes import org.jetbrains.dokka.MarkdownNode -fun buildContent(node: MarkdownNode, platforms: List<PlatformData>): List<ContentNode> { +class NewContentBuilder { + fun buildContent(node: MarkdownNode, platforms: List<PlatformData>): List<ContentNode> { // println(tree.toTestString()) - fun buildChildren(node: MarkdownNode) = node.children.flatMap{ buildContent(it, platforms)} - - return when (node.type) { - MarkdownElementTypes.ATX_1 -> ContentHeader(node.text, 1, platforms) // TODO Header levels: ?? - MarkdownElementTypes.ATX_2 -> ContentHeader("", 2, platforms) - MarkdownElementTypes.ATX_3 -> ContentHeader("", 3, platforms) - MarkdownElementTypes.ATX_4 -> ContentHeader("", 4, platforms) - MarkdownElementTypes.ATX_5 -> ContentHeader("", 5, platforms) - MarkdownElementTypes.ATX_6 -> ContentHeader("", 6, platforms) - MarkdownElementTypes.UNORDERED_LIST -> ContentList(buildChildren(node), false, platforms) - MarkdownElementTypes.ORDERED_LIST -> ContentList(buildChildren(node), true, platforms) - MarkdownElementTypes.LIST_ITEM -> TODO() - MarkdownElementTypes.EMPH -> ContentStyle(buildChildren(node), ContentText("", platforms), platforms) // TODO - MarkdownElementTypes.STRONG -> ContentStyle(buildChildren(node), ContentText("", platforms), platforms) // TODO - MarkdownElementTypes.CODE_SPAN -> TODO() + fun buildChildren(node: MarkdownNode) = node.children.flatMap { buildContent(it, platforms) }.coalesceText() + + return when (node.type) { + MarkdownElementTypes.ATX_1 -> listOf(ContentHeader(buildChildren(node), 1, platforms)) + MarkdownElementTypes.ATX_2 -> listOf(ContentHeader(buildChildren(node), 2, platforms)) + MarkdownElementTypes.ATX_3 -> listOf(ContentHeader(buildChildren(node), 3, platforms)) + MarkdownElementTypes.ATX_4 -> listOf(ContentHeader(buildChildren(node), 4, platforms)) + MarkdownElementTypes.ATX_5 -> listOf(ContentHeader(buildChildren(node), 5, platforms)) + MarkdownElementTypes.ATX_6 -> listOf(ContentHeader(buildChildren(node), 6, platforms)) + MarkdownElementTypes.UNORDERED_LIST -> listOf(ContentList(buildChildren(node), false, platforms)) + MarkdownElementTypes.ORDERED_LIST -> listOf(ContentList(buildChildren(node), true, platforms)) + MarkdownElementTypes.LIST_ITEM -> TODO() + MarkdownElementTypes.EMPH -> listOf( + ContentStyle( + buildChildren(node), + Style.Emphasis, + platforms + ) + )// TODO + MarkdownElementTypes.STRONG -> listOf( + ContentStyle( + buildChildren(node), + Style.Strong, + platforms + ) + ) // TODO + MarkdownElementTypes.CODE_SPAN -> TODO() // val startDelimiter = node.child(MarkdownTokenTypes.BACKTICK)?.text // if (startDelimiter != null) { // val text = node.text.substring(startDelimiter.length).removeSuffix(startDelimiter) @@ -29,14 +42,14 @@ fun buildContent(node: MarkdownNode, platforms: List<PlatformData>): List<Conten // parent.append(codeSpan) // } - MarkdownElementTypes.CODE_BLOCK, - MarkdownElementTypes.CODE_FENCE -> { - val language = node.child(MarkdownTokenTypes.FENCE_LANG)?.text?.trim() ?: "" - ContentCode(buildChildren(node).toString(), language, platforms) // TODO - } - MarkdownElementTypes.PARAGRAPH -> ContentText(buildChildren(node).toString(), platforms) // TODO + MarkdownElementTypes.CODE_BLOCK, + MarkdownElementTypes.CODE_FENCE -> { + val language = node.child(MarkdownTokenTypes.FENCE_LANG)?.text?.trim() ?: "" + listOf(ContentCode(buildChildren(node).toString(), language, platforms)) // TODO + } + MarkdownElementTypes.PARAGRAPH -> listOf(ContentStyle(buildChildren(node), Style.Paragraph, platforms)) // TODO - MarkdownElementTypes.INLINE_LINK -> { + MarkdownElementTypes.INLINE_LINK -> { // val linkTextNode = node.child(MarkdownElementTypes.LINK_TEXT) // val destination = node.child(MarkdownElementTypes.LINK_DESTINATION) // if (linkTextNode != null) { @@ -50,12 +63,12 @@ fun buildContent(node: MarkdownNode, platforms: List<PlatformData>): List<Conten // parent.append(link) // } // } - //TODO: Linking!!! + //TODO: Linking!!! // ContentLink() - TODO() - } - MarkdownElementTypes.SHORT_REFERENCE_LINK, - MarkdownElementTypes.FULL_REFERENCE_LINK -> { + TODO() + } + MarkdownElementTypes.SHORT_REFERENCE_LINK, + MarkdownElementTypes.FULL_REFERENCE_LINK -> { // val labelElement = node.child(MarkdownElementTypes.LINK_LABEL) // if (labelElement != null) { // val linkInfo = linkResolver.getLinkInfo(labelElement.text) @@ -72,36 +85,36 @@ fun buildContent(node: MarkdownNode, platforms: List<PlatformData>): List<Conten // } // parent.append(link) // } - TODO() - } - MarkdownTokenTypes.WHITE_SPACE -> { - // Don't append first space if start of header (it is added during formatting later) - // v - // #### Some Heading + TODO() + } + MarkdownTokenTypes.WHITE_SPACE -> { + // Don't append first space if start of header (it is added during formatting later) + // v + // #### Some Heading // if (nodeStack.peek() !is ContentHeading || node.parent?.children?.first() != node) { // parent.append(ContentText(node.text)) // } - ContentText(" ", platforms) - } - MarkdownTokenTypes.EOL -> { + listOf(ContentText(" ", platforms)) + } + MarkdownTokenTypes.EOL -> { // if ((keepEol(nodeStack.peek()) && node.parent?.children?.last() != node) || // // Keep extra blank lines when processing lists (affects Markdown formatting) // (processingList(nodeStack.peek()) && node.previous?.type == MarkdownTokenTypes.EOL)) { // parent.append(ContentText(node.text)) // } - ContentText("\n", platforms) // TODO? - } + emptyList() + } - MarkdownTokenTypes.CODE_LINE -> { - ContentText(node.text, platforms) // TODO check + MarkdownTokenTypes.CODE_LINE -> { + listOf(ContentText(node.text, platforms)) // TODO check // if (parent is ContentBlockCode) { // parent.append(content) // } else { // parent.append(ContentBlockCode().apply { append(content) }) // } - } + } - MarkdownTokenTypes.TEXT -> + MarkdownTokenTypes.TEXT -> // fun createEntityOrText(text: String): ContentNode { // if (text == "&" || text == """ || text == "<" || text == ">") { // return ContentEntity(text) @@ -117,40 +130,64 @@ fun buildContent(node: MarkdownNode, platforms: List<PlatformData>): List<Conten // } // // parent.append(createEntityOrText(node.text)) - ContentText(node.text, platforms) // TODO + listOf(ContentText(node.text, platforms)) // TODO - MarkdownTokenTypes.EMPH -> + MarkdownTokenTypes.EMPH -> // val parentNodeType = node.parent?.type // if (parentNodeType != MarkdownElementTypes.EMPH && parentNodeType != MarkdownElementTypes.STRONG) { // parent.append(ContentText(node.text)) // } - ContentStyle(buildChildren(node), ContentText("", platforms), platforms) // TODO - - - MarkdownTokenTypes.COLON, - MarkdownTokenTypes.SINGLE_QUOTE, - MarkdownTokenTypes.DOUBLE_QUOTE, - MarkdownTokenTypes.LT, - MarkdownTokenTypes.GT, - MarkdownTokenTypes.LPAREN, - MarkdownTokenTypes.RPAREN, - MarkdownTokenTypes.LBRACKET, - MarkdownTokenTypes.RBRACKET, - MarkdownTokenTypes.EXCLAMATION_MARK, - MarkdownTokenTypes.BACKTICK, - MarkdownTokenTypes.CODE_FENCE_CONTENT -> { - ContentText(node.text, platforms) + listOf(ContentStyle(buildChildren(node), Style.Emphasis, platforms)) // TODO + + MarkdownTokenTypes.COLON, + MarkdownTokenTypes.SINGLE_QUOTE, + MarkdownTokenTypes.DOUBLE_QUOTE, + MarkdownTokenTypes.LT, + MarkdownTokenTypes.GT, + MarkdownTokenTypes.LPAREN, + MarkdownTokenTypes.RPAREN, + MarkdownTokenTypes.LBRACKET, + MarkdownTokenTypes.RBRACKET, + MarkdownTokenTypes.EXCLAMATION_MARK, + MarkdownTokenTypes.BACKTICK, + MarkdownTokenTypes.CODE_FENCE_CONTENT -> { + listOf(ContentText(node.text, platforms)) + } + + MarkdownElementTypes.LINK_DEFINITION -> TODO() + + MarkdownTokenTypes.EMAIL_AUTOLINK -> + listOf(ContentResolvedLink(node.text, "mailto:${node.text}", platforms)) + + else -> buildChildren(node) } - - MarkdownElementTypes.LINK_DEFINITION -> TODO() - - - MarkdownTokenTypes.EMAIL_AUTOLINK -> - ContentText(node.text, platforms) // TODO: create new ContentType for email to create mailto: links - - - else -> ContentText("", platforms) - - }.let {listOf(it)} + } + + private fun Collection<ContentNode>.coalesceText() = + this + .sliceWhen { prev, next -> prev::class != next::class } + .flatMap { nodes -> + when (nodes.first()) { + is ContentText -> listOf(ContentText(nodes.joinToString("") { (it as ContentText).text }, nodes.first().platforms)) + else -> nodes + } + } +} + +fun <T> Collection<T>.sliceWhen(predicate: (before: T, after: T)->Boolean): Collection<Collection<T>> { + val newCollection = mutableListOf<Collection<T>>() + var currentSlice = mutableListOf<T>() + for ((prev, next) in this.windowed(2, 1, false)) { + currentSlice.add(prev) + if(predicate(prev, next)) { + newCollection.add(currentSlice) + currentSlice = mutableListOf<T>() + } + } + if(this.isNotEmpty()) { + currentSlice.add(this.last()) + newCollection.add(currentSlice) + } + return newCollection }
\ No newline at end of file diff --git a/core/src/test/kotlin/markdownParser/MarkdownParserTest.kt b/core/src/test/kotlin/markdownParser/MarkdownParserTest.kt index 466d78a6..70554045 100644 --- a/core/src/test/kotlin/markdownParser/MarkdownParserTest.kt +++ b/core/src/test/kotlin/markdownParser/MarkdownParserTest.kt @@ -1,12 +1,8 @@ package org.jetbrains.dokka.tests.markdownParser -import junit.framework.Assert.assertEquals -import junit.framework.Assert.assertTrue -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.pages.buildContent +import org.jetbrains.dokka.pages.NewContentBuilder import org.jetbrains.dokka.parseMarkdown -import org.jetbrains.dokka.resolvers.ExternalLocationProvider +import org.junit.Assert.assertTrue import org.junit.Test @@ -20,7 +16,7 @@ class MarkdownParserTest { let's say there are some parentheses, like ( and ) """.trimIndent() val node = parseMarkdown(markdown) - val content = buildContent(node, emptyList()) + val content = NewContentBuilder().buildContent(node, emptyList()) assertTrue(content.isNotEmpty()) } |