Specific node visitors for core nodes

This commit is contained in:
Dimitry Ivanov 2018-12-02 14:29:27 +03:00
parent 42aab2280e
commit 19cd94febb
17 changed files with 406 additions and 273 deletions

View File

@ -17,7 +17,11 @@ public interface MarkwonVisitor extends Visitor {
interface Builder {
@NonNull
<N extends Node> Builder on(@NonNull Class<N> node, @Nullable NodeVisitor<N> nodeVisitor);
<N extends Node> Builder on(@NonNull Class<N> node, @Nullable NodeVisitor<? super N> nodeVisitor);
// to obtain currently registered one
@Nullable
<N extends Node> NodeVisitor<N> registeredVisitor(@NonNull Class<N> node);
@NonNull
MarkwonVisitor build(@NonNull MarkwonConfiguration configuration);

View File

@ -281,7 +281,7 @@ class MarkwonVisitorImpl implements MarkwonVisitor {
@NonNull
@Override
public <N extends Node> Builder on(@NonNull Class<N> node, @Nullable NodeVisitor<N> nodeVisitor) {
public <N extends Node> Builder on(@NonNull Class<N> node, @Nullable NodeVisitor<? super N> nodeVisitor) {
// we should allow `null` to exclude node from being visited (for example to disable
// some functionality)
if (nodeVisitor == null) {
@ -292,6 +292,13 @@ class MarkwonVisitorImpl implements MarkwonVisitor {
return this;
}
@Nullable
@Override
public <N extends Node> NodeVisitor<N> registeredVisitor(@NonNull Class<N> node) {
//noinspection unchecked
return (NodeVisitor<N>) nodes.get(node);
}
@NonNull
@Override
public MarkwonVisitor build(@NonNull MarkwonConfiguration configuration) {

View File

@ -1,7 +1,6 @@
package ru.noties.markwon.core;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.TextView;
import org.commonmark.node.BlockQuote;
@ -13,9 +12,7 @@ import org.commonmark.node.HardLineBreak;
import org.commonmark.node.Heading;
import org.commonmark.node.IndentedCodeBlock;
import org.commonmark.node.Link;
import org.commonmark.node.ListBlock;
import org.commonmark.node.ListItem;
import org.commonmark.node.Node;
import org.commonmark.node.OrderedList;
import org.commonmark.node.Paragraph;
import org.commonmark.node.SoftLineBreak;
@ -24,21 +21,25 @@ import org.commonmark.node.Text;
import org.commonmark.node.ThematicBreak;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.core.visitor.BlockQuoteNodeVisitor;
import ru.noties.markwon.core.visitor.CodeBlockNodeVisitor;
import ru.noties.markwon.core.visitor.CodeNodeVisitor;
import ru.noties.markwon.core.visitor.EmphasisNodeVisitor;
import ru.noties.markwon.core.visitor.HardLineBreakNodeVisitor;
import ru.noties.markwon.core.visitor.HeadingNodeVisitor;
import ru.noties.markwon.core.visitor.LinkNodeVisitor;
import ru.noties.markwon.core.visitor.ListBlockNodeVisitor;
import ru.noties.markwon.core.visitor.ListItemNodeVisitor;
import ru.noties.markwon.core.visitor.ParagraphNodeVisitor;
import ru.noties.markwon.core.visitor.SoftLineBreakNodeVisitor;
import ru.noties.markwon.core.visitor.StrongEmphasisNodeVisitor;
import ru.noties.markwon.core.visitor.TextNodeVisitor;
import ru.noties.markwon.core.visitor.ThematicBreakNodeVisitor;
import ru.noties.markwon.spans.OrderedListItemSpan;
public class CorePlugin extends AbstractMarkwonPlugin {
// todo: factory. Logically it must be here only, but in order to make spans
// uniform in HTML (for example) we should expose it... Anyway, this factory _must_
// include only _core_ spans
// todo: softBreak adds new line should be here (or maybe removed even?)
// todo: add a simple HTML handler
// todo: configure primitive images (without okhttp -> just HttpUrlConnection and simple types (static, data)
@NonNull
public static CorePlugin create() {
return create(false);
@ -72,7 +73,6 @@ public class CorePlugin extends AbstractMarkwonPlugin {
softLineBreak(builder);
hardLineBreak(builder);
paragraph(builder);
// image(builder);
link(builder);
}
@ -88,303 +88,66 @@ public class CorePlugin extends AbstractMarkwonPlugin {
}
protected void text(@NonNull MarkwonVisitor.Builder builder) {
builder.on(Text.class, new MarkwonVisitor.NodeVisitor<Text>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Text text) {
visitor.builder().append(text.getLiteral());
}
});
builder.on(Text.class, new TextNodeVisitor());
}
protected void strongEmphasis(@NonNull MarkwonVisitor.Builder builder) {
builder.on(StrongEmphasis.class, new MarkwonVisitor.NodeVisitor<StrongEmphasis>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull StrongEmphasis strongEmphasis) {
final int length = visitor.length();
visitor.visitChildren(strongEmphasis);
visitor.setSpans(length, visitor.factory().strongEmphasis());
}
});
builder.on(StrongEmphasis.class, new StrongEmphasisNodeVisitor());
}
protected void emphasis(@NonNull MarkwonVisitor.Builder builder) {
builder.on(Emphasis.class, new MarkwonVisitor.NodeVisitor<Emphasis>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Emphasis emphasis) {
final int length = visitor.length();
visitor.visitChildren(emphasis);
visitor.setSpans(length, visitor.factory().emphasis());
}
});
builder.on(Emphasis.class, new EmphasisNodeVisitor());
}
protected void blockQuote(@NonNull MarkwonVisitor.Builder builder) {
builder.on(BlockQuote.class, new MarkwonVisitor.NodeVisitor<BlockQuote>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull BlockQuote blockQuote) {
visitor.ensureNewLine();
final int length = visitor.length();
visitor.incrementBlockIndent();
visitor.visitChildren(blockQuote);
visitor.setSpans(length, visitor.factory().blockQuote(visitor.theme()));
visitor.decrementBlockIndent();
if (visitor.hasNext(blockQuote)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
});
builder.on(BlockQuote.class, new BlockQuoteNodeVisitor());
}
protected void code(@NonNull MarkwonVisitor.Builder builder) {
builder.on(Code.class, new MarkwonVisitor.NodeVisitor<Code>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Code code) {
final int length = visitor.length();
// NB, in order to provide a _padding_ feeling code is wrapped inside two unbreakable spaces
// unfortunately we cannot use this for multiline code as we cannot control where a new line break will be inserted
visitor.builder()
.append('\u00a0')
.append(code.getLiteral())
.append('\u00a0');
visitor.setSpans(length, visitor.factory().code(visitor.theme(), false));
}
});
builder.on(Code.class, new CodeNodeVisitor());
}
protected void fencedCodeBlock(@NonNull MarkwonVisitor.Builder builder) {
builder.on(FencedCodeBlock.class, new MarkwonVisitor.NodeVisitor<FencedCodeBlock>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull FencedCodeBlock fencedCodeBlock) {
visitCodeBlock(visitor, fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral(), fencedCodeBlock);
}
});
builder.on(FencedCodeBlock.class, new CodeBlockNodeVisitor.Fenced());
}
protected void indentedCodeBlock(@NonNull MarkwonVisitor.Builder builder) {
builder.on(IndentedCodeBlock.class, new MarkwonVisitor.NodeVisitor<IndentedCodeBlock>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull IndentedCodeBlock indentedCodeBlock) {
visitCodeBlock(visitor, null, indentedCodeBlock.getLiteral(), indentedCodeBlock);
}
});
}
protected void visitCodeBlock(
@NonNull MarkwonVisitor visitor,
@Nullable String info,
@NonNull String code,
@NonNull Node node) {
visitor.ensureNewLine();
final int length = visitor.length();
visitor.builder()
.append('\u00a0').append('\n')
.append(visitor.configuration().syntaxHighlight().highlight(info, code));
visitor.ensureNewLine();
visitor.builder().append('\u00a0');
visitor.setSpans(length, visitor.factory().code(visitor.theme(), true));
if (visitor.hasNext(node)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
builder.on(IndentedCodeBlock.class, new CodeBlockNodeVisitor.Indented());
}
protected void bulletList(@NonNull MarkwonVisitor.Builder builder) {
builder.on(BulletList.class, new MarkwonVisitor.NodeVisitor<BulletList>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull BulletList bulletList) {
visitList(visitor, bulletList);
}
});
builder.on(BulletList.class, new ListBlockNodeVisitor());
}
protected void orderedList(@NonNull MarkwonVisitor.Builder builder) {
builder.on(OrderedList.class, new MarkwonVisitor.NodeVisitor<OrderedList>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull OrderedList orderedList) {
visitList(visitor, orderedList);
}
});
}
protected void visitList(@NonNull MarkwonVisitor visitor, @NonNull Node node) {
visitor.ensureNewLine();
visitor.visitChildren(node);
if (visitor.hasNext(node)) {
visitor.ensureNewLine();
if (visitor.listLevel() == 0
&& visitor.blockIndent() == 0) {
visitor.forceNewLine();
}
}
builder.on(OrderedList.class, new ListBlockNodeVisitor());
}
protected void listItem(@NonNull MarkwonVisitor.Builder builder) {
builder.on(ListItem.class, new MarkwonVisitor.NodeVisitor<ListItem>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull ListItem listItem) {
final int length = visitor.length();
visitor.incrementBlockIndent();
visitor.incrementListLevel();
final Node parent = listItem.getParent();
if (parent instanceof OrderedList) {
final int start = ((OrderedList) parent).getStartNumber();
visitor.visitChildren(listItem);
visitor.setSpans(length, visitor.factory().orderedListItem(visitor.theme(), start));
// after we have visited the children increment start number
final OrderedList orderedList = (OrderedList) parent;
orderedList.setStartNumber(orderedList.getStartNumber() + 1);
} else {
visitor.visitChildren(listItem);
visitor.setSpans(length, visitor.factory().bulletListItem(visitor.theme(), visitor.listLevel() - 1));
}
visitor.decrementBlockIndent();
visitor.decrementListLevel();
if (visitor.hasNext(listItem)) {
visitor.ensureNewLine();
}
}
});
builder.on(ListItem.class, new ListItemNodeVisitor());
}
protected void thematicBreak(@NonNull MarkwonVisitor.Builder builder) {
builder.on(ThematicBreak.class, new MarkwonVisitor.NodeVisitor<ThematicBreak>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull ThematicBreak thematicBreak) {
visitor.ensureNewLine();
final int length = visitor.length();
// without space it won't render
visitor.builder().append('\u00a0');
visitor.setSpans(length, visitor.factory().thematicBreak(visitor.theme()));
if (visitor.hasNext(thematicBreak)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
});
builder.on(ThematicBreak.class, new ThematicBreakNodeVisitor());
}
protected void heading(@NonNull MarkwonVisitor.Builder builder) {
builder.on(Heading.class, new MarkwonVisitor.NodeVisitor<Heading>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) {
visitor.ensureNewLine();
final int length = visitor.length();
visitor.visitChildren(heading);
visitor.setSpans(length, visitor.factory().heading(visitor.theme(), heading.getLevel()));
if (visitor.hasNext(heading)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
});
builder.on(Heading.class, new HeadingNodeVisitor());
}
protected void softLineBreak(@NonNull MarkwonVisitor.Builder builder) {
builder.on(SoftLineBreak.class, new MarkwonVisitor.NodeVisitor<SoftLineBreak>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull SoftLineBreak softLineBreak) {
if (softBreakAddsNewLine) {
visitor.ensureNewLine();
} else {
visitor.builder().append(' ');
}
}
});
builder.on(SoftLineBreak.class, new SoftLineBreakNodeVisitor(softBreakAddsNewLine));
}
protected void hardLineBreak(@NonNull MarkwonVisitor.Builder builder) {
builder.on(HardLineBreak.class, new MarkwonVisitor.NodeVisitor<HardLineBreak>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull HardLineBreak hardLineBreak) {
visitor.ensureNewLine();
}
});
builder.on(HardLineBreak.class, new HardLineBreakNodeVisitor());
}
protected void paragraph(@NonNull MarkwonVisitor.Builder builder) {
builder.on(Paragraph.class, new MarkwonVisitor.NodeVisitor<Paragraph>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Paragraph paragraph) {
final boolean inTightList = isInTightList(paragraph);
if (!inTightList) {
visitor.ensureNewLine();
}
final int length = visitor.length();
visitor.visitChildren(paragraph);
// @since 1.1.1 apply paragraph span
visitor.setSpans(length, visitor.factory().paragraph(inTightList));
if (!inTightList && visitor.hasNext(paragraph)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
});
builder.on(Paragraph.class, new ParagraphNodeVisitor());
}
protected void link(@NonNull MarkwonVisitor.Builder builder) {
builder.on(Link.class, new MarkwonVisitor.NodeVisitor<Link>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Link link) {
final int length = visitor.length();
visitor.visitChildren(link);
final MarkwonConfiguration configuration = visitor.configuration();
final String destination = configuration.urlProcessor().process(link.getDestination());
visitor.setSpans(length, visitor.factory().link(visitor.theme(), destination, configuration.linkResolver()));
}
});
}
private static boolean isInTightList(@NonNull Paragraph paragraph) {
final Node parent = paragraph.getParent();
if (parent != null) {
final Node gramps = parent.getParent();
if (gramps instanceof ListBlock) {
ListBlock list = (ListBlock) gramps;
return list.isTight();
}
}
return false;
builder.on(Link.class, new LinkNodeVisitor());
}
}

View File

@ -1,4 +1,26 @@
package ru.noties.markwon.core.visitor;
public class BlockQuoteNodeVisitor {
import android.support.annotation.NonNull;
import org.commonmark.node.BlockQuote;
import ru.noties.markwon.MarkwonVisitor;
public class BlockQuoteNodeVisitor implements MarkwonVisitor.NodeVisitor<BlockQuote> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull BlockQuote blockQuote) {
visitor.ensureNewLine();
final int length = visitor.length();
visitor.incrementBlockIndent();
visitor.visitChildren(blockQuote);
visitor.setSpans(length, visitor.factory().blockQuote(visitor.theme()));
visitor.decrementBlockIndent();
if (visitor.hasNext(blockQuote)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
}

View File

@ -0,0 +1,56 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.FencedCodeBlock;
import org.commonmark.node.IndentedCodeBlock;
import org.commonmark.node.Node;
import ru.noties.markwon.MarkwonVisitor;
public abstract class CodeBlockNodeVisitor {
public static class Fenced implements MarkwonVisitor.NodeVisitor<FencedCodeBlock> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull FencedCodeBlock fencedCodeBlock) {
visitCodeBlock(visitor, fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral(), fencedCodeBlock);
}
}
public static class Indented implements MarkwonVisitor.NodeVisitor<IndentedCodeBlock> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull IndentedCodeBlock indentedCodeBlock) {
visitCodeBlock(visitor, null, indentedCodeBlock.getLiteral(), indentedCodeBlock);
}
}
public static void visitCodeBlock(
@NonNull MarkwonVisitor visitor,
@Nullable String info,
@NonNull String code,
@NonNull Node node) {
visitor.ensureNewLine();
final int length = visitor.length();
visitor.builder()
.append('\u00a0').append('\n')
.append(visitor.configuration().syntaxHighlight().highlight(info, code));
visitor.ensureNewLine();
visitor.builder().append('\u00a0');
visitor.setSpans(length, visitor.factory().code(visitor.theme(), true));
if (visitor.hasNext(node)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
}

View File

@ -0,0 +1,24 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.Code;
import ru.noties.markwon.MarkwonVisitor;
public class CodeNodeVisitor implements MarkwonVisitor.NodeVisitor<Code> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Code code) {
final int length = visitor.length();
// NB, in order to provide a _padding_ feeling code is wrapped inside two unbreakable spaces
// unfortunately we cannot use this for multiline code as we cannot control where a new line break will be inserted
visitor.builder()
.append('\u00a0')
.append(code.getLiteral())
.append('\u00a0');
visitor.setSpans(length, visitor.factory().code(visitor.theme(), false));
}
}

View File

@ -1,4 +1,16 @@
package ru.noties.markwon.core.visitor;
public class EmphasisNodeVisitor {
import android.support.annotation.NonNull;
import org.commonmark.node.Emphasis;
import ru.noties.markwon.MarkwonVisitor;
public class EmphasisNodeVisitor implements MarkwonVisitor.NodeVisitor<Emphasis> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Emphasis emphasis) {
final int length = visitor.length();
visitor.visitChildren(emphasis);
visitor.setSpans(length, visitor.factory().emphasis());
}
}

View File

@ -0,0 +1,14 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.HardLineBreak;
import ru.noties.markwon.MarkwonVisitor;
public class HardLineBreakNodeVisitor implements MarkwonVisitor.NodeVisitor<HardLineBreak> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull HardLineBreak hardLineBreak) {
visitor.ensureNewLine();
}
}

View File

@ -0,0 +1,24 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.Heading;
import ru.noties.markwon.MarkwonVisitor;
public class HeadingNodeVisitor implements MarkwonVisitor.NodeVisitor<Heading> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) {
visitor.ensureNewLine();
final int length = visitor.length();
visitor.visitChildren(heading);
visitor.setSpans(length, visitor.factory().heading(visitor.theme(), heading.getLevel()));
if (visitor.hasNext(heading)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
}

View File

@ -0,0 +1,19 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.Link;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonVisitor;
public class LinkNodeVisitor implements MarkwonVisitor.NodeVisitor<Link> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Link link) {
final int length = visitor.length();
visitor.visitChildren(link);
final MarkwonConfiguration configuration = visitor.configuration();
final String destination = configuration.urlProcessor().process(link.getDestination());
visitor.setSpans(length, visitor.factory().link(visitor.theme(), destination, configuration.linkResolver()));
}
}

View File

@ -0,0 +1,22 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.Node;
import ru.noties.markwon.MarkwonVisitor;
public class ListBlockNodeVisitor implements MarkwonVisitor.NodeVisitor<Node> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Node node) {
visitor.ensureNewLine();
visitor.visitChildren(node);
if (visitor.hasNext(node)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
}

View File

@ -0,0 +1,48 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.ListItem;
import org.commonmark.node.Node;
import org.commonmark.node.OrderedList;
import ru.noties.markwon.MarkwonVisitor;
public class ListItemNodeVisitor implements MarkwonVisitor.NodeVisitor<ListItem> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull ListItem listItem) {
final int length = visitor.length();
visitor.incrementBlockIndent();
visitor.incrementListLevel();
final Node parent = listItem.getParent();
if (parent instanceof OrderedList) {
final int start = ((OrderedList) parent).getStartNumber();
visitor.visitChildren(listItem);
visitor.setSpans(length, visitor.factory().orderedListItem(visitor.theme(), start));
// after we have visited the children increment start number
final OrderedList orderedList = (OrderedList) parent;
orderedList.setStartNumber(orderedList.getStartNumber() + 1);
} else {
visitor.visitChildren(listItem);
visitor.setSpans(length, visitor.factory().bulletListItem(visitor.theme(), visitor.listLevel() - 1));
}
visitor.decrementBlockIndent();
visitor.decrementListLevel();
if (visitor.hasNext(listItem)) {
visitor.ensureNewLine();
}
}
}

View File

@ -0,0 +1,44 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.ListBlock;
import org.commonmark.node.Node;
import org.commonmark.node.Paragraph;
import ru.noties.markwon.MarkwonVisitor;
public class ParagraphNodeVisitor implements MarkwonVisitor.NodeVisitor<Paragraph> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Paragraph paragraph) {
final boolean inTightList = isInTightList(paragraph);
if (!inTightList) {
visitor.ensureNewLine();
}
final int length = visitor.length();
visitor.visitChildren(paragraph);
// @since 1.1.1 apply paragraph span
visitor.setSpans(length, visitor.factory().paragraph(inTightList));
if (!inTightList && visitor.hasNext(paragraph)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
private static boolean isInTightList(@NonNull Paragraph paragraph) {
final Node parent = paragraph.getParent();
if (parent != null) {
final Node gramps = parent.getParent();
if (gramps instanceof ListBlock) {
ListBlock list = (ListBlock) gramps;
return list.isTight();
}
}
return false;
}
}

View File

@ -0,0 +1,25 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.SoftLineBreak;
import ru.noties.markwon.MarkwonVisitor;
public class SoftLineBreakNodeVisitor implements MarkwonVisitor.NodeVisitor<SoftLineBreak> {
private final boolean softBreakAddsNewLine;
public SoftLineBreakNodeVisitor(boolean softBreakAddsNewLine) {
this.softBreakAddsNewLine = softBreakAddsNewLine;
}
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull SoftLineBreak softLineBreak) {
if (softBreakAddsNewLine) {
visitor.ensureNewLine();
} else {
visitor.builder().append(' ');
}
}
}

View File

@ -1,4 +1,16 @@
package ru.noties.markwon.core.visitor;
public class StrongEmphasisNodeVisitor {
import android.support.annotation.NonNull;
import org.commonmark.node.StrongEmphasis;
import ru.noties.markwon.MarkwonVisitor;
public class StrongEmphasisNodeVisitor implements MarkwonVisitor.NodeVisitor<StrongEmphasis> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull StrongEmphasis strongEmphasis) {
final int length = visitor.length();
visitor.visitChildren(strongEmphasis);
visitor.setSpans(length, visitor.factory().strongEmphasis());
}
}

View File

@ -1,4 +1,14 @@
package ru.noties.markwon.core.visitor;
public class TextNodeVisitor {
import android.support.annotation.NonNull;
import org.commonmark.node.Text;
import ru.noties.markwon.MarkwonVisitor;
public class TextNodeVisitor implements MarkwonVisitor.NodeVisitor<Text> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Text text) {
visitor.builder().append(text.getLiteral());
}
}

View File

@ -0,0 +1,27 @@
package ru.noties.markwon.core.visitor;
import android.support.annotation.NonNull;
import org.commonmark.node.ThematicBreak;
import ru.noties.markwon.MarkwonVisitor;
public class ThematicBreakNodeVisitor implements MarkwonVisitor.NodeVisitor<ThematicBreak> {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull ThematicBreak thematicBreak) {
visitor.ensureNewLine();
final int length = visitor.length();
// without space it won't render
visitor.builder().append('\u00a0');
visitor.setSpans(length, visitor.factory().thematicBreak(visitor.theme()));
if (visitor.hasNext(thematicBreak)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
}