From 49e2309f315e357177b1961df6c7392352de3c37 Mon Sep 17 00:00:00 2001 From: Jacob Logsdon Date: Thu, 28 Mar 2024 17:17:20 -0700 Subject: [PATCH] Add an autolink extension for Markdown 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. --- gradle/libs.versions.toml | 1 + .../extensions/MarkdownProcessorExtension.kt | 6 +++--- .../markdown/processing/MarkdownProcessor.kt | 2 +- markdown/extension/autolink/api/autolink.api | 8 ++++++++ markdown/extension/autolink/build.gradle.kts | 17 ++++++++++++++++ .../autolink/AutolinkProcessorExtension.kt | 20 +++++++++++++++++++ .../AutolinkProcessorExtensionTest.kt | 18 +++++++++++++++++ settings.gradle.kts | 1 + 8 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 markdown/extension/autolink/api/autolink.api create mode 100644 markdown/extension/autolink/build.gradle.kts create mode 100644 markdown/extension/autolink/src/main/kotlin/org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtension.kt create mode 100644 markdown/extension/autolink/src/test/kotlin/org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtensionTest.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2d0cd0e3b..5d1e8aa30 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" } diff --git a/markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension.kt b/markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension.kt index 8f5d706b4..a8fafd626 100644 --- a/markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension.kt +++ b/markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension.kt @@ -14,14 +14,14 @@ public interface MarkdownProcessorExtension { * A CommonMark [ParserExtension] that will be used to parse the extended * syntax represented by this extension instance. */ - 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]. */ - public val textRendererExtension: TextContentRendererExtension + public val textRendererExtension: TextContentRendererExtension? /** * An extension for @@ -29,5 +29,5 @@ public interface MarkdownProcessorExtension { * that will transform a supported [CustomBlock] into the corresponding * [MarkdownBlock.Extension]. */ - public val processorExtension: MarkdownBlockProcessorExtension + public val processorExtension: MarkdownBlockProcessorExtension? } diff --git a/markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/processing/MarkdownProcessor.kt b/markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/processing/MarkdownProcessor.kt index 5090de9c2..6509161a7 100644 --- a/markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/processing/MarkdownProcessor.kt +++ b/markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/processing/MarkdownProcessor.kt @@ -104,7 +104,7 @@ public class MarkdownProcessor(private val extensions: List 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) } diff --git a/markdown/extension/autolink/api/autolink.api b/markdown/extension/autolink/api/autolink.api new file mode 100644 index 000000000..76809e0ee --- /dev/null +++ b/markdown/extension/autolink/api/autolink.api @@ -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 fun ()V + 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; +} + diff --git a/markdown/extension/autolink/build.gradle.kts b/markdown/extension/autolink/build.gradle.kts new file mode 100644 index 000000000..052dbcea8 --- /dev/null +++ b/markdown/extension/autolink/build.gradle.kts @@ -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("main") { + val ijpTarget = project.property("ijp.target") as String + artifactId = "jewel-markdown-extension-${project.name}-$ijpTarget" +} diff --git a/markdown/extension/autolink/src/main/kotlin/org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtension.kt b/markdown/extension/autolink/src/main/kotlin/org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtension.kt new file mode 100644 index 000000000..54234b6c8 --- /dev/null +++ b/markdown/extension/autolink/src/main/kotlin/org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtension.kt @@ -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 class 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 +} diff --git a/markdown/extension/autolink/src/test/kotlin/org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtensionTest.kt b/markdown/extension/autolink/src/test/kotlin/org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtensionTest.kt new file mode 100644 index 000000000..a38798479 --- /dev/null +++ b/markdown/extension/autolink/src/test/kotlin/org/jetbrains/jewel/markdown/extension/autolink/AutolinkProcessorExtensionTest.kt @@ -0,0 +1,18 @@ +package org.jetbrains.jewel.markdown.extension.autolink + +import junit.framework.TestCase.assertEquals +import org.jetbrains.jewel.markdown.MarkdownBlock +import org.jetbrains.jewel.markdown.processing.MarkdownProcessor +import org.junit.Test + +class AutolinkProcessorExtensionTest { + // testing a simple case to assure wiring up our AutolinkProcessorExtension works correctly + @Test + fun `one text node`() { + val processor = MarkdownProcessor(listOf(AutolinkProcessorExtension())) + val rawMarkDown = "https://commonmark.org" + val processed = processor.processMarkdownDocument(rawMarkDown) + val paragraph = processed[0] as MarkdownBlock.Paragraph + assertEquals(paragraph.inlineContent.content, "[https://commonmark.org](https://commonmark.org)") + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 7d7e33b08..69a2b6a3e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -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",