From 0c5ad6e1f16ae2b655db93fd07c0af502fead16e Mon Sep 17 00:00:00 2001
From: Robin Stocker <robin@nibor.org>
Date: Thu, 8 Feb 2024 23:26:03 +1100
Subject: [PATCH] Use parsed delimiter for emphasis if available

---
 .../markdown/CoreMarkdownNodeRenderer.java    | 10 ++++--
 .../markdown/MarkdownRendererTest.java        | 34 ++++++++++++++-----
 2 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java b/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java
index 2db7ef30..748ff5df 100644
--- a/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java
+++ b/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java
@@ -45,7 +45,7 @@ public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRen
         this.context = context;
         this.writer = context.getWriter();
 
-        textEscape = AsciiMatcher.builder().anyOf("[]<>`*&\n\\").anyOf(context.getSpecialCharacters()).build();
+        textEscape = AsciiMatcher.builder().anyOf("[]<>`*_&\n\\").anyOf(context.getSpecialCharacters()).build();
         textEscapeInHeading = AsciiMatcher.builder(textEscape).anyOf("#").build();
     }
 
@@ -282,8 +282,12 @@ public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRen
 
     @Override
     public void visit(Emphasis emphasis) {
-        // When emphasis is nested, a different delimiter needs to be used
-        char delimiter = writer.getLastChar() == '*' ? '_' : '*';
+        String delimiter = emphasis.getOpeningDelimiter();
+        // Use delimiter that was parsed if available
+        if (delimiter == null) {
+            // When emphasis is nested, a different delimiter needs to be used
+            delimiter = writer.getLastChar() == '*' ? "_" : "*";
+        }
         writer.raw(delimiter);
         super.visit(emphasis);
         writer.raw(delimiter);
diff --git a/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java b/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java
index 20453eed..af6a3488 100644
--- a/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java
+++ b/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java
@@ -1,6 +1,6 @@
 package org.commonmark.renderer.markdown;
 
-import org.commonmark.node.Node;
+import org.commonmark.node.*;
 import org.commonmark.parser.Parser;
 import org.junit.Test;
 
@@ -173,9 +173,21 @@ public class MarkdownRendererTest {
         // When nesting, a different delimiter needs to be used
         assertRoundTrip("*_foo_*\n");
         assertRoundTrip("*_*foo*_*\n");
+        assertRoundTrip("_*foo*_\n");
 
         // Not emphasis (needs * inside words)
-        assertRoundTrip("foo_bar_\n");
+        assertRoundTrip("foo\\_bar\\_\n");
+
+        // Even when rendering a manually constructed tree, the emphasis delimiter needs to be chosen correctly.
+        Document doc = new Document();
+        Paragraph p = new Paragraph();
+        doc.appendChild(p);
+        Emphasis e1 = new Emphasis();
+        p.appendChild(e1);
+        Emphasis e2 = new Emphasis();
+        e1.appendChild(e2);
+        e2.appendChild(new Text("hi"));
+        assertEquals("*_hi_*\n", render(doc));
     }
 
     @Test
@@ -226,17 +238,21 @@ public class MarkdownRendererTest {
         assertRoundTrip("foo\nbar\n");
     }
 
-    private Node parse(String source) {
-        return Parser.builder().build().parse(source);
+    private void assertRoundTrip(String input) {
+        String rendered = parseAndRender(input);
+        assertEquals(input, rendered);
     }
 
-    private String render(String source) {
+    private String parseAndRender(String source) {
         Node parsed = parse(source);
-        return MarkdownRenderer.builder().build().render(parsed);
+        return render(parsed);
     }
 
-    private void assertRoundTrip(String input) {
-        String rendered = render(input);
-        assertEquals(input, rendered);
+    private Node parse(String source) {
+        return Parser.builder().build().parse(source);
+    }
+
+    private String render(Node node) {
+        return MarkdownRenderer.builder().build().render(node);
     }
 }
-- 
GitLab