Specific node visitors for core nodes
This commit is contained in:
parent
42aab2280e
commit
19cd94febb
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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()));
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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(' ');
|
||||
}
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user