From 5221a72b54c90f7866bd561924423798c1655604 Mon Sep 17 00:00:00 2001 From: Konrad Windszus Date: Tue, 8 Oct 2024 15:11:35 +0200 Subject: [PATCH] [DOXIA-746] Sink API: add method for block comment Add tests for consecutive comments --- .../maven/doxia/sink/impl/Xhtml5BaseSink.java | 48 +++++++++------- .../doxia/sink/impl/AbstractSinkTest.java | 57 +++++++++++++++++++ .../maven/doxia/module/apt/AptParser.java | 2 +- .../maven/doxia/module/apt/AptSink.java | 10 ++-- .../maven/doxia/module/apt/AptParserTest.java | 30 ++++++++++ .../maven/doxia/module/apt/AptSinkTest.java | 19 ++++++- .../src/test/resources/test/comments2.apt | 6 ++ .../doxia/module/markdown/MarkdownSink.java | 16 ++++-- .../module/markdown/MarkdownSinkTest.java | 9 ++- .../maven/doxia/module/xdoc/XdocSinkTest.java | 7 ++- .../doxia/module/xhtml5/Xhtml5SinkTest.java | 7 ++- .../org/apache/maven/doxia/sink/Sink.java | 11 ++++ 12 files changed, 188 insertions(+), 34 deletions(-) create mode 100644 doxia-modules/doxia-module-apt/src/test/resources/test/comments2.apt diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java index bbe3107e6..29387849c 100644 --- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java +++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java @@ -1403,7 +1403,7 @@ public void lineBreakOpportunity(SinkEventAttributes attributes) { /** {@inheritDoc} */ @Override public void pageBreak() { - comment(" PB "); + comment(" PB ", false); } /** {@inheritDoc} */ @@ -1444,34 +1444,44 @@ public void rawText(String text) { } } - /** {@inheritDoc} */ @Override public void comment(String comment) { + comment(comment, false); + } + + /** {@inheritDoc} */ + @Override + public void comment(String comment, boolean isBlockComment) { if (comment != null) { - final String originalComment = comment; + write(encodeAsHtmlComment(comment, isBlockComment, getLocationLogPrefix())); + } + } - // http://www.w3.org/TR/2000/REC-xml-20001006#sec-comments - while (comment.contains("--")) { - comment = comment.replace("--", "- -"); - } + public static String encodeAsHtmlComment(String comment, boolean isBlockComment, String locationLogPrefix) { + final String originalComment = comment; - if (comment.endsWith("-")) { - comment += " "; - } + // http://www.w3.org/TR/2000/REC-xml-20001006#sec-comments + while (comment.contains("--")) { + comment = comment.replace("--", "- -"); + } - if (!originalComment.equals(comment)) { - LOGGER.warn( - "{}Modified invalid comment '{}' to '{}'", getLocationLogPrefix(), originalComment, comment); - } + if (comment.endsWith("-")) { + comment += " "; + } - final StringBuilder buffer = new StringBuilder(comment.length() + 7); + if (!originalComment.equals(comment)) { + LOGGER.warn("{}Modified invalid comment '{}' to '{}'", locationLogPrefix, originalComment, comment); + } - buffer.append(LESS_THAN).append(BANG).append(MINUS).append(MINUS); - buffer.append(comment); - buffer.append(MINUS).append(MINUS).append(GREATER_THAN); + final StringBuilder buffer = new StringBuilder(comment.length() + 7); - write(buffer.toString()); + buffer.append(LESS_THAN).append(BANG).append(MINUS).append(MINUS); + buffer.append(comment); + buffer.append(MINUS).append(MINUS).append(GREATER_THAN); + if (isBlockComment) { + buffer.append(EOL); } + return buffer.toString(); } /** diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/AbstractSinkTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/AbstractSinkTest.java index e109bad15..5cd096d2c 100644 --- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/AbstractSinkTest.java +++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/AbstractSinkTest.java @@ -1142,6 +1142,54 @@ public void testComment() { assertEquals(expected, actual, "Wrong comment!"); } + /** + * Checks the line separator between two consecutive comments. + */ + @Test + public void testTwoConsecutiveInlineComments() { + String comment = "Simple comment"; + sink.comment(comment); + sink.comment(comment); + sink.flush(); + sink.close(); + assertEquals(getCommentBlock(comment) + getCommentBlock(comment), testWriter.toString(), "Wrong comment!"); + } + + /** + * Checks the line separator between two consecutive comments. + */ + @Test + public void testTwoConsecutiveBlockComments() { + String comment = "Simple comment"; + sink.comment(comment, true); + sink.comment(comment, true); + sink.flush(); + sink.close(); + assertEquals( + getCommentBlock(comment) + EOL + getCommentBlock(comment) + EOL, + testWriter.toString(), + "Wrong comment!"); + } + + /** + * Checks the line separator between comment and paragraph (in most markup languages a block element which needs to start in the new line) + */ + @Test + public void testCommentFollowedByParagraph() { + String comment = "Simple comment"; + sink.comment(comment); + sink.paragraph(); + sink.text("Paragraph"); + sink.paragraph_(); + sink.flush(); + sink.close(); + + String actual = testWriter.toString(); + String expected = getCommentBlockFollowedByParagraph(comment, "Paragraph"); + + assertEquals(expected, actual, "Wrong comment!"); + } + // ---------------------------------------------------------------------- // Utility methods // ---------------------------------------------------------------------- @@ -1545,6 +1593,15 @@ protected String getOutputDir() { */ protected abstract String getCommentBlock(String text); + /** + * Returns a comment block generated by this sink followed by a paragraph block + * @param text The text to use. + * @return The result of invoking a comment block followed by a paragraph block on the current sink. + * @see #testCommentFollowedByParagraph() + * @since 2.1.0 + */ + protected abstract String getCommentBlockFollowedByParagraph(String comment, String paragraph); + protected final void verifyValignSup(String text) { sink.text("ValignSup", new SinkEventAttributeSet(SinkEventAttributes.VALIGN, "sup")); sink.flush(); diff --git a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java index 52e8ec5a0..2d9c8eb88 100644 --- a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java +++ b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java @@ -1855,7 +1855,7 @@ private class Comment extends Block { /** {@inheritDoc} */ public void traverse() throws AptParseException { if (isEmitComments()) { - AptParser.this.sink.comment(text); + AptParser.this.sink.comment(text, true); } } } diff --git a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java index 656f1efc6..8df6368bf 100644 --- a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java +++ b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java @@ -209,9 +209,6 @@ public void head(SinkEventAttributes attributes) { public void head_() { headerFlag = false; - if (!startFlag) { - write(EOL); - } write(HEADER_START_MARKUP + EOL); if (title != null) { write(" " + title + EOL); @@ -839,7 +836,12 @@ public void rawText(String text) { /** {@inheritDoc} */ public void comment(String comment) { - rawText((startFlag ? "" : EOL) + COMMENT + COMMENT + comment); + comment(comment, false); + } + + @Override + public void comment(String comment, boolean isBlockComment) { + rawText("" + COMMENT + COMMENT + comment + EOL); // comments are always block comments in APT } /** diff --git a/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptParserTest.java b/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptParserTest.java index c6a6a501c..e6efe4bd2 100644 --- a/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptParserTest.java +++ b/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptParserTest.java @@ -85,6 +85,36 @@ public void testCommentsBeforeTitle() throws Exception { + " -----" + EOL + " Test DOXIA-379")); } + @Test + public void testCommentsAfterParagraph() throws Exception { + SinkEventTestingSink sink = new SinkEventTestingSink(); + try (Reader reader = getTestReader("test/comments2")) { + createParser().parse(reader, sink); + } + + Iterator it = sink.getEventList().iterator(); + + assertSinkEquals( + it, + "head", + "head_", + "body", + "section1", + "sectionTitle1", + "text", + "sectionTitle1_", + "paragraph", + "text", + "paragraph_", + "comment", // a comment implicitly ends a paragraph (similar to an empty line) + "comment", + "paragraph", + "text", + "paragraph_", + "section1_", + "body_"); + } + @Test public void testSnippet() throws Exception { // DOXIA-259 diff --git a/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptSinkTest.java b/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptSinkTest.java index 3e23c073e..f27e23d81 100644 --- a/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptSinkTest.java +++ b/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptSinkTest.java @@ -355,7 +355,24 @@ private static String getSpecialCharacters(char c) { /** {@inheritDoc} */ protected String getCommentBlock(String text) { - return "~~" + text; + return "~~" + text + EOL; + } + + @Override + protected String getCommentBlockFollowedByParagraph(String comment, String paragraph) { + return getCommentBlock(comment) + getParagraphBlock(paragraph); + } + + /* Overwrite the test from AbstractSinkTest as EOLs are part of getCommentBlock(...) */ + @Test + public void testTwoConsecutiveBlockComments() { + final Sink sink = getSink(); + String comment = "Simple comment"; + sink.comment(comment, true); + sink.comment(comment, true); + sink.flush(); + sink.close(); + assertEquals(getCommentBlock(comment) + getCommentBlock(comment), getSinkContent(), "Wrong comment!"); } /** diff --git a/doxia-modules/doxia-module-apt/src/test/resources/test/comments2.apt b/doxia-modules/doxia-module-apt/src/test/resources/test/comments2.apt new file mode 100644 index 000000000..12c62721e --- /dev/null +++ b/doxia-modules/doxia-module-apt/src/test/resources/test/comments2.apt @@ -0,0 +1,6 @@ +Section Title + + paragraph +~~ some comment +~~ another comment + text 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 91dceae90..7fdcd5f74 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 @@ -35,6 +35,7 @@ import org.apache.maven.doxia.sink.SinkEventAttributes; import org.apache.maven.doxia.sink.impl.AbstractTextSink; import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet; +import org.apache.maven.doxia.sink.impl.Xhtml5BaseSink; import org.apache.maven.doxia.util.HtmlTools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -93,13 +94,13 @@ public class MarkdownSink extends AbstractTextSink implements MarkdownMarkup { private String figureSrc; - /** Most important contextual metadata (of the surrounding element) */ + /** Most important contextual metadata (of elements). This contains information about necessary escaping rules, potential prefixes and newlines */ enum ElementContext { HEAD("head", Type.GENERIC_CONTAINER, null, true), BODY("body", Type.GENERIC_CONTAINER, MarkdownSink::escapeMarkdown), // only the elements, which affect rendering of children and are different from BODY or HEAD are listed here FIGURE("", Type.INLINE, MarkdownSink::escapeMarkdown, true), - CODE_BLOCK("code block", Type.LEAF_BLOCK, null, false), + CODE_BLOCK("code block", Type.LEAF_BLOCK, null), CODE_SPAN("code span", Type.INLINE, null), TABLE_CAPTION("table caption", Type.INLINE, MarkdownSink::escapeMarkdown), TABLE_CELL( @@ -269,8 +270,8 @@ private void ensureBeginningOfLine() { } /** - * Ensures that the {@link #writer} is either at the beginning or preceded by a blank line. - * Optionally writes a blank line to ensure that. + * Ensures that the {@link #writer} is preceded by a blank line. + * Optionally writes a blank line or just line delimiter to ensure that. */ private void ensureBlankLine() { // prevent duplicate blank lines @@ -882,7 +883,12 @@ public void rawText(String text) { @Override public void comment(String comment) { - rawText(COMMENT_START + comment + COMMENT_END); + comment(comment, false); + } + + @Override + public void comment(String comment, boolean isBlockComment) { + rawText(Xhtml5BaseSink.encodeAsHtmlComment(comment, isBlockComment, getLocationLogPrefix())); } /** 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 44d1162e4..beb386d4f 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 @@ -332,9 +332,14 @@ private String getEscapedText(String text) { return text.replaceAll("\\\\|\\`|\\*|_|\\{|\\}|\\[|\\]|\\(|\\)|#|\\+|\\-|\\.|\\!", "\\\\$0"); } - /** {@inheritDoc} */ + @Override protected String getCommentBlock(String text) { - return ""; + return ""; + } + + @Override + protected String getCommentBlockFollowedByParagraph(String comment, String paragraph) { + return getCommentBlock(comment) + EOL + EOL + getParagraphBlock(paragraph); // paragraph separated by blank line } @Test diff --git a/doxia-modules/doxia-module-xdoc/src/test/java/org/apache/maven/doxia/module/xdoc/XdocSinkTest.java b/doxia-modules/doxia-module-xdoc/src/test/java/org/apache/maven/doxia/module/xdoc/XdocSinkTest.java index de16c6afe..3f0315c44 100644 --- a/doxia-modules/doxia-module-xdoc/src/test/java/org/apache/maven/doxia/module/xdoc/XdocSinkTest.java +++ b/doxia-modules/doxia-module-xdoc/src/test/java/org/apache/maven/doxia/module/xdoc/XdocSinkTest.java @@ -373,8 +373,13 @@ public void testLinkWithTarget() { assertEquals("", writer.toString()); } - /** {@inheritDoc} */ + @Override protected String getCommentBlock(String text) { return ""; } + + @Override + protected String getCommentBlockFollowedByParagraph(String comment, String paragraph) { + return getCommentBlock(comment) + getParagraphBlock(paragraph); // no line break in between + } } diff --git a/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkTest.java b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkTest.java index 875c246a1..c125ee116 100644 --- a/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkTest.java +++ b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkTest.java @@ -404,8 +404,13 @@ public void testHead() { assertTrue(actual.contains(expected), actual); } - /** {@inheritDoc} */ + @Override protected String getCommentBlock(String text) { return ""; } + + @Override + protected String getCommentBlockFollowedByParagraph(String comment, String paragraph) { + return getCommentBlock(comment) + getParagraphBlock(paragraph); // no line break in between + } } diff --git a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java index ec4d28331..c33c346a6 100644 --- a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java +++ b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java @@ -1724,6 +1724,17 @@ public interface Sink extends AutoCloseable { */ void comment(String comment); + /** + * Add a comment. The default implementation will just call {@link #comment(String)}. + * + * @param comment The comment to write. + * @param isBlockComment If true this is a block comment, i.e. nothing should follow on the same line + * @since 2.1 + */ + default void comment(String comment, boolean isBlockComment) { + comment(comment); + } + /** * Add an unknown event. This may be used by parsers to notify a general Sink about * an event that doesn't fit into any event defined by the Sink API.