Fix markwon main artifact tests

This commit is contained in:
Dimitry Ivanov 2018-12-22 17:16:46 +03:00
parent f86cf1d109
commit 4f02a793e7
41 changed files with 246 additions and 342 deletions

View File

@ -40,18 +40,18 @@ public class GifAwarePlugin extends AbstractMarkwonPlugin {
builder.setFactory(Image.class, new SpanFactory() { builder.setFactory(Image.class, new SpanFactory() {
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new AsyncDrawableSpan( return new AsyncDrawableSpan(
configuration.theme(), configuration.theme(),
new GifAwareAsyncDrawable( new GifAwareAsyncDrawable(
gifPlaceholder, gifPlaceholder,
ImageProps.DESTINATION.require(context), ImageProps.DESTINATION.require(props),
configuration.asyncDrawableLoader(), configuration.asyncDrawableLoader(),
configuration.imageSizeResolver(), configuration.imageSizeResolver(),
ImageProps.IMAGE_SIZE.get(context) ImageProps.IMAGE_SIZE.get(props)
), ),
AsyncDrawableSpan.ALIGN_BOTTOM, AsyncDrawableSpan.ALIGN_BOTTOM,
ImageProps.REPLACEMENT_TEXT_IS_LINK.get(context, false) ImageProps.REPLACEMENT_TEXT_IS_LINK.get(props, false)
); );
} }
}); });

View File

@ -32,7 +32,7 @@ public class StrikethroughPlugin extends AbstractMarkwonPlugin {
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
builder.setFactory(Strikethrough.class, new SpanFactory() { builder.setFactory(Strikethrough.class, new SpanFactory() {
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new StrikethroughSpan(); return new StrikethroughSpan();
} }
}); });

View File

@ -18,12 +18,12 @@ public class TaskListSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new TaskListSpan( return new TaskListSpan(
configuration.theme(), configuration.theme(),
drawable, drawable,
TaskListProps.BLOCK_INDENT.get(context, 0), TaskListProps.BLOCK_INDENT.get(props, 0),
TaskListProps.DONE.get(context, false) TaskListProps.DONE.get(props, false)
); );
} }
} }

View File

@ -11,5 +11,5 @@ public interface SpanFactory {
@Nullable @Nullable
Object getSpans( Object getSpans(
@NonNull MarkwonConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull RenderProps context); @NonNull RenderProps props);
} }

View File

@ -2,6 +2,7 @@ package ru.noties.markwon.core;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.widget.TextView; import android.widget.TextView;
import org.commonmark.node.BlockQuote; import org.commonmark.node.BlockQuote;
@ -142,9 +143,18 @@ public class CorePlugin extends AbstractMarkwonPlugin {
builder.on(BlockQuote.class, new MarkwonVisitor.NodeVisitor<BlockQuote>() { builder.on(BlockQuote.class, new MarkwonVisitor.NodeVisitor<BlockQuote>() {
@Override @Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull BlockQuote blockQuote) { public void visit(@NonNull MarkwonVisitor visitor, @NonNull BlockQuote blockQuote) {
visitor.ensureNewLine();
final int length = visitor.length(); final int length = visitor.length();
visitor.visitChildren(blockQuote); visitor.visitChildren(blockQuote);
visitor.setSpansForNode(blockQuote, length); visitor.setSpansForNode(blockQuote, length);
if (visitor.hasNext(blockQuote)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
} }
}); });
} }
@ -186,7 +196,8 @@ public class CorePlugin extends AbstractMarkwonPlugin {
}); });
} }
private static void visitCodeBlock( @VisibleForTesting
static void visitCodeBlock(
@NonNull MarkwonVisitor visitor, @NonNull MarkwonVisitor visitor,
@Nullable String info, @Nullable String info,
@NonNull String code, @NonNull String code,
@ -227,6 +238,11 @@ public class CorePlugin extends AbstractMarkwonPlugin {
final int length = visitor.length(); final int length = visitor.length();
// it's important to visit children before applying render props (
// we can have nested children, who are list items also, thus they will
// override out props (if we set them before visiting children)
visitor.visitChildren(listItem);
final Node parent = listItem.getParent(); final Node parent = listItem.getParent();
if (parent instanceof OrderedList) { if (parent instanceof OrderedList) {
@ -244,7 +260,6 @@ public class CorePlugin extends AbstractMarkwonPlugin {
CoreProps.BULLET_LIST_ITEM_LEVEL.set(visitor.renderProps(), listLevel(listItem)); CoreProps.BULLET_LIST_ITEM_LEVEL.set(visitor.renderProps(), listLevel(listItem));
} }
visitor.visitChildren(listItem);
visitor.setSpansForNode(listItem, length); visitor.setSpansForNode(listItem, length);
if (visitor.hasNext(listItem)) { if (visitor.hasNext(listItem)) {

View File

@ -1,51 +0,0 @@
package ru.noties.markwon.core;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.core.spans.LinkSpan;
/**
* Each method can return null or a Span object or an array of spans
*
* @since 1.1.0
*/
@Deprecated
public interface MarkwonSpannableFactory {
@Nullable
Object strongEmphasis();
@Nullable
Object emphasis();
@Nullable
Object blockQuote(@NonNull MarkwonTheme theme);
@Nullable
Object code(@NonNull MarkwonTheme theme, boolean multiline);
@Nullable
Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber);
@Nullable
Object bulletListItem(@NonNull MarkwonTheme theme, int level);
@Nullable
Object thematicBreak(@NonNull MarkwonTheme theme);
@Nullable
Object heading(@NonNull MarkwonTheme theme, int level);
/**
* @since 1.1.1
*/
@Nullable
Object paragraph(boolean inTightList);
@Nullable
Object link(
@NonNull MarkwonTheme theme,
@NonNull String destination,
@NonNull LinkSpan.Resolver resolver);
}

View File

@ -1,90 +0,0 @@
package ru.noties.markwon.core;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.core.spans.BlockQuoteSpan;
import ru.noties.markwon.core.spans.BulletListItemSpan;
import ru.noties.markwon.core.spans.CodeSpan;
import ru.noties.markwon.core.spans.EmphasisSpan;
import ru.noties.markwon.core.spans.HeadingSpan;
import ru.noties.markwon.core.spans.LinkSpan;
import ru.noties.markwon.core.spans.OrderedListItemSpan;
import ru.noties.markwon.core.spans.StrongEmphasisSpan;
import ru.noties.markwon.core.spans.ThematicBreakSpan;
/**
* @since 1.1.0
*/
@Deprecated
public class MarkwonSpannableFactoryDef implements MarkwonSpannableFactory {
@NonNull
public static MarkwonSpannableFactoryDef create() {
return new MarkwonSpannableFactoryDef();
}
@Nullable
@Override
public Object strongEmphasis() {
return new StrongEmphasisSpan();
}
@Nullable
@Override
public Object emphasis() {
return new EmphasisSpan();
}
@Nullable
@Override
public Object blockQuote(@NonNull MarkwonTheme theme) {
return new BlockQuoteSpan(theme);
}
@Nullable
@Override
public Object code(@NonNull MarkwonTheme theme, boolean multiline) {
return new CodeSpan(theme, multiline);
}
@Nullable
@Override
public Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber) {
// todo| in order to provide real RTL experience there must be a way to provide this string
return new OrderedListItemSpan(theme, String.valueOf(startNumber) + "." + '\u00a0');
}
@Nullable
@Override
public Object bulletListItem(@NonNull MarkwonTheme theme, int level) {
return new BulletListItemSpan(theme, level);
}
@Nullable
@Override
public Object thematicBreak(@NonNull MarkwonTheme theme) {
return new ThematicBreakSpan(theme);
}
@Nullable
@Override
public Object heading(@NonNull MarkwonTheme theme, int level) {
return new HeadingSpan(theme, level);
}
/**
* @since 1.1.1
*/
@Nullable
@Override
public Object paragraph(boolean inTightList) {
return null;
}
@Nullable
@Override
public Object link(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) {
return new LinkSpan(theme, destination, resolver);
}
}

View File

@ -11,7 +11,7 @@ import ru.noties.markwon.core.spans.BlockQuoteSpan;
public class BlockQuoteSpanFactory implements SpanFactory { public class BlockQuoteSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new BlockQuoteSpan(configuration.theme()); return new BlockQuoteSpan(configuration.theme());
} }
} }

View File

@ -11,7 +11,7 @@ import ru.noties.markwon.core.spans.CodeSpan;
public class CodeBlockSpanFactory implements SpanFactory { public class CodeBlockSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new CodeSpan(configuration.theme(), true); return new CodeSpan(configuration.theme(), true);
} }
} }

View File

@ -11,7 +11,7 @@ import ru.noties.markwon.core.spans.CodeSpan;
public class CodeSpanFactory implements SpanFactory { public class CodeSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new CodeSpan(configuration.theme(), false); return new CodeSpan(configuration.theme(), false);
} }
} }

View File

@ -11,7 +11,7 @@ import ru.noties.markwon.core.spans.EmphasisSpan;
public class EmphasisSpanFactory implements SpanFactory { public class EmphasisSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new EmphasisSpan(); return new EmphasisSpan();
} }
} }

View File

@ -12,10 +12,10 @@ import ru.noties.markwon.core.spans.HeadingSpan;
public class HeadingSpanFactory implements SpanFactory { public class HeadingSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new HeadingSpan( return new HeadingSpan(
configuration.theme(), configuration.theme(),
CoreProps.HEADING_LEVEL.require(context) CoreProps.HEADING_LEVEL.require(props)
); );
} }
} }

View File

@ -12,10 +12,10 @@ import ru.noties.markwon.core.spans.LinkSpan;
public class LinkSpanFactory implements SpanFactory { public class LinkSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new LinkSpan( return new LinkSpan(
configuration.theme(), configuration.theme(),
CoreProps.LINK_DESTINATION.require(context), CoreProps.LINK_DESTINATION.require(props),
configuration.linkResolver() configuration.linkResolver()
); );
} }

View File

@ -14,22 +14,22 @@ public class ListItemSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
// type of list item // type of list item
// bullet : level // bullet : level
// ordered: number // ordered: number
final Object spans; final Object spans;
if (CoreProps.ListItemType.BULLET == CoreProps.LIST_ITEM_TYPE.require(context)) { if (CoreProps.ListItemType.BULLET == CoreProps.LIST_ITEM_TYPE.require(props)) {
spans = new BulletListItemSpan( spans = new BulletListItemSpan(
configuration.theme(), configuration.theme(),
CoreProps.BULLET_LIST_ITEM_LEVEL.require(context) CoreProps.BULLET_LIST_ITEM_LEVEL.require(props)
); );
} else { } else {
// todo| in order to provide real RTL experience there must be a way to provide this string // todo| in order to provide real RTL experience there must be a way to provide this string
final String number = String.valueOf(CoreProps.ORDERED_LIST_ITEM_NUMBER.require(context)) final String number = String.valueOf(CoreProps.ORDERED_LIST_ITEM_NUMBER.require(props))
+ "." + '\u00a0'; + "." + '\u00a0';
spans = new OrderedListItemSpan( spans = new OrderedListItemSpan(

View File

@ -11,7 +11,7 @@ import ru.noties.markwon.core.spans.StrongEmphasisSpan;
public class StrongEmphasisSpanFactory implements SpanFactory { public class StrongEmphasisSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new StrongEmphasisSpan(); return new StrongEmphasisSpan();
} }
} }

View File

@ -11,7 +11,7 @@ import ru.noties.markwon.core.spans.ThematicBreakSpan;
public class ThematicBreakSpanFactory implements SpanFactory { public class ThematicBreakSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new ThematicBreakSpan(configuration.theme()); return new ThematicBreakSpan(configuration.theme());
} }
} }

View File

@ -10,17 +10,17 @@ import ru.noties.markwon.SpanFactory;
public class ImageSpanFactory implements SpanFactory { public class ImageSpanFactory implements SpanFactory {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return new AsyncDrawableSpan( return new AsyncDrawableSpan(
configuration.theme(), configuration.theme(),
new AsyncDrawable( new AsyncDrawable(
ImageProps.DESTINATION.require(context), ImageProps.DESTINATION.require(props),
configuration.asyncDrawableLoader(), configuration.asyncDrawableLoader(),
configuration.imageSizeResolver(), configuration.imageSizeResolver(),
ImageProps.IMAGE_SIZE.get(context) ImageProps.IMAGE_SIZE.get(props)
), ),
AsyncDrawableSpan.ALIGN_BOTTOM, AsyncDrawableSpan.ALIGN_BOTTOM,
ImageProps.REPLACEMENT_TEXT_IS_LINK.get(context, false) ImageProps.REPLACEMENT_TEXT_IS_LINK.get(props, false)
); );
} }
} }

View File

@ -10,7 +10,8 @@ public class AbstractMarkwonVisitorImpl extends MarkwonVisitorImpl {
public AbstractMarkwonVisitorImpl( public AbstractMarkwonVisitorImpl(
@NonNull MarkwonConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull RenderProps renderProps,
@NonNull Map<Class<? extends Node>, NodeVisitor<? extends Node>> nodes) { @NonNull Map<Class<? extends Node>, NodeVisitor<? extends Node>> nodes) {
super(configuration, nodes); super(configuration, renderProps, nodes);
} }
} }

View File

@ -0,0 +1,22 @@
package ru.noties.markwon.core;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.Node;
import ru.noties.markwon.MarkwonVisitor;
public abstract class CorePluginBridge {
public static void visitCodeBlock(
@NonNull MarkwonVisitor visitor,
@Nullable String info,
@NonNull String code,
@NonNull Node node) {
CorePlugin.visitCodeBlock(visitor, info, code, node);
}
private CorePluginBridge() {
}
}

View File

@ -3,6 +3,8 @@ package ru.noties.markwon.core;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.Spanned; import android.text.Spanned;
import org.commonmark.node.Emphasis;
import org.commonmark.node.StrongEmphasis;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
@ -12,6 +14,9 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonSpansFactory;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.test.TestSpan; import ru.noties.markwon.test.TestSpan;
import ru.noties.markwon.test.TestSpanMatcher; import ru.noties.markwon.test.TestSpanMatcher;
@ -31,20 +36,21 @@ public class CoreTest {
span("bold", span("bold",
span("italic", text("bold italic")))); span("italic", text("bold italic"))));
final Spanned spanned = (Spanned) Markwon.builder(RuntimeEnvironment.application) final Spanned spanned = Markwon.builder(RuntimeEnvironment.application)
.usePlugin(CorePlugin.create()) .usePlugin(CorePlugin.create())
.usePlugin(new AbstractMarkwonPlugin() { .usePlugin(new AbstractMarkwonPlugin() {
@Override @Override
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
builder.factory(new MarkwonSpannableFactoryDef() { builder
.setFactory(StrongEmphasis.class, new SpanFactory() {
@Override @Override
public Object strongEmphasis() { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span("bold"); return span("bold");
} }
})
.setFactory(Emphasis.class, new SpanFactory() {
@Override @Override
public Object emphasis() { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span("italic"); return span("italic");
} }
}); });

View File

@ -1,20 +1,55 @@
package ru.noties.markwon.core.suite; package ru.noties.markwon.core.suite;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.Spanned; import android.text.Spanned;
import org.commonmark.node.BlockQuote;
import org.commonmark.node.Code;
import org.commonmark.node.Emphasis;
import org.commonmark.node.FencedCodeBlock;
import org.commonmark.node.Heading;
import org.commonmark.node.IndentedCodeBlock;
import org.commonmark.node.Link;
import org.commonmark.node.ListItem;
import org.commonmark.node.Node;
import org.commonmark.node.Paragraph;
import org.commonmark.node.StrongEmphasis;
import org.commonmark.node.ThematicBreak;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonSpansFactory;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.CoreProps;
import ru.noties.markwon.test.TestSpan; import ru.noties.markwon.test.TestSpan;
import ru.noties.markwon.test.TestSpanMatcher; import ru.noties.markwon.test.TestSpanMatcher;
import ru.noties.markwon.test.TestUtil; import ru.noties.markwon.test.TestUtil;
import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.span;
abstract class BaseSuiteTest { abstract class BaseSuiteTest {
static final String BOLD = "bold";
static final String ITALIC = "italic";
static final String CODE = "code";
static final String LINK = "link";
static final String BLOCK_QUOTE = "blockquote";
static final String PARAGRAPH = "paragraph";
static final String ORDERED_LIST = "ordered-list";
static final String UN_ORDERED_LIST = "un-ordered-list";
static final String HEADING = "heading";
static final String THEMATIC_BREAK = "thematic-break";
void match(@NonNull String markdown, @NonNull TestSpan.Document document) { void match(@NonNull String markdown, @NonNull TestSpan.Document document) {
final Spanned spanned = markwon().toMarkdown(markdown); final Spanned spanned = markwon().toMarkdown(markdown);
TestSpanMatcher.matches(spanned, document); TestSpanMatcher.matches(spanned, document);
@ -36,8 +71,20 @@ abstract class BaseSuiteTest {
.usePlugin(CorePlugin.create(softBreakAddsNewLine())) .usePlugin(CorePlugin.create(softBreakAddsNewLine()))
.usePlugin(new AbstractMarkwonPlugin() { .usePlugin(new AbstractMarkwonPlugin() {
@Override @Override
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
builder.factory(new TestFactory(useParagraphs()));
for (Map.Entry<Class<? extends Node>, SpanFactory> entry : CORE_NODES.entrySet()) {
builder.setFactory(entry.getKey(), entry.getValue());
}
if (useParagraphs()) {
builder.setFactory(Paragraph.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span(PARAGRAPH);
}
});
}
} }
}) })
.build(); .build();
@ -50,4 +97,75 @@ abstract class BaseSuiteTest {
boolean softBreakAddsNewLine() { boolean softBreakAddsNewLine() {
return false; return false;
} }
private static final Map<Class<? extends Node>, SpanFactory> CORE_NODES;
static {
final Map<Class<? extends Node>, SpanFactory> factories = new HashMap<>();
factories.put(BlockQuote.class, new NamedSpanFactory(BLOCK_QUOTE));
factories.put(Code.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span(CODE, args("multiline", false));
}
});
factories.put(FencedCodeBlock.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span(CODE, args("multiline", true));
}
});
factories.put(IndentedCodeBlock.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span(CODE, args("multiline", true));
}
});
factories.put(Emphasis.class, new NamedSpanFactory(ITALIC));
factories.put(Heading.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span(HEADING, args("level", CoreProps.HEADING_LEVEL.require(props)));
}
});
factories.put(Link.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span(LINK, args("href", CoreProps.LINK_DESTINATION.require(props)));
}
});
factories.put(ListItem.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
final CoreProps.ListItemType type = CoreProps.LIST_ITEM_TYPE.require(props);
if (CoreProps.ListItemType.BULLET == type) {
return span(UN_ORDERED_LIST, args("level", CoreProps.BULLET_LIST_ITEM_LEVEL.require(props)));
}
return span(ORDERED_LIST, args("start", CoreProps.ORDERED_LIST_ITEM_NUMBER.require(props)));
}
});
factories.put(StrongEmphasis.class, new NamedSpanFactory(BOLD));
factories.put(ThematicBreak.class, new NamedSpanFactory(THEMATIC_BREAK));
CORE_NODES = factories;
}
private static class NamedSpanFactory implements SpanFactory {
private final String name;
private NamedSpanFactory(@NonNull String name) {
this.name = name;
}
@Nullable
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span(name, extractArgs(props));
}
@NonNull
Map<String, Object> extractArgs(@NonNull RenderProps props) {
return Collections.emptyMap();
}
}
} }

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.BLOCK_QUOTE;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;
import static ru.noties.markwon.test.TestSpan.text; import static ru.noties.markwon.test.TestSpan.text;

View File

@ -7,8 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan; import ru.noties.markwon.test.TestSpan;
import static ru.noties.markwon.core.suite.TestFactory.BOLD;
import static ru.noties.markwon.core.suite.TestFactory.ITALIC;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;
import static ru.noties.markwon.test.TestSpan.text; import static ru.noties.markwon.test.TestSpan.text;

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.CODE;
import static ru.noties.markwon.test.TestSpan.args; import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;

View File

@ -7,9 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.BOLD;
import static ru.noties.markwon.core.suite.TestFactory.CODE;
import static ru.noties.markwon.core.suite.TestFactory.ITALIC;
import static ru.noties.markwon.test.TestSpan.args; import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.ITALIC;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;
import static ru.noties.markwon.test.TestSpan.text; import static ru.noties.markwon.test.TestSpan.text;

View File

@ -7,9 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.BOLD;
import static ru.noties.markwon.core.suite.TestFactory.ITALIC;
import static ru.noties.markwon.core.suite.TestFactory.LINK;
import static ru.noties.markwon.test.TestSpan.args; import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.HEADING;
import static ru.noties.markwon.test.TestSpan.args; import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.LINK;
import static ru.noties.markwon.test.TestSpan.args; import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.ORDERED_LIST;
import static ru.noties.markwon.test.TestSpan.args; import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.PARAGRAPH;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;
import static ru.noties.markwon.test.TestSpan.text; import static ru.noties.markwon.test.TestSpan.text;

View File

@ -7,11 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.BLOCK_QUOTE;
import static ru.noties.markwon.core.suite.TestFactory.BOLD;
import static ru.noties.markwon.core.suite.TestFactory.CODE;
import static ru.noties.markwon.core.suite.TestFactory.HEADING;
import static ru.noties.markwon.core.suite.TestFactory.ITALIC;
import static ru.noties.markwon.test.TestSpan.args; import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.BOLD;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;
import static ru.noties.markwon.test.TestSpan.text; import static ru.noties.markwon.test.TestSpan.text;

View File

@ -1,93 +0,0 @@
package ru.noties.markwon.core.suite;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.core.MarkwonSpannableFactory;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.core.spans.LinkSpan;
import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.span;
class TestFactory implements MarkwonSpannableFactory {
static final String BOLD = "bold";
static final String ITALIC = "italic";
static final String CODE = "code";
static final String LINK = "link";
static final String BLOCK_QUOTE = "blockquote";
static final String PARAGRAPH = "paragraph";
static final String ORDERED_LIST = "ordered-list";
static final String UN_ORDERED_LIST = "un-ordered-list";
static final String HEADING = "heading";
static final String THEMATIC_BREAK = "thematic-break";
private final boolean useParagraphs;
TestFactory(boolean useParagraphs) {
this.useParagraphs = useParagraphs;
}
@Nullable
@Override
public Object strongEmphasis() {
return span(BOLD);
}
@Nullable
@Override
public Object emphasis() {
return span(ITALIC);
}
@Nullable
@Override
public Object blockQuote(@NonNull MarkwonTheme theme) {
return span(BLOCK_QUOTE);
}
@Nullable
@Override
public Object code(@NonNull MarkwonTheme theme, boolean multiline) {
return span(CODE, args("multiline", multiline));
}
@Nullable
@Override
public Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber) {
return span(ORDERED_LIST, args("start", startNumber));
}
@Nullable
@Override
public Object bulletListItem(@NonNull MarkwonTheme theme, int level) {
return span(UN_ORDERED_LIST, args("level", level));
}
@Nullable
@Override
public Object thematicBreak(@NonNull MarkwonTheme theme) {
return span(THEMATIC_BREAK);
}
@Nullable
@Override
public Object heading(@NonNull MarkwonTheme theme, int level) {
return span(HEADING, args("level", level));
}
@Nullable
@Override
public Object paragraph(boolean inTightList) {
return useParagraphs
? span(PARAGRAPH)
: null;
}
@Nullable
@Override
public Object link(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) {
return span(LINK, args("href", destination));
}
}

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.THEMATIC_BREAK;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;
import static ru.noties.markwon.test.TestSpan.text; import static ru.noties.markwon.test.TestSpan.text;

View File

@ -7,7 +7,6 @@ import org.robolectric.annotation.Config;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
import static ru.noties.markwon.core.suite.TestFactory.UN_ORDERED_LIST;
import static ru.noties.markwon.test.TestSpan.args; import static ru.noties.markwon.test.TestSpan.args;
import static ru.noties.markwon.test.TestSpan.document; import static ru.noties.markwon.test.TestSpan.document;
import static ru.noties.markwon.test.TestSpan.span; import static ru.noties.markwon.test.TestSpan.span;

View File

@ -1,18 +0,0 @@
package ru.noties.markwon.core.visitor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import static org.junit.Assert.*;
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class BlockQuoteNodeVisitorTest {
@Test
public void test() {
fail();
}
}

View File

@ -2,14 +2,21 @@ package ru.noties.markwon.image;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.Image;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonSpansFactory;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.test.TestSpan.Document; import ru.noties.markwon.test.TestSpan.Document;
@ -32,10 +39,16 @@ public class ImageTest {
final Context context = RuntimeEnvironment.application; final Context context = RuntimeEnvironment.application;
final Markwon markwon = Markwon.builder(context) final Markwon markwon = Markwon.builder(context)
.usePlugin(CorePlugin.create()) .usePlugin(CorePlugin.create())
.usePlugin(new ImagesPlugin(context, false) { .usePlugin(new ImagesPlugin(context, false))
.usePlugin(new AbstractMarkwonPlugin() {
@Override @Override
protected Object imageSpan(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull AsyncDrawableLoader loader, @NonNull ImageSizeResolver imageSizeResolver, boolean replacementTextIsLink) { public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
return span("image", args("href", destination)); builder.setFactory(Image.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return span("image", args("href", ImageProps.DESTINATION.require(props)));
}
});
} }
}) })
.build(); .build();

View File

@ -1,6 +1,5 @@
package ru.noties.markwon.syntax; package ru.noties.markwon.syntax;
import android.content.Context;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -14,21 +13,24 @@ import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import java.util.HashMap; import java.util.Collections;
import java.util.Map; import java.util.Map;
import ru.noties.markwon.AbstractMarkwonVisitorImpl; import ru.noties.markwon.AbstractMarkwonVisitorImpl;
import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonSpansFactory;
import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.RenderPropsImpl;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.core.CorePluginBridge;
import ru.noties.markwon.core.MarkwonTheme; import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.core.MarkwonSpannableFactory;
import ru.noties.markwon.image.AsyncDrawableLoader; import ru.noties.markwon.image.AsyncDrawableLoader;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -53,6 +55,7 @@ public class SyntaxHighlightTest {
@Test @Test
public void test() { public void test() {
// code span must be first in the list, then should go highlight spans
class Highlight { class Highlight {
} }
@ -70,19 +73,23 @@ public class SyntaxHighlightTest {
} }
}; };
final MarkwonSpannableFactory factory = mock(MarkwonSpannableFactory.class); final MarkwonSpansFactory spansFactory = mock(MarkwonSpansFactory.class);
when(factory.code(any(MarkwonTheme.class), anyBoolean())).thenReturn(codeSpan); when(spansFactory.require(any(FencedCodeBlock.class))).thenReturn(new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
return codeSpan;
}
});
final MarkwonConfiguration configuration = MarkwonConfiguration.builder(mock(Context.class)) final MarkwonConfiguration configuration = MarkwonConfiguration.builder()
.syntaxHighlight(highlight) .syntaxHighlight(highlight)
.factory(factory) .build(mock(MarkwonTheme.class), mock(AsyncDrawableLoader.class), spansFactory);
.build(mock(MarkwonTheme.class), mock(AsyncDrawableLoader.class));
final Map<Class<? extends Node>, MarkwonVisitor.NodeVisitor<? extends Node>> visitorMap = new HashMap<>(1); final Map<Class<? extends Node>, MarkwonVisitor.NodeVisitor<? extends Node>> visitorMap = Collections.emptyMap();
visitorMap.put(FencedCodeBlock.class, new CodeBlockNodeVisitor.Fenced());
final MarkwonVisitor visitor = new AbstractMarkwonVisitorImpl( final MarkwonVisitor visitor = new AbstractMarkwonVisitorImpl(
configuration, configuration,
new RenderPropsImpl(),
visitorMap); visitorMap);
final SpannableBuilder builder = visitor.builder(); final SpannableBuilder builder = visitor.builder();
@ -96,12 +103,7 @@ public class SyntaxHighlightTest {
final FencedCodeBlock fencedCodeBlock = new FencedCodeBlock(); final FencedCodeBlock fencedCodeBlock = new FencedCodeBlock();
fencedCodeBlock.setLiteral("{code}"); fencedCodeBlock.setLiteral("{code}");
CodeBlockNodeVisitor.visitCodeBlock( CorePluginBridge.visitCodeBlock(visitor, null, "{code}", fencedCodeBlock);
visitor,
null,
"{code}",
fencedCodeBlock
);
final int end = builder.length(); final int end = builder.length();
@ -116,6 +118,7 @@ public class SyntaxHighlightTest {
assertEquals(length, spans.length); assertEquals(length, spans.length);
assertEquals(codeSpan, spans[0]); assertEquals(codeSpan, spans[0]);
// each character
for (int i = 1; i < length; i++) { for (int i = 1; i < length; i++) {
assertTrue(spans[i] instanceof Highlight); assertTrue(spans[i] instanceof Highlight);
} }

View File

@ -24,7 +24,6 @@ public class IconPlugin extends AbstractMarkwonPlugin {
@Override @Override
public void configureParser(@NonNull Parser.Builder builder) { public void configureParser(@NonNull Parser.Builder builder) {
builder.customDelimiterProcessor(IconProcessor.create()); builder.customDelimiterProcessor(IconProcessor.create());
builder.postProcessor()
} }
@Override @Override

View File

@ -25,6 +25,8 @@ public class MainActivity extends Activity {
.usePlugin(new AbstractMarkwonPlugin() { .usePlugin(new AbstractMarkwonPlugin() {
@Override @Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) { public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
// this part has nothing to do with actual IconPlugin
// this part is used to showcase that headers can be controlled via Theme
final float[] textSizeMultipliers = new float[]{3f, 2f, 1.5f, 1f, .5f, .25f}; final float[] textSizeMultipliers = new float[]{3f, 2f, 1.5f, 1f, .5f, .25f};
builder builder
.headingTypeface(Typeface.MONOSPACE) .headingTypeface(Typeface.MONOSPACE)