From 99d0eea364a3fd9ffdddf88781e5c981f6df449b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 7 Sep 2023 15:08:48 -0700 Subject: [PATCH] Option to use parsed Markdown --- richtext-commonmark/build.gradle.kts | 3 +-- .../richtext/markdown/AstNodeConvert.kt | 11 ++++---- .../halilibo/richtext/markdown/Markdown.kt | 27 ++++++++++++++++--- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/richtext-commonmark/build.gradle.kts b/richtext-commonmark/build.gradle.kts index 33d6a5a1..8da34d12 100644 --- a/richtext-commonmark/build.gradle.kts +++ b/richtext-commonmark/build.gradle.kts @@ -18,6 +18,7 @@ kotlin { dependencies { implementation(compose.runtime) implementation(compose.foundation) + api(Commonmark.core) api(project(":richtext-ui")) } } @@ -28,7 +29,6 @@ kotlin { dependencies { implementation(Compose.coil) - implementation(Commonmark.core) implementation(Commonmark.tables) implementation(Commonmark.strikethrough) implementation(Commonmark.autolink) @@ -41,7 +41,6 @@ kotlin { implementation(compose.desktop.currentOs) implementation(Network.okHttp) - implementation(Commonmark.core) implementation(Commonmark.tables) implementation(Commonmark.strikethrough) implementation(Commonmark.autolink) diff --git a/richtext-commonmark/src/commonJvmAndroid/kotlin/com/halilibo/richtext/markdown/AstNodeConvert.kt b/richtext-commonmark/src/commonJvmAndroid/kotlin/com/halilibo/richtext/markdown/AstNodeConvert.kt index a9f3fa0a..48327ef2 100644 --- a/richtext-commonmark/src/commonJvmAndroid/kotlin/com/halilibo/richtext/markdown/AstNodeConvert.kt +++ b/richtext-commonmark/src/commonJvmAndroid/kotlin/com/halilibo/richtext/markdown/AstNodeConvert.kt @@ -186,10 +186,10 @@ internal fun convert( return newNode } -internal fun Node.convert() = convert(this) +internal actual fun Node.toAstNode() = convert(this) @Composable -internal actual fun parsedMarkdownAst(text: String, options: MarkdownParseOptions): AstNode? { +internal actual fun parsedMarkdown(text: String, options: MarkdownParseOptions): Node? { val parser = remember(options) { Parser.builder() .extensions( @@ -202,10 +202,9 @@ internal actual fun parsedMarkdownAst(text: String, options: MarkdownParseOption .build() } - val astRootNode by produceState(null, text, parser) { - value = parser.parse(text).convert() + val rootNode by produceState(null, text, parser) { + value = parser.parse(text) } - return astRootNode + return rootNode } - diff --git a/richtext-commonmark/src/commonMain/kotlin/com/halilibo/richtext/markdown/Markdown.kt b/richtext-commonmark/src/commonMain/kotlin/com/halilibo/richtext/markdown/Markdown.kt index 2a395c1c..1ac3c14b 100644 --- a/richtext-commonmark/src/commonMain/kotlin/com/halilibo/richtext/markdown/Markdown.kt +++ b/richtext-commonmark/src/commonMain/kotlin/com/halilibo/richtext/markdown/Markdown.kt @@ -40,6 +40,7 @@ import com.halilibo.richtext.ui.RichTextScope import com.halilibo.richtext.ui.string.InlineContent import com.halilibo.richtext.ui.string.Text import com.halilibo.richtext.ui.string.richTextString +import org.commonmark.node.Node /** * A composable that renders Markdown content using RichText. @@ -53,6 +54,21 @@ public fun RichTextScope.Markdown( content: String, markdownParseOptions: MarkdownParseOptions = MarkdownParseOptions.Default, onLinkClicked: ((String) -> Unit)? = null +) { + val markdown = parsedMarkdown(text = content, options = markdownParseOptions) + markdown?.let { Markdown(it, onLinkClicked) } +} + +/** + * A composable that renders Markdown node using RichText. + * + * @param content CommonMark node to render. + * @param onLinkClicked A function to invoke when a link is clicked from rendered content. + */ +@Composable +public fun RichTextScope.Markdown( + content: Node, + onLinkClicked: ((String) -> Unit)? = null ) { val onLinkClickedState = rememberUpdatedState(onLinkClicked) // Can't use UriHandlerAmbient.current::openUri here, @@ -63,11 +79,16 @@ public fun RichTextScope.Markdown( } } CompositionLocalProvider(LocalOnLinkClicked provides realLinkClickedHandler) { - val markdownAst = parsedMarkdownAst(text = content, options = markdownParseOptions) - RecursiveRenderMarkdownAst(astNode = markdownAst) + RecursiveRenderMarkdownAst(astNode = content.toAstNode()) } } +/** + * Convert CommonMark [Node] to [AstNode]. + */ +@Composable +internal expect fun Node.toAstNode(): AstNode? + /** * Parse markdown content and return Abstract Syntax Tree(AST). * Composable is efficient thanks to remember construct. @@ -76,7 +97,7 @@ public fun RichTextScope.Markdown( * @param options Options for the Markdown parser. */ @Composable -internal expect fun parsedMarkdownAst(text: String, options: MarkdownParseOptions): AstNode? +internal expect fun parsedMarkdown(text: String, options: MarkdownParseOptions): Node? /** * When parsed, markdown content or any other rich text can be represented as a tree.