package org.jetbrains.dokka import org.intellij.markdown.* import org.intellij.markdown.ast.* import org.intellij.markdown.parser.* import org.intellij.markdown.parser.dialects.commonmark.CommonMarkMarkerProcessor class MarkdownNode(val node: ASTNode, val parent: MarkdownNode?, val markdown: String) { val children: List = node.children.map { MarkdownNode(it, this, markdown) } val endOffset: Int get() = node.endOffset val startOffset: Int get() = node.startOffset val type: IElementType get() = node.type val text: String get() = markdown.substring(startOffset, endOffset) fun child(type: IElementType): MarkdownNode? = children.firstOrNull { it.type == type } override fun toString(): String = present() } fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) { action(this) { for (child in children) { child.visit(action) } } } public fun MarkdownNode.toTestString(): String { val sb = StringBuilder() var level = 0 visit {(node, visitChildren) -> sb.append(" ".repeat(level * 2)) node.presentTo(sb) level++ visitChildren() level-- } return sb.toString() } private fun MarkdownNode.present() = StringBuilder { presentTo(this) }.toString() private fun MarkdownNode.presentTo(sb: StringBuilder) { sb.append(type.toString()) sb.append(":" + text.replace("\n", "\u23CE")) sb.appendln() } public fun MarkdownNode.toHtml(): String { val sb = StringBuilder() visit {(node, processChildren) -> val nodeType = node.type val nodeText = node.text when (nodeType) { MarkdownElementTypes.UNORDERED_LIST -> { sb.appendln("") } MarkdownElementTypes.ORDERED_LIST -> { sb.appendln("
    ") processChildren() sb.appendln("
") } MarkdownElementTypes.LIST_ITEM -> { sb.append("
  • ") processChildren() sb.appendln("
  • ") } MarkdownElementTypes.EMPH -> { sb.append("") processChildren() sb.append("") } MarkdownElementTypes.STRONG -> { sb.append("") processChildren() sb.append("") } MarkdownElementTypes.ATX_1 -> { sb.append("

    ") processChildren() sb.append("

    ") } MarkdownElementTypes.ATX_2 -> { sb.append("

    ") processChildren() sb.append("

    ") } MarkdownElementTypes.ATX_3 -> { sb.append("

    ") processChildren() sb.append("

    ") } MarkdownElementTypes.ATX_4 -> { sb.append("

    ") processChildren() sb.append("

    ") } MarkdownElementTypes.ATX_5 -> { sb.append("
    ") processChildren() sb.append("
    ") } MarkdownElementTypes.ATX_6 -> { sb.append("
    ") processChildren() sb.append("
    ") } MarkdownElementTypes.BLOCK_QUOTE -> { sb.append("
    ") processChildren() sb.append("
    ") } MarkdownElementTypes.PARAGRAPH -> { sb.append("

    ") processChildren() sb.appendln("

    ") } MarkdownTokenTypes.CODE -> { sb.append("
    ")
                    sb.append(nodeText)
                    sb.append("
    ")
                }
                MarkdownTokenTypes.TEXT -> {
                    sb.append(nodeText)
                }
                else -> {
                    processChildren()
                }
            }
        }
        return sb.toString()
    }
    
    fun parseMarkdown(markdown: String): MarkdownNode {
        if (markdown.isEmpty())
            return MarkdownNode(LeafASTNode(MarkdownElementTypes.MARKDOWN_FILE, 0, 0), null, markdown)
        return MarkdownNode(MarkdownParser(CommonMarkMarkerProcessor.Factory()).buildMarkdownTreeFromString(markdown), null, markdown)
    }
    
    fun markdownToHtml(markdown: String): String {
    
        val tree = MarkdownParser(CommonMarkMarkerProcessor.Factory()).buildMarkdownTreeFromString(markdown)
        val markdownTree = MarkdownNode(tree, null, markdown)
        val ast = markdownTree.toTestString()
        return markdownTree.toHtml()
    }