From f5b04efdae2c48e46f8f108df71308a7521ac223 Mon Sep 17 00:00:00 2001
From: Robin Stocker <robin@nibor.org>
Date: Tue, 23 Jan 2024 23:35:48 +1100
Subject: [PATCH] Disregard prefixes for line start logic

---
 .../markdown/CoreMarkdownNodeRenderer.java    | 14 +++++++-------
 .../renderer/markdown/MarkdownWriter.java     | 19 +++++++++++++++++--
 .../markdown/MarkdownRendererTest.java        |  5 +++++
 .../markdown/SpecMarkdownRendererTest.java    |  2 +-
 4 files changed, 30 insertions(+), 10 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 8cb67e0f..11e7ae5f 100644
--- a/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java
+++ b/commonmark/src/main/java/org/commonmark/renderer/markdown/CoreMarkdownNodeRenderer.java
@@ -88,7 +88,7 @@ public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRen
 
     @Override
     public void visit(BlockQuote blockQuote) {
-        writer.write("> ");
+        writer.writePrefix("> ");
         writer.pushPrefix("> ");
         visitChildren(blockQuote);
         writer.popPrefix();
@@ -124,16 +124,16 @@ public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRen
         if (listHolder instanceof BulletListHolder) {
             BulletListHolder bulletListHolder = (BulletListHolder) listHolder;
             String marker = repeat(" ", listItem.getMarkerIndent()) + bulletListHolder.bulletMarker;
-            writer.write(marker);
-            writer.write(repeat(" ", contentIndent - marker.length()));
+            writer.writePrefix(marker);
+            writer.writePrefix(repeat(" ", contentIndent - marker.length()));
             writer.pushPrefix(repeat(" ", contentIndent));
             pushedPrefix = true;
         } else if (listHolder instanceof OrderedListHolder) {
             OrderedListHolder orderedListHolder = (OrderedListHolder) listHolder;
             String marker = repeat(" ", listItem.getMarkerIndent()) + orderedListHolder.number + orderedListHolder.delimiter;
             orderedListHolder.number++;
-            writer.write(marker);
-            writer.write(repeat(" ", contentIndent - marker.length()));
+            writer.writePrefix(marker);
+            writer.writePrefix(repeat(" ", contentIndent - marker.length()));
             writer.pushPrefix(repeat(" ", contentIndent));
             pushedPrefix = true;
         }
@@ -190,7 +190,7 @@ public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRen
 
         if (indent > 0) {
             String indentPrefix = repeat(" ", indent);
-            writer.write(indentPrefix);
+            writer.writePrefix(indentPrefix);
             writer.pushPrefix(indentPrefix);
         }
 
@@ -286,7 +286,7 @@ public class CoreMarkdownNodeRenderer extends AbstractVisitor implements NodeRen
         String literal = indentedCodeBlock.getLiteral();
         // We need to respect line prefixes which is why we need to write it line by line (e.g. an indented code block
         // within a block quote)
-        writer.write("    ");
+        writer.writePrefix("    ");
         writer.pushPrefix("    ");
         List<String> lines = getLines(literal);
         for (int i = 0; i < lines.size(); i++) {
diff --git a/commonmark/src/main/java/org/commonmark/renderer/markdown/MarkdownWriter.java b/commonmark/src/main/java/org/commonmark/renderer/markdown/MarkdownWriter.java
index bc10f020..d95c0bd8 100644
--- a/commonmark/src/main/java/org/commonmark/renderer/markdown/MarkdownWriter.java
+++ b/commonmark/src/main/java/org/commonmark/renderer/markdown/MarkdownWriter.java
@@ -11,7 +11,8 @@ public class MarkdownWriter {
 
     private int blockSeparator = 0;
     private boolean tight;
-    private char lastChar = '\n';
+    private char lastChar;
+    private boolean atLineStart = true;
     private final LinkedList<String> prefixes = new LinkedList<>();
 
     public MarkdownWriter(Appendable out) {
@@ -22,8 +23,11 @@ public class MarkdownWriter {
         return lastChar;
     }
 
+    /**
+     * @return whether we're at the line start (not counting any prefixes), i.e. after a {@link #line} or {@link #block}.
+     */
     public boolean isAtLineStart() {
-        return lastChar == '\n' || blockSeparator > 0;
+        return atLineStart;
     }
 
     public void write(String s) {
@@ -54,11 +58,13 @@ public class MarkdownWriter {
         }
 
         lastChar = s.charAt(s.length() - 1);
+        atLineStart = false;
     }
 
     public void line() {
         append('\n');
         writePrefixes();
+        atLineStart = true;
     }
 
     /**
@@ -69,12 +75,19 @@ public class MarkdownWriter {
         // Remember whether this should be a tight or loose separator now because tight could get changed in between
         // this and the next flush.
         blockSeparator = tight ? 1 : 2;
+        atLineStart = true;
     }
 
     public void pushPrefix(String prefix) {
         prefixes.addLast(prefix);
     }
 
+    public void writePrefix(String prefix) {
+        boolean tmp = atLineStart;
+        write(prefix);
+        atLineStart = tmp;
+    }
+
     public void popPrefix() {
         prefixes.removeLast();
     }
@@ -90,6 +103,7 @@ public class MarkdownWriter {
         if (length != 0) {
             lastChar = s.charAt(length - 1);
         }
+        atLineStart = false;
     }
 
     private void append(char c) {
@@ -100,6 +114,7 @@ public class MarkdownWriter {
         }
 
         lastChar = c;
+        atLineStart = false;
     }
 
     private void writePrefixes() {
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 59039799..6f9e1e6f 100644
--- a/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java
+++ b/commonmark/src/test/java/org/commonmark/renderer/markdown/MarkdownRendererTest.java
@@ -137,6 +137,11 @@ public class MarkdownRendererTest {
         assertRoundTrip("\\## Test\n");
         assertRoundTrip("\\#\n");
         assertRoundTrip("Foo\n\\===\n");
+        // The beginning of the line within the block, so disregarding prefixes
+        assertRoundTrip("> \\- Test\n");
+        assertRoundTrip("- \\- Test\n");
+        // That's not the beginning of the line
+        assertRoundTrip("`a`- foo\n");
 
         // This is a bit more tricky as we need to check for a list start
         assertRoundTrip("1\\. Foo\n");
diff --git a/commonmark/src/test/java/org/commonmark/renderer/markdown/SpecMarkdownRendererTest.java b/commonmark/src/test/java/org/commonmark/renderer/markdown/SpecMarkdownRendererTest.java
index d6bdf9cf..39269368 100644
--- a/commonmark/src/test/java/org/commonmark/renderer/markdown/SpecMarkdownRendererTest.java
+++ b/commonmark/src/test/java/org/commonmark/renderer/markdown/SpecMarkdownRendererTest.java
@@ -62,7 +62,7 @@ public class SpecMarkdownRendererTest {
             System.out.println();
         }
 
-        int expectedPassed = 647;
+        int expectedPassed = 650;
         assertTrue("Expected at least " + expectedPassed + " examples to pass but was " + passes.size(), passes.size() >= expectedPassed);
     }
 
-- 
GitLab