POC for plugin system

This commit is contained in:
Dimitry Ivanov 2018-11-24 16:03:08 +03:00
parent 340ce5753c
commit 498c811987
64 changed files with 1170 additions and 207 deletions

View File

@ -9,7 +9,7 @@ import android.util.AttributeSet;
import android.view.View; import android.view.View;
import ru.noties.markwon.R; import ru.noties.markwon.R;
import ru.noties.markwon.spans.TaskListDrawable; import ru.noties.markwon.tasklist.TaskListDrawable;
public class DebugCheckboxDrawableView extends View { public class DebugCheckboxDrawableView extends View {

View File

@ -7,7 +7,7 @@ import ru.noties.markwon.renderer.ImageSize;
import ru.noties.markwon.renderer.ImageSizeResolver; import ru.noties.markwon.renderer.ImageSizeResolver;
import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.AsyncDrawableSpan; import ru.noties.markwon.spans.AsyncDrawableSpan;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
public class GifAwareSpannableFactory extends SpannableFactoryDef { public class GifAwareSpannableFactory extends SpannableFactoryDef {
@ -19,7 +19,7 @@ public class GifAwareSpannableFactory extends SpannableFactoryDef {
@Nullable @Nullable
@Override @Override
public Object image(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) { public Object image(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
return new AsyncDrawableSpan( return new AsyncDrawableSpan(
theme, theme,
new GifAwareAsyncDrawable( new GifAwareAsyncDrawable(

View File

@ -12,6 +12,9 @@ import android.widget.TextView;
import javax.inject.Inject; import javax.inject.Inject;
import ru.noties.debug.Debug; import ru.noties.debug.Debug;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.tasklist.TaskListDrawable;
import ru.noties.markwon.tasklist.TaskListPlugin;
public class MainActivity extends Activity { public class MainActivity extends Activity {
@ -40,7 +43,7 @@ public class MainActivity extends Activity {
themes.apply(this); themes.apply(this);
// how can we obtain SpannableConfiguration after theme was applied? // how can we obtain MarkwonConfiguration after theme was applied?
// as we inject `themes` we won't be able to inject configuration, as it requires theme set // as we inject `themes` we won't be able to inject configuration, as it requires theme set
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
@ -63,6 +66,16 @@ public class MainActivity extends Activity {
appBarRenderer.render(appBarState()); appBarRenderer.render(appBarState());
if (true) {
final Markwon2 markwon2 = Markwon2.builder(this)
.use(new CorePlugin())
.use(TaskListPlugin.create(new TaskListDrawable(0xffff0000, 0xffff0000, -1)))
.build();
final CharSequence markdown = markwon2.markdown("**hello _dear_** `code`\n\n- [ ] first\n- [x] second");
textView.setText(markdown);
return;
}
markdownLoader.load(uri(), new MarkdownLoader.OnMarkdownTextLoaded() { markdownLoader.load(uri(), new MarkdownLoader.OnMarkdownTextLoaded() {
@Override @Override
public void apply(final String text) { public void apply(final String text) {

View File

@ -14,7 +14,7 @@ import javax.inject.Inject;
import ru.noties.debug.Debug; import ru.noties.debug.Debug;
import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import ru.noties.markwon.syntax.Prism4jSyntaxHighlight; import ru.noties.markwon.syntax.Prism4jSyntaxHighlight;
import ru.noties.markwon.syntax.Prism4jTheme; import ru.noties.markwon.syntax.Prism4jTheme;
import ru.noties.markwon.syntax.Prism4jThemeDarkula; import ru.noties.markwon.syntax.Prism4jThemeDarkula;
@ -87,11 +87,11 @@ public class MarkdownRenderer {
0x20000000 0x20000000
); );
final SpannableConfiguration configuration = SpannableConfiguration.builder(context) final MarkwonConfiguration configuration = MarkwonConfiguration.builder(context)
.asyncDrawableLoader(loader) .asyncDrawableLoader(loader)
.urlProcessor(urlProcessor) .urlProcessor(urlProcessor)
.syntaxHighlight(Prism4jSyntaxHighlight.create(prism4j, prism4jTheme)) .syntaxHighlight(Prism4jSyntaxHighlight.create(prism4j, prism4jTheme))
.theme(SpannableTheme.builderWithDefaults(context) .theme(MarkwonTheme.builderWithDefaults(context)
.codeBackgroundColor(background) .codeBackgroundColor(background)
.codeTextColor(prism4jTheme.textColor()) .codeTextColor(prism4jTheme.textColor())
.build()) .build())

View File

@ -209,4 +209,4 @@ Background of header table row
Drawable of task list item Drawable of task list item
<ThemeProperty name="taskListDrawable" type="android.graphics.drawable.Drawable" defaults="ru.noties.markwon.spans.TaskListDrawable" /> <ThemeProperty name="taskListDrawable" type="android.graphics.drawable.Drawable" defaults="ru.noties.markwon.tasklist.TaskListDrawable" />

View File

@ -3,27 +3,27 @@ package ru.noties.markwon.view.debug;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import ru.noties.markwon.view.IMarkwonView; import ru.noties.markwon.view.IMarkwonView;
public class DebugConfigurationProvider implements IMarkwonView.ConfigurationProvider { public class DebugConfigurationProvider implements IMarkwonView.ConfigurationProvider {
private SpannableConfiguration cached; private MarkwonConfiguration cached;
@NonNull @NonNull
@Override @Override
public SpannableConfiguration provide(@NonNull Context context) { public MarkwonConfiguration provide(@NonNull Context context) {
if (cached == null) { if (cached == null) {
cached = SpannableConfiguration.builder(context) cached = MarkwonConfiguration.builder(context)
.theme(debugTheme(context)) .theme(debugTheme(context))
.build(); .build();
} }
return cached; return cached;
} }
private static SpannableTheme debugTheme(@NonNull Context context) { private static MarkwonTheme debugTheme(@NonNull Context context) {
return SpannableTheme.builderWithDefaults(context) return MarkwonTheme.builderWithDefaults(context)
.blockQuoteColor(0xFFff0000) .blockQuoteColor(0xFFff0000)
.codeBackgroundColor(0x40FF0000) .codeBackgroundColor(0x40FF0000)
.build(); .build();

View File

@ -4,19 +4,19 @@ import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
public interface IMarkwonView { public interface IMarkwonView {
interface ConfigurationProvider { interface ConfigurationProvider {
@NonNull @NonNull
SpannableConfiguration provide(@NonNull Context context); MarkwonConfiguration provide(@NonNull Context context);
} }
void setConfigurationProvider(@NonNull ConfigurationProvider provider); void setConfigurationProvider(@NonNull ConfigurationProvider provider);
void setMarkdown(@Nullable String markdown); void setMarkdown(@Nullable String markdown);
void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown); void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown);
@Nullable @Nullable
String getMarkdown(); String getMarkdown();

View File

@ -7,7 +7,7 @@ import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.TextView; import android.widget.TextView;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
@SuppressLint("AppCompatCustomView") @SuppressLint("AppCompatCustomView")
public class MarkwonView extends TextView implements IMarkwonView { public class MarkwonView extends TextView implements IMarkwonView {
@ -38,7 +38,7 @@ public class MarkwonView extends TextView implements IMarkwonView {
helper.setMarkdown(markdown); helper.setMarkdown(markdown);
} }
public void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown) { public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
helper.setMarkdown(configuration, markdown); helper.setMarkdown(configuration, markdown);
} }

View File

@ -6,7 +6,7 @@ import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatTextView; import android.support.v7.widget.AppCompatTextView;
import android.util.AttributeSet; import android.util.AttributeSet;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView { public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView {
@ -38,7 +38,7 @@ public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView
} }
@Override @Override
public void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown) { public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
helper.setMarkdown(configuration, markdown); helper.setMarkdown(configuration, markdown);
} }

View File

@ -9,7 +9,7 @@ import android.util.AttributeSet;
import android.widget.TextView; import android.widget.TextView;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
public class MarkwonViewHelper implements IMarkwonView { public class MarkwonViewHelper implements IMarkwonView {
@ -21,7 +21,7 @@ public class MarkwonViewHelper implements IMarkwonView {
private ConfigurationProvider provider; private ConfigurationProvider provider;
private SpannableConfiguration configuration; private MarkwonConfiguration configuration;
private String markdown; private String markdown;
private MarkwonViewHelper(@NonNull TextView textView) { private MarkwonViewHelper(@NonNull TextView textView) {
@ -71,14 +71,14 @@ public class MarkwonViewHelper implements IMarkwonView {
} }
@Override @Override
public void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown) { public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
this.markdown = markdown; this.markdown = markdown;
if (configuration == null) { if (configuration == null) {
if (this.configuration == null) { if (this.configuration == null) {
if (provider != null) { if (provider != null) {
this.configuration = provider.provide(textView.getContext()); this.configuration = provider.provide(textView.getContext());
} else { } else {
this.configuration = SpannableConfiguration.create(textView.getContext()); this.configuration = MarkwonConfiguration.create(textView.getContext());
} }
} }
configuration = this.configuration; configuration = this.configuration;

View File

@ -0,0 +1,46 @@
package ru.noties.markwon;
import android.support.annotation.NonNull;
import android.widget.TextView;
import org.commonmark.parser.Parser;
import ru.noties.markwon.spans.MarkwonTheme;
public abstract class AbstractMarkwonPlugin implements MarkwonPlugin {
@Override
public void configureParser(@NonNull Parser.Builder builder) {
}
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
}
@Override
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
}
@Override
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
}
@NonNull
@Override
public String processMarkdown(@NonNull String markdown) {
return markdown;
}
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) {
}
@Override
public void afterSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) {
}
}

View File

@ -40,11 +40,11 @@ public abstract class Markwon {
} }
/** /**
* @see #setMarkdown(TextView, SpannableConfiguration, String) * @see #setMarkdown(TextView, MarkwonConfiguration, String)
* @since 1.0.0 * @since 1.0.0
*/ */
public static void setMarkdown(@NonNull TextView view, @NonNull String markdown) { public static void setMarkdown(@NonNull TextView view, @NonNull String markdown) {
setMarkdown(view, SpannableConfiguration.create(view.getContext()), markdown); setMarkdown(view, MarkwonConfiguration.create(view.getContext()), markdown);
} }
/** /**
@ -52,16 +52,16 @@ public abstract class Markwon {
* and applies it to view * and applies it to view
* *
* @param view {@link TextView} to set markdown into * @param view {@link TextView} to set markdown into
* @param configuration a {@link SpannableConfiguration} instance * @param configuration a {@link MarkwonConfiguration} instance
* @param markdown raw markdown String (for example: {@code `**Hello**`}) * @param markdown raw markdown String (for example: {@code `**Hello**`})
* @see #markdown(SpannableConfiguration, String) * @see #markdown(MarkwonConfiguration, String)
* @see #setText(TextView, CharSequence) * @see #setText(TextView, CharSequence)
* @see SpannableConfiguration * @see MarkwonConfiguration
* @since 1.0.0 * @since 1.0.0
*/ */
public static void setMarkdown( public static void setMarkdown(
@NonNull TextView view, @NonNull TextView view,
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull String markdown @NonNull String markdown
) { ) {
@ -117,7 +117,7 @@ public abstract class Markwon {
} }
/** /**
* Returns parsed markdown with default {@link SpannableConfiguration} obtained from {@link Context} * Returns parsed markdown with default {@link MarkwonConfiguration} obtained from {@link Context}
* *
* @param context {@link Context} * @param context {@link Context}
* @param markdown raw markdown * @param markdown raw markdown
@ -126,21 +126,21 @@ public abstract class Markwon {
*/ */
@NonNull @NonNull
public static CharSequence markdown(@NonNull Context context, @NonNull String markdown) { public static CharSequence markdown(@NonNull Context context, @NonNull String markdown) {
final SpannableConfiguration configuration = SpannableConfiguration.create(context); final MarkwonConfiguration configuration = MarkwonConfiguration.create(context);
return markdown(configuration, markdown); return markdown(configuration, markdown);
} }
/** /**
* Returns parsed markdown with provided {@link SpannableConfiguration} * Returns parsed markdown with provided {@link MarkwonConfiguration}
* *
* @param configuration a {@link SpannableConfiguration} * @param configuration a {@link MarkwonConfiguration}
* @param markdown raw markdown * @param markdown raw markdown
* @return parsed markdown * @return parsed markdown
* @see SpannableConfiguration * @see MarkwonConfiguration
* @since 1.0.0 * @since 1.0.0
*/ */
@NonNull @NonNull
public static CharSequence markdown(@NonNull SpannableConfiguration configuration, @NonNull String markdown) { public static CharSequence markdown(@NonNull MarkwonConfiguration configuration, @NonNull String markdown) {
final Parser parser = createParser(); final Parser parser = createParser();
final Node node = parser.parse(markdown); final Node node = parser.parse(markdown);
final SpannableRenderer renderer = new SpannableRenderer(); final SpannableRenderer renderer = new SpannableRenderer();

View File

@ -0,0 +1,32 @@
package ru.noties.markwon;
import android.content.Context;
import android.support.annotation.NonNull;
import org.commonmark.node.Node;
public abstract class Markwon2 {
@NonNull
public static Builder builder(@NonNull Context context) {
return new MarkwonBuilderImpl(context);
}
@NonNull
public abstract Node parse(@NonNull String input);
@NonNull
public abstract CharSequence render(@NonNull Node node);
@NonNull
public abstract CharSequence markdown(@NonNull String input);
public interface Builder {
@NonNull
Builder use(@NonNull MarkwonPlugin plugin);
@NonNull
Markwon2 build();
}
}

View File

@ -0,0 +1,53 @@
package ru.noties.markwon;
import android.content.Context;
import android.support.annotation.NonNull;
import org.commonmark.parser.Parser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import ru.noties.markwon.spans.MarkwonTheme;
class MarkwonBuilderImpl implements Markwon2.Builder {
private final Context context;
private final List<MarkwonPlugin> plugins = new ArrayList<>(3);
MarkwonBuilderImpl(@NonNull Context context) {
this.context = context;
}
@NonNull
@Override
public Markwon2.Builder use(@NonNull MarkwonPlugin plugin) {
plugins.add(plugin);
return this;
}
@NonNull
@Override
public Markwon2 build() {
final Parser.Builder parserBuilder = new Parser.Builder();
final MarkwonTheme.Builder themeBuilder = MarkwonTheme.builderWithDefaults(context);
final MarkwonConfiguration.Builder configurationBuilder = new MarkwonConfiguration.Builder(context);
final MarkwonVisitor.Builder visitorBuilder = new MarkwonVisitorImpl.BuilderImpl();
for (MarkwonPlugin plugin : plugins) {
plugin.configureParser(parserBuilder);
plugin.configureTheme(themeBuilder);
plugin.configureConfiguration(configurationBuilder);
plugin.configureVisitor(visitorBuilder);
}
return new MarkwonImpl(
parserBuilder.build(),
visitorBuilder.build(themeBuilder.build(), configurationBuilder.build()),
Collections.unmodifiableList(plugins)
);
}
}

View File

@ -9,14 +9,17 @@ import ru.noties.markwon.renderer.ImageSizeResolverDef;
import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer; import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer;
import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.LinkSpan; import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
/**
* since 3.0.0 renamed `SpannableConfiguration` -&gt; `MarkwonConfiguration`
*/
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public class SpannableConfiguration { public class MarkwonConfiguration {
// creates default configuration // creates default configuration
@NonNull @NonNull
public static SpannableConfiguration create(@NonNull Context context) { public static MarkwonConfiguration create(@NonNull Context context) {
return new Builder(context).build(); return new Builder(context).build();
} }
@ -25,7 +28,9 @@ public class SpannableConfiguration {
return new Builder(context); return new Builder(context);
} }
private final SpannableTheme theme; @Deprecated
private final MarkwonTheme theme;
private final AsyncDrawable.Loader asyncDrawableLoader; private final AsyncDrawable.Loader asyncDrawableLoader;
private final SyntaxHighlight syntaxHighlight; private final SyntaxHighlight syntaxHighlight;
private final LinkSpan.Resolver linkResolver; private final LinkSpan.Resolver linkResolver;
@ -37,7 +42,7 @@ public class SpannableConfiguration {
private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0 private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
private final boolean htmlAllowNonClosedTags; // @since 2.0.0 private final boolean htmlAllowNonClosedTags; // @since 2.0.0
private SpannableConfiguration(@NonNull Builder builder) { private MarkwonConfiguration(@NonNull Builder builder) {
this.theme = builder.theme; this.theme = builder.theme;
this.asyncDrawableLoader = builder.asyncDrawableLoader; this.asyncDrawableLoader = builder.asyncDrawableLoader;
this.syntaxHighlight = builder.syntaxHighlight; this.syntaxHighlight = builder.syntaxHighlight;
@ -60,7 +65,8 @@ public class SpannableConfiguration {
} }
@NonNull @NonNull
public SpannableTheme theme() { @Deprecated
public MarkwonTheme theme() {
return theme; return theme;
} }
@ -130,7 +136,9 @@ public class SpannableConfiguration {
public static class Builder { public static class Builder {
private final Context context; private final Context context;
private SpannableTheme theme;
@Deprecated
private MarkwonTheme theme;
private AsyncDrawable.Loader asyncDrawableLoader; private AsyncDrawable.Loader asyncDrawableLoader;
private SyntaxHighlight syntaxHighlight; private SyntaxHighlight syntaxHighlight;
private LinkSpan.Resolver linkResolver; private LinkSpan.Resolver linkResolver;
@ -146,7 +154,7 @@ public class SpannableConfiguration {
this.context = context; this.context = context;
} }
Builder(@NonNull Context context, @NonNull SpannableConfiguration configuration) { Builder(@NonNull Context context, @NonNull MarkwonConfiguration configuration) {
this(context); this(context);
this.theme = configuration.theme; this.theme = configuration.theme;
this.asyncDrawableLoader = configuration.asyncDrawableLoader; this.asyncDrawableLoader = configuration.asyncDrawableLoader;
@ -162,7 +170,8 @@ public class SpannableConfiguration {
} }
@NonNull @NonNull
public Builder theme(@NonNull SpannableTheme theme) { @Deprecated
public Builder theme(@NonNull MarkwonTheme theme) {
this.theme = theme; this.theme = theme;
return this; return this;
} }
@ -254,10 +263,10 @@ public class SpannableConfiguration {
} }
@NonNull @NonNull
public SpannableConfiguration build() { public MarkwonConfiguration build() {
if (theme == null) { if (theme == null) {
theme = SpannableTheme.create(context); theme = MarkwonTheme.create(context);
} }
if (asyncDrawableLoader == null) { if (asyncDrawableLoader == null) {
@ -300,7 +309,7 @@ public class SpannableConfiguration {
htmlRenderer = MarkwonHtmlRenderer.create(); htmlRenderer = MarkwonHtmlRenderer.create();
} }
return new SpannableConfiguration(this); return new MarkwonConfiguration(this);
} }
} }

View File

@ -0,0 +1,48 @@
package ru.noties.markwon;
import android.support.annotation.NonNull;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import java.util.List;
class MarkwonImpl extends Markwon2 {
private final Parser parser;
private final MarkwonVisitor visitor;
private final List<MarkwonPlugin> plugins;
MarkwonImpl(
@NonNull Parser parser,
@NonNull MarkwonVisitor visitor,
@NonNull List<MarkwonPlugin> plugins) {
this.parser = parser;
this.visitor = visitor;
this.plugins = plugins;
}
@NonNull
@Override
public Node parse(@NonNull String input) {
for (MarkwonPlugin plugin : plugins) {
input = plugin.processMarkdown(input);
}
return parser.parse(input);
}
@NonNull
@Override
public CharSequence render(@NonNull Node node) {
node.accept(visitor);
return visitor.builder().text();
}
@NonNull
@Override
public CharSequence markdown(@NonNull String input) {
return render(parse(input));
}
}

View File

@ -0,0 +1,29 @@
package ru.noties.markwon;
import android.support.annotation.NonNull;
import android.widget.TextView;
import org.commonmark.parser.Parser;
import ru.noties.markwon.spans.MarkwonTheme;
public interface MarkwonPlugin {
void configureParser(@NonNull Parser.Builder builder);
void configureTheme(@NonNull MarkwonTheme.Builder builder);
void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder);
void configureVisitor(@NonNull MarkwonVisitor.Builder builder);
// images
// html
@NonNull
String processMarkdown(@NonNull String markdown);
void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder);
void afterSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder);
}

View File

@ -0,0 +1,60 @@
package ru.noties.markwon;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.Node;
import org.commonmark.node.Visitor;
import ru.noties.markwon.spans.MarkwonTheme;
public interface MarkwonVisitor extends Visitor {
interface NodeVisitor<N extends Node> {
void visit(@NonNull MarkwonVisitor visitor, @NonNull N n);
}
interface Builder {
@NonNull
<N extends Node> Builder on(@NonNull Class<N> node, @NonNull NodeVisitor<N> nodeVisitor);
@NonNull
MarkwonVisitor build(@NonNull MarkwonTheme theme, @NonNull MarkwonConfiguration configuration);
}
@NonNull
MarkwonTheme theme();
@NonNull
MarkwonConfiguration configuration();
@NonNull
SpannableBuilder builder();
void visitChildren(@NonNull Node node);
boolean hasNext(@NonNull Node node);
void incrementBlockQuoteIndent();
void decrementBlockQuoteIndent();
void blockQuoteIntent(int blockQuoteIndent);
int blockQuoteIndent();
void incrementListLevel();
void decrementListLevel();
int listLevel();
void ensureNewLine();
void forceNewLine();
int length();
void setSpans(int start, @Nullable Object spans);
}

View File

@ -0,0 +1,290 @@
package ru.noties.markwon;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.BlockQuote;
import org.commonmark.node.BulletList;
import org.commonmark.node.Code;
import org.commonmark.node.CustomBlock;
import org.commonmark.node.CustomNode;
import org.commonmark.node.Document;
import org.commonmark.node.Emphasis;
import org.commonmark.node.FencedCodeBlock;
import org.commonmark.node.HardLineBreak;
import org.commonmark.node.Heading;
import org.commonmark.node.HtmlBlock;
import org.commonmark.node.HtmlInline;
import org.commonmark.node.Image;
import org.commonmark.node.IndentedCodeBlock;
import org.commonmark.node.Link;
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;
import org.commonmark.node.StrongEmphasis;
import org.commonmark.node.Text;
import org.commonmark.node.ThematicBreak;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import ru.noties.markwon.spans.MarkwonTheme;
class MarkwonVisitorImpl implements MarkwonVisitor {
private final Map<Class<? extends Node>, NodeVisitor<? extends Node>> nodes;
private final MarkwonTheme theme;
private final MarkwonConfiguration configuration;
private final SpannableBuilder builder = new SpannableBuilder();
private int blockQuoteIndent;
private int listLevel;
private MarkwonVisitorImpl(
@NonNull MarkwonTheme theme,
@NonNull MarkwonConfiguration configuration,
@NonNull Map<Class<? extends Node>, NodeVisitor<? extends Node>> nodes) {
this.theme = theme;
this.configuration = configuration;
this.nodes = nodes;
}
@Override
public void visit(BlockQuote blockQuote) {
visit((Node) blockQuote);
}
@Override
public void visit(BulletList bulletList) {
visit((Node) bulletList);
}
@Override
public void visit(Code code) {
visit((Node) code);
}
@Override
public void visit(Document document) {
visit((Node) document);
}
@Override
public void visit(Emphasis emphasis) {
visit((Node) emphasis);
}
@Override
public void visit(FencedCodeBlock fencedCodeBlock) {
visit((Node) fencedCodeBlock);
}
@Override
public void visit(HardLineBreak hardLineBreak) {
visit((Node) hardLineBreak);
}
@Override
public void visit(Heading heading) {
visit((Node) heading);
}
@Override
public void visit(ThematicBreak thematicBreak) {
visit((Node) thematicBreak);
}
@Override
public void visit(HtmlInline htmlInline) {
visit((Node) htmlInline);
}
@Override
public void visit(HtmlBlock htmlBlock) {
visit((Node) htmlBlock);
}
@Override
public void visit(Image image) {
visit((Node) image);
}
@Override
public void visit(IndentedCodeBlock indentedCodeBlock) {
visit((Node) indentedCodeBlock);
}
@Override
public void visit(Link link) {
visit((Node) link);
}
@Override
public void visit(ListItem listItem) {
visit((Node) listItem);
}
@Override
public void visit(OrderedList orderedList) {
visit((Node) orderedList);
}
@Override
public void visit(Paragraph paragraph) {
visit((Node) paragraph);
}
@Override
public void visit(SoftLineBreak softLineBreak) {
visit((Node) softLineBreak);
}
@Override
public void visit(StrongEmphasis strongEmphasis) {
visit((Node) strongEmphasis);
}
@Override
public void visit(Text text) {
visit((Node) text);
}
@Override
public void visit(CustomBlock customBlock) {
visit((Node) customBlock);
}
@Override
public void visit(CustomNode customNode) {
visit((Node) customNode);
}
private void visit(@NonNull Node node) {
//noinspection unchecked
final NodeVisitor<Node> nodeVisitor = (NodeVisitor<Node>) nodes.get(node.getClass());
if (nodeVisitor != null) {
nodeVisitor.visit(this, node);
} else {
visitChildren(node);
}
}
@NonNull
@Override
public MarkwonTheme theme() {
return theme;
}
@NonNull
@Override
public MarkwonConfiguration configuration() {
return configuration;
}
@NonNull
@Override
public SpannableBuilder builder() {
return builder;
}
@Override
public void visitChildren(@NonNull Node parent) {
Node node = parent.getFirstChild();
while (node != null) {
// A subclass of this visitor might modify the node, resulting in getNext returning a different node or no
// node after visiting it. So get the next node before visiting.
Node next = node.getNext();
node.accept(this);
node = next;
}
}
@Override
public boolean hasNext(@NonNull Node node) {
return node.getNext() != null;
}
@Override
public void incrementBlockQuoteIndent() {
blockQuoteIndent += 1;
}
@Override
public void decrementBlockQuoteIndent() {
blockQuoteIndent -= 1;
}
@Override
public void blockQuoteIntent(int blockQuoteIndent) {
this.blockQuoteIndent = blockQuoteIndent;
}
@Override
public int blockQuoteIndent() {
return blockQuoteIndent;
}
@Override
public void incrementListLevel() {
listLevel += 1;
}
@Override
public void decrementListLevel() {
listLevel -= 1;
}
@Override
public int listLevel() {
return listLevel;
}
@Override
public void ensureNewLine() {
if (builder.length() > 0
&& '\n' != builder.lastChar()) {
builder.append('\n');
}
}
@Override
public void forceNewLine() {
builder.append('\n');
}
@Override
public int length() {
return builder.length();
}
@Override
public void setSpans(int start, @Nullable Object spans) {
SpannableBuilder.setSpans(builder, spans, start, builder.length());
}
static class BuilderImpl implements Builder {
private final Map<Class<? extends Node>, NodeVisitor<? extends Node>> nodes =
new HashMap<>(3);
@NonNull
@Override
public <N extends Node> Builder on(@NonNull Class<N> node, @NonNull NodeVisitor<N> nodeVisitor) {
nodes.put(node, nodeVisitor);
return this;
}
@NonNull
@Override
public MarkwonVisitor build(@NonNull MarkwonTheme theme, @NonNull MarkwonConfiguration configuration) {
return new MarkwonVisitorImpl(
theme,
configuration,
Collections.unmodifiableMap(nodes));
}
}
}

View File

@ -208,7 +208,7 @@ public class SpannableBuilder implements Appendable, CharSequence {
/** /**
* This method will return all {@link Span} spans that <em>overlap</em> specified range, * This method will return all {@link Span} spans that <em>overlap</em> specified range,
* so if for example a 1..9 range is specified some spans might have 0..6 or 0..10 start/end ranges. * so if for example a 1..9 range is specified some spans might have 0..6 or 0..10 start/end ranges.
* NB spans are returned in reversed order (no in order that we store them internally) * NB spans are returned in reversed order (not in order that we store them internally)
* *
* @since 2.0.1 * @since 2.0.1
*/ */

View File

@ -9,7 +9,7 @@ import ru.noties.markwon.renderer.ImageSize;
import ru.noties.markwon.renderer.ImageSizeResolver; import ru.noties.markwon.renderer.ImageSizeResolver;
import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.LinkSpan; import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import ru.noties.markwon.spans.TableRowSpan; import ru.noties.markwon.spans.TableRowSpan;
/** /**
@ -26,32 +26,32 @@ public interface SpannableFactory {
Object emphasis(); Object emphasis();
@Nullable @Nullable
Object blockQuote(@NonNull SpannableTheme theme); Object blockQuote(@NonNull MarkwonTheme theme);
@Nullable @Nullable
Object code(@NonNull SpannableTheme theme, boolean multiline); Object code(@NonNull MarkwonTheme theme, boolean multiline);
@Nullable @Nullable
Object orderedListItem(@NonNull SpannableTheme theme, int startNumber); Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber);
@Nullable @Nullable
Object bulletListItem(@NonNull SpannableTheme theme, int level); Object bulletListItem(@NonNull MarkwonTheme theme, int level);
@Nullable @Nullable
Object thematicBreak(@NonNull SpannableTheme theme); Object thematicBreak(@NonNull MarkwonTheme theme);
@Nullable @Nullable
Object heading(@NonNull SpannableTheme theme, int level); Object heading(@NonNull MarkwonTheme theme, int level);
@Nullable @Nullable
Object strikethrough(); Object strikethrough();
@Nullable @Nullable
Object taskListItem(@NonNull SpannableTheme theme, int blockIndent, boolean isDone); Object taskListItem(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone);
@Nullable @Nullable
Object tableRow( Object tableRow(
@NonNull SpannableTheme theme, @NonNull MarkwonTheme theme,
@NonNull List<TableRowSpan.Cell> cells, @NonNull List<TableRowSpan.Cell> cells,
boolean isHeader, boolean isHeader,
boolean isOdd); boolean isOdd);
@ -64,7 +64,7 @@ public interface SpannableFactory {
@Nullable @Nullable
Object image( Object image(
@NonNull SpannableTheme theme, @NonNull MarkwonTheme theme,
@NonNull String destination, @NonNull String destination,
@NonNull AsyncDrawable.Loader loader, @NonNull AsyncDrawable.Loader loader,
@NonNull ImageSizeResolver imageSizeResolver, @NonNull ImageSizeResolver imageSizeResolver,
@ -73,17 +73,17 @@ public interface SpannableFactory {
@Nullable @Nullable
Object link( Object link(
@NonNull SpannableTheme theme, @NonNull MarkwonTheme theme,
@NonNull String destination, @NonNull String destination,
@NonNull LinkSpan.Resolver resolver); @NonNull LinkSpan.Resolver resolver);
// Currently used by HTML parser // Currently used by HTML parser
@Nullable @Nullable
Object superScript(@NonNull SpannableTheme theme); Object superScript(@NonNull MarkwonTheme theme);
// Currently used by HTML parser // Currently used by HTML parser
@Nullable @Nullable
Object subScript(@NonNull SpannableTheme theme); Object subScript(@NonNull MarkwonTheme theme);
// Currently used by HTML parser // Currently used by HTML parser
@Nullable @Nullable

View File

@ -18,12 +18,12 @@ import ru.noties.markwon.spans.EmphasisSpan;
import ru.noties.markwon.spans.HeadingSpan; import ru.noties.markwon.spans.HeadingSpan;
import ru.noties.markwon.spans.LinkSpan; import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.OrderedListItemSpan; import ru.noties.markwon.spans.OrderedListItemSpan;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import ru.noties.markwon.spans.StrongEmphasisSpan; import ru.noties.markwon.spans.StrongEmphasisSpan;
import ru.noties.markwon.spans.SubScriptSpan; import ru.noties.markwon.spans.SubScriptSpan;
import ru.noties.markwon.spans.SuperScriptSpan; import ru.noties.markwon.spans.SuperScriptSpan;
import ru.noties.markwon.spans.TableRowSpan; import ru.noties.markwon.spans.TableRowSpan;
import ru.noties.markwon.spans.TaskListSpan; import ru.noties.markwon.tasklist.TaskListSpan;
import ru.noties.markwon.spans.ThematicBreakSpan; import ru.noties.markwon.spans.ThematicBreakSpan;
/** /**
@ -50,38 +50,38 @@ public class SpannableFactoryDef implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object blockQuote(@NonNull SpannableTheme theme) { public Object blockQuote(@NonNull MarkwonTheme theme) {
return new BlockQuoteSpan(theme); return new BlockQuoteSpan(theme);
} }
@Nullable @Nullable
@Override @Override
public Object code(@NonNull SpannableTheme theme, boolean multiline) { public Object code(@NonNull MarkwonTheme theme, boolean multiline) {
return new CodeSpan(theme, multiline); return new CodeSpan(theme, multiline);
} }
@Nullable @Nullable
@Override @Override
public Object orderedListItem(@NonNull SpannableTheme theme, int startNumber) { 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 // 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'); return new OrderedListItemSpan(theme, String.valueOf(startNumber) + "." + '\u00a0');
} }
@Nullable @Nullable
@Override @Override
public Object bulletListItem(@NonNull SpannableTheme theme, int level) { public Object bulletListItem(@NonNull MarkwonTheme theme, int level) {
return new BulletListItemSpan(theme, level); return new BulletListItemSpan(theme, level);
} }
@Nullable @Nullable
@Override @Override
public Object thematicBreak(@NonNull SpannableTheme theme) { public Object thematicBreak(@NonNull MarkwonTheme theme) {
return new ThematicBreakSpan(theme); return new ThematicBreakSpan(theme);
} }
@Nullable @Nullable
@Override @Override
public Object heading(@NonNull SpannableTheme theme, int level) { public Object heading(@NonNull MarkwonTheme theme, int level) {
return new HeadingSpan(theme, level); return new HeadingSpan(theme, level);
} }
@ -93,13 +93,13 @@ public class SpannableFactoryDef implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object taskListItem(@NonNull SpannableTheme theme, int blockIndent, boolean isDone) { public Object taskListItem(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone) {
return new TaskListSpan(theme, blockIndent, isDone); return new TaskListSpan(theme, blockIndent, isDone);
} }
@Nullable @Nullable
@Override @Override
public Object tableRow(@NonNull SpannableTheme theme, @NonNull List<TableRowSpan.Cell> cells, boolean isHeader, boolean isOdd) { public Object tableRow(@NonNull MarkwonTheme theme, @NonNull List<TableRowSpan.Cell> cells, boolean isHeader, boolean isOdd) {
return new TableRowSpan(theme, cells, isHeader, isOdd); return new TableRowSpan(theme, cells, isHeader, isOdd);
} }
@ -114,7 +114,7 @@ public class SpannableFactoryDef implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object image(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) { public Object image(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
return new AsyncDrawableSpan( return new AsyncDrawableSpan(
theme, theme,
new AsyncDrawable( new AsyncDrawable(
@ -130,18 +130,18 @@ public class SpannableFactoryDef implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object link(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) { public Object link(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) {
return new LinkSpan(theme, destination, resolver); return new LinkSpan(theme, destination, resolver);
} }
@Nullable @Nullable
@Override @Override
public Object superScript(@NonNull SpannableTheme theme) { public Object superScript(@NonNull MarkwonTheme theme) {
return new SuperScriptSpan(theme); return new SuperScriptSpan(theme);
} }
@Override @Override
public Object subScript(@NonNull SpannableTheme theme) { public Object subScript(@NonNull MarkwonTheme theme) {
return new SubScriptSpan(theme); return new SubScriptSpan(theme);
} }

View File

@ -0,0 +1,268 @@
package ru.noties.markwon.core;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.TextView;
import org.commonmark.node.BlockQuote;
import org.commonmark.node.BulletList;
import org.commonmark.node.Code;
import org.commonmark.node.Emphasis;
import org.commonmark.node.FencedCodeBlock;
import org.commonmark.node.IndentedCodeBlock;
import org.commonmark.node.ListItem;
import org.commonmark.node.Node;
import org.commonmark.node.OrderedList;
import org.commonmark.node.StrongEmphasis;
import org.commonmark.node.Text;
import org.commonmark.node.ThematicBreak;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.SpannableBuilder;
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?)
@Override
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
text(builder);
strongEmphasis(builder);
emphasis(builder);
blockQuote(builder);
code(builder);
fencedCodeBlock(builder);
indentedCodeBlock(builder);
bulletList(builder);
orderedList(builder);
listItem(builder);
thematicBreak(builder);
}
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) {
OrderedListItemSpan.measure(textView, builder);
}
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());
}
});
}
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.configuration().factory().strongEmphasis());
}
});
}
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.configuration().factory().emphasis());
}
});
}
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();
if (visitor.blockQuoteIndent() > 0) {
visitor.forceNewLine();
}
final int length = visitor.length();
visitor.incrementBlockQuoteIndent();
visitor.visitChildren(blockQuote);
visitor.setSpans(length, visitor.configuration().factory().blockQuote(visitor.theme()));
visitor.decrementBlockQuoteIndent();
if (visitor.hasNext(blockQuote)) {
visitor.ensureNewLine();
if (visitor.blockQuoteIndent() > 0) {
visitor.forceNewLine();
}
}
}
});
}
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.configuration().factory().code(visitor.theme(), false));
}
});
}
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);
}
});
}
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.configuration().factory().code(visitor.theme(), true));
if (visitor.hasNext(node)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
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);
}
});
}
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.blockQuoteIndent() == 0) {
visitor.forceNewLine();
}
}
}
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.incrementBlockQuoteIndent();
visitor.incrementListLevel();
final Node parent = listItem.getParent();
if (parent instanceof OrderedList) {
final int start = ((OrderedList) parent).getStartNumber();
visitor.visitChildren(listItem);
visitor.setSpans(length, visitor.configuration().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.configuration().factory().bulletListItem(visitor.theme(), visitor.listLevel() - 1));
}
visitor.decrementBlockQuoteIndent();
visitor.decrementListLevel();
if (visitor.hasNext(listItem)) {
visitor.ensureNewLine();
}
}
});
}
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.configuration().factory().thematicBreak(visitor.theme()));
if (visitor.hasNext(thematicBreak)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
});
}
}

View File

@ -38,10 +38,10 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableFactory; import ru.noties.markwon.SpannableFactory;
import ru.noties.markwon.html.api.MarkwonHtmlParser; import ru.noties.markwon.html.api.MarkwonHtmlParser;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import ru.noties.markwon.spans.TableRowSpan; import ru.noties.markwon.spans.TableRowSpan;
import ru.noties.markwon.tasklist.TaskListBlock; import ru.noties.markwon.tasklist.TaskListBlock;
import ru.noties.markwon.tasklist.TaskListItem; import ru.noties.markwon.tasklist.TaskListItem;
@ -49,11 +49,11 @@ import ru.noties.markwon.tasklist.TaskListItem;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public class SpannableMarkdownVisitor extends AbstractVisitor { public class SpannableMarkdownVisitor extends AbstractVisitor {
private final SpannableConfiguration configuration; private final MarkwonConfiguration configuration;
private final SpannableBuilder builder; private final SpannableBuilder builder;
private final MarkwonHtmlParser htmlParser; private final MarkwonHtmlParser htmlParser;
private final SpannableTheme theme; private final MarkwonTheme theme;
private final SpannableFactory factory; private final SpannableFactory factory;
private int blockQuoteIndent; private int blockQuoteIndent;
@ -64,7 +64,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
private int tableRows; private int tableRows;
public SpannableMarkdownVisitor( public SpannableMarkdownVisitor(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder @NonNull SpannableBuilder builder
) { ) {
this.configuration = configuration; this.configuration = configuration;

View File

@ -4,13 +4,13 @@ import android.support.annotation.NonNull;
import org.commonmark.node.Node; import org.commonmark.node.Node;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration;
public class SpannableRenderer { public class SpannableRenderer {
@NonNull @NonNull
public CharSequence render(@NonNull SpannableConfiguration configuration, @NonNull Node node) { public CharSequence render(@NonNull MarkwonConfiguration configuration, @NonNull Node node) {
final SpannableBuilder builder = new SpannableBuilder(); final SpannableBuilder builder = new SpannableBuilder();
node.accept(new SpannableMarkdownVisitor(configuration, builder)); node.accept(new SpannableMarkdownVisitor(configuration, builder));
return builder.text(); return builder.text();

View File

@ -9,7 +9,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.MarkwonHtmlParser; import ru.noties.markwon.html.api.MarkwonHtmlParser;
import ru.noties.markwon.renderer.html2.tag.BlockquoteHandler; import ru.noties.markwon.renderer.html2.tag.BlockquoteHandler;
import ru.noties.markwon.renderer.html2.tag.EmphasisHandler; import ru.noties.markwon.renderer.html2.tag.EmphasisHandler;
@ -30,7 +30,7 @@ import ru.noties.markwon.renderer.html2.tag.UnderlineHandler;
public abstract class MarkwonHtmlRenderer { public abstract class MarkwonHtmlRenderer {
public abstract void render( public abstract void render(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder, @NonNull SpannableBuilder builder,
@NonNull MarkwonHtmlParser parser @NonNull MarkwonHtmlParser parser
); );

View File

@ -7,7 +7,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
import ru.noties.markwon.html.api.MarkwonHtmlParser; import ru.noties.markwon.html.api.MarkwonHtmlParser;
import ru.noties.markwon.renderer.html2.tag.TagHandler; import ru.noties.markwon.renderer.html2.tag.TagHandler;
@ -22,7 +22,7 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer {
@Override @Override
public void render( public void render(
@NonNull final SpannableConfiguration configuration, @NonNull final MarkwonConfiguration configuration,
@NonNull final SpannableBuilder builder, @NonNull final SpannableBuilder builder,
@NonNull MarkwonHtmlParser parser) { @NonNull MarkwonHtmlParser parser) {

View File

@ -3,14 +3,14 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class BlockquoteHandler extends TagHandler { public class BlockquoteHandler extends TagHandler {
@Override @Override
public void handle( public void handle(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder, @NonNull SpannableBuilder builder,
@NonNull HtmlTag tag) { @NonNull HtmlTag tag) {

View File

@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class EmphasisHandler extends SimpleTagHandler { public class EmphasisHandler extends SimpleTagHandler {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().emphasis(); return configuration.factory().emphasis();
} }
} }

View File

@ -3,7 +3,7 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class HeadingHandler extends SimpleTagHandler { public class HeadingHandler extends SimpleTagHandler {
@ -16,7 +16,7 @@ public class HeadingHandler extends SimpleTagHandler {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().heading(configuration.theme(), level); return configuration.factory().heading(configuration.theme(), level);
} }
} }

View File

@ -6,7 +6,7 @@ import android.text.TextUtils;
import java.util.Map; import java.util.Map;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
import ru.noties.markwon.renderer.ImageSize; import ru.noties.markwon.renderer.ImageSize;
import ru.noties.markwon.renderer.html2.CssInlineStyleParser; import ru.noties.markwon.renderer.html2.CssInlineStyleParser;
@ -31,7 +31,7 @@ public class ImageHandler extends SimpleTagHandler {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
final Map<String, String> attributes = tag.attributes(); final Map<String, String> attributes = tag.attributes();
final String src = attributes.get("src"); final String src = attributes.get("src");

View File

@ -4,13 +4,13 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class LinkHandler extends SimpleTagHandler { public class LinkHandler extends SimpleTagHandler {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
final String destination = tag.attributes().get("href"); final String destination = tag.attributes().get("href");
if (!TextUtils.isEmpty(destination)) { if (!TextUtils.isEmpty(destination)) {
return configuration.factory().link( return configuration.factory().link(

View File

@ -2,15 +2,15 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class ListHandler extends TagHandler { public class ListHandler extends TagHandler {
@Override @Override
public void handle( public void handle(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder, @NonNull SpannableBuilder builder,
@NonNull HtmlTag tag) { @NonNull HtmlTag tag) {

View File

@ -4,16 +4,16 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public abstract class SimpleTagHandler extends TagHandler { public abstract class SimpleTagHandler extends TagHandler {
@Nullable @Nullable
public abstract Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag); public abstract Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag);
@Override @Override
public void handle(@NonNull SpannableConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) { public void handle(@NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) {
final Object spans = getSpans(configuration, tag); final Object spans = getSpans(configuration, tag);
if (spans != null) { if (spans != null) {
SpannableBuilder.setSpans(builder, spans, tag.start(), tag.end()); SpannableBuilder.setSpans(builder, spans, tag.start(), tag.end());

View File

@ -2,15 +2,15 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class StrikeHandler extends TagHandler { public class StrikeHandler extends TagHandler {
@Override @Override
public void handle( public void handle(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder, @NonNull SpannableBuilder builder,
@NonNull HtmlTag tag) { @NonNull HtmlTag tag) {

View File

@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class StrongEmphasisHandler extends SimpleTagHandler { public class StrongEmphasisHandler extends SimpleTagHandler {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().strongEmphasis(); return configuration.factory().strongEmphasis();
} }
} }

View File

@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class SubScriptHandler extends SimpleTagHandler { public class SubScriptHandler extends SimpleTagHandler {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().subScript(configuration.theme()); return configuration.factory().subScript(configuration.theme());
} }
} }

View File

@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class SuperScriptHandler extends SimpleTagHandler { public class SuperScriptHandler extends SimpleTagHandler {
@Nullable @Nullable
@Override @Override
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().superScript(configuration.theme()); return configuration.factory().superScript(configuration.theme());
} }
} }

View File

@ -2,20 +2,20 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public abstract class TagHandler { public abstract class TagHandler {
public abstract void handle( public abstract void handle(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder, @NonNull SpannableBuilder builder,
@NonNull HtmlTag tag @NonNull HtmlTag tag
); );
protected static void visitChildren( protected static void visitChildren(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder, @NonNull SpannableBuilder builder,
@NonNull HtmlTag.Block block) { @NonNull HtmlTag.Block block) {

View File

@ -3,14 +3,14 @@ package ru.noties.markwon.renderer.html2.tag;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.api.HtmlTag; import ru.noties.markwon.html.api.HtmlTag;
public class UnderlineHandler extends TagHandler { public class UnderlineHandler extends TagHandler {
@Override @Override
public void handle( public void handle(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder, @NonNull SpannableBuilder builder,
@NonNull HtmlTag tag) { @NonNull HtmlTag tag) {

View File

@ -24,24 +24,24 @@ public class AsyncDrawableSpan extends ReplacementSpan {
public static final int ALIGN_BASELINE = 1; public static final int ALIGN_BASELINE = 1;
public static final int ALIGN_CENTER = 2; // will only center if drawable height is less than text line height public static final int ALIGN_CENTER = 2; // will only center if drawable height is less than text line height
private final SpannableTheme theme; private final MarkwonTheme theme;
private final AsyncDrawable drawable; private final AsyncDrawable drawable;
private final int alignment; private final int alignment;
private final boolean replacementTextIsLink; private final boolean replacementTextIsLink;
public AsyncDrawableSpan(@NonNull SpannableTheme theme, @NonNull AsyncDrawable drawable) { public AsyncDrawableSpan(@NonNull MarkwonTheme theme, @NonNull AsyncDrawable drawable) {
this(theme, drawable, ALIGN_BOTTOM); this(theme, drawable, ALIGN_BOTTOM);
} }
public AsyncDrawableSpan( public AsyncDrawableSpan(
@NonNull SpannableTheme theme, @NonNull MarkwonTheme theme,
@NonNull AsyncDrawable drawable, @NonNull AsyncDrawable drawable,
@Alignment int alignment) { @Alignment int alignment) {
this(theme, drawable, alignment, false); this(theme, drawable, alignment, false);
} }
public AsyncDrawableSpan( public AsyncDrawableSpan(
@NonNull SpannableTheme theme, @NonNull MarkwonTheme theme,
@NonNull AsyncDrawable drawable, @NonNull AsyncDrawable drawable,
@Alignment int alignment, @Alignment int alignment,
boolean replacementTextIsLink) { boolean replacementTextIsLink) {

View File

@ -9,11 +9,11 @@ import android.text.style.LeadingMarginSpan;
public class BlockQuoteSpan implements LeadingMarginSpan { public class BlockQuoteSpan implements LeadingMarginSpan {
private final SpannableTheme theme; private final MarkwonTheme theme;
private final Rect rect = ObjectsPool.rect(); private final Rect rect = ObjectsPool.rect();
private final Paint paint = ObjectsPool.paint(); private final Paint paint = ObjectsPool.paint();
public BlockQuoteSpan(@NonNull SpannableTheme theme) { public BlockQuoteSpan(@NonNull MarkwonTheme theme) {
this.theme = theme; this.theme = theme;
} }

View File

@ -9,9 +9,11 @@ import android.support.annotation.NonNull;
import android.text.Layout; import android.text.Layout;
import android.text.style.LeadingMarginSpan; import android.text.style.LeadingMarginSpan;
import ru.noties.markwon.utils.LeadingMarginUtils;
public class BulletListItemSpan implements LeadingMarginSpan { public class BulletListItemSpan implements LeadingMarginSpan {
private SpannableTheme theme; private MarkwonTheme theme;
private final Paint paint = ObjectsPool.paint(); private final Paint paint = ObjectsPool.paint();
private final RectF circle = ObjectsPool.rectF(); private final RectF circle = ObjectsPool.rectF();
@ -20,7 +22,7 @@ public class BulletListItemSpan implements LeadingMarginSpan {
private final int level; private final int level;
public BulletListItemSpan( public BulletListItemSpan(
@NonNull SpannableTheme theme, @NonNull MarkwonTheme theme,
@IntRange(from = 0) int level) { @IntRange(from = 0) int level) {
this.theme = theme; this.theme = theme;
this.level = level; this.level = level;

View File

@ -11,13 +11,13 @@ import android.text.style.MetricAffectingSpan;
public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan { public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan {
private final SpannableTheme theme; private final MarkwonTheme theme;
private final Rect rect = ObjectsPool.rect(); private final Rect rect = ObjectsPool.rect();
private final Paint paint = ObjectsPool.paint(); private final Paint paint = ObjectsPool.paint();
private final boolean multiline; private final boolean multiline;
public CodeSpan(@NonNull SpannableTheme theme, boolean multiline) { public CodeSpan(@NonNull MarkwonTheme theme, boolean multiline) {
this.theme = theme; this.theme = theme;
this.multiline = multiline; this.multiline = multiline;
} }

View File

@ -10,14 +10,16 @@ import android.text.TextPaint;
import android.text.style.LeadingMarginSpan; import android.text.style.LeadingMarginSpan;
import android.text.style.MetricAffectingSpan; import android.text.style.MetricAffectingSpan;
import ru.noties.markwon.utils.LeadingMarginUtils;
public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpan { public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpan {
private final SpannableTheme theme; private final MarkwonTheme theme;
private final Rect rect = ObjectsPool.rect(); private final Rect rect = ObjectsPool.rect();
private final Paint paint = ObjectsPool.paint(); private final Paint paint = ObjectsPool.paint();
private final int level; private final int level;
public HeadingSpan(@NonNull SpannableTheme theme, @IntRange(from = 1, to = 6) int level) { public HeadingSpan(@NonNull MarkwonTheme theme, @IntRange(from = 1, to = 6) int level) {
this.theme = theme; this.theme = theme;
this.level = level; this.level = level;
} }

View File

@ -2,7 +2,6 @@ package ru.noties.markwon.spans;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextPaint; import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan; import android.text.style.URLSpan;
import android.view.View; import android.view.View;
@ -12,11 +11,11 @@ public class LinkSpan extends URLSpan {
void resolve(View view, @NonNull String link); void resolve(View view, @NonNull String link);
} }
private final SpannableTheme theme; private final MarkwonTheme theme;
private final String link; private final String link;
private final Resolver resolver; private final Resolver resolver;
public LinkSpan(@NonNull SpannableTheme theme, @NonNull String link, @NonNull Resolver resolver) { public LinkSpan(@NonNull MarkwonTheme theme, @NonNull String link, @NonNull Resolver resolver) {
super(link); super(link);
this.theme = theme; this.theme = theme;
this.link = link; this.link = link;

View File

@ -7,7 +7,6 @@ import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.AttrRes; import android.support.annotation.AttrRes;
import android.support.annotation.ColorInt; import android.support.annotation.ColorInt;
import android.support.annotation.Dimension;
import android.support.annotation.FloatRange; import android.support.annotation.FloatRange;
import android.support.annotation.IntRange; import android.support.annotation.IntRange;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -20,19 +19,21 @@ import android.util.TypedValue;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import ru.noties.markwon.tasklist.TaskListDrawable;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public class SpannableTheme { public class MarkwonTheme {
/** /**
* Factory method to obtain an instance of {@link SpannableTheme} with all values as defaults * Factory method to obtain an instance of {@link MarkwonTheme} with all values as defaults
* *
* @param context Context in order to resolve defaults * @param context Context in order to resolve defaults
* @return {@link SpannableTheme} instance * @return {@link MarkwonTheme} instance
* @see #builderWithDefaults(Context) * @see #builderWithDefaults(Context)
* @since 1.0.0 * @since 1.0.0
*/ */
@NonNull @NonNull
public static SpannableTheme create(@NonNull Context context) { public static MarkwonTheme create(@NonNull Context context) {
return builderWithDefaults(context).build(); return builderWithDefaults(context).build();
} }
@ -43,7 +44,7 @@ public class SpannableTheme {
* *
* @return {@link Builder instance} * @return {@link Builder instance}
* @see #builderWithDefaults(Context) * @see #builderWithDefaults(Context)
* @see #builder(SpannableTheme) * @see #builder(MarkwonTheme)
* @since 1.0.0 * @since 1.0.0
*/ */
@NonNull @NonNull
@ -53,15 +54,15 @@ public class SpannableTheme {
/** /**
* Factory method to create a {@link Builder} instance and initialize it with values * Factory method to create a {@link Builder} instance and initialize it with values
* from supplied {@link SpannableTheme} * from supplied {@link MarkwonTheme}
* *
* @param copyFrom {@link SpannableTheme} to copy values from * @param copyFrom {@link MarkwonTheme} to copy values from
* @return {@link Builder} instance * @return {@link Builder} instance
* @see #builderWithDefaults(Context) * @see #builderWithDefaults(Context)
* @since 1.0.0 * @since 1.0.0
*/ */
@NonNull @NonNull
public static Builder builder(@NonNull SpannableTheme copyFrom) { public static Builder builder(@NonNull MarkwonTheme copyFrom) {
return new Builder(copyFrom); return new Builder(copyFrom);
} }
@ -217,9 +218,10 @@ public class SpannableTheme {
// drawable that will be used to render checkbox (should be stateful) // drawable that will be used to render checkbox (should be stateful)
// TaskListDrawable can be used // TaskListDrawable can be used
@Deprecated
protected final Drawable taskListDrawable; protected final Drawable taskListDrawable;
protected SpannableTheme(@NonNull Builder builder) { protected MarkwonTheme(@NonNull Builder builder) {
this.linkColor = builder.linkColor; this.linkColor = builder.linkColor;
this.blockMargin = builder.blockMargin; this.blockMargin = builder.blockMargin;
this.blockQuoteWidth = builder.blockQuoteWidth; this.blockQuoteWidth = builder.blockQuoteWidth;
@ -526,6 +528,7 @@ public class SpannableTheme {
* @since 1.0.1 * @since 1.0.1
*/ */
@Nullable @Nullable
@Deprecated
public Drawable getTaskListDrawable() { public Drawable getTaskListDrawable() {
return taskListDrawable; return taskListDrawable;
} }
@ -565,7 +568,7 @@ public class SpannableTheme {
Builder() { Builder() {
} }
Builder(@NonNull SpannableTheme theme) { Builder(@NonNull MarkwonTheme theme) {
this.linkColor = theme.linkColor; this.linkColor = theme.linkColor;
this.blockMargin = theme.blockMargin; this.blockMargin = theme.blockMargin;
this.blockQuoteWidth = theme.blockQuoteWidth; this.blockQuoteWidth = theme.blockQuoteWidth;
@ -792,14 +795,15 @@ public class SpannableTheme {
* @since 1.0.1 * @since 1.0.1
*/ */
@NonNull @NonNull
@Deprecated
public Builder taskListDrawable(@NonNull Drawable taskListDrawable) { public Builder taskListDrawable(@NonNull Drawable taskListDrawable) {
this.taskListDrawable = taskListDrawable; this.taskListDrawable = taskListDrawable;
return this; return this;
} }
@NonNull @NonNull
public SpannableTheme build() { public MarkwonTheme build() {
return new SpannableTheme(this); return new MarkwonTheme(this);
} }
} }

View File

@ -9,6 +9,8 @@ import android.text.TextPaint;
import android.text.style.LeadingMarginSpan; import android.text.style.LeadingMarginSpan;
import android.widget.TextView; import android.widget.TextView;
import ru.noties.markwon.utils.LeadingMarginUtils;
public class OrderedListItemSpan implements LeadingMarginSpan { public class OrderedListItemSpan implements LeadingMarginSpan {
/** /**
@ -42,7 +44,7 @@ public class OrderedListItemSpan implements LeadingMarginSpan {
} }
} }
private final SpannableTheme theme; private final MarkwonTheme theme;
private final String number; private final String number;
private final Paint paint = ObjectsPool.paint(); private final Paint paint = ObjectsPool.paint();
@ -52,7 +54,7 @@ public class OrderedListItemSpan implements LeadingMarginSpan {
private int margin; private int margin;
public OrderedListItemSpan( public OrderedListItemSpan(
@NonNull SpannableTheme theme, @NonNull MarkwonTheme theme,
@NonNull String number @NonNull String number
) { ) {
this.theme = theme; this.theme = theme;

View File

@ -6,9 +6,9 @@ import android.text.style.MetricAffectingSpan;
public class SubScriptSpan extends MetricAffectingSpan { public class SubScriptSpan extends MetricAffectingSpan {
private final SpannableTheme theme; private final MarkwonTheme theme;
public SubScriptSpan(@NonNull SpannableTheme theme) { public SubScriptSpan(@NonNull MarkwonTheme theme) {
this.theme = theme; this.theme = theme;
} }

View File

@ -6,9 +6,9 @@ import android.text.style.MetricAffectingSpan;
public class SuperScriptSpan extends MetricAffectingSpan { public class SuperScriptSpan extends MetricAffectingSpan {
private final SpannableTheme theme; private final MarkwonTheme theme;
public SuperScriptSpan(@NonNull SpannableTheme theme) { public SuperScriptSpan(@NonNull MarkwonTheme theme) {
this.theme = theme; this.theme = theme;
} }

View File

@ -61,7 +61,7 @@ public class TableRowSpan extends ReplacementSpan {
} }
} }
private final SpannableTheme theme; private final MarkwonTheme theme;
private final List<Cell> cells; private final List<Cell> cells;
private final List<StaticLayout> layouts; private final List<StaticLayout> layouts;
private final TextPaint textPaint; private final TextPaint textPaint;
@ -76,7 +76,7 @@ public class TableRowSpan extends ReplacementSpan {
private Invalidator invalidator; private Invalidator invalidator;
public TableRowSpan( public TableRowSpan(
@NonNull SpannableTheme theme, @NonNull MarkwonTheme theme,
@NonNull List<Cell> cells, @NonNull List<Cell> cells,
boolean header, boolean header,
boolean odd) { boolean odd) {

View File

@ -9,11 +9,11 @@ import android.text.style.LeadingMarginSpan;
public class ThematicBreakSpan implements LeadingMarginSpan { public class ThematicBreakSpan implements LeadingMarginSpan {
private final SpannableTheme theme; private final MarkwonTheme theme;
private final Rect rect = ObjectsPool.rect(); private final Rect rect = ObjectsPool.rect();
private final Paint paint = ObjectsPool.paint(); private final Paint paint = ObjectsPool.paint();
public ThematicBreakSpan(@NonNull SpannableTheme theme) { public ThematicBreakSpan(@NonNull MarkwonTheme theme) {
this.theme = theme; this.theme = theme;
} }

View File

@ -1,4 +1,4 @@
package ru.noties.markwon.spans; package ru.noties.markwon.tasklist;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;

View File

@ -7,6 +7,7 @@ import org.commonmark.parser.Parser;
/** /**
* @since 1.0.1 * @since 1.0.1
*/ */
@Deprecated
public class TaskListExtension implements Parser.ParserExtension { public class TaskListExtension implements Parser.ParserExtension {
@NonNull @NonNull

View File

@ -0,0 +1,93 @@
package ru.noties.markwon.tasklist;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import org.commonmark.parser.Parser;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.MarkwonVisitor;
public class TaskListPlugin extends AbstractMarkwonPlugin {
/**
* @see TaskListDrawable
*/
@NonNull
public static TaskListPlugin create(@NonNull Drawable drawable) {
return new TaskListPlugin(drawable);
}
@NonNull
public static TaskListPlugin create(@NonNull Context context) {
// resolve link color and background color
return null;
}
@NonNull
public static TaskListPlugin create(
@ColorInt int checkedFillColor,
@ColorInt int normalOutlineColor,
@ColorInt int checkMarkColor) {
return new TaskListPlugin(new TaskListDrawable(
checkedFillColor,
normalOutlineColor,
checkMarkColor));
}
private final Drawable drawable;
private TaskListPlugin(@NonNull Drawable drawable) {
this.drawable = drawable;
}
@Override
public void configureParser(@NonNull Parser.Builder builder) {
builder.customBlockParserFactory(new TaskListBlockParser.Factory());
}
@Override
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
builder
.on(TaskListBlock.class, new MarkwonVisitor.NodeVisitor<TaskListBlock>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TaskListBlock taskListBlock) {
visitor.ensureNewLine();
visitor.incrementBlockQuoteIndent();
visitor.visitChildren(taskListBlock);
visitor.decrementBlockQuoteIndent();
if (visitor.hasNext(taskListBlock)) {
visitor.ensureNewLine();
visitor.forceNewLine();
}
}
})
.on(TaskListItem.class, new MarkwonVisitor.NodeVisitor<TaskListItem>() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TaskListItem taskListItem) {
final int length = visitor.length();
final int indent = visitor.blockQuoteIndent();
visitor.blockQuoteIntent(indent + taskListItem.indent());
visitor.visitChildren(taskListItem);
visitor.setSpans(length, new TaskListSpan(
visitor.theme(),
drawable,
visitor.blockQuoteIndent(),
taskListItem.done()));
if (visitor.hasNext(taskListItem)) {
visitor.ensureNewLine();
}
visitor.blockQuoteIntent(indent);
}
});
}
}

View File

@ -1,4 +1,4 @@
package ru.noties.markwon.spans; package ru.noties.markwon.tasklist;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
@ -7,6 +7,9 @@ import android.support.annotation.NonNull;
import android.text.Layout; import android.text.Layout;
import android.text.style.LeadingMarginSpan; import android.text.style.LeadingMarginSpan;
import ru.noties.markwon.spans.MarkwonTheme;
import ru.noties.markwon.utils.LeadingMarginUtils;
/** /**
* @since 1.0.1 * @since 1.0.1
*/ */
@ -16,14 +19,24 @@ public class TaskListSpan implements LeadingMarginSpan {
private static final int[] STATE_NONE = new int[0]; private static final int[] STATE_NONE = new int[0];
private final SpannableTheme theme; private final MarkwonTheme theme;
private final Drawable drawable;
private final int blockIndent; private final int blockIndent;
// @since 2.0.1 field is NOT final (to allow mutation) // @since 2.0.1 field is NOT final (to allow mutation)
private boolean isDone; private boolean isDone;
public TaskListSpan(@NonNull SpannableTheme theme, int blockIndent, boolean isDone) { @Deprecated
public TaskListSpan(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone) {
this.theme = theme; this.theme = theme;
this.drawable = null;
this.blockIndent = blockIndent;
this.isDone = isDone;
}
public TaskListSpan(@NonNull MarkwonTheme theme, @NonNull Drawable drawable, int blockIndent, boolean isDone) {
this.theme = theme;
this.drawable = drawable;
this.blockIndent = blockIndent; this.blockIndent = blockIndent;
this.isDone = isDone; this.isDone = isDone;
} }
@ -58,10 +71,10 @@ public class TaskListSpan implements LeadingMarginSpan {
return; return;
} }
final Drawable drawable = theme.getTaskListDrawable(); // final Drawable drawable = theme.getTaskListDrawable();
if (drawable == null) { // if (drawable == null) {
return; // return;
} // }
final int save = c.save(); final int save = c.save();
try { try {

View File

@ -1,14 +1,14 @@
package ru.noties.markwon.spans; package ru.noties.markwon.utils;
import android.text.Spanned; import android.text.Spanned;
abstract class LeadingMarginUtils { public abstract class LeadingMarginUtils {
static boolean selfStart(int start, CharSequence text, Object span) { public static boolean selfStart(int start, CharSequence text, Object span) {
return text instanceof Spanned && ((Spanned) text).getSpanStart(span) == start; return text instanceof Spanned && ((Spanned) text).getSpanStart(span) == start;
} }
static boolean selfEnd(int end, CharSequence text, Object span) { public static boolean selfEnd(int end, CharSequence text, Object span) {
return text instanceof Spanned && ((Spanned) text).getSpanEnd(span) == end; return text instanceof Spanned && ((Spanned) text).getSpanEnd(span) == end;
} }

View File

@ -2,7 +2,7 @@ package ru.noties.markwon.renderer;
import org.junit.Test; import org.junit.Test;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableFactory; import ru.noties.markwon.SpannableFactory;
import ru.noties.markwon.SyntaxHighlight; import ru.noties.markwon.SyntaxHighlight;
import ru.noties.markwon.UrlProcessor; import ru.noties.markwon.UrlProcessor;
@ -10,17 +10,17 @@ import ru.noties.markwon.html.api.MarkwonHtmlParser;
import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer; import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer;
import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.LinkSpan; import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
public class SpannableConfigurationTest { public class MarkwonConfigurationTest {
@Test @Test
public void testNewBuilder() { public void testNewBuilder() {
final SpannableConfiguration configuration = SpannableConfiguration final MarkwonConfiguration configuration = MarkwonConfiguration
.builder(null) .builder(null)
.theme(mock(SpannableTheme.class)) .theme(mock(MarkwonTheme.class))
.asyncDrawableLoader(mock(AsyncDrawable.Loader.class)) .asyncDrawableLoader(mock(AsyncDrawable.Loader.class))
.syntaxHighlight(mock(SyntaxHighlight.class)) .syntaxHighlight(mock(SyntaxHighlight.class))
.linkResolver(mock(LinkSpan.Resolver.class)) .linkResolver(mock(LinkSpan.Resolver.class))
@ -33,7 +33,7 @@ public class SpannableConfigurationTest {
.htmlAllowNonClosedTags(true) .htmlAllowNonClosedTags(true)
.build(); .build();
final SpannableConfiguration newConfiguration = configuration final MarkwonConfiguration newConfiguration = configuration
.newBuilder(null) .newBuilder(null)
.build(); .build();

View File

@ -13,11 +13,11 @@ import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.SpannableFactory; import ru.noties.markwon.SpannableFactory;
import ru.noties.markwon.SyntaxHighlight; import ru.noties.markwon.SyntaxHighlight;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -63,12 +63,12 @@ public class SyntaxHighlightTest {
}; };
final SpannableFactory factory = mock(SpannableFactory.class); final SpannableFactory factory = mock(SpannableFactory.class);
when(factory.code(any(SpannableTheme.class), anyBoolean())).thenReturn(codeSpan); when(factory.code(any(MarkwonTheme.class), anyBoolean())).thenReturn(codeSpan);
final SpannableConfiguration configuration = SpannableConfiguration.builder(mock(Context.class)) final MarkwonConfiguration configuration = MarkwonConfiguration.builder(mock(Context.class))
.syntaxHighlight(highlight) .syntaxHighlight(highlight)
.factory(factory) .factory(factory)
.theme(mock(SpannableTheme.class)) .theme(mock(MarkwonTheme.class))
.build(); .build();
final SpannableBuilder builder = new SpannableBuilder(); final SpannableBuilder builder = new SpannableBuilder();

View File

@ -14,12 +14,12 @@ import java.util.Collection;
import ru.noties.markwon.LinkResolverDef; import ru.noties.markwon.LinkResolverDef;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.SpannableFactory; import ru.noties.markwon.SpannableFactory;
import ru.noties.markwon.html.api.MarkwonHtmlParser; import ru.noties.markwon.html.api.MarkwonHtmlParser;
import ru.noties.markwon.renderer.SpannableMarkdownVisitor; import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -44,7 +44,7 @@ public class SpannableMarkdownVisitorTest {
final TestData data = TestDataReader.readTest(file); final TestData data = TestDataReader.readTest(file);
final SpannableConfiguration configuration = configuration(data.config()); final MarkwonConfiguration configuration = configuration(data.config());
final SpannableBuilder builder = new SpannableBuilder(); final SpannableBuilder builder = new SpannableBuilder();
final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(configuration, builder); final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(configuration, builder);
final Node node = Markwon.createParser().parse(data.input()); final Node node = Markwon.createParser().parse(data.input());
@ -73,7 +73,7 @@ public class SpannableMarkdownVisitorTest {
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
@NonNull @NonNull
private SpannableConfiguration configuration(@NonNull TestConfig config) { private MarkwonConfiguration configuration(@NonNull TestConfig config) {
final SpannableFactory factory = new TestFactory(config.hasOption(TestConfig.USE_PARAGRAPHS)); final SpannableFactory factory = new TestFactory(config.hasOption(TestConfig.USE_PARAGRAPHS));
final MarkwonHtmlParser htmlParser = config.hasOption(TestConfig.USE_HTML) final MarkwonHtmlParser htmlParser = config.hasOption(TestConfig.USE_HTML)
@ -83,8 +83,8 @@ public class SpannableMarkdownVisitorTest {
final boolean softBreakAddsNewLine = config.hasOption(TestConfig.SOFT_BREAK_ADDS_NEW_LINE); final boolean softBreakAddsNewLine = config.hasOption(TestConfig.SOFT_BREAK_ADDS_NEW_LINE);
final boolean htmlAllowNonClosedTags = config.hasOption(TestConfig.HTML_ALLOW_NON_CLOSED_TAGS); final boolean htmlAllowNonClosedTags = config.hasOption(TestConfig.HTML_ALLOW_NON_CLOSED_TAGS);
return SpannableConfiguration.builder(null) return MarkwonConfiguration.builder(null)
.theme(mock(SpannableTheme.class)) .theme(mock(MarkwonTheme.class))
.linkResolver(mock(LinkResolverDef.class)) .linkResolver(mock(LinkResolverDef.class))
.htmlParser(htmlParser) .htmlParser(htmlParser)
.factory(factory) .factory(factory)

View File

@ -13,7 +13,7 @@ import ru.noties.markwon.renderer.ImageSize;
import ru.noties.markwon.renderer.ImageSizeResolver; import ru.noties.markwon.renderer.ImageSizeResolver;
import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.LinkSpan; import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.SpannableTheme; import ru.noties.markwon.spans.MarkwonTheme;
import ru.noties.markwon.spans.TableRowSpan; import ru.noties.markwon.spans.TableRowSpan;
import static ru.noties.markwon.renderer.visitor.TestSpan.BLOCK_QUOTE; import static ru.noties.markwon.renderer.visitor.TestSpan.BLOCK_QUOTE;
@ -57,13 +57,13 @@ class TestFactory implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object blockQuote(@NonNull SpannableTheme theme) { public Object blockQuote(@NonNull MarkwonTheme theme) {
return new TestSpan(BLOCK_QUOTE); return new TestSpan(BLOCK_QUOTE);
} }
@Nullable @Nullable
@Override @Override
public Object code(@NonNull SpannableTheme theme, boolean multiline) { public Object code(@NonNull MarkwonTheme theme, boolean multiline) {
final String name = multiline final String name = multiline
? CODE_BLOCK ? CODE_BLOCK
: CODE; : CODE;
@ -72,25 +72,25 @@ class TestFactory implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object orderedListItem(@NonNull SpannableTheme theme, int startNumber) { public Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber) {
return new TestSpan(ORDERED_LIST, map("start", startNumber)); return new TestSpan(ORDERED_LIST, map("start", startNumber));
} }
@Nullable @Nullable
@Override @Override
public Object bulletListItem(@NonNull SpannableTheme theme, int level) { public Object bulletListItem(@NonNull MarkwonTheme theme, int level) {
return new TestSpan(BULLET_LIST, map("level", level)); return new TestSpan(BULLET_LIST, map("level", level));
} }
@Nullable @Nullable
@Override @Override
public Object thematicBreak(@NonNull SpannableTheme theme) { public Object thematicBreak(@NonNull MarkwonTheme theme) {
return new TestSpan(THEMATIC_BREAK); return new TestSpan(THEMATIC_BREAK);
} }
@Nullable @Nullable
@Override @Override
public Object heading(@NonNull SpannableTheme theme, int level) { public Object heading(@NonNull MarkwonTheme theme, int level) {
return new TestSpan(HEADING + level); return new TestSpan(HEADING + level);
} }
@ -102,7 +102,7 @@ class TestFactory implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object taskListItem(@NonNull SpannableTheme theme, int blockIndent, boolean isDone) { public Object taskListItem(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone) {
return new TestSpan(TASK_LIST, map( return new TestSpan(TASK_LIST, map(
Pair.of("blockIdent", blockIndent), Pair.of("blockIdent", blockIndent),
Pair.of("done", isDone) Pair.of("done", isDone)
@ -111,7 +111,7 @@ class TestFactory implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object tableRow(@NonNull SpannableTheme theme, @NonNull List<TableRowSpan.Cell> cells, boolean isHeader, boolean isOdd) { public Object tableRow(@NonNull MarkwonTheme theme, @NonNull List<TableRowSpan.Cell> cells, boolean isHeader, boolean isOdd) {
return new TestSpan(TABLE_ROW, map( return new TestSpan(TABLE_ROW, map(
Pair.of("cells", cells), Pair.of("cells", cells),
Pair.of("header", isHeader), Pair.of("header", isHeader),
@ -129,7 +129,7 @@ class TestFactory implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object image(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) { public Object image(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
return new TestSpan(IMAGE, map( return new TestSpan(IMAGE, map(
Pair.of("src", destination), Pair.of("src", destination),
Pair.of("imageSize", imageSize), Pair.of("imageSize", imageSize),
@ -139,19 +139,19 @@ class TestFactory implements SpannableFactory {
@Nullable @Nullable
@Override @Override
public Object link(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) { public Object link(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) {
return new TestSpan(LINK, map("href", destination)); return new TestSpan(LINK, map("href", destination));
} }
@Nullable @Nullable
@Override @Override
public Object superScript(@NonNull SpannableTheme theme) { public Object superScript(@NonNull MarkwonTheme theme) {
return new TestSpan(SUPER_SCRIPT); return new TestSpan(SUPER_SCRIPT);
} }
@Nullable @Nullable
@Override @Override
public Object subScript(@NonNull SpannableTheme theme) { public Object subScript(@NonNull MarkwonTheme theme) {
return new TestSpan(SUB_SCRIPT); return new TestSpan(SUB_SCRIPT);
} }

View File

@ -2,12 +2,11 @@ package ru.noties.markwon.sample.extension;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.widget.TextView;
import org.commonmark.node.CustomNode; import org.commonmark.node.CustomNode;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.renderer.SpannableMarkdownVisitor; import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
@ -18,7 +17,7 @@ public class IconVisitor extends SpannableMarkdownVisitor {
private final IconSpanProvider iconSpanProvider; private final IconSpanProvider iconSpanProvider;
public IconVisitor( public IconVisitor(
@NonNull SpannableConfiguration configuration, @NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder, @NonNull SpannableBuilder builder,
@NonNull IconSpanProvider iconSpanProvider @NonNull IconSpanProvider iconSpanProvider
) { ) {

View File

@ -12,9 +12,9 @@ import org.commonmark.parser.Parser;
import java.util.Arrays; import java.util.Arrays;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.spans.MarkwonTheme;
import ru.noties.markwon.spans.SpannableTheme;
import ru.noties.markwon.tasklist.TaskListExtension; import ru.noties.markwon.tasklist.TaskListExtension;
public class MainActivity extends Activity { public class MainActivity extends Activity {
@ -53,8 +53,8 @@ public class MainActivity extends Activity {
final IconSpanProvider spanProvider = IconSpanProvider.create(this, 0); final IconSpanProvider spanProvider = IconSpanProvider.create(this, 0);
final float[] textSizeMultipliers = new float[]{3f, 2f, 1.5f, 1f, .5f, .25f}; final float[] textSizeMultipliers = new float[]{3f, 2f, 1.5f, 1f, .5f, .25f};
SpannableConfiguration configuration = SpannableConfiguration.builder(this) MarkwonConfiguration configuration = MarkwonConfiguration.builder(this)
.theme(SpannableTheme.builder() .theme(MarkwonTheme.builder()
.headingTypeface(Typeface.MONOSPACE) .headingTypeface(Typeface.MONOSPACE)
.headingTextSizeMultipliers(textSizeMultipliers) .headingTextSizeMultipliers(textSizeMultipliers)
.build()) .build())

View File

@ -10,8 +10,8 @@ import org.commonmark.parser.Parser;
import ru.noties.jlatexmath.JLatexMathAndroid; import ru.noties.jlatexmath.JLatexMathAndroid;
import ru.noties.markwon.Markwon; import ru.noties.markwon.Markwon;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.il.AsyncDrawableLoader; import ru.noties.markwon.il.AsyncDrawableLoader;
import ru.noties.markwon.renderer.ImageSize; import ru.noties.markwon.renderer.ImageSize;
import ru.noties.markwon.renderer.SpannableMarkdownVisitor; import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
@ -55,7 +55,7 @@ public class MainActivity extends Activity {
.mediaDecoders(jLatexMathMedia.mediaDecoder()) .mediaDecoders(jLatexMathMedia.mediaDecoder())
.build(); .build();
final SpannableConfiguration configuration = SpannableConfiguration.builder(this) final MarkwonConfiguration configuration = MarkwonConfiguration.builder(this)
.asyncDrawableLoader(asyncDrawableLoader) .asyncDrawableLoader(asyncDrawableLoader)
.build(); .build();
@ -68,7 +68,7 @@ public class MainActivity extends Activity {
final Node node = parser.parse(markdown); final Node node = parser.parse(markdown);
final SpannableBuilder builder = new SpannableBuilder(); final SpannableBuilder builder = new SpannableBuilder();
final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(SpannableConfiguration.create(this), builder) { final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(MarkwonConfiguration.create(this), builder) {
@Override @Override
public void visit(CustomBlock customBlock) { public void visit(CustomBlock customBlock) {