Skip to content

Commit

Permalink
Add strikethrough markdown support
Browse files Browse the repository at this point in the history
Since it's inlined, the extension is added directly to the core module.
  • Loading branch information
Oleg Baskakov authored and obask committed Mar 31, 2024
1 parent 82d3581 commit e2a3dc1
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 1 deletion.
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-extGfmStrikethrough = { module = "org.commonmark:commonmark-ext-gfm-strikethrough", version.ref = "commonmark" }

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

Expand Down
2 changes: 1 addition & 1 deletion markdown/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ Currently supports the [CommonMark 0.31.2](https://spec.commonmark.org/0.31.2/)
Additional supported Markdown, via extensions:

* Alerts ([GitHub Flavored Markdown][alerts-specs]) — see [`extension-gfm-alerts`](extension/gfm-alerts)
* Strikethrough(builtin) ([GitHub Flavored Markdown](https://github.github.com/gfm/#strikethrough-extension-))

[alerts-specs]: https://github.com/orgs/community/discussions/16925

On the roadmap, but not currently supported — in no particular order:

* Tables ([GitHub Flavored Markdown](https://github.github.com/gfm/#tables-extension-))
* Strikethrough ([GitHub Flavored Markdown](https://github.github.com/gfm/#strikethrough-extension-))
* Image loading (via [Coil 3](https://coil-kt.github.io/coil/upgrading_to_coil3/))
* Auto-linking ([GitHub Flavored Markdown](https://github.github.com/gfm/#autolinks-extension-))
* Task list items ([GitHub Flavored Markdown](https://github.github.com/gfm/#task-list-items-extension-))
Expand Down
1 change: 1 addition & 0 deletions markdown/core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ plugins {
dependencies {
api(projects.ui)
api(libs.commonmark.core)
api(libs.commonmark.extGfmStrikethrough)

testImplementation(compose.desktop.uiTestJUnit4)
testImplementation(projects.ui)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jetbrains.jewel.markdown.processing

import org.commonmark.ext.gfm.strikethrough.Strikethrough
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension
import org.commonmark.node.Block
import org.commonmark.node.BlockQuote
import org.commonmark.node.BulletList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.UrlAnnotation
import androidx.compose.ui.text.buildAnnotatedString
import org.commonmark.ext.gfm.strikethrough.Strikethrough
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension
import org.commonmark.renderer.text.TextContentRenderer
import org.jetbrains.jewel.foundation.ExperimentalJewelApi
import org.jetbrains.jewel.markdown.InlineMarkdown
Expand All @@ -17,8 +19,16 @@ public open class DefaultInlineMarkdownRenderer(rendererExtensions: List<Markdow

public constructor(vararg extensions: MarkdownProcessorExtension) : this(extensions.toList())

private val strikethroughExtension = StrikethroughExtension.create()

private val commonMarkParser =
Parser.builder()
.extensions(listOf(strikethroughExtension))
.extensions(rendererExtensions.map { it.parserExtension }).build()

private val plainTextRenderer =
TextContentRenderer.builder()
.extensions(listOf(strikethroughExtension))
.extensions(rendererExtensions.map { it.textRendererExtension })
.build()

Expand All @@ -44,6 +54,10 @@ public open class DefaultInlineMarkdownRenderer(rendererExtensions: List<Markdow
withStyles(styling.emphasis, child) { appendInlineMarkdownFrom(it.children, styling) }
}

is Strikethrough -> {
withStyles(styling.strikethrough, child) { appendInlineMarkdownFrom(it, styling) }
}

is InlineMarkdown.StrongEmphasis -> {
withStyles(styling.strongEmphasis, child) { appendInlineMarkdownFrom(it.children, styling) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ public class InlinesStyling(
public val link: SpanStyle,
public val emphasis: SpanStyle,
public val strongEmphasis: SpanStyle,
public val strikethrough: SpanStyle,
public val inlineHtml: SpanStyle,
public val renderInlineHtml: Boolean,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,56 @@ class MarkdownProcessorDocumentParsingExtraTest {
*/
parsed.assertEquals(paragraph("*_*foo *bar* a*_*"))
}

@Test
fun `should parse gfm spec example 491 correctly (Strikethrough)`() {
val parsed = processor.processMarkdownDocument("~~Hi~~ Hello, ~~there~~ world!")

/*
* Expected HTML:
* <p><del>Hi</del> Hello, <del>there</del> world!</p>
*/
parsed.assertEquals(paragraph("~~Hi~~ Hello, ~~there~~ world\\!"))
}

@org.junit.Ignore("Strikethrough is any text wrapped in a pair of one tildes, but our implementation assumes two")
@Test
fun `should parse gfm spec example 491b correctly (Strikethrough)`() {
val parsed = processor.processMarkdownDocument("~there~ world!")

parsed.assertEquals(paragraph("~there~ world\\!"))
}

/** As with regular emphasis delimiters, a new paragraph will cause strikethrough parsing to cease */
@Test
fun `should parse gfm spec example 492 correctly (Strikethrough)`() {
val parsed = processor.processMarkdownDocument(
"""
|This ~~has a
|
|new paragraph~~.
""".trimMargin(),
)

/*
* Expected HTML:
* <p>This ~~has a</p>
* <p>new paragraph~~.</p>
*/
parsed.assertEquals(
paragraph("This \\~\\~has a"),
paragraph("new paragraph\\~\\~."),
)
}

@Test
fun `should parse gfm spec example 493 correctly (Strikethrough)`() {
val parsed = processor.processMarkdownDocument("This will ~~~not~~~ strike.")

/*
* Expected HTML:
* <p>This will ~~~not~~~ strike.</p>
*/
parsed.assertEquals(paragraph("This will \\~\\~\\~not\\~\\~\\~ strike."))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ public fun InlinesStyling.Companion.light(
textStyle.copy(color = Color(0xFF0969DA), textDecoration = TextDecoration.Underline).toSpanStyle(),
emphasis: SpanStyle = textStyle.copy(fontStyle = FontStyle.Italic).toSpanStyle(),
strongEmphasis: SpanStyle = textStyle.copy(fontWeight = FontWeight.Bold).toSpanStyle(),
strikethrough: SpanStyle = textStyle.copy(textDecoration = TextDecoration.LineThrough).toSpanStyle().copy(),
inlineHtml: SpanStyle = textStyle.toSpanStyle(),
renderInlineHtml: Boolean = false,
): InlinesStyling =
Expand All @@ -596,6 +597,7 @@ public fun InlinesStyling.Companion.light(
link,
emphasis,
strongEmphasis,
strikethrough,
inlineHtml,
renderInlineHtml,
)
Expand All @@ -616,6 +618,7 @@ public fun InlinesStyling.Companion.dark(
.toSpanStyle(),
emphasis: SpanStyle = textStyle.copy(fontStyle = FontStyle.Italic).toSpanStyle(),
strongEmphasis: SpanStyle = textStyle.copy(fontWeight = FontWeight.Bold).toSpanStyle(),
strikethrough: SpanStyle = textStyle.copy(textDecoration = TextDecoration.LineThrough).toSpanStyle().copy(),
inlineHtml: SpanStyle = textStyle.toSpanStyle(),
renderInlineHtml: Boolean = false,
): InlinesStyling =
Expand All @@ -625,6 +628,7 @@ public fun InlinesStyling.Companion.dark(
link,
emphasis,
strongEmphasis,
strikethrough,
inlineHtml,
renderInlineHtml,
)
Expand Down
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@ gradleEnterprise {
termsOfServiceAgree = "yes"
}
}
include("markdown:commonmark-extensions")
findProject(":markdown:commonmark-extensions")?.name = "commonmark-extensions"

0 comments on commit e2a3dc1

Please sign in to comment.