Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to use parsed Markdown #123

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions richtext-commonmark/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ kotlin {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
api(Commonmark.core)
api(project(":richtext-ui"))
}
}
Expand All @@ -28,7 +29,6 @@ kotlin {
dependencies {
implementation(Compose.coil)

implementation(Commonmark.core)
implementation(Commonmark.tables)
implementation(Commonmark.strikethrough)
implementation(Commonmark.autolink)
Expand All @@ -41,7 +41,6 @@ kotlin {
implementation(compose.desktop.currentOs)
implementation(Network.okHttp)

implementation(Commonmark.core)
implementation(Commonmark.tables)
implementation(Commonmark.strikethrough)
implementation(Commonmark.autolink)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -202,10 +202,9 @@ internal actual fun parsedMarkdownAst(text: String, options: MarkdownParseOption
.build()
}

val astRootNode by produceState<AstNode?>(null, text, parser) {
value = parser.parse(text).convert()
val rootNode by produceState<Node?>(null, text, parser) {
value = parser.parse(text)
}

return astRootNode
return rootNode
}

Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
Expand All @@ -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.
Expand All @@ -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.
Expand Down