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 b3c046b5 Fallback to HTML markup inside HTML blocks
b3c046b5 is described below
commit b3c046b5ca78876e8ec40c74ab0fcbd87330802d
Author: Konrad Windszus <[email protected]>
AuthorDate: Tue Nov 4 16:10:06 2025 +0100
Fallback to HTML markup inside HTML blocks
Call the Xhtml5BaseSink (super class) whenever markup is not allowed (in
an HTML context)
Add test for link inside html block
This closes #1015
---
.../maven/doxia/sink/impl/AbstractSinkTest.java | 2 +-
.../maven/doxia/module/markdown/MarkdownSink.java | 561 +++++++++++++--------
.../doxia/module/markdown/MarkdownSinkFactory.java | 2 +-
.../doxia/module/markdown/MarkdownSinkTest.java | 45 +-
4 files changed, 380 insertions(+), 230 deletions(-)
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 87658e82..5e5cc0c2 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
@@ -471,7 +471,7 @@ public abstract class AbstractSinkTest extends
AbstractModuleTest {
/**
* Checks that the sequence <code>[footer(), footer_()]</code>,
* invoked on the current sink, produces the same result as
- * {@link #getHeaderBlock getHeaderBlock()}.
+ * {@link #getFooterBlock()}.
*/
@Test
public void footer() {
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 1464343c..e40d59dd 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
@@ -18,8 +18,6 @@
*/
package org.apache.maven.doxia.module.markdown;
-import javax.swing.text.MutableAttributeSet;
-
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
@@ -34,12 +32,9 @@ import java.util.stream.Collectors;
import org.apache.maven.doxia.sink.Sink;
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.SinkUtils;
import org.apache.maven.doxia.sink.impl.Xhtml5BaseSink;
import org.apache.maven.doxia.util.DoxiaStringUtils;
-import org.apache.maven.doxia.util.DoxiaUtils;
import org.apache.maven.doxia.util.HtmlTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,8 +43,9 @@ import org.slf4j.LoggerFactory;
* Markdown generator implementation.
* <br>
* <b>Note</b>: The encoding used is UTF-8.
+ * Extends the Xhtml5 sink as in some context HTML needs to be emitted.
*/
-public class MarkdownSink extends AbstractTextSink implements MarkdownMarkup {
+public class MarkdownSink extends Xhtml5BaseSink implements MarkdownMarkup {
private static final Logger LOGGER =
LoggerFactory.getLogger(MarkdownSink.class);
// ----------------------------------------------------------------------
@@ -93,10 +89,10 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
private final LastTwoLinesBufferingWriter bufferingWriter;
/** Keep track of end markup for inline events. */
- protected Queue<Queue<String>> inlineStack = Collections.asLifoQueue(new
LinkedList<>());
+ protected Queue<Queue<String>> inlineStack;
/** The context of the surrounding elements as stack (LIFO) */
- protected Queue<ElementContext> elementContextStack =
Collections.asLifoQueue(new LinkedList<>());
+ protected Queue<ElementContext> elementContextStack;
private String figureSrc;
@@ -220,6 +216,13 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
return type == Type.CONTAINER_BLOCK || type == Type.LEAF_BLOCK;
}
+ /**
+ *
+ * @return {@code true} if only HTML is allowed in this context
+ */
+ boolean isHtml() {
+ return this.equals(HTML_BLOCK);
+ }
/**
*
* @return {@code true} for all containers (allowing block elements as
children), {@code false} otherwise
@@ -332,14 +335,20 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
// Public protected methods
// ----------------------------------------------------------------------
+ protected static MarkdownSink newInstance(Writer writer) {
+ LastTwoLinesBufferingWriter bufferingWriter = new
LastTwoLinesBufferingWriter(writer);
+ return new MarkdownSink(bufferingWriter, new
PrintWriter(bufferingWriter));
+ }
+
/**
* Constructor, initialize the Writer and the variables.
*
* @param writer not null writer to write the result. <b>Should</b> be an
UTF-8 Writer.
*/
- protected MarkdownSink(Writer writer) {
- this.bufferingWriter = new LastTwoLinesBufferingWriter(writer);
- this.writer = new PrintWriter(bufferingWriter);
+ private MarkdownSink(LastTwoLinesBufferingWriter bufferingWriter,
PrintWriter writer) {
+ super(writer);
+ this.bufferingWriter = bufferingWriter;
+ this.writer = writer;
init();
}
@@ -467,8 +476,8 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
this.tableHeaderCellFlag = false;
this.cellCount = 0;
this.cellJustif = null;
- this.elementContextStack.clear();
- this.inlineStack.clear();
+ this.elementContextStack = Collections.asLifoQueue(new LinkedList<>());
+ this.inlineStack = Collections.asLifoQueue(new LinkedList<>());
// always set a default context (at least for tests not emitting a
body)
elementContextStack.add(ElementContext.BODY);
}
@@ -539,6 +548,26 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
}
}
+ @Override
+ public void section(int level, SinkEventAttributes attributes) {
+ // not supported as often used around sectionTitles which would
otherwise no longer be emitted as markdown
+ }
+
+ @Override
+ public void section_(int level) {
+ // not supported as often used around sectionTitles which would
otherwise no longer be emitted as markdown
+ }
+
+ @Override
+ public void header(SinkEventAttributes attributes) {
+ // not supported as often used around sectionTitles which would
otherwise no longer be emitted as markdown
+ }
+
+ @Override
+ public void header_() {
+ // not supported as often used around sectionTitles which would
otherwise no longer be emitted as markdown
+ }
+
@Override
public void sectionTitle(int level, SinkEventAttributes attributes) {
startContext(ElementContext.HEADING);
@@ -556,6 +585,13 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
}
}
+ @Override
+ public void list(SinkEventAttributes attributes) {
+ if (elementContextStack.element().isHtml()) {
+ super.list(attributes);
+ }
+ }
+
@Override
public void list_() {
ensureBeginningOfLine();
@@ -641,9 +677,9 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
@Override
public void paragraph(SinkEventAttributes attributes) {
+ ensureBlankLine();
// ignore paragraphs outside container contexts
if (elementContextStack.element().isContainer()) {
- ensureBlankLine();
writeUnescaped(getLinePrefix());
}
}
@@ -658,33 +694,49 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
@Override
public void verbatim(SinkEventAttributes attributes) {
- // if no source attribute, then don't emit an info string
- startContext(ElementContext.CODE_BLOCK);
- writeUnescaped(VERBATIM_START_MARKUP);
- if (attributes != null &&
attributes.containsAttributes(SinkEventAttributeSet.SOURCE)) {
- writeUnescaped("unknown"); // unknown language
+ if (elementContextStack.element().isHtml()) {
+ super.verbatim(attributes);
+ } else {
+ // if no source attribute, then don't emit an info string
+ startContext(ElementContext.CODE_BLOCK);
+ writeUnescaped(VERBATIM_START_MARKUP);
+ if (attributes != null &&
attributes.containsAttributes(SinkEventAttributeSet.SOURCE)) {
+ writeUnescaped("unknown"); // unknown language
+ }
+ writeUnescaped(EOL);
+ writeUnescaped(getLinePrefix());
}
- writeUnescaped(EOL);
- writeUnescaped(getLinePrefix());
}
@Override
public void verbatim_() {
- ensureBeginningOfLine();
- writeUnescaped(getLinePrefix());
- writeUnescaped(VERBATIM_END_MARKUP + BLANK_LINE);
- endContext(ElementContext.CODE_BLOCK);
+ if (elementContextStack.element().isHtml()) {
+ super.verbatim_();
+ } else {
+ ensureBeginningOfLine();
+ writeUnescaped(getLinePrefix());
+ writeUnescaped(VERBATIM_END_MARKUP + BLANK_LINE);
+ endContext(ElementContext.CODE_BLOCK);
+ }
}
@Override
public void blockquote(SinkEventAttributes attributes) {
- startContext(ElementContext.BLOCKQUOTE);
- writeUnescaped(BLOCKQUOTE_START_MARKUP);
+ if (elementContextStack.element().isHtml()) {
+ super.blockquote(attributes);
+ } else {
+ startContext(ElementContext.BLOCKQUOTE);
+ writeUnescaped(BLOCKQUOTE_START_MARKUP);
+ }
}
@Override
public void blockquote_() {
- endContext(ElementContext.BLOCKQUOTE);
+ if (elementContextStack.element().isHtml()) {
+ super.blockquote_();
+ } else {
+ endContext(ElementContext.BLOCKQUOTE);
+ }
}
@Override
@@ -696,58 +748,82 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
@Override
public void table(SinkEventAttributes attributes) {
- ensureBlankLine();
- writeUnescaped(getLinePrefix());
+ if (elementContextStack.element().isHtml()) {
+ super.table(attributes);
+ } else {
+ ensureBlankLine();
+ writeUnescaped(getLinePrefix());
+ }
+ }
+
+ @Override
+ public void table_() {
+ if (elementContextStack.element().isHtml()) {
+ super.table_();
+ }
}
@Override
public void tableRows(int[] justification, boolean grid) {
- if (justification != null) {
- cellJustif =
Arrays.stream(justification).boxed().collect(Collectors.toCollection(ArrayList::new));
+ if (elementContextStack.element().isHtml()) {
+ super.tableRows(justification, grid);
} else {
- cellJustif = new ArrayList<>();
+ if (justification != null) {
+ cellJustif =
Arrays.stream(justification).boxed().collect(Collectors.toCollection(ArrayList::new));
+ } else {
+ cellJustif = new ArrayList<>();
+ }
+ // grid flag is not supported
+ isFirstTableRow = true;
}
- // grid flag is not supported
- isFirstTableRow = true;
}
@Override
public void tableRows_() {
- cellJustif = null;
+ if (elementContextStack.element().isHtml()) {
+ super.tableRows_();
+ } else {
+ cellJustif = null;
+ }
}
@Override
public void tableRow(SinkEventAttributes attributes) {
- startContext(ElementContext.TABLE_ROW);
- cellCount = 0;
+ if (elementContextStack.element().isHtml()) {
+ super.tableRow(attributes);
+ } else {
+ startContext(ElementContext.TABLE_ROW);
+ cellCount = 0;
+ }
}
@Override
public void tableRow_() {
- String buffer = consumeBuffer();
- endContext(ElementContext.TABLE_ROW);
- if (isFirstTableRow && !tableHeaderCellFlag) {
- // emit empty table header as this is mandatory for GFM table
extension
- // (https://stackoverflow.com/a/17543474/5155923)
- writeEmptyTableHeader();
- writeTableDelimiterRow();
- tableHeaderCellFlag = false;
- isFirstTableRow = false;
- // afterwards emit the first row
- }
-
- writeUnescaped(TABLE_ROW_PREFIX);
- writeUnescaped(buffer);
- writeUnescaped(EOL);
-
- if (isFirstTableRow) {
- // emit delimiter row
- writeTableDelimiterRow();
- isFirstTableRow = false;
+ if (elementContextStack.element().isHtml()) {
+ super.tableRow_();
+ } else {
+ String buffer = consumeBuffer();
+ endContext(ElementContext.TABLE_ROW);
+ if (isFirstTableRow && !tableHeaderCellFlag) {
+ // emit empty table header as this is mandatory for GFM table
extension
+ // (https://stackoverflow.com/a/17543474/5155923)
+ writeEmptyTableHeader();
+ writeTableDelimiterRow();
+ tableHeaderCellFlag = false;
+ isFirstTableRow = false;
+ // afterwards emit the first row
+ }
+ writeUnescaped(TABLE_ROW_PREFIX);
+ writeUnescaped(buffer);
+ writeUnescaped(EOL);
+ if (isFirstTableRow) {
+ // emit delimiter row
+ writeTableDelimiterRow();
+ isFirstTableRow = false;
+ }
+ // only reset cell count if this is the last row
+ cellCount = 0;
}
-
- // only reset cell count if this is the last row
- cellCount = 0;
}
private void writeEmptyTableHeader() {
@@ -789,30 +865,34 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
@Override
public void tableCell(SinkEventAttributes attributes) {
- startContext(ElementContext.TABLE_CELL);
- if (attributes != null) {
- // evaluate alignment attributes
- final int cellJustification;
- if (attributes.containsAttributes(SinkEventAttributeSet.LEFT)) {
- cellJustification = Sink.JUSTIFY_LEFT;
- } else if
(attributes.containsAttributes(SinkEventAttributeSet.RIGHT)) {
- cellJustification = Sink.JUSTIFY_RIGHT;
- } else if
(attributes.containsAttributes(SinkEventAttributeSet.CENTER)) {
- cellJustification = Sink.JUSTIFY_CENTER;
- } else {
- cellJustification = -1;
- }
- if (cellJustification > -1) {
- if (cellJustif.size() > cellCount) {
- cellJustif.set(cellCount, cellJustification);
- } else if (cellJustif.size() == cellCount) {
- cellJustif.add(cellJustification);
+ if (elementContextStack.element().isHtml()) {
+ super.tableCell(attributes);
+ } else {
+ startContext(ElementContext.TABLE_CELL);
+ if (attributes != null) {
+ // evaluate alignment attributes
+ final int cellJustification;
+ if (attributes.containsAttributes(SinkEventAttributeSet.LEFT))
{
+ cellJustification = Sink.JUSTIFY_LEFT;
+ } else if
(attributes.containsAttributes(SinkEventAttributeSet.RIGHT)) {
+ cellJustification = Sink.JUSTIFY_RIGHT;
+ } else if
(attributes.containsAttributes(SinkEventAttributeSet.CENTER)) {
+ cellJustification = Sink.JUSTIFY_CENTER;
} else {
- // create non-existing justifications for preceding columns
- for (int precedingCol = cellJustif.size(); precedingCol <
cellCount; precedingCol++) {
- cellJustif.add(Sink.JUSTIFY_DEFAULT);
+ cellJustification = -1;
+ }
+ if (cellJustification > -1) {
+ if (cellJustif.size() > cellCount) {
+ cellJustif.set(cellCount, cellJustification);
+ } else if (cellJustif.size() == cellCount) {
+ cellJustif.add(cellJustification);
+ } else {
+ // create non-existing justifications for preceding
columns
+ for (int precedingCol = cellJustif.size();
precedingCol < cellCount; precedingCol++) {
+ cellJustif.add(Sink.JUSTIFY_DEFAULT);
+ }
+ cellJustif.add(cellJustification);
}
- cellJustif.add(cellJustification);
}
}
}
@@ -820,18 +900,30 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
@Override
public void tableHeaderCell(SinkEventAttributes attributes) {
- tableCell(attributes);
- tableHeaderCellFlag = true;
+ if (elementContextStack.element().isHtml()) {
+ super.tableHeaderCell(attributes);
+ } else {
+ tableCell(attributes);
+ tableHeaderCellFlag = true;
+ }
}
@Override
public void tableCell_() {
- endTableCell();
+ if (elementContextStack.element().isHtml()) {
+ super.tableCell_();
+ } else {
+ endTableCell();
+ }
}
@Override
public void tableHeaderCell_() {
- endTableCell();
+ if (elementContextStack.element().isHtml()) {
+ super.tableHeaderCell_();
+ } else {
+ endTableCell();
+ }
}
/**
@@ -845,42 +937,76 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
@Override
public void tableCaption(SinkEventAttributes attributes) {
- elementContextStack.add(ElementContext.TABLE_CAPTION);
+ if (elementContextStack.element().isHtml()) {
+ super.tableCaption(attributes);
+ } else {
+ elementContextStack.add(ElementContext.TABLE_CAPTION);
+ }
}
@Override
public void tableCaption_() {
- endContext(ElementContext.TABLE_CAPTION);
+ if (elementContextStack.element().isHtml()) {
+ super.tableCaption_();
+ } else {
+ endContext(ElementContext.TABLE_CAPTION);
+ }
}
@Override
public void figure(SinkEventAttributes attributes) {
- figureSrc = null;
- startContext(ElementContext.FIGURE);
+ if (elementContextStack.element().isHtml()) {
+ super.figure(attributes);
+ } else {
+ figureSrc = null;
+ startContext(ElementContext.FIGURE);
+ }
+ }
+
+ @Override
+ public void figureCaption(SinkEventAttributes attributes) {
+ if (elementContextStack.element().isHtml()) {
+ super.figureCaption(attributes);
+ }
+ }
+
+ @Override
+ public void figureCaption_() {
+ if (elementContextStack.element().isHtml()) {
+ super.figureCaption_();
+ }
}
@Override
public void figureGraphics(String name, SinkEventAttributes attributes) {
- figureSrc = name;
- // is it a standalone image (outside a figure)?
- if (elementContextStack.peek() != ElementContext.FIGURE) {
- Object alt = attributes.getAttribute(SinkEventAttributes.ALT);
- if (alt == null) {
- alt = "";
+ if (elementContextStack.element().isHtml()) {
+ super.figureGraphics(name, attributes);
+ } else {
+ figureSrc = name;
+ // is it a standalone image (outside a figure)?
+ if (elementContextStack.peek() != ElementContext.FIGURE) {
+ Object alt = attributes.getAttribute(SinkEventAttributes.ALT);
+ if (alt == null) {
+ alt = "";
+ }
+
writeImage(elementContextStack.element().escape(bufferingWriter,
alt.toString()), name);
}
- writeImage(elementContextStack.element().escape(bufferingWriter,
alt.toString()), name);
}
}
@Override
public void figure_() {
- StringBuilder buffer = getCurrentBuffer();
- String label = "";
- if (buffer != null) {
- label = buffer.toString();
+ if (elementContextStack.element().isHtml()) {
+ super.figure_();
+ } else {
+ StringBuilder buffer = getCurrentBuffer();
+ String label = "";
+ if (buffer != null) {
+ label = buffer.toString();
+ }
+ endContext(ElementContext.FIGURE);
+ writeImage(label, figureSrc);
}
- endContext(ElementContext.FIGURE);
- writeImage(label, figureSrc);
}
private void writeImage(String alt, String src) {
@@ -890,123 +1016,129 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
}
public void anchor(String name, SinkEventAttributes attributes) {
- // emit html anchor as markdown does not support anchors
- MutableAttributeSet atts = SinkUtils.filterAttributes(attributes,
SinkUtils.SINK_BASE_ATTRIBUTES);
-
- String id = name;
-
- if (!DoxiaUtils.isValidId(id)) {
- id = DoxiaUtils.encodeId(name);
-
- LOGGER.debug("{}Modified invalid anchor name '{}' to '{}'",
getLocationLogPrefix(), name, id);
+ super.anchor(name, attributes);
+ if (!elementContextStack.element().isHtml()) {
+ // close anchor tag immediately otherwise markdown would not be
allowed afterwards
+ writeUnescaped("</a>");
}
-
- MutableAttributeSet att = new SinkEventAttributeSet();
- att.addAttribute(SinkEventAttributes.ID, id);
- att.addAttributes(atts);
- StringBuilder htmlAnchor = new StringBuilder("<a");
- htmlAnchor.append(SinkUtils.getAttributeString(att));
- htmlAnchor.append(">");
- htmlAnchor.append("</a>"); // close anchor tag immediately otherwise
markdown would not be allowed afterwards
- writeUnescaped(htmlAnchor.toString());
}
@Override
public void anchor_() {
- // anchor is always empty html element, i.e. already closed with
anchor()
+ if (elementContextStack.element().isHtml()) {
+ super.anchor_();
+ } else {
+ // anchor is always empty html element, i.e. already closed with
anchor()
+ }
}
public void link(String name, SinkEventAttributes attributes) {
- if (elementContextStack.element() == ElementContext.CODE_BLOCK) {
- LOGGER.warn("{}Ignoring unsupported link inside code block",
getLocationLogPrefix());
- } else if (elementContextStack.element() == ElementContext.CODE_SPAN) {
- // emit link outside the code span, i.e. insert at the beginning
of the buffer
- getCurrentBuffer().insert(0, LINK_START_1_MARKUP);
- linkName = name;
+ if (elementContextStack.element().isHtml()) {
+ super.link(name, attributes);
} else {
- writeUnescaped(LINK_START_1_MARKUP);
- linkName = name;
+ if (elementContextStack.element() == ElementContext.CODE_BLOCK) {
+ LOGGER.warn("{}Ignoring unsupported link inside code block",
getLocationLogPrefix());
+ } else if (elementContextStack.element() ==
ElementContext.CODE_SPAN) {
+ // emit link outside the code span, i.e. insert at the
beginning of the buffer
+ getCurrentBuffer().insert(0, LINK_START_1_MARKUP);
+ linkName = name;
+ } else {
+ writeUnescaped(LINK_START_1_MARKUP);
+ linkName = name;
+ }
}
}
@Override
public void link_() {
- if (elementContextStack.element() == ElementContext.CODE_BLOCK) {
- return;
- } else if (elementContextStack.element() == ElementContext.CODE_SPAN) {
- // defer emitting link end markup until inline_() is called
- StringBuilder linkEndMarkup = new StringBuilder();
- linkEndMarkup.append(LINK_START_2_MARKUP);
- linkEndMarkup.append(linkName);
- linkEndMarkup.append(LINK_END_MARKUP);
- Queue<String> endMarkups = new LinkedList<>(inlineStack.poll());
- endMarkups.add(linkEndMarkup.toString());
- inlineStack.add(endMarkups);
+ if (elementContextStack.element().isHtml()) {
+ super.link_();
} else {
- writeUnescaped(LINK_START_2_MARKUP + linkName + LINK_END_MARKUP);
+ if (elementContextStack.element() == ElementContext.CODE_BLOCK) {
+ return;
+ } else if (elementContextStack.element() ==
ElementContext.CODE_SPAN) {
+ // defer emitting link end markup until inline_() is called
+ StringBuilder linkEndMarkup = new StringBuilder();
+ linkEndMarkup.append(LINK_START_2_MARKUP);
+ linkEndMarkup.append(linkName);
+ linkEndMarkup.append(LINK_END_MARKUP);
+ Queue<String> endMarkups = new
LinkedList<>(inlineStack.poll());
+ endMarkups.add(linkEndMarkup.toString());
+ inlineStack.add(endMarkups);
+ } else {
+ writeUnescaped(LINK_START_2_MARKUP + linkName +
LINK_END_MARKUP);
+ }
+ linkName = null;
}
- linkName = null;
}
@Override
public void inline(SinkEventAttributes attributes) {
- Queue<String> endMarkups = Collections.asLifoQueue(new LinkedList<>());
-
- boolean requiresHtml = elementContextStack.element() ==
ElementContext.HTML_BLOCK;
- if (attributes != null
- && elementContextStack.element() != ElementContext.CODE_BLOCK
- && elementContextStack.element() != ElementContext.CODE_SPAN) {
- // code excludes other styles in markdown
- if (attributes.containsAttribute(SinkEventAttributes.SEMANTICS,
"code")
- ||
attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "monospaced")
- || attributes.containsAttribute(SinkEventAttributes.STYLE,
"monospaced")) {
- if (requiresHtml) {
- writeUnescaped("<code>");
- endMarkups.add("</code>");
- } else {
- startContext(ElementContext.CODE_SPAN);
- writeUnescaped(MONOSPACED_START_MARKUP);
- endMarkups.add(MONOSPACED_END_MARKUP);
- }
- } else {
- // in XHTML "<em>" is used, but some tests still rely on the
outdated "<italic>"
- if
(attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "emphasis")
- ||
attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "italic")
- ||
attributes.containsAttribute(SinkEventAttributes.STYLE, "italic")) {
+ if (elementContextStack.element().isHtml()) {
+ super.inline(attributes);
+ } else {
+ Queue<String> endMarkups = Collections.asLifoQueue(new
LinkedList<>());
+
+ boolean requiresHtml = elementContextStack.element() ==
ElementContext.HTML_BLOCK;
+ if (attributes != null
+ && elementContextStack.element() !=
ElementContext.CODE_BLOCK
+ && elementContextStack.element() !=
ElementContext.CODE_SPAN) {
+ // code excludes other styles in markdown
+ if
(attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "code")
+ ||
attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "monospaced")
+ ||
attributes.containsAttribute(SinkEventAttributes.STYLE, "monospaced")) {
if (requiresHtml) {
- writeUnescaped("<em>");
- endMarkups.add("</em>");
+ writeUnescaped("<code>");
+ endMarkups.add("</code>");
} else {
- writeUnescaped(ITALIC_START_MARKUP);
- endMarkups.add(ITALIC_END_MARKUP);
+ startContext(ElementContext.CODE_SPAN);
+ writeUnescaped(MONOSPACED_START_MARKUP);
+ endMarkups.add(MONOSPACED_END_MARKUP);
}
- }
- // in XHTML "<strong>" is used, but some tests still rely on
the outdated "<bold>"
- if
(attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "strong")
- ||
attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "bold")
- ||
attributes.containsAttribute(SinkEventAttributes.STYLE, "bold")) {
- if (requiresHtml) {
- writeUnescaped("<strong>");
- endMarkups.add("</strong>");
- } else {
- writeUnescaped(BOLD_START_MARKUP);
- endMarkups.add(BOLD_END_MARKUP);
+ } else {
+ // in XHTML "<em>" is used, but some tests still rely on
the outdated "<italic>"
+ if
(attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "emphasis")
+ ||
attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "italic")
+ ||
attributes.containsAttribute(SinkEventAttributes.STYLE, "italic")) {
+ if (requiresHtml) {
+ writeUnescaped("<em>");
+ endMarkups.add("</em>");
+ } else {
+ writeUnescaped(ITALIC_START_MARKUP);
+ endMarkups.add(ITALIC_END_MARKUP);
+ }
+ }
+ // in XHTML "<strong>" is used, but some tests still rely
on the outdated "<bold>"
+ if
(attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "strong")
+ ||
attributes.containsAttribute(SinkEventAttributes.SEMANTICS, "bold")
+ ||
attributes.containsAttribute(SinkEventAttributes.STYLE, "bold")) {
+ if (requiresHtml) {
+ writeUnescaped("<strong>");
+ endMarkups.add("</strong>");
+ } else {
+ writeUnescaped(BOLD_START_MARKUP);
+ endMarkups.add(BOLD_END_MARKUP);
+ }
}
}
}
+ inlineStack.add(endMarkups);
}
- inlineStack.add(endMarkups);
}
@Override
public void inline_() {
- for (String endMarkup : inlineStack.remove()) {
- if (endMarkup.equals(MONOSPACED_END_MARKUP)) {
- String buffer = getCurrentBuffer().toString();
- endContext(ElementContext.CODE_SPAN);
- writeUnescaped(buffer);
+ if (elementContextStack.element().isHtml()) {
+ super.inline_();
+ } else {
+ for (String endMarkup : inlineStack.remove()) {
+ if (endMarkup.equals(MONOSPACED_END_MARKUP)) {
+ String buffer = getCurrentBuffer().toString();
+ endContext(ElementContext.CODE_SPAN);
+ writeUnescaped(buffer);
+ }
+ writeUnescaped(endMarkup);
}
- writeUnescaped(endMarkup);
}
}
@@ -1057,27 +1189,32 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
@Override
public void text(String text, SinkEventAttributes attributes) {
- if (attributes != null) {
- inline(attributes);
- }
- ElementContext currentContext = elementContextStack.element();
- if (currentContext == ElementContext.TABLE_CAPTION) {
- // table caption cannot even be emitted via XHTML in markdown as
there is no suitable location
- LOGGER.warn("{}Ignoring unsupported table caption in Markdown",
getLocationLogPrefix());
+ if (elementContextStack.element().isHtml()) {
+ super.text(text, attributes);
} else {
- String unifiedText = currentContext.escape(bufferingWriter,
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);
+ if (attributes != null) {
+ inline(attributes);
+ }
+ ElementContext currentContext = elementContextStack.element();
+ if (currentContext == ElementContext.TABLE_CAPTION) {
+ // table caption cannot even be emitted via XHTML in markdown
as there is no suitable location
+ LOGGER.warn("{}Ignoring unsupported table caption in
Markdown", getLocationLogPrefix());
+ } else {
+ String unifiedText = currentContext.escape(bufferingWriter,
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) {
+ inline_();
}
- writeUnescaped(unifiedText);
- }
- if (attributes != null) {
- inline_();
}
}
@@ -1086,16 +1223,6 @@ public class MarkdownSink extends AbstractTextSink
implements MarkdownMarkup {
writeUnescaped(text);
}
- @Override
- public void comment(String comment) {
- comment(comment, false);
- }
-
- @Override
- public void comment(String comment, boolean endsWithLineBreak) {
- rawText(Xhtml5BaseSink.encodeAsHtmlComment(comment, endsWithLineBreak,
getLocationLogPrefix()));
- }
-
/**
* {@inheritDoc}
*
diff --git
a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSinkFactory.java
b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSinkFactory.java
index 6c0b8421..4703a574 100644
---
a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSinkFactory.java
+++
b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownSinkFactory.java
@@ -35,6 +35,6 @@ public class MarkdownSinkFactory extends
AbstractTextSinkFactory {
protected Sink createSink(Writer writer, String encoding) {
// encoding can safely be ignored since it isn't written into the
generated Markdown source
- return new MarkdownSink(writer);
+ return MarkdownSink.newInstance(writer);
}
}
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 f8b847c3..f2f78504 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
@@ -51,7 +51,7 @@ class MarkdownSinkTest extends AbstractSinkTest {
}
protected Sink createSink(Writer writer) {
- return new MarkdownSink(writer);
+ return MarkdownSink.newInstance(writer);
}
protected boolean isXmlSink() {
@@ -79,15 +79,15 @@ class MarkdownSinkTest extends AbstractSinkTest {
}
protected String getArticleBlock() {
- return "";
+ return "<article></article>";
}
protected String getNavigationBlock() {
- return "";
+ return "<nav></nav>";
}
protected String getSidebarBlock() {
- return "";
+ return "<aside></aside>";
}
protected String getSectionBlock(String title, int level) {
@@ -119,15 +119,16 @@ class MarkdownSinkTest extends AbstractSinkTest {
}
protected String getHeaderBlock() {
+ // never emitted by Markdown sink as otherwise too often markdown
could not be used
return "";
}
protected String getContentBlock() {
- return "";
+ return "<main>" + EOL + "<div class=\"content\"></div></main>";
}
protected String getFooterBlock() {
- return "";
+ return "<footer></footer>";
}
protected String getListBlock(String item) {
@@ -194,15 +195,15 @@ class MarkdownSinkTest extends AbstractSinkTest {
}
protected String getDataBlock(String value, String text) {
- return text;
+ return "<data value=\"" + value + "\">" + text + "</data>";
}
protected String getTimeBlock(String datetime, String text) {
- return text;
+ return "<time datetime=\"" + datetime + "\">" + text + "</time>";
}
protected String getAddressBlock(String text) {
- return text;
+ return "<address>" + text + "</address>";
}
protected String getBlockquoteBlock(String text) {
@@ -210,7 +211,7 @@ class MarkdownSinkTest extends AbstractSinkTest {
}
protected String getDivisionBlock(String text) {
- return text;
+ return "<div>" + text + "</div>";
}
protected String getVerbatimBlock(String text) {
@@ -275,7 +276,7 @@ class MarkdownSinkTest extends AbstractSinkTest {
}
protected String getLineBreakOpportunityBlock() {
- return "";
+ return "<wbr />";
}
protected String getNonBreakingSpaceBlock() {
@@ -576,4 +577,26 @@ class MarkdownSinkTest extends AbstractSinkTest {
+ "- item 3" + EOL;
assertEquals(expected, getSinkContent());
}
+
+ @Test
+ public void testLinkInsideHtmlSection() {
+ try (Sink sink = getSink()) {
+ sink.definitionList();
+ sink.definedTerm();
+ sink.text("question1");
+ sink.definedTerm_();
+ sink.definition();
+ sink.link("#top");
+ sink.text("[top]");
+ sink.link_();
+ sink.definition_();
+ sink.definitionList_();
+ }
+ String expected = "<dl>" + EOL
+ + "<dt>question1</dt>" + EOL
+ + "<dd><a href=\"#top\">[top]</a></dd>" + EOL
+ + "</dl>" + EOL
+ + EOL;
+ assertEquals(expected, getSinkContent());
+ }
}