This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-doxia.git


The following commit(s) were added to refs/heads/master by this push:
     new 4ff3e3dd [DOXIA-749] Correctly indent and separate blocks inside list 
items (#238)
4ff3e3dd is described below

commit 4ff3e3dd24aa79e2b222e0a488f4f9426ac86faf
Author: Konrad Windszus <k...@apache.org>
AuthorDate: Sun Oct 20 17:27:36 2024 +0200

    [DOXIA-749] Correctly indent and separate blocks inside list items (#238)
    
    Block elements should be surrounded by blank lines inside list items to
    be compliant with more MD parsers
    Do not prefix standalone linebreaks (as often emitted from HTML parsers
    without any semantical meaning)
---
 .../maven/doxia/sink/impl/SinkEventElement.java    | 10 ++++-
 .../doxia/sink/impl/SinkEventTestingSink.java      |  2 +-
 .../maven/doxia/module/markdown/MarkdownSink.java  | 46 ++++++++++++++++------
 .../doxia/module/markdown/MarkdownSinkTest.java    | 34 ++++++++++++----
 4 files changed, 70 insertions(+), 22 deletions(-)

diff --git 
a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventElement.java
 
b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventElement.java
index 764e0c4b..97e12bf1 100644
--- 
a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventElement.java
+++ 
b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventElement.java
@@ -35,6 +35,9 @@ public class SinkEventElement {
     /** The array of arguments to the sink method. */
     private final Object[] args;
 
+    /** The line number of the source which emitted the event (-1 if unknown) 
*/
+    private final int lineNumber;
+
     /**
      * A SinkEventElement is characterized by the method name and associated 
array of arguments.
      *
@@ -42,11 +45,12 @@ public class SinkEventElement {
      * @param arguments The array of arguments to the sink method.
      *      For a no-arg element this may be null or an empty array.
      */
-    public SinkEventElement(String name, Object[] arguments) {
+    public SinkEventElement(String name, Object[] arguments, int lineNumber) {
         Objects.requireNonNull(name, "name cannot be null");
 
         this.methodName = name;
         this.args = arguments;
+        this.lineNumber = lineNumber;
     }
 
     /**
@@ -77,6 +81,10 @@ public class SinkEventElement {
         builder.append(this.getClass().getSimpleName()).append('[');
         builder.append("methodName: ").append(methodName).append(", ");
         builder.append("args: ").append(Arrays.deepToString(args));
+        if (lineNumber != -1) {
+            builder.append(", ");
+            builder.append("lineNumber: ").append(lineNumber);
+        }
         builder.append(']');
         return builder.toString();
     }
diff --git 
a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventTestingSink.java
 
b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventTestingSink.java
index 17bd4884..3a35f8fd 100644
--- 
a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventTestingSink.java
+++ 
b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventTestingSink.java
@@ -558,6 +558,6 @@ public class SinkEventTestingSink extends AbstractSink {
      * @param arguments The array of arguments to the sink method.
      */
     private void addEvent(String string, Object[] arguments) {
-        events.add(new SinkEventElement(string, arguments));
+        events.add(new SinkEventElement(string, arguments, 
getDocumentLocator().getLineNumber()));
     }
 }
diff --git 
a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSink.java
 
b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSink.java
index 9d95224a..fa07703f 100644
--- 
a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSink.java
+++ 
b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSink.java
@@ -152,7 +152,7 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
         final boolean requiresBuffering;
 
         /**
-         * prefix to be used for a (nested) block elements inside the current 
container context (only not empty for {@link #type} being {@link 
Type#CONTAINER_BLOCK})
+         * prefix to be used for each line of (nested) block elements inside 
the current container context (only not empty for {@link #type} being {@link 
Type#CONTAINER_BLOCK})
          */
         final String prefix;
 
@@ -248,13 +248,18 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
             throw new IllegalStateException("Unexpected context " + 
removedContext + ", expected " + expectedContext);
         }
         if (removedContext.isBlock()) {
-            endBlock(removedContext.requiresSurroundingByBlankLines);
+            endBlock(removedContext.requiresSurroundingByBlankLines
+                    || (isInListItem() && (removedContext == 
ElementContext.BLOCKQUOTE)
+                            || (removedContext == ElementContext.CODE_BLOCK)));
         }
     }
 
     private void startContext(ElementContext newContext) {
         if (newContext.isBlock()) {
-            startBlock(newContext.requiresSurroundingByBlankLines);
+            // every block element within a list item must
+            startBlock(newContext.requiresSurroundingByBlankLines
+                    || (isInListItem() && (newContext == 
ElementContext.BLOCKQUOTE)
+                            || (newContext == ElementContext.CODE_BLOCK)));
         }
         elementContextStack.add(newContext);
     }
@@ -291,7 +296,7 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
         } else {
             ensureBeginningOfLine();
         }
-        writeUnescaped(getContainerLinePrefixes());
+        writeUnescaped(getLinePrefix());
     }
 
     private void endBlock(boolean requireBlankLine) {
@@ -302,12 +307,21 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
         }
     }
 
-    private String getContainerLinePrefixes() {
+    /**
+     * @return the prefix to be used for each line in the current context 
(i.e. the prefix of the current container context and all its ancestors), may 
be empty
+     */
+    private String getLinePrefix() {
         StringBuilder prefix = new StringBuilder();
         elementContextStack.stream().filter(c -> c.prefix.length() > 
0).forEachOrdered(c -> prefix.insert(0, c.prefix));
         return prefix.toString();
     }
 
+    private boolean isInListItem() {
+        return elementContextStack.stream()
+                .filter(c -> c == ElementContext.LIST_ITEM)
+                .findFirst()
+                .isPresent();
+    }
     /**
      * Returns the buffer that holds the current text.
      *
@@ -512,7 +526,7 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
         // ignore paragraphs outside container contexts
         if (elementContextStack.element().isContainer()) {
             ensureBlankLine();
-            writeUnescaped(getContainerLinePrefixes());
+            writeUnescaped(getLinePrefix());
         }
     }
 
@@ -529,13 +543,13 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
         // always assume is supposed to be monospaced (i.e. emitted inside a 
<pre><code>...</code></pre>)
         startContext(ElementContext.CODE_BLOCK);
         writeUnescaped(VERBATIM_START_MARKUP + EOL);
-        writeUnescaped(getContainerLinePrefixes());
+        writeUnescaped(getLinePrefix());
     }
 
     @Override
     public void verbatim_() {
         ensureBeginningOfLine();
-        writeUnescaped(getContainerLinePrefixes());
+        writeUnescaped(getLinePrefix());
         writeUnescaped(VERBATIM_END_MARKUP + BLANK_LINE);
         endContext(ElementContext.CODE_BLOCK);
     }
@@ -555,13 +569,13 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
     public void horizontalRule(SinkEventAttributes attributes) {
         ensureBeginningOfLine();
         writeUnescaped(HORIZONTAL_RULE_MARKUP + BLANK_LINE);
-        writeUnescaped(getContainerLinePrefixes());
+        writeUnescaped(getLinePrefix());
     }
 
     @Override
     public void table(SinkEventAttributes attributes) {
         ensureBlankLine();
-        writeUnescaped(getContainerLinePrefixes());
+        writeUnescaped(getLinePrefix());
     }
 
     @Override
@@ -621,7 +635,7 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
             writeUnescaped(StringUtils.repeat(String.valueOf(SPACE), 3) + 
TABLE_CELL_SEPARATOR_MARKUP);
         }
         writeUnescaped(EOL);
-        writeUnescaped(getContainerLinePrefixes());
+        writeUnescaped(getLinePrefix());
     }
 
     /** Emit the delimiter row which determines the alignment */
@@ -868,7 +882,7 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
         } else {
             writeUnescaped("" + SPACE + SPACE + EOL);
         }
-        writeUnescaped(getContainerLinePrefixes());
+        writeUnescaped(getLinePrefix());
     }
 
     @Override
@@ -887,6 +901,14 @@ public class MarkdownSink extends AbstractTextSink 
implements MarkdownMarkup {
             LOGGER.warn("{}Ignoring unsupported table caption in Markdown", 
getLocationLogPrefix());
         } else {
             String unifiedText = currentContext.escape(unifyEOLs(text));
+            // ignore newlines only, because those are emitted often coming 
from linebreaks in HTML with no semantical
+            // meaning
+            if (!unifiedText.equals(EOL)) {
+                String prefix = getLinePrefix();
+                if (prefix.length() > 0) {
+                    unifiedText = unifiedText.replaceAll(EOL, EOL + prefix);
+                }
+            }
             writeUnescaped(unifiedText);
         }
         if (attributes != null) {
diff --git 
a/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownSinkTest.java
 
b/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownSinkTest.java
index d9d29345..e3c3a89a 100644
--- 
a/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownSinkTest.java
+++ 
b/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownSinkTest.java
@@ -33,11 +33,10 @@ import org.apache.maven.doxia.sink.impl.AbstractSinkTest;
 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
 import org.apache.maven.doxia.sink.impl.SinkEventTestingSink;
 import org.apache.maven.doxia.util.HtmlTools;
-import org.hamcrest.MatcherAssert;
-import org.hamcrest.Matchers;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertIterableEquals;
 
 /**
  * Test the <code>MarkdownSink</code> class
@@ -377,12 +376,11 @@ public class MarkdownSinkTest extends AbstractSinkTest {
 
         final SinkEventTestingSink originalSink = new SinkEventTestingSink();
         parseFile(parser, "test", originalSink);
+        // strip empty lines from sink content
 
         // compare sink events from parsing original markdown with sink events 
from re-generated markdown
         try {
-            MatcherAssert.assertThat(
-                    regeneratedSink.getEventList(),
-                    Matchers.contains(originalSink.getEventList().toArray()));
+            assertIterableEquals(originalSink.getEventList(), 
regeneratedSink.getEventList());
         } catch (AssertionError e) {
             // emit generated markdown to ease debugging
             System.err.println(getSinkContent());
@@ -488,13 +486,13 @@ public class MarkdownSinkTest extends AbstractSinkTest {
         String expected = "- item1" + EOL
                 + "    - item1a" + EOL
                 + EOL
-                + "- " + EOL
-                + "    > blockquote" + EOL
+                + "- " + EOL + EOL
+                + "    > blockquote" + EOL + EOL
                 + "- item3" + EOL
                 + EOL
                 + "    item3paragraph2" + EOL
                 + EOL
-                + "- item4" + EOL
+                + "- item4" + EOL + EOL
                 + "    ```" + EOL
                 + "    item4verbatim" + EOL
                 + "    item4verbatimline2" + EOL
@@ -519,6 +517,26 @@ public class MarkdownSinkTest extends AbstractSinkTest {
         assertEquals(expected, getSinkContent(), "Wrong heading after inline 
element!");
     }
 
+    @Test
+    public void testMultilineVerbatimSourceAfterListItem() {
+        try (final Sink sink = getSink()) {
+            sink.list();
+            sink.listItem();
+            sink.text("Before");
+            sink.verbatim(SinkEventAttributeSet.SOURCE);
+            sink.text("codeline1" + EOL + "codeline2");
+            sink.verbatim_();
+            sink.text("After");
+            sink.listItem_();
+            sink.list_();
+        }
+
+        String expected = "- Before" + EOL + EOL + MarkdownMarkup.INDENT + 
MarkdownMarkup.VERBATIM_START_MARKUP + EOL
+                + MarkdownMarkup.INDENT + "codeline1" + EOL + 
MarkdownMarkup.INDENT + "codeline2" + EOL
+                + MarkdownMarkup.INDENT + MarkdownMarkup.VERBATIM_END_MARKUP + 
EOL + EOL + "After" + EOL + EOL;
+        assertEquals(expected, getSinkContent(), "Wrong verbatim!");
+    }
+
     @Test
     public void testDefinitionListWithInlineStyles() {
         try (final Sink sink = getSink()) {

Reply via email to