diff --git a/CHANGELOG.md b/CHANGELOG.md index 297f3a83..bec4dde5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # intellij-markdown Changelog ## [Unreleased] +- Generate HTML with `code-line line-added`/`line-deleted` classes for added/deleted lines in `diff` / `patch` blocks - Support tables inside list items - Android compatibility issues diff --git a/src/commonMain/kotlin/org/intellij/markdown/html/GeneratingProviders.kt b/src/commonMain/kotlin/org/intellij/markdown/html/GeneratingProviders.kt index eaabdc1c..4df462f0 100644 --- a/src/commonMain/kotlin/org/intellij/markdown/html/GeneratingProviders.kt +++ b/src/commonMain/kotlin/org/intellij/markdown/html/GeneratingProviders.kt @@ -197,18 +197,37 @@ internal class CodeFenceGeneratingProvider : GeneratingProvider { } var lastChildWasContent = false + var isDiff = false val attributes = ArrayList() for (child in childrenToConsider) { if (state == 1 && child.type in listOf(MarkdownTokenTypes.CODE_FENCE_CONTENT, MarkdownTokenTypes.EOL)) { - visitor.consumeHtml(HtmlGenerator.trimIndents(HtmlGenerator.leafText(text, child, false), indentBefore)) + val content = HtmlGenerator.trimIndents(HtmlGenerator.leafText(text, child, false), indentBefore) + if (isDiff && child.type == MarkdownTokenTypes.CODE_FENCE_CONTENT) { + val lineClass = when { + content.startsWith("+") -> "line-added" + content.startsWith("-") -> "line-deleted" + else -> null + } + if (lineClass != null) { + visitor.consumeTagOpen(child, "span", "class=\"code-line $lineClass\"") + visitor.consumeHtml(content) + visitor.consumeTagClose("span") + } else { + visitor.consumeHtml(content) + } + } else { + visitor.consumeHtml(content) + } lastChildWasContent = child.type == MarkdownTokenTypes.CODE_FENCE_CONTENT } if (state == 0 && child.type == MarkdownTokenTypes.FENCE_LANG) { - attributes.add("class=\"language-${ - HtmlGenerator.leafText(text, child).toString().trim().split(' ')[0] - }\"") + val info = HtmlGenerator.leafText(text, child).toString().trim() + val whitespaceIndex = info.indexOfFirst { it.isWhitespace() } + val language = if (whitespaceIndex == -1) info else info.substring(0, whitespaceIndex) + isDiff = language == "diff" || language == "patch" + attributes.add("class=\"language-$language\"") } if (state == 0 && child.type == MarkdownTokenTypes.EOL) { visitor.consumeTagOpen(node, "code", *attributes.toTypedArray()) @@ -323,4 +342,3 @@ open class ImageGeneratingProvider(linkMap: LinkMap, baseURI: URI?) : LinkGenera val REGEX = Regex("[^a-zA-Z0-9 ]") } } - diff --git a/src/fileBasedTest/kotlin/org/intellij/markdown/HtmlGeneratorCommonTest.kt b/src/fileBasedTest/kotlin/org/intellij/markdown/HtmlGeneratorCommonTest.kt index 2c349f9a..129fa790 100644 --- a/src/fileBasedTest/kotlin/org/intellij/markdown/HtmlGeneratorCommonTest.kt +++ b/src/fileBasedTest/kotlin/org/intellij/markdown/HtmlGeneratorCommonTest.kt @@ -50,6 +50,11 @@ class HtmlGeneratorCommonTest : HtmlGeneratorTestBase() { defaultTest() } + @Test + fun testDiffCodeFences() { + defaultTest() + } + @Test fun testEscaping() { defaultTest() diff --git a/src/fileBasedTest/resources/data/html/diffCodeFences.md b/src/fileBasedTest/resources/data/html/diffCodeFences.md new file mode 100644 index 00000000..1ce86972 --- /dev/null +++ b/src/fileBasedTest/resources/data/html/diffCodeFences.md @@ -0,0 +1,32 @@ +```diff ++added line 1 ++added line 2 ++added line 3 +``` + +```diff metadata ++tab-separated info string +``` + +```diff +-removed line 1 +-removed line 2 +-removed line 3 +``` + +```diff + context line ++added line 1 ++added line 2 +-removed line 1 +-removed line 2 + context line +``` + +```diff ++ & +- ++ + plain line + +``` diff --git a/src/fileBasedTest/resources/data/html/diffCodeFences.txt b/src/fileBasedTest/resources/data/html/diffCodeFences.txt new file mode 100644 index 00000000..2fd424a6 --- /dev/null +++ b/src/fileBasedTest/resources/data/html/diffCodeFences.txt @@ -0,0 +1,44 @@ + +

++added line 1
+
++added line 2
+
++added line 3
+
+
+

++tab-separated info string
+
+
+

+-removed line 1
+
+-removed line 2
+
+-removed line 3
+
+
+

+ context line
++added line 1
+
++added line 2
+
+-removed line 1
+
+-removed line 2
+
+ context line
+
+

++ <tag>&
+
+-
+
++
+
+ plain line
+
+
+