Skip to content
Snippets Groups Projects
Commit a490faee authored by Robin Stocker's avatar Robin Stocker
Browse files

Strikethrough markdown renderer

parent 01a52bce
No related branches found
No related tags found
No related merge requests found
...@@ -4,19 +4,23 @@ import org.commonmark.node.CustomNode; ...@@ -4,19 +4,23 @@ import org.commonmark.node.CustomNode;
import org.commonmark.node.Delimited; import org.commonmark.node.Delimited;
/** /**
* A strikethrough node containing text and other inline nodes nodes as children. * A strikethrough node containing text and other inline nodes as children.
*/ */
public class Strikethrough extends CustomNode implements Delimited { public class Strikethrough extends CustomNode implements Delimited {
private static final String DELIMITER = "~~"; private String delimiter;
public Strikethrough(String delimiter) {
this.delimiter = delimiter;
}
@Override @Override
public String getOpeningDelimiter() { public String getOpeningDelimiter() {
return DELIMITER; return delimiter;
} }
@Override @Override
public String getClosingDelimiter() { public String getClosingDelimiter() {
return DELIMITER; return delimiter;
} }
} }
package org.commonmark.ext.gfm.strikethrough; package org.commonmark.ext.gfm.strikethrough;
import org.commonmark.Extension; import org.commonmark.Extension;
import org.commonmark.renderer.text.TextContentRenderer;
import org.commonmark.renderer.text.TextContentNodeRendererContext;
import org.commonmark.renderer.text.TextContentNodeRendererFactory;
import org.commonmark.ext.gfm.strikethrough.internal.StrikethroughDelimiterProcessor; import org.commonmark.ext.gfm.strikethrough.internal.StrikethroughDelimiterProcessor;
import org.commonmark.ext.gfm.strikethrough.internal.StrikethroughHtmlNodeRenderer; import org.commonmark.ext.gfm.strikethrough.internal.StrikethroughHtmlNodeRenderer;
import org.commonmark.ext.gfm.strikethrough.internal.StrikethroughMarkdownNodeRenderer;
import org.commonmark.ext.gfm.strikethrough.internal.StrikethroughTextContentNodeRenderer; import org.commonmark.ext.gfm.strikethrough.internal.StrikethroughTextContentNodeRenderer;
import org.commonmark.renderer.html.HtmlRenderer;
import org.commonmark.renderer.html.HtmlNodeRendererContext;
import org.commonmark.renderer.html.HtmlNodeRendererFactory;
import org.commonmark.parser.Parser; import org.commonmark.parser.Parser;
import org.commonmark.renderer.NodeRenderer; 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;
/** /**
* Extension for GFM strikethrough using {@code ~} or {@code ~~} (GitHub Flavored Markdown). * Extension for GFM strikethrough using {@code ~} or {@code ~~} (GitHub Flavored Markdown).
...@@ -42,7 +46,7 @@ import org.commonmark.renderer.NodeRenderer; ...@@ -42,7 +46,7 @@ import org.commonmark.renderer.NodeRenderer;
* </p> * </p>
*/ */
public class StrikethroughExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension, public class StrikethroughExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension,
TextContentRenderer.TextContentRendererExtension { TextContentRenderer.TextContentRendererExtension, MarkdownRenderer.MarkdownRendererExtension {
private final boolean requireTwoTildes; private final boolean requireTwoTildes;
...@@ -89,6 +93,16 @@ public class StrikethroughExtension implements Parser.ParserExtension, HtmlRende ...@@ -89,6 +93,16 @@ public class StrikethroughExtension implements Parser.ParserExtension, HtmlRende
}); });
} }
@Override
public void extend(MarkdownRenderer.Builder rendererBuilder) {
rendererBuilder.nodeRendererFactory(new MarkdownNodeRendererFactory() {
@Override
public NodeRenderer create(MarkdownNodeRendererContext context) {
return new StrikethroughMarkdownNodeRenderer(context);
}
});
}
public static class Builder { public static class Builder {
private boolean requireTwoTildes = false; private boolean requireTwoTildes = false;
......
...@@ -43,7 +43,8 @@ public class StrikethroughDelimiterProcessor implements DelimiterProcessor { ...@@ -43,7 +43,8 @@ public class StrikethroughDelimiterProcessor implements DelimiterProcessor {
Text opener = openingRun.getOpener(); Text opener = openingRun.getOpener();
// Wrap nodes between delimiters in strikethrough. // Wrap nodes between delimiters in strikethrough.
Node strikethrough = new Strikethrough(); String delimiter = openingRun.length() == 1 ? opener.getLiteral() : opener.getLiteral() + opener.getLiteral();
Node strikethrough = new Strikethrough(delimiter);
SourceSpans sourceSpans = new SourceSpans(); SourceSpans sourceSpans = new SourceSpans();
sourceSpans.addAllFrom(openingRun.getOpeners(openingRun.length())); sourceSpans.addAllFrom(openingRun.getOpeners(openingRun.length()));
......
package org.commonmark.ext.gfm.strikethrough.internal;
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
import org.commonmark.node.Node;
import org.commonmark.renderer.markdown.MarkdownNodeRendererContext;
import org.commonmark.renderer.markdown.MarkdownWriter;
public class StrikethroughMarkdownNodeRenderer extends StrikethroughNodeRenderer {
private final MarkdownNodeRendererContext context;
private final MarkdownWriter writer;
public StrikethroughMarkdownNodeRenderer(MarkdownNodeRendererContext context) {
this.context = context;
this.writer = context.getWriter();
}
@Override
public void render(Node node) {
Strikethrough strikethrough = (Strikethrough) node;
writer.raw(strikethrough.getOpeningDelimiter());
renderChildren(node);
writer.raw(strikethrough.getClosingDelimiter());
}
private void renderChildren(Node parent) {
Node node = parent.getFirstChild();
while (node != null) {
Node next = node.getNext();
context.render(node);
node = next;
}
}
}
package org.commonmark.ext.gfm.strikethrough;
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 StrikethroughMarkdownRendererTest {
private static final Set<Extension> EXTENSIONS = Collections.singleton(StrikethroughExtension.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~ ~bar~\n");
assertRoundTrip("~~f~oo~~ ~~bar~~\n");
// TODO this new special character needs to be escaped:
// 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);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment