From 2966df1113eb28c5a3940718e62a25a75a24fd69 Mon Sep 17 00:00:00 2001
From: Robin Stocker <robin@nibor.org>
Date: Wed, 7 Feb 2024 19:13:55 +1100
Subject: [PATCH] Ins extensions markdown renderer

---
 .../org/commonmark/ext/ins/InsExtension.java  | 28 +++++++++++++--
 .../ins/internal/InsMarkdownNodeRenderer.java | 32 +++++++++++++++++
 .../ext/ins/InsMarkdownRendererTest.java      | 34 +++++++++++++++++++
 3 files changed, 91 insertions(+), 3 deletions(-)
 create mode 100644 commonmark-ext-ins/src/main/java/org/commonmark/ext/ins/internal/InsMarkdownNodeRenderer.java
 create mode 100644 commonmark-ext-ins/src/test/java/org/commonmark/ext/ins/InsMarkdownRendererTest.java

diff --git a/commonmark-ext-ins/src/main/java/org/commonmark/ext/ins/InsExtension.java b/commonmark-ext-ins/src/main/java/org/commonmark/ext/ins/InsExtension.java
index 2f980d93..06571955 100644
--- a/commonmark-ext-ins/src/main/java/org/commonmark/ext/ins/InsExtension.java
+++ b/commonmark-ext-ins/src/main/java/org/commonmark/ext/ins/InsExtension.java
@@ -3,16 +3,23 @@ package org.commonmark.ext.ins;
 import org.commonmark.Extension;
 import org.commonmark.ext.ins.internal.InsDelimiterProcessor;
 import org.commonmark.ext.ins.internal.InsHtmlNodeRenderer;
+import org.commonmark.ext.ins.internal.InsMarkdownNodeRenderer;
 import org.commonmark.ext.ins.internal.InsTextContentNodeRenderer;
 import org.commonmark.parser.Parser;
 import org.commonmark.renderer.NodeRenderer;
 import org.commonmark.renderer.html.HtmlNodeRendererContext;
 import org.commonmark.renderer.html.HtmlNodeRendererFactory;
 import org.commonmark.renderer.html.HtmlRenderer;
+import org.commonmark.renderer.markdown.MarkdownNodeRendererContext;
+import org.commonmark.renderer.markdown.MarkdownNodeRendererFactory;
+import org.commonmark.renderer.markdown.MarkdownRenderer;
 import org.commonmark.renderer.text.TextContentNodeRendererContext;
 import org.commonmark.renderer.text.TextContentNodeRendererFactory;
 import org.commonmark.renderer.text.TextContentRenderer;
 
+import java.util.Collections;
+import java.util.Set;
+
 /**
  * Extension for ins using ++
  * <p>
@@ -24,9 +31,7 @@ import org.commonmark.renderer.text.TextContentRenderer;
  * The parsed ins text regions are turned into {@link Ins} nodes.
  * </p>
  */
-public class InsExtension implements Parser.ParserExtension,
-        HtmlRenderer.HtmlRendererExtension,
-        TextContentRenderer.TextContentRendererExtension {
+public class InsExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension, TextContentRenderer.TextContentRendererExtension, MarkdownRenderer.MarkdownRendererExtension {
 
     private InsExtension() {
     }
@@ -59,4 +64,21 @@ public class InsExtension implements Parser.ParserExtension,
             }
         });
     }
+
+    @Override
+    public void extend(MarkdownRenderer.Builder rendererBuilder) {
+        rendererBuilder.nodeRendererFactory(new MarkdownNodeRendererFactory() {
+            @Override
+            public NodeRenderer create(MarkdownNodeRendererContext context) {
+                return new InsMarkdownNodeRenderer(context);
+            }
+
+            @Override
+            public Set<Character> getSpecialCharacters() {
+                // We technically don't need to escape single occurrences of +, but that's all the extension API
+                // exposes currently.
+                return Collections.singleton('+');
+            }
+        });
+    }
 }
diff --git a/commonmark-ext-ins/src/main/java/org/commonmark/ext/ins/internal/InsMarkdownNodeRenderer.java b/commonmark-ext-ins/src/main/java/org/commonmark/ext/ins/internal/InsMarkdownNodeRenderer.java
new file mode 100644
index 00000000..851d4728
--- /dev/null
+++ b/commonmark-ext-ins/src/main/java/org/commonmark/ext/ins/internal/InsMarkdownNodeRenderer.java
@@ -0,0 +1,32 @@
+package org.commonmark.ext.ins.internal;
+
+import org.commonmark.node.Node;
+import org.commonmark.renderer.markdown.MarkdownNodeRendererContext;
+import org.commonmark.renderer.markdown.MarkdownWriter;
+
+public class InsMarkdownNodeRenderer extends InsNodeRenderer {
+
+    private final MarkdownNodeRendererContext context;
+    private final MarkdownWriter writer;
+
+    public InsMarkdownNodeRenderer(MarkdownNodeRendererContext context) {
+        this.context = context;
+        this.writer = context.getWriter();
+    }
+
+    @Override
+    public void render(Node node) {
+        writer.raw("++");
+        renderChildren(node);
+        writer.raw("++");
+    }
+
+    private void renderChildren(Node parent) {
+        Node node = parent.getFirstChild();
+        while (node != null) {
+            Node next = node.getNext();
+            context.render(node);
+            node = next;
+        }
+    }
+}
diff --git a/commonmark-ext-ins/src/test/java/org/commonmark/ext/ins/InsMarkdownRendererTest.java b/commonmark-ext-ins/src/test/java/org/commonmark/ext/ins/InsMarkdownRendererTest.java
new file mode 100644
index 00000000..16cefc7f
--- /dev/null
+++ b/commonmark-ext-ins/src/test/java/org/commonmark/ext/ins/InsMarkdownRendererTest.java
@@ -0,0 +1,34 @@
+package org.commonmark.ext.ins;
+
+import org.commonmark.Extension;
+import org.commonmark.parser.Parser;
+import org.commonmark.renderer.markdown.MarkdownRenderer;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+public class InsMarkdownRendererTest {
+
+    private static final Set<Extension> EXTENSIONS = Collections.singleton(InsExtension.create());
+    private static final Parser PARSER = Parser.builder().extensions(EXTENSIONS).build();
+    private static final MarkdownRenderer RENDERER = MarkdownRenderer.builder().extensions(EXTENSIONS).build();
+
+    @Test
+    public void testStrikethrough() {
+        assertRoundTrip("++foo++\n");
+
+        assertRoundTrip("\\+\\+foo\\+\\+\n");
+    }
+
+    protected String render(String source) {
+        return RENDERER.render(PARSER.parse(source));
+    }
+
+    private void assertRoundTrip(String input) {
+        String rendered = render(input);
+        assertEquals(input, rendered);
+    }
+}
-- 
GitLab