Skip to content

Commit

Permalink
Add an autolink extension for Markdown (#341)
Browse files Browse the repository at this point in the history
Exposes the autolink extension offered by the commonmark java library,
to markdown rendering in Compose. Since links are already supported
for processing and rendering, we only need to hookup the
parserExtension to get this to work.
  • Loading branch information
jrlogsdon authored Apr 2, 2024
1 parent 82d3581 commit 2ee753f
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 11 deletions.
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ poko = "0.13.1"

[libraries]
commonmark-core = { module = "org.commonmark:commonmark", version.ref = "commonmark" }
commonmark-ext-autolink = { module = "org.commonmark:commonmark-ext-autolink", version.ref = "commonmark" }

filePicker = { module = "com.darkrockstudios:mpfilepicker", version = "3.1.0" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,28 @@ import org.jetbrains.jewel.markdown.MarkdownBlock
/** An extension for the Jewel Markdown processing engine. */
@ExperimentalJewelApi
public interface MarkdownProcessorExtension {

/**
* A CommonMark [ParserExtension] that will be used to parse the extended
* syntax represented by this extension instance.
* syntax represented by this extension instance. Null in the case where
* parsing is already handled by an existing [org.commonmark.parser.Parser].
*/
public val parserExtension: ParserExtension
public val parserExtension: ParserExtension?

/**
* A CommonMark [TextContentRendererExtension] that will be used to render
* the text content of the CommonMark [CustomBlock] produced by the
* [parserExtension].
* [parserExtension]. Null in the case where rendering is already
* handled by an existing [org.commonmark.renderer.Renderer].
*/
public val textRendererExtension: TextContentRendererExtension
public val textRendererExtension: TextContentRendererExtension?

/**
* An extension for
* [`MarkdownParser`][org.jetbrains.jewel.markdown.parsing.MarkdownParser]
* that will transform a supported [CustomBlock] into the corresponding
* [MarkdownBlock.CustomBlock].
* [MarkdownBlock.CustomBlock]. Null in the case where processing
* is already be handled by [org.jetbrains.jewel.markdown.processing.MarkdownProcessor]
* or another [org.jetbrains.jewel.markdown.extensions.MarkdownProcessorExtension].
*/
public val processorExtension: MarkdownBlockProcessorExtension
public val processorExtension: MarkdownBlockProcessorExtension?
}
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public class MarkdownProcessor(
is ThematicBreak -> MarkdownBlock.ThematicBreak
is HtmlBlock -> toMarkdownHtmlBlockOrNull()
is CustomBlock -> {
extensions.find { it.processorExtension.canProcess(this) }
extensions.find { it.processorExtension?.canProcess(this) == true }
?.processorExtension?.processMarkdownBlock(this, this@MarkdownProcessor)
}
else -> null
Expand Down
8 changes: 8 additions & 0 deletions markdown/extension/autolink/api/autolink.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public final class org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtension : org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension {
public static final field $stable I
public static final field INSTANCE Lorg/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtension;
public fun getParserExtension ()Lorg/commonmark/parser/Parser$ParserExtension;
public fun getProcessorExtension ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension;
public fun getTextRendererExtension ()Lorg/commonmark/renderer/text/TextContentRenderer$TextContentRendererExtension;
}

17 changes: 17 additions & 0 deletions markdown/extension/autolink/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
plugins {
jewel
`jewel-publish`
`jewel-check-public-api`
alias(libs.plugins.composeDesktop)
}

dependencies {
implementation(projects.markdown.core)
implementation(libs.commonmark.ext.autolink)
testImplementation(compose.desktop.uiTestJUnit4)
}

publishing.publications.named<MavenPublication>("main") {
val ijpTarget = project.property("ijp.target") as String
artifactId = "jewel-markdown-extension-${project.name}-$ijpTarget"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.jetbrains.jewel.markdown.extension.autolink

import org.commonmark.ext.autolink.AutolinkExtension
import org.commonmark.parser.Parser.ParserExtension
import org.commonmark.renderer.text.TextContentRenderer
import org.jetbrains.jewel.markdown.extensions.MarkdownBlockProcessorExtension
import org.jetbrains.jewel.markdown.extensions.MarkdownProcessorExtension

public object AutolinkProcessorExtension : MarkdownProcessorExtension {
override val parserExtension: ParserExtension
get() = AutolinkExtension.create() as ParserExtension

/**
* Rendering and processing is already handled by [org.jetbrains.jewel.markdown.rendering.DefaultInlineMarkdownRenderer]
*/
override val textRendererExtension: TextContentRenderer.TextContentRendererExtension?
get() = null
override val processorExtension: MarkdownBlockProcessorExtension?
get() = null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.jetbrains.jewel.markdown.extension.autolink

import org.jetbrains.jewel.markdown.InlineMarkdown
import org.jetbrains.jewel.markdown.MarkdownBlock
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor
import org.junit.Assert.assertTrue
import org.junit.Test

class AutolinkProcessorExtensionTest {
// testing a simple case to assure wiring up our AutolinkProcessorExtension works correctly
@Test
fun `https text gets processed into a link`() {
val processor = MarkdownProcessor(listOf(AutolinkProcessorExtension))
val rawMarkDown = "https://commonmark.org"
val processed = processor.processMarkdownDocument(rawMarkDown)
val paragraph = processed[0] as MarkdownBlock.Paragraph

assertTrue(paragraph.inlineContent[0] is InlineMarkdown.Link)
}
}
2 changes: 1 addition & 1 deletion samples/standalone/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies {
implementation(projects.intUi.intUiDecoratedWindow)
implementation(projects.markdown.intUiStandaloneStyling)
implementation(projects.markdown.extension.gfmAlerts)

implementation(projects.markdown.extension.autolink)
implementation(compose.desktop.currentOs) {
exclude(group = "org.jetbrains.compose.material")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import org.jetbrains.jewel.intui.markdown.styling.extension.github.alerts.dark
import org.jetbrains.jewel.intui.markdown.styling.extension.github.alerts.light
import org.jetbrains.jewel.intui.markdown.styling.light
import org.jetbrains.jewel.markdown.MarkdownBlock
import org.jetbrains.jewel.markdown.extension.autolink.AutolinkProcessorExtension
import org.jetbrains.jewel.markdown.extensions.github.alerts.AlertStyling
import org.jetbrains.jewel.markdown.extensions.github.alerts.GitHubAlertProcessorExtension
import org.jetbrains.jewel.markdown.extensions.github.alerts.GitHubAlertRendererExtension
Expand All @@ -43,14 +44,17 @@ import java.awt.Desktop
import java.net.URI

@Composable
internal fun MarkdownPreview(rawMarkdown: String, modifier: Modifier = Modifier) {
internal fun MarkdownPreview(
rawMarkdown: String,
modifier: Modifier = Modifier,
) {
val isDark = JewelTheme.isDark

val markdownStyling =
remember(isDark) { if (isDark) MarkdownStyling.dark() else MarkdownStyling.light() }

var markdownBlocks by remember { mutableStateOf(emptyList<MarkdownBlock>()) }
val extensions = listOf(GitHubAlertProcessorExtension)
val extensions = listOf(GitHubAlertProcessorExtension, AutolinkProcessorExtension)
val processor = remember { MarkdownProcessor(extensions) }

LaunchedEffect(rawMarkdown) {
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ include(
":int-ui:int-ui-decorated-window",
":int-ui:int-ui-standalone",
":markdown:core",
":markdown:extension:autolink",
":markdown:extension:gfm-alerts",
":markdown:int-ui-standalone-styling",
":markdown:ide-laf-bridge-styling",
Expand Down

0 comments on commit 2ee753f

Please sign in to comment.