From 19cd94febb8ce34f02350e64b6a3a91a935b7fd9 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sun, 2 Dec 2018 14:29:27 +0300 Subject: [PATCH] Specific node visitors for core nodes --- .../ru/noties/markwon/MarkwonVisitor.java | 6 +- .../ru/noties/markwon/MarkwonVisitorImpl.java | 9 +- .../ru/noties/markwon/core/CorePlugin.java | 297 ++---------------- .../core/visitor/BlockQuoteNodeVisitor.java | 24 +- .../core/visitor/CodeBlockNodeVisitor.java | 56 ++++ .../markwon/core/visitor/CodeNodeVisitor.java | 24 ++ .../core/visitor/EmphasisNodeVisitor.java | 14 +- .../visitor/HardLineBreakNodeVisitor.java | 14 + .../core/visitor/HeadingNodeVisitor.java | 24 ++ .../markwon/core/visitor/LinkNodeVisitor.java | 19 ++ .../core/visitor/ListBlockNodeVisitor.java | 22 ++ .../core/visitor/ListItemNodeVisitor.java | 48 +++ .../core/visitor/ParagraphNodeVisitor.java | 44 +++ .../visitor/SoftLineBreakNodeVisitor.java | 25 ++ .../visitor/StrongEmphasisNodeVisitor.java | 14 +- .../markwon/core/visitor/TextNodeVisitor.java | 12 +- .../visitor/ThematicBreakNodeVisitor.java | 27 ++ 17 files changed, 406 insertions(+), 273 deletions(-) create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/CodeBlockNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/CodeNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/HardLineBreakNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/HeadingNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/LinkNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/ListBlockNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/ListItemNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/ParagraphNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/SoftLineBreakNodeVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/visitor/ThematicBreakNodeVisitor.java diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java index 40d389b4..1b72218c 100644 --- a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java @@ -17,7 +17,11 @@ public interface MarkwonVisitor extends Visitor { interface Builder { @NonNull - Builder on(@NonNull Class node, @Nullable NodeVisitor nodeVisitor); + Builder on(@NonNull Class node, @Nullable NodeVisitor nodeVisitor); + + // to obtain currently registered one + @Nullable + NodeVisitor registeredVisitor(@NonNull Class node); @NonNull MarkwonVisitor build(@NonNull MarkwonConfiguration configuration); diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java index 94399509..70684e00 100644 --- a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java @@ -281,7 +281,7 @@ class MarkwonVisitorImpl implements MarkwonVisitor { @NonNull @Override - public Builder on(@NonNull Class node, @Nullable NodeVisitor nodeVisitor) { + public Builder on(@NonNull Class node, @Nullable NodeVisitor 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 NodeVisitor registeredVisitor(@NonNull Class node) { + //noinspection unchecked + return (NodeVisitor) nodes.get(node); + } + @NonNull @Override public MarkwonVisitor build(@NonNull MarkwonConfiguration configuration) { diff --git a/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java index 01c35d37..832536da 100644 --- a/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java +++ b/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java @@ -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() { - @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() { - @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() { - @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
() { - @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() { - @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() { - @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() { - @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() { - @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() { - @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() { - @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() { - @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() { - @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() { - @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() { - @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() { - @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() { - @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()); } } diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/BlockQuoteNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/BlockQuoteNodeVisitor.java index 46ad855e..08681545 100644 --- a/markwon/src/main/java/ru/noties/markwon/core/visitor/BlockQuoteNodeVisitor.java +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/BlockQuoteNodeVisitor.java @@ -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
{ + @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(); + } + } } diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/CodeBlockNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/CodeBlockNodeVisitor.java new file mode 100644 index 00000000..491da0e8 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/CodeBlockNodeVisitor.java @@ -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 { + + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull FencedCodeBlock fencedCodeBlock) { + visitCodeBlock(visitor, fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral(), fencedCodeBlock); + } + } + + public static class Indented implements MarkwonVisitor.NodeVisitor { + + @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(); + } + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/CodeNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/CodeNodeVisitor.java new file mode 100644 index 00000000..fb893839 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/CodeNodeVisitor.java @@ -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 { + @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)); + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/EmphasisNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/EmphasisNodeVisitor.java index bfc5847e..f4010b32 100644 --- a/markwon/src/main/java/ru/noties/markwon/core/visitor/EmphasisNodeVisitor.java +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/EmphasisNodeVisitor.java @@ -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 { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Emphasis emphasis) { + final int length = visitor.length(); + visitor.visitChildren(emphasis); + visitor.setSpans(length, visitor.factory().emphasis()); + } } diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/HardLineBreakNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/HardLineBreakNodeVisitor.java new file mode 100644 index 00000000..809638b7 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/HardLineBreakNodeVisitor.java @@ -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 { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull HardLineBreak hardLineBreak) { + visitor.ensureNewLine(); + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/HeadingNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/HeadingNodeVisitor.java new file mode 100644 index 00000000..c82d51fe --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/HeadingNodeVisitor.java @@ -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 { + @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(); + } + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/LinkNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/LinkNodeVisitor.java new file mode 100644 index 00000000..cc4dfd6d --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/LinkNodeVisitor.java @@ -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 { + @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())); + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/ListBlockNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/ListBlockNodeVisitor.java new file mode 100644 index 00000000..f06d324b --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/ListBlockNodeVisitor.java @@ -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 { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Node node) { + + visitor.ensureNewLine(); + + visitor.visitChildren(node); + + if (visitor.hasNext(node)) { + visitor.ensureNewLine(); + visitor.forceNewLine(); + } + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/ListItemNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/ListItemNodeVisitor.java new file mode 100644 index 00000000..e60dfca6 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/ListItemNodeVisitor.java @@ -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 { + + @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(); + } + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/ParagraphNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/ParagraphNodeVisitor.java new file mode 100644 index 00000000..b945c501 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/ParagraphNodeVisitor.java @@ -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 { + @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; + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/SoftLineBreakNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/SoftLineBreakNodeVisitor.java new file mode 100644 index 00000000..79880bb2 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/SoftLineBreakNodeVisitor.java @@ -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 { + + 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(' '); + } + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/StrongEmphasisNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/StrongEmphasisNodeVisitor.java index 64176e0c..ae3c701d 100644 --- a/markwon/src/main/java/ru/noties/markwon/core/visitor/StrongEmphasisNodeVisitor.java +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/StrongEmphasisNodeVisitor.java @@ -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 { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull StrongEmphasis strongEmphasis) { + final int length = visitor.length(); + visitor.visitChildren(strongEmphasis); + visitor.setSpans(length, visitor.factory().strongEmphasis()); + } } diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/TextNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/TextNodeVisitor.java index 8f553ace..17ebfbb0 100644 --- a/markwon/src/main/java/ru/noties/markwon/core/visitor/TextNodeVisitor.java +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/TextNodeVisitor.java @@ -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 { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Text text) { + visitor.builder().append(text.getLiteral()); + } } diff --git a/markwon/src/main/java/ru/noties/markwon/core/visitor/ThematicBreakNodeVisitor.java b/markwon/src/main/java/ru/noties/markwon/core/visitor/ThematicBreakNodeVisitor.java new file mode 100644 index 00000000..2bc2886a --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/visitor/ThematicBreakNodeVisitor.java @@ -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 { + @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(); + } + } +}