From 498c811987b44c8626ab1dd487d0d8b0de105d79 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sat, 24 Nov 2018 16:03:08 +0300 Subject: [PATCH] POC for plugin system --- .../debug/DebugCheckboxDrawableView.java | 2 +- .../markwon/GifAwareSpannableFactory.java | 4 +- .../java/ru/noties/markwon/MainActivity.java | 15 +- .../ru/noties/markwon/MarkdownRenderer.java | 6 +- docs/docs/theme.md | 2 +- .../debug/DebugConfigurationProvider.java | 14 +- .../ru/noties/markwon/view/IMarkwonView.java | 6 +- .../ru/noties/markwon/view/MarkwonView.java | 4 +- .../markwon/view/MarkwonViewCompat.java | 4 +- .../markwon/view/MarkwonViewHelper.java | 8 +- .../noties/markwon/AbstractMarkwonPlugin.java | 46 +++ .../main/java/ru/noties/markwon/Markwon.java | 24 +- .../main/java/ru/noties/markwon/Markwon2.java | 32 ++ .../ru/noties/markwon/MarkwonBuilderImpl.java | 53 ++++ ...uration.java => MarkwonConfiguration.java} | 33 +- .../java/ru/noties/markwon/MarkwonImpl.java | 48 +++ .../java/ru/noties/markwon/MarkwonPlugin.java | 29 ++ .../ru/noties/markwon/MarkwonVisitor.java | 60 ++++ .../ru/noties/markwon/MarkwonVisitorImpl.java | 290 ++++++++++++++++++ .../ru/noties/markwon/SpannableBuilder.java | 2 +- .../ru/noties/markwon/SpannableFactory.java | 26 +- .../noties/markwon/SpannableFactoryDef.java | 28 +- .../ru/noties/markwon/core/CorePlugin.java | 268 ++++++++++++++++ .../renderer/SpannableMarkdownVisitor.java | 10 +- .../markwon/renderer/SpannableRenderer.java | 4 +- .../renderer/html2/MarkwonHtmlRenderer.java | 4 +- .../html2/MarkwonHtmlRendererImpl.java | 4 +- .../renderer/html2/tag/BlockquoteHandler.java | 4 +- .../renderer/html2/tag/EmphasisHandler.java | 4 +- .../renderer/html2/tag/HeadingHandler.java | 4 +- .../renderer/html2/tag/ImageHandler.java | 4 +- .../renderer/html2/tag/LinkHandler.java | 4 +- .../renderer/html2/tag/ListHandler.java | 4 +- .../renderer/html2/tag/SimpleTagHandler.java | 6 +- .../renderer/html2/tag/StrikeHandler.java | 4 +- .../html2/tag/StrongEmphasisHandler.java | 4 +- .../renderer/html2/tag/SubScriptHandler.java | 4 +- .../html2/tag/SuperScriptHandler.java | 4 +- .../renderer/html2/tag/TagHandler.java | 6 +- .../renderer/html2/tag/UnderlineHandler.java | 4 +- .../markwon/spans/AsyncDrawableSpan.java | 8 +- .../noties/markwon/spans/BlockQuoteSpan.java | 4 +- .../markwon/spans/BulletListItemSpan.java | 6 +- .../ru/noties/markwon/spans/CodeSpan.java | 4 +- .../ru/noties/markwon/spans/HeadingSpan.java | 6 +- .../ru/noties/markwon/spans/LinkSpan.java | 5 +- ...{SpannableTheme.java => MarkwonTheme.java} | 30 +- .../markwon/spans/OrderedListItemSpan.java | 6 +- .../noties/markwon/spans/SubScriptSpan.java | 4 +- .../noties/markwon/spans/SuperScriptSpan.java | 4 +- .../ru/noties/markwon/spans/TableRowSpan.java | 4 +- .../markwon/spans/ThematicBreakSpan.java | 4 +- .../{spans => tasklist}/TaskListDrawable.java | 2 +- .../markwon/tasklist/TaskListExtension.java | 1 + .../markwon/tasklist/TaskListPlugin.java | 93 ++++++ .../{spans => tasklist}/TaskListSpan.java | 27 +- .../{spans => utils}/LeadingMarginUtils.java | 8 +- ...est.java => MarkwonConfigurationTest.java} | 12 +- .../markwon/renderer/SyntaxHighlightTest.java | 10 +- .../visitor/SpannableMarkdownVisitorTest.java | 12 +- .../markwon/renderer/visitor/TestFactory.java | 26 +- .../markwon/sample/extension/IconVisitor.java | 5 +- .../sample/extension/MainActivity.java | 8 +- .../sample/jlatexmath/MainActivity.java | 6 +- 64 files changed, 1170 insertions(+), 207 deletions(-) create mode 100644 markwon/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java create mode 100644 markwon/src/main/java/ru/noties/markwon/Markwon2.java create mode 100644 markwon/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java rename markwon/src/main/java/ru/noties/markwon/{SpannableConfiguration.java => MarkwonConfiguration.java} (92%) create mode 100644 markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java create mode 100644 markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java create mode 100644 markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java create mode 100644 markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java create mode 100644 markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java rename markwon/src/main/java/ru/noties/markwon/spans/{SpannableTheme.java => MarkwonTheme.java} (97%) rename markwon/src/main/java/ru/noties/markwon/{spans => tasklist}/TaskListDrawable.java (99%) create mode 100644 markwon/src/main/java/ru/noties/markwon/tasklist/TaskListPlugin.java rename markwon/src/main/java/ru/noties/markwon/{spans => tasklist}/TaskListSpan.java (77%) rename markwon/src/main/java/ru/noties/markwon/{spans => utils}/LeadingMarginUtils.java (52%) rename markwon/src/test/java/ru/noties/markwon/renderer/{SpannableConfigurationTest.java => MarkwonConfigurationTest.java} (86%) diff --git a/app/src/debug/java/ru/noties/markwon/debug/DebugCheckboxDrawableView.java b/app/src/debug/java/ru/noties/markwon/debug/DebugCheckboxDrawableView.java index 34bef820..e99e35fc 100644 --- a/app/src/debug/java/ru/noties/markwon/debug/DebugCheckboxDrawableView.java +++ b/app/src/debug/java/ru/noties/markwon/debug/DebugCheckboxDrawableView.java @@ -9,7 +9,7 @@ import android.util.AttributeSet; import android.view.View; import ru.noties.markwon.R; -import ru.noties.markwon.spans.TaskListDrawable; +import ru.noties.markwon.tasklist.TaskListDrawable; public class DebugCheckboxDrawableView extends View { diff --git a/app/src/main/java/ru/noties/markwon/GifAwareSpannableFactory.java b/app/src/main/java/ru/noties/markwon/GifAwareSpannableFactory.java index f070e9fc..7c387a1c 100644 --- a/app/src/main/java/ru/noties/markwon/GifAwareSpannableFactory.java +++ b/app/src/main/java/ru/noties/markwon/GifAwareSpannableFactory.java @@ -7,7 +7,7 @@ import ru.noties.markwon.renderer.ImageSize; import ru.noties.markwon.renderer.ImageSizeResolver; import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawableSpan; -import ru.noties.markwon.spans.SpannableTheme; +import ru.noties.markwon.spans.MarkwonTheme; public class GifAwareSpannableFactory extends SpannableFactoryDef { @@ -19,7 +19,7 @@ public class GifAwareSpannableFactory extends SpannableFactoryDef { @Nullable @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( theme, new GifAwareAsyncDrawable( diff --git a/app/src/main/java/ru/noties/markwon/MainActivity.java b/app/src/main/java/ru/noties/markwon/MainActivity.java index 3bf49109..a14caf2e 100644 --- a/app/src/main/java/ru/noties/markwon/MainActivity.java +++ b/app/src/main/java/ru/noties/markwon/MainActivity.java @@ -12,6 +12,9 @@ import android.widget.TextView; import javax.inject.Inject; 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 { @@ -40,7 +43,7 @@ public class MainActivity extends Activity { 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 setContentView(R.layout.activity_main); @@ -63,6 +66,16 @@ public class MainActivity extends Activity { 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() { @Override public void apply(final String text) { diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java index 23ff268b..9151b115 100644 --- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java +++ b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java @@ -14,7 +14,7 @@ import javax.inject.Inject; import ru.noties.debug.Debug; 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.Prism4jTheme; import ru.noties.markwon.syntax.Prism4jThemeDarkula; @@ -87,11 +87,11 @@ public class MarkdownRenderer { 0x20000000 ); - final SpannableConfiguration configuration = SpannableConfiguration.builder(context) + final MarkwonConfiguration configuration = MarkwonConfiguration.builder(context) .asyncDrawableLoader(loader) .urlProcessor(urlProcessor) .syntaxHighlight(Prism4jSyntaxHighlight.create(prism4j, prism4jTheme)) - .theme(SpannableTheme.builderWithDefaults(context) + .theme(MarkwonTheme.builderWithDefaults(context) .codeBackgroundColor(background) .codeTextColor(prism4jTheme.textColor()) .build()) diff --git a/docs/docs/theme.md b/docs/docs/theme.md index b01f7f31..4bc6cfb0 100644 --- a/docs/docs/theme.md +++ b/docs/docs/theme.md @@ -209,4 +209,4 @@ Background of header table row Drawable of task list item - + diff --git a/markwon-view/src/debug/java/ru/noties/markwon/view/debug/DebugConfigurationProvider.java b/markwon-view/src/debug/java/ru/noties/markwon/view/debug/DebugConfigurationProvider.java index e530bab5..50ad7fec 100644 --- a/markwon-view/src/debug/java/ru/noties/markwon/view/debug/DebugConfigurationProvider.java +++ b/markwon-view/src/debug/java/ru/noties/markwon/view/debug/DebugConfigurationProvider.java @@ -3,27 +3,27 @@ package ru.noties.markwon.view.debug; import android.content.Context; import android.support.annotation.NonNull; -import ru.noties.markwon.SpannableConfiguration; -import ru.noties.markwon.spans.SpannableTheme; +import ru.noties.markwon.MarkwonConfiguration; +import ru.noties.markwon.spans.MarkwonTheme; import ru.noties.markwon.view.IMarkwonView; public class DebugConfigurationProvider implements IMarkwonView.ConfigurationProvider { - private SpannableConfiguration cached; + private MarkwonConfiguration cached; @NonNull @Override - public SpannableConfiguration provide(@NonNull Context context) { + public MarkwonConfiguration provide(@NonNull Context context) { if (cached == null) { - cached = SpannableConfiguration.builder(context) + cached = MarkwonConfiguration.builder(context) .theme(debugTheme(context)) .build(); } return cached; } - private static SpannableTheme debugTheme(@NonNull Context context) { - return SpannableTheme.builderWithDefaults(context) + private static MarkwonTheme debugTheme(@NonNull Context context) { + return MarkwonTheme.builderWithDefaults(context) .blockQuoteColor(0xFFff0000) .codeBackgroundColor(0x40FF0000) .build(); diff --git a/markwon-view/src/main/java/ru/noties/markwon/view/IMarkwonView.java b/markwon-view/src/main/java/ru/noties/markwon/view/IMarkwonView.java index 4db6d2c7..bc66e8b8 100644 --- a/markwon-view/src/main/java/ru/noties/markwon/view/IMarkwonView.java +++ b/markwon-view/src/main/java/ru/noties/markwon/view/IMarkwonView.java @@ -4,19 +4,19 @@ import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; public interface IMarkwonView { interface ConfigurationProvider { @NonNull - SpannableConfiguration provide(@NonNull Context context); + MarkwonConfiguration provide(@NonNull Context context); } void setConfigurationProvider(@NonNull ConfigurationProvider provider); void setMarkdown(@Nullable String markdown); - void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown); + void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown); @Nullable String getMarkdown(); diff --git a/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonView.java b/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonView.java index 19ab09b0..f42d8727 100644 --- a/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonView.java +++ b/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonView.java @@ -7,7 +7,7 @@ import android.support.annotation.Nullable; import android.util.AttributeSet; import android.widget.TextView; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; @SuppressLint("AppCompatCustomView") public class MarkwonView extends TextView implements IMarkwonView { @@ -38,7 +38,7 @@ public class MarkwonView extends TextView implements IMarkwonView { 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); } diff --git a/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewCompat.java b/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewCompat.java index da5c1934..b30ecaa2 100644 --- a/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewCompat.java +++ b/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewCompat.java @@ -6,7 +6,7 @@ import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatTextView; import android.util.AttributeSet; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView { @@ -38,7 +38,7 @@ public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView } @Override - public void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown) { + public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) { helper.setMarkdown(configuration, markdown); } diff --git a/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewHelper.java b/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewHelper.java index c8c813f6..f3669b77 100644 --- a/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewHelper.java +++ b/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewHelper.java @@ -9,7 +9,7 @@ import android.util.AttributeSet; import android.widget.TextView; import ru.noties.markwon.Markwon; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; public class MarkwonViewHelper implements IMarkwonView { @@ -21,7 +21,7 @@ public class MarkwonViewHelper implements IMarkwonView { private ConfigurationProvider provider; - private SpannableConfiguration configuration; + private MarkwonConfiguration configuration; private String markdown; private MarkwonViewHelper(@NonNull TextView textView) { @@ -71,14 +71,14 @@ public class MarkwonViewHelper implements IMarkwonView { } @Override - public void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown) { + public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) { this.markdown = markdown; if (configuration == null) { if (this.configuration == null) { if (provider != null) { this.configuration = provider.provide(textView.getContext()); } else { - this.configuration = SpannableConfiguration.create(textView.getContext()); + this.configuration = MarkwonConfiguration.create(textView.getContext()); } } configuration = this.configuration; diff --git a/markwon/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java b/markwon/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java new file mode 100644 index 00000000..d96e2a6d --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java @@ -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) { + + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/Markwon.java b/markwon/src/main/java/ru/noties/markwon/Markwon.java index 6ecb9ca8..c7fdf550 100644 --- a/markwon/src/main/java/ru/noties/markwon/Markwon.java +++ b/markwon/src/main/java/ru/noties/markwon/Markwon.java @@ -40,11 +40,11 @@ public abstract class Markwon { } /** - * @see #setMarkdown(TextView, SpannableConfiguration, String) + * @see #setMarkdown(TextView, MarkwonConfiguration, String) * @since 1.0.0 */ 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 * * @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**`}) - * @see #markdown(SpannableConfiguration, String) + * @see #markdown(MarkwonConfiguration, String) * @see #setText(TextView, CharSequence) - * @see SpannableConfiguration + * @see MarkwonConfiguration * @since 1.0.0 */ public static void setMarkdown( @NonNull TextView view, - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @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 markdown raw markdown @@ -126,21 +126,21 @@ public abstract class Markwon { */ @NonNull 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); } /** - * 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 * @return parsed markdown - * @see SpannableConfiguration + * @see MarkwonConfiguration * @since 1.0.0 */ @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 Node node = parser.parse(markdown); final SpannableRenderer renderer = new SpannableRenderer(); diff --git a/markwon/src/main/java/ru/noties/markwon/Markwon2.java b/markwon/src/main/java/ru/noties/markwon/Markwon2.java new file mode 100644 index 00000000..59feb9a5 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/Markwon2.java @@ -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(); + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java b/markwon/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java new file mode 100644 index 00000000..635e3138 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java @@ -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 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) + ); + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/SpannableConfiguration.java b/markwon/src/main/java/ru/noties/markwon/MarkwonConfiguration.java similarity index 92% rename from markwon/src/main/java/ru/noties/markwon/SpannableConfiguration.java rename to markwon/src/main/java/ru/noties/markwon/MarkwonConfiguration.java index 5df9d316..510f10b1 100644 --- a/markwon/src/main/java/ru/noties/markwon/SpannableConfiguration.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonConfiguration.java @@ -9,14 +9,17 @@ import ru.noties.markwon.renderer.ImageSizeResolverDef; import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer; import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.LinkSpan; -import ru.noties.markwon.spans.SpannableTheme; +import ru.noties.markwon.spans.MarkwonTheme; +/** + * since 3.0.0 renamed `SpannableConfiguration` -> `MarkwonConfiguration` + */ @SuppressWarnings("WeakerAccess") -public class SpannableConfiguration { +public class MarkwonConfiguration { // creates default configuration @NonNull - public static SpannableConfiguration create(@NonNull Context context) { + public static MarkwonConfiguration create(@NonNull Context context) { return new Builder(context).build(); } @@ -25,7 +28,9 @@ public class SpannableConfiguration { return new Builder(context); } - private final SpannableTheme theme; + @Deprecated + private final MarkwonTheme theme; + private final AsyncDrawable.Loader asyncDrawableLoader; private final SyntaxHighlight syntaxHighlight; private final LinkSpan.Resolver linkResolver; @@ -37,7 +42,7 @@ public class SpannableConfiguration { private final MarkwonHtmlRenderer htmlRenderer; // @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.asyncDrawableLoader = builder.asyncDrawableLoader; this.syntaxHighlight = builder.syntaxHighlight; @@ -60,7 +65,8 @@ public class SpannableConfiguration { } @NonNull - public SpannableTheme theme() { + @Deprecated + public MarkwonTheme theme() { return theme; } @@ -130,7 +136,9 @@ public class SpannableConfiguration { public static class Builder { private final Context context; - private SpannableTheme theme; + + @Deprecated + private MarkwonTheme theme; private AsyncDrawable.Loader asyncDrawableLoader; private SyntaxHighlight syntaxHighlight; private LinkSpan.Resolver linkResolver; @@ -146,7 +154,7 @@ public class SpannableConfiguration { this.context = context; } - Builder(@NonNull Context context, @NonNull SpannableConfiguration configuration) { + Builder(@NonNull Context context, @NonNull MarkwonConfiguration configuration) { this(context); this.theme = configuration.theme; this.asyncDrawableLoader = configuration.asyncDrawableLoader; @@ -162,7 +170,8 @@ public class SpannableConfiguration { } @NonNull - public Builder theme(@NonNull SpannableTheme theme) { + @Deprecated + public Builder theme(@NonNull MarkwonTheme theme) { this.theme = theme; return this; } @@ -254,10 +263,10 @@ public class SpannableConfiguration { } @NonNull - public SpannableConfiguration build() { + public MarkwonConfiguration build() { if (theme == null) { - theme = SpannableTheme.create(context); + theme = MarkwonTheme.create(context); } if (asyncDrawableLoader == null) { @@ -300,7 +309,7 @@ public class SpannableConfiguration { htmlRenderer = MarkwonHtmlRenderer.create(); } - return new SpannableConfiguration(this); + return new MarkwonConfiguration(this); } } diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java b/markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java new file mode 100644 index 00000000..0252568e --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java @@ -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 plugins; + + MarkwonImpl( + @NonNull Parser parser, + @NonNull MarkwonVisitor visitor, + @NonNull List 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)); + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java b/markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java new file mode 100644 index 00000000..48e3674e --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java @@ -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); +} diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java new file mode 100644 index 00000000..58c28111 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java @@ -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 { + void visit(@NonNull MarkwonVisitor visitor, @NonNull N n); + } + + interface Builder { + + @NonNull + Builder on(@NonNull Class node, @NonNull NodeVisitor 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); +} diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java new file mode 100644 index 00000000..55971a38 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java @@ -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, NodeVisitor> 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, NodeVisitor> 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 nodeVisitor = (NodeVisitor) 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, NodeVisitor> nodes = + new HashMap<>(3); + + @NonNull + @Override + public Builder on(@NonNull Class node, @NonNull NodeVisitor 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)); + } + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/SpannableBuilder.java b/markwon/src/main/java/ru/noties/markwon/SpannableBuilder.java index 07e2bb85..556d7cc7 100644 --- a/markwon/src/main/java/ru/noties/markwon/SpannableBuilder.java +++ b/markwon/src/main/java/ru/noties/markwon/SpannableBuilder.java @@ -208,7 +208,7 @@ public class SpannableBuilder implements Appendable, CharSequence { /** * This method will return all {@link Span} spans that overlap specified range, * 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 */ diff --git a/markwon/src/main/java/ru/noties/markwon/SpannableFactory.java b/markwon/src/main/java/ru/noties/markwon/SpannableFactory.java index 472261a4..6297b777 100644 --- a/markwon/src/main/java/ru/noties/markwon/SpannableFactory.java +++ b/markwon/src/main/java/ru/noties/markwon/SpannableFactory.java @@ -9,7 +9,7 @@ import ru.noties.markwon.renderer.ImageSize; import ru.noties.markwon.renderer.ImageSizeResolver; import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.LinkSpan; -import ru.noties.markwon.spans.SpannableTheme; +import ru.noties.markwon.spans.MarkwonTheme; import ru.noties.markwon.spans.TableRowSpan; /** @@ -26,32 +26,32 @@ public interface SpannableFactory { Object emphasis(); @Nullable - Object blockQuote(@NonNull SpannableTheme theme); + Object blockQuote(@NonNull MarkwonTheme theme); @Nullable - Object code(@NonNull SpannableTheme theme, boolean multiline); + Object code(@NonNull MarkwonTheme theme, boolean multiline); @Nullable - Object orderedListItem(@NonNull SpannableTheme theme, int startNumber); + Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber); @Nullable - Object bulletListItem(@NonNull SpannableTheme theme, int level); + Object bulletListItem(@NonNull MarkwonTheme theme, int level); @Nullable - Object thematicBreak(@NonNull SpannableTheme theme); + Object thematicBreak(@NonNull MarkwonTheme theme); @Nullable - Object heading(@NonNull SpannableTheme theme, int level); + Object heading(@NonNull MarkwonTheme theme, int level); @Nullable Object strikethrough(); @Nullable - Object taskListItem(@NonNull SpannableTheme theme, int blockIndent, boolean isDone); + Object taskListItem(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone); @Nullable Object tableRow( - @NonNull SpannableTheme theme, + @NonNull MarkwonTheme theme, @NonNull List cells, boolean isHeader, boolean isOdd); @@ -64,7 +64,7 @@ public interface SpannableFactory { @Nullable Object image( - @NonNull SpannableTheme theme, + @NonNull MarkwonTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @@ -73,17 +73,17 @@ public interface SpannableFactory { @Nullable Object link( - @NonNull SpannableTheme theme, + @NonNull MarkwonTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver); // Currently used by HTML parser @Nullable - Object superScript(@NonNull SpannableTheme theme); + Object superScript(@NonNull MarkwonTheme theme); // Currently used by HTML parser @Nullable - Object subScript(@NonNull SpannableTheme theme); + Object subScript(@NonNull MarkwonTheme theme); // Currently used by HTML parser @Nullable diff --git a/markwon/src/main/java/ru/noties/markwon/SpannableFactoryDef.java b/markwon/src/main/java/ru/noties/markwon/SpannableFactoryDef.java index ee553329..6fc8d48f 100644 --- a/markwon/src/main/java/ru/noties/markwon/SpannableFactoryDef.java +++ b/markwon/src/main/java/ru/noties/markwon/SpannableFactoryDef.java @@ -18,12 +18,12 @@ import ru.noties.markwon.spans.EmphasisSpan; import ru.noties.markwon.spans.HeadingSpan; import ru.noties.markwon.spans.LinkSpan; 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.SubScriptSpan; import ru.noties.markwon.spans.SuperScriptSpan; import ru.noties.markwon.spans.TableRowSpan; -import ru.noties.markwon.spans.TaskListSpan; +import ru.noties.markwon.tasklist.TaskListSpan; import ru.noties.markwon.spans.ThematicBreakSpan; /** @@ -50,38 +50,38 @@ public class SpannableFactoryDef implements SpannableFactory { @Nullable @Override - public Object blockQuote(@NonNull SpannableTheme theme) { + public Object blockQuote(@NonNull MarkwonTheme theme) { return new BlockQuoteSpan(theme); } @Nullable @Override - public Object code(@NonNull SpannableTheme theme, boolean multiline) { + public Object code(@NonNull MarkwonTheme theme, boolean multiline) { return new CodeSpan(theme, multiline); } @Nullable @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 return new OrderedListItemSpan(theme, String.valueOf(startNumber) + "." + '\u00a0'); } @Nullable @Override - public Object bulletListItem(@NonNull SpannableTheme theme, int level) { + public Object bulletListItem(@NonNull MarkwonTheme theme, int level) { return new BulletListItemSpan(theme, level); } @Nullable @Override - public Object thematicBreak(@NonNull SpannableTheme theme) { + public Object thematicBreak(@NonNull MarkwonTheme theme) { return new ThematicBreakSpan(theme); } @Nullable @Override - public Object heading(@NonNull SpannableTheme theme, int level) { + public Object heading(@NonNull MarkwonTheme theme, int level) { return new HeadingSpan(theme, level); } @@ -93,13 +93,13 @@ public class SpannableFactoryDef implements SpannableFactory { @Nullable @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); } @Nullable @Override - public Object tableRow(@NonNull SpannableTheme theme, @NonNull List cells, boolean isHeader, boolean isOdd) { + public Object tableRow(@NonNull MarkwonTheme theme, @NonNull List cells, boolean isHeader, boolean isOdd) { return new TableRowSpan(theme, cells, isHeader, isOdd); } @@ -114,7 +114,7 @@ public class SpannableFactoryDef implements SpannableFactory { @Nullable @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( theme, new AsyncDrawable( @@ -130,18 +130,18 @@ public class SpannableFactoryDef implements SpannableFactory { @Nullable @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); } @Nullable @Override - public Object superScript(@NonNull SpannableTheme theme) { + public Object superScript(@NonNull MarkwonTheme theme) { return new SuperScriptSpan(theme); } @Override - public Object subScript(@NonNull SpannableTheme theme) { + public Object subScript(@NonNull MarkwonTheme theme) { return new SubScriptSpan(theme); } diff --git a/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java new file mode 100644 index 00000000..a1495c67 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java @@ -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() { + @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() { + @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() { + @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
() { + @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() { + @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() { + @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() { + @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() { + @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() { + @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() { + @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() { + @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(); + } + } + }); + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java b/markwon/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java index 967784e5..3ea3cc83 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java @@ -38,10 +38,10 @@ import java.util.ArrayList; import java.util.List; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableFactory; 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.tasklist.TaskListBlock; import ru.noties.markwon.tasklist.TaskListItem; @@ -49,11 +49,11 @@ import ru.noties.markwon.tasklist.TaskListItem; @SuppressWarnings("WeakerAccess") public class SpannableMarkdownVisitor extends AbstractVisitor { - private final SpannableConfiguration configuration; + private final MarkwonConfiguration configuration; private final SpannableBuilder builder; private final MarkwonHtmlParser htmlParser; - private final SpannableTheme theme; + private final MarkwonTheme theme; private final SpannableFactory factory; private int blockQuoteIndent; @@ -64,7 +64,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { private int tableRows; public SpannableMarkdownVisitor( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder ) { this.configuration = configuration; diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java b/markwon/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java index 32d620dd..b78f9c72 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/SpannableRenderer.java @@ -4,13 +4,13 @@ import android.support.annotation.NonNull; import org.commonmark.node.Node; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; public class SpannableRenderer { @NonNull - public CharSequence render(@NonNull SpannableConfiguration configuration, @NonNull Node node) { + public CharSequence render(@NonNull MarkwonConfiguration configuration, @NonNull Node node) { final SpannableBuilder builder = new SpannableBuilder(); node.accept(new SpannableMarkdownVisitor(configuration, builder)); return builder.text(); diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/MarkwonHtmlRenderer.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/MarkwonHtmlRenderer.java index bd69445a..b66045e6 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/MarkwonHtmlRenderer.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/MarkwonHtmlRenderer.java @@ -9,7 +9,7 @@ import java.util.Locale; import java.util.Map; 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.renderer.html2.tag.BlockquoteHandler; 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 void render( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull MarkwonHtmlParser parser ); diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/MarkwonHtmlRendererImpl.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/MarkwonHtmlRendererImpl.java index 6de698f5..cc34f55b 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/MarkwonHtmlRendererImpl.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/MarkwonHtmlRendererImpl.java @@ -7,7 +7,7 @@ import java.util.List; import java.util.Map; 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.MarkwonHtmlParser; import ru.noties.markwon.renderer.html2.tag.TagHandler; @@ -22,7 +22,7 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { @Override public void render( - @NonNull final SpannableConfiguration configuration, + @NonNull final MarkwonConfiguration configuration, @NonNull final SpannableBuilder builder, @NonNull MarkwonHtmlParser parser) { diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/BlockquoteHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/BlockquoteHandler.java index 99ddf153..9f90dc93 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/BlockquoteHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/BlockquoteHandler.java @@ -3,14 +3,14 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class BlockquoteHandler extends TagHandler { @Override public void handle( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) { diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/EmphasisHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/EmphasisHandler.java index d34218de..aa452ebf 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/EmphasisHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/EmphasisHandler.java @@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class EmphasisHandler extends SimpleTagHandler { @Nullable @Override - public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) { return configuration.factory().emphasis(); } } diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/HeadingHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/HeadingHandler.java index e2138b05..99626259 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/HeadingHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/HeadingHandler.java @@ -3,7 +3,7 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class HeadingHandler extends SimpleTagHandler { @@ -16,7 +16,7 @@ public class HeadingHandler extends SimpleTagHandler { @Nullable @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); } } diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/ImageHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/ImageHandler.java index ed5f7f3f..fe41f9d1 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/ImageHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/ImageHandler.java @@ -6,7 +6,7 @@ import android.text.TextUtils; 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.renderer.ImageSize; import ru.noties.markwon.renderer.html2.CssInlineStyleParser; @@ -31,7 +31,7 @@ public class ImageHandler extends SimpleTagHandler { @Nullable @Override - public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) { final Map attributes = tag.attributes(); final String src = attributes.get("src"); diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/LinkHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/LinkHandler.java index 134874b9..74ac3c00 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/LinkHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/LinkHandler.java @@ -4,13 +4,13 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class LinkHandler extends SimpleTagHandler { @Nullable @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"); if (!TextUtils.isEmpty(destination)) { return configuration.factory().link( diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/ListHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/ListHandler.java index fca098e7..671e2297 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/ListHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/ListHandler.java @@ -2,15 +2,15 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class ListHandler extends TagHandler { @Override public void handle( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) { diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SimpleTagHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SimpleTagHandler.java index e5940cc7..d6fd93dc 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SimpleTagHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SimpleTagHandler.java @@ -4,16 +4,16 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public abstract class SimpleTagHandler extends TagHandler { @Nullable - public abstract Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag); + public abstract Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag); @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); if (spans != null) { SpannableBuilder.setSpans(builder, spans, tag.start(), tag.end()); diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/StrikeHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/StrikeHandler.java index 965ddfea..9b8cad2d 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/StrikeHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/StrikeHandler.java @@ -2,15 +2,15 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class StrikeHandler extends TagHandler { @Override public void handle( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) { diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/StrongEmphasisHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/StrongEmphasisHandler.java index 04d18a25..7e50bc72 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/StrongEmphasisHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/StrongEmphasisHandler.java @@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class StrongEmphasisHandler extends SimpleTagHandler { @Nullable @Override - public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) { return configuration.factory().strongEmphasis(); } } diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SubScriptHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SubScriptHandler.java index a96f34bc..145cf261 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SubScriptHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SubScriptHandler.java @@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class SubScriptHandler extends SimpleTagHandler { @Nullable @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()); } } diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SuperScriptHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SuperScriptHandler.java index c5eee815..60da420d 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SuperScriptHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/SuperScriptHandler.java @@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class SuperScriptHandler extends SimpleTagHandler { @Nullable @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()); } } diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/TagHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/TagHandler.java index 818c4a98..bdf9b134 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/TagHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/TagHandler.java @@ -2,20 +2,20 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.html.api.HtmlTag; public abstract class TagHandler { public abstract void handle( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag ); protected static void visitChildren( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag.Block block) { diff --git a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/UnderlineHandler.java b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/UnderlineHandler.java index ff870ef6..d9e03e2a 100644 --- a/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/UnderlineHandler.java +++ b/markwon/src/main/java/ru/noties/markwon/renderer/html2/tag/UnderlineHandler.java @@ -3,14 +3,14 @@ package ru.noties.markwon.renderer.html2.tag; import android.support.annotation.NonNull; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.html.api.HtmlTag; public class UnderlineHandler extends TagHandler { @Override public void handle( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) { diff --git a/markwon/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java index f9bd8f33..b1ac85d4 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/AsyncDrawableSpan.java @@ -24,24 +24,24 @@ public class AsyncDrawableSpan extends ReplacementSpan { 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 - private final SpannableTheme theme; + private final MarkwonTheme theme; private final AsyncDrawable drawable; private final int alignment; 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); } public AsyncDrawableSpan( - @NonNull SpannableTheme theme, + @NonNull MarkwonTheme theme, @NonNull AsyncDrawable drawable, @Alignment int alignment) { this(theme, drawable, alignment, false); } public AsyncDrawableSpan( - @NonNull SpannableTheme theme, + @NonNull MarkwonTheme theme, @NonNull AsyncDrawable drawable, @Alignment int alignment, boolean replacementTextIsLink) { diff --git a/markwon/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java index aa85c33c..0101199f 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/BlockQuoteSpan.java @@ -9,11 +9,11 @@ import android.text.style.LeadingMarginSpan; public class BlockQuoteSpan implements LeadingMarginSpan { - private final SpannableTheme theme; + private final MarkwonTheme theme; private final Rect rect = ObjectsPool.rect(); private final Paint paint = ObjectsPool.paint(); - public BlockQuoteSpan(@NonNull SpannableTheme theme) { + public BlockQuoteSpan(@NonNull MarkwonTheme theme) { this.theme = theme; } diff --git a/markwon/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java index 368f13a9..ee9aefc7 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java @@ -9,9 +9,11 @@ import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; +import ru.noties.markwon.utils.LeadingMarginUtils; + public class BulletListItemSpan implements LeadingMarginSpan { - private SpannableTheme theme; + private MarkwonTheme theme; private final Paint paint = ObjectsPool.paint(); private final RectF circle = ObjectsPool.rectF(); @@ -20,7 +22,7 @@ public class BulletListItemSpan implements LeadingMarginSpan { private final int level; public BulletListItemSpan( - @NonNull SpannableTheme theme, + @NonNull MarkwonTheme theme, @IntRange(from = 0) int level) { this.theme = theme; this.level = level; diff --git a/markwon/src/main/java/ru/noties/markwon/spans/CodeSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/CodeSpan.java index b1098654..7488885d 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/CodeSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/CodeSpan.java @@ -11,13 +11,13 @@ import android.text.style.MetricAffectingSpan; public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan { - private final SpannableTheme theme; + private final MarkwonTheme theme; private final Rect rect = ObjectsPool.rect(); private final Paint paint = ObjectsPool.paint(); private final boolean multiline; - public CodeSpan(@NonNull SpannableTheme theme, boolean multiline) { + public CodeSpan(@NonNull MarkwonTheme theme, boolean multiline) { this.theme = theme; this.multiline = multiline; } diff --git a/markwon/src/main/java/ru/noties/markwon/spans/HeadingSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/HeadingSpan.java index 6293d554..c7d8d595 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/HeadingSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/HeadingSpan.java @@ -10,14 +10,16 @@ import android.text.TextPaint; import android.text.style.LeadingMarginSpan; import android.text.style.MetricAffectingSpan; +import ru.noties.markwon.utils.LeadingMarginUtils; + public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpan { - private final SpannableTheme theme; + private final MarkwonTheme theme; private final Rect rect = ObjectsPool.rect(); private final Paint paint = ObjectsPool.paint(); 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.level = level; } diff --git a/markwon/src/main/java/ru/noties/markwon/spans/LinkSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/LinkSpan.java index 2359f9a4..f879c5ec 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/LinkSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/LinkSpan.java @@ -2,7 +2,6 @@ package ru.noties.markwon.spans; import android.support.annotation.NonNull; import android.text.TextPaint; -import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.view.View; @@ -12,11 +11,11 @@ public class LinkSpan extends URLSpan { void resolve(View view, @NonNull String link); } - private final SpannableTheme theme; + private final MarkwonTheme theme; private final String link; 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); this.theme = theme; this.link = link; diff --git a/markwon/src/main/java/ru/noties/markwon/spans/SpannableTheme.java b/markwon/src/main/java/ru/noties/markwon/spans/MarkwonTheme.java similarity index 97% rename from markwon/src/main/java/ru/noties/markwon/spans/SpannableTheme.java rename to markwon/src/main/java/ru/noties/markwon/spans/MarkwonTheme.java index a3ba8c55..b5c9f34a 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/SpannableTheme.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/MarkwonTheme.java @@ -7,7 +7,6 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.support.annotation.AttrRes; import android.support.annotation.ColorInt; -import android.support.annotation.Dimension; import android.support.annotation.FloatRange; import android.support.annotation.IntRange; import android.support.annotation.NonNull; @@ -20,19 +19,21 @@ import android.util.TypedValue; import java.util.Arrays; import java.util.Locale; +import ru.noties.markwon.tasklist.TaskListDrawable; + @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 - * @return {@link SpannableTheme} instance + * @return {@link MarkwonTheme} instance * @see #builderWithDefaults(Context) * @since 1.0.0 */ @NonNull - public static SpannableTheme create(@NonNull Context context) { + public static MarkwonTheme create(@NonNull Context context) { return builderWithDefaults(context).build(); } @@ -43,7 +44,7 @@ public class SpannableTheme { * * @return {@link Builder instance} * @see #builderWithDefaults(Context) - * @see #builder(SpannableTheme) + * @see #builder(MarkwonTheme) * @since 1.0.0 */ @NonNull @@ -53,15 +54,15 @@ public class SpannableTheme { /** * 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 * @see #builderWithDefaults(Context) * @since 1.0.0 */ @NonNull - public static Builder builder(@NonNull SpannableTheme copyFrom) { + public static Builder builder(@NonNull MarkwonTheme copyFrom) { return new Builder(copyFrom); } @@ -217,9 +218,10 @@ public class SpannableTheme { // drawable that will be used to render checkbox (should be stateful) // TaskListDrawable can be used + @Deprecated protected final Drawable taskListDrawable; - protected SpannableTheme(@NonNull Builder builder) { + protected MarkwonTheme(@NonNull Builder builder) { this.linkColor = builder.linkColor; this.blockMargin = builder.blockMargin; this.blockQuoteWidth = builder.blockQuoteWidth; @@ -526,6 +528,7 @@ public class SpannableTheme { * @since 1.0.1 */ @Nullable + @Deprecated public Drawable getTaskListDrawable() { return taskListDrawable; } @@ -565,7 +568,7 @@ public class SpannableTheme { Builder() { } - Builder(@NonNull SpannableTheme theme) { + Builder(@NonNull MarkwonTheme theme) { this.linkColor = theme.linkColor; this.blockMargin = theme.blockMargin; this.blockQuoteWidth = theme.blockQuoteWidth; @@ -792,14 +795,15 @@ public class SpannableTheme { * @since 1.0.1 */ @NonNull + @Deprecated public Builder taskListDrawable(@NonNull Drawable taskListDrawable) { this.taskListDrawable = taskListDrawable; return this; } @NonNull - public SpannableTheme build() { - return new SpannableTheme(this); + public MarkwonTheme build() { + return new MarkwonTheme(this); } } diff --git a/markwon/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java index 1db29e1a..e2bc1fb0 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java @@ -9,6 +9,8 @@ import android.text.TextPaint; import android.text.style.LeadingMarginSpan; import android.widget.TextView; +import ru.noties.markwon.utils.LeadingMarginUtils; + 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 Paint paint = ObjectsPool.paint(); @@ -52,7 +54,7 @@ public class OrderedListItemSpan implements LeadingMarginSpan { private int margin; public OrderedListItemSpan( - @NonNull SpannableTheme theme, + @NonNull MarkwonTheme theme, @NonNull String number ) { this.theme = theme; diff --git a/markwon/src/main/java/ru/noties/markwon/spans/SubScriptSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/SubScriptSpan.java index 4386613d..318697b1 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/SubScriptSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/SubScriptSpan.java @@ -6,9 +6,9 @@ import android.text.style.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; } diff --git a/markwon/src/main/java/ru/noties/markwon/spans/SuperScriptSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/SuperScriptSpan.java index 4b8151ec..d1aa172b 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/SuperScriptSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/SuperScriptSpan.java @@ -6,9 +6,9 @@ import android.text.style.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; } diff --git a/markwon/src/main/java/ru/noties/markwon/spans/TableRowSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/TableRowSpan.java index 4d3a35fb..a54b3206 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/TableRowSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/TableRowSpan.java @@ -61,7 +61,7 @@ public class TableRowSpan extends ReplacementSpan { } } - private final SpannableTheme theme; + private final MarkwonTheme theme; private final List cells; private final List layouts; private final TextPaint textPaint; @@ -76,7 +76,7 @@ public class TableRowSpan extends ReplacementSpan { private Invalidator invalidator; public TableRowSpan( - @NonNull SpannableTheme theme, + @NonNull MarkwonTheme theme, @NonNull List cells, boolean header, boolean odd) { diff --git a/markwon/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java index 316e4312..a19f7528 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/ThematicBreakSpan.java @@ -9,11 +9,11 @@ import android.text.style.LeadingMarginSpan; public class ThematicBreakSpan implements LeadingMarginSpan { - private final SpannableTheme theme; + private final MarkwonTheme theme; private final Rect rect = ObjectsPool.rect(); private final Paint paint = ObjectsPool.paint(); - public ThematicBreakSpan(@NonNull SpannableTheme theme) { + public ThematicBreakSpan(@NonNull MarkwonTheme theme) { this.theme = theme; } diff --git a/markwon/src/main/java/ru/noties/markwon/spans/TaskListDrawable.java b/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListDrawable.java similarity index 99% rename from markwon/src/main/java/ru/noties/markwon/spans/TaskListDrawable.java rename to markwon/src/main/java/ru/noties/markwon/tasklist/TaskListDrawable.java index 5119deb4..15924e8f 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/TaskListDrawable.java +++ b/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListDrawable.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.spans; +package ru.noties.markwon.tasklist; import android.graphics.Canvas; import android.graphics.ColorFilter; diff --git a/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListExtension.java b/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListExtension.java index 3bb49355..a721c297 100644 --- a/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListExtension.java +++ b/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListExtension.java @@ -7,6 +7,7 @@ import org.commonmark.parser.Parser; /** * @since 1.0.1 */ +@Deprecated public class TaskListExtension implements Parser.ParserExtension { @NonNull diff --git a/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListPlugin.java b/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListPlugin.java new file mode 100644 index 00000000..bf75d5c7 --- /dev/null +++ b/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListPlugin.java @@ -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() { + @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() { + @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); + } + }); + } +} diff --git a/markwon/src/main/java/ru/noties/markwon/spans/TaskListSpan.java b/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListSpan.java similarity index 77% rename from markwon/src/main/java/ru/noties/markwon/spans/TaskListSpan.java rename to markwon/src/main/java/ru/noties/markwon/tasklist/TaskListSpan.java index 25bc6a41..5c59b167 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/TaskListSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/tasklist/TaskListSpan.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.spans; +package ru.noties.markwon.tasklist; import android.graphics.Canvas; import android.graphics.Paint; @@ -7,6 +7,9 @@ import android.support.annotation.NonNull; import android.text.Layout; import android.text.style.LeadingMarginSpan; +import ru.noties.markwon.spans.MarkwonTheme; +import ru.noties.markwon.utils.LeadingMarginUtils; + /** * @since 1.0.1 */ @@ -16,14 +19,24 @@ public class TaskListSpan implements LeadingMarginSpan { 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; // @since 2.0.1 field is NOT final (to allow mutation) 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.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.isDone = isDone; } @@ -58,10 +71,10 @@ public class TaskListSpan implements LeadingMarginSpan { return; } - final Drawable drawable = theme.getTaskListDrawable(); - if (drawable == null) { - return; - } +// final Drawable drawable = theme.getTaskListDrawable(); +// if (drawable == null) { +// return; +// } final int save = c.save(); try { diff --git a/markwon/src/main/java/ru/noties/markwon/spans/LeadingMarginUtils.java b/markwon/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java similarity index 52% rename from markwon/src/main/java/ru/noties/markwon/spans/LeadingMarginUtils.java rename to markwon/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java index ab1a7de3..f783fcae 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/LeadingMarginUtils.java +++ b/markwon/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java @@ -1,14 +1,14 @@ -package ru.noties.markwon.spans; +package ru.noties.markwon.utils; 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; } - 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; } diff --git a/markwon/src/test/java/ru/noties/markwon/renderer/SpannableConfigurationTest.java b/markwon/src/test/java/ru/noties/markwon/renderer/MarkwonConfigurationTest.java similarity index 86% rename from markwon/src/test/java/ru/noties/markwon/renderer/SpannableConfigurationTest.java rename to markwon/src/test/java/ru/noties/markwon/renderer/MarkwonConfigurationTest.java index daa70332..e094164b 100644 --- a/markwon/src/test/java/ru/noties/markwon/renderer/SpannableConfigurationTest.java +++ b/markwon/src/test/java/ru/noties/markwon/renderer/MarkwonConfigurationTest.java @@ -2,7 +2,7 @@ package ru.noties.markwon.renderer; import org.junit.Test; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableFactory; import ru.noties.markwon.SyntaxHighlight; 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.spans.AsyncDrawable; 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.mockito.Mockito.mock; -public class SpannableConfigurationTest { +public class MarkwonConfigurationTest { @Test public void testNewBuilder() { - final SpannableConfiguration configuration = SpannableConfiguration + final MarkwonConfiguration configuration = MarkwonConfiguration .builder(null) - .theme(mock(SpannableTheme.class)) + .theme(mock(MarkwonTheme.class)) .asyncDrawableLoader(mock(AsyncDrawable.Loader.class)) .syntaxHighlight(mock(SyntaxHighlight.class)) .linkResolver(mock(LinkSpan.Resolver.class)) @@ -33,7 +33,7 @@ public class SpannableConfigurationTest { .htmlAllowNonClosedTags(true) .build(); - final SpannableConfiguration newConfiguration = configuration + final MarkwonConfiguration newConfiguration = configuration .newBuilder(null) .build(); diff --git a/markwon/src/test/java/ru/noties/markwon/renderer/SyntaxHighlightTest.java b/markwon/src/test/java/ru/noties/markwon/renderer/SyntaxHighlightTest.java index 1f5d88d4..ecca6e91 100644 --- a/markwon/src/test/java/ru/noties/markwon/renderer/SyntaxHighlightTest.java +++ b/markwon/src/test/java/ru/noties/markwon/renderer/SyntaxHighlightTest.java @@ -13,11 +13,11 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.SpannableFactory; 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.assertTrue; @@ -63,12 +63,12 @@ public class SyntaxHighlightTest { }; 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) .factory(factory) - .theme(mock(SpannableTheme.class)) + .theme(mock(MarkwonTheme.class)) .build(); final SpannableBuilder builder = new SpannableBuilder(); diff --git a/markwon/src/test/java/ru/noties/markwon/renderer/visitor/SpannableMarkdownVisitorTest.java b/markwon/src/test/java/ru/noties/markwon/renderer/visitor/SpannableMarkdownVisitorTest.java index 047a0584..6d77b130 100644 --- a/markwon/src/test/java/ru/noties/markwon/renderer/visitor/SpannableMarkdownVisitorTest.java +++ b/markwon/src/test/java/ru/noties/markwon/renderer/visitor/SpannableMarkdownVisitorTest.java @@ -14,12 +14,12 @@ import java.util.Collection; import ru.noties.markwon.LinkResolverDef; import ru.noties.markwon.Markwon; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.SpannableFactory; import ru.noties.markwon.html.api.MarkwonHtmlParser; 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.mockito.Mockito.mock; @@ -44,7 +44,7 @@ public class SpannableMarkdownVisitorTest { final TestData data = TestDataReader.readTest(file); - final SpannableConfiguration configuration = configuration(data.config()); + final MarkwonConfiguration configuration = configuration(data.config()); final SpannableBuilder builder = new SpannableBuilder(); final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(configuration, builder); final Node node = Markwon.createParser().parse(data.input()); @@ -73,7 +73,7 @@ public class SpannableMarkdownVisitorTest { @SuppressWarnings("ConstantConditions") @NonNull - private SpannableConfiguration configuration(@NonNull TestConfig config) { + private MarkwonConfiguration configuration(@NonNull TestConfig config) { final SpannableFactory factory = new TestFactory(config.hasOption(TestConfig.USE_PARAGRAPHS)); 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 htmlAllowNonClosedTags = config.hasOption(TestConfig.HTML_ALLOW_NON_CLOSED_TAGS); - return SpannableConfiguration.builder(null) - .theme(mock(SpannableTheme.class)) + return MarkwonConfiguration.builder(null) + .theme(mock(MarkwonTheme.class)) .linkResolver(mock(LinkResolverDef.class)) .htmlParser(htmlParser) .factory(factory) diff --git a/markwon/src/test/java/ru/noties/markwon/renderer/visitor/TestFactory.java b/markwon/src/test/java/ru/noties/markwon/renderer/visitor/TestFactory.java index 89a0f646..42d46f99 100644 --- a/markwon/src/test/java/ru/noties/markwon/renderer/visitor/TestFactory.java +++ b/markwon/src/test/java/ru/noties/markwon/renderer/visitor/TestFactory.java @@ -13,7 +13,7 @@ import ru.noties.markwon.renderer.ImageSize; import ru.noties.markwon.renderer.ImageSizeResolver; import ru.noties.markwon.spans.AsyncDrawable; 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 static ru.noties.markwon.renderer.visitor.TestSpan.BLOCK_QUOTE; @@ -57,13 +57,13 @@ class TestFactory implements SpannableFactory { @Nullable @Override - public Object blockQuote(@NonNull SpannableTheme theme) { + public Object blockQuote(@NonNull MarkwonTheme theme) { return new TestSpan(BLOCK_QUOTE); } @Nullable @Override - public Object code(@NonNull SpannableTheme theme, boolean multiline) { + public Object code(@NonNull MarkwonTheme theme, boolean multiline) { final String name = multiline ? CODE_BLOCK : CODE; @@ -72,25 +72,25 @@ class TestFactory implements SpannableFactory { @Nullable @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)); } @Nullable @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)); } @Nullable @Override - public Object thematicBreak(@NonNull SpannableTheme theme) { + public Object thematicBreak(@NonNull MarkwonTheme theme) { return new TestSpan(THEMATIC_BREAK); } @Nullable @Override - public Object heading(@NonNull SpannableTheme theme, int level) { + public Object heading(@NonNull MarkwonTheme theme, int level) { return new TestSpan(HEADING + level); } @@ -102,7 +102,7 @@ class TestFactory implements SpannableFactory { @Nullable @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( Pair.of("blockIdent", blockIndent), Pair.of("done", isDone) @@ -111,7 +111,7 @@ class TestFactory implements SpannableFactory { @Nullable @Override - public Object tableRow(@NonNull SpannableTheme theme, @NonNull List cells, boolean isHeader, boolean isOdd) { + public Object tableRow(@NonNull MarkwonTheme theme, @NonNull List cells, boolean isHeader, boolean isOdd) { return new TestSpan(TABLE_ROW, map( Pair.of("cells", cells), Pair.of("header", isHeader), @@ -129,7 +129,7 @@ class TestFactory implements SpannableFactory { @Nullable @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( Pair.of("src", destination), Pair.of("imageSize", imageSize), @@ -139,19 +139,19 @@ class TestFactory implements SpannableFactory { @Nullable @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)); } @Nullable @Override - public Object superScript(@NonNull SpannableTheme theme) { + public Object superScript(@NonNull MarkwonTheme theme) { return new TestSpan(SUPER_SCRIPT); } @Nullable @Override - public Object subScript(@NonNull SpannableTheme theme) { + public Object subScript(@NonNull MarkwonTheme theme) { return new TestSpan(SUB_SCRIPT); } diff --git a/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/IconVisitor.java b/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/IconVisitor.java index d373ff75..77c5da2e 100644 --- a/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/IconVisitor.java +++ b/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/IconVisitor.java @@ -2,12 +2,11 @@ package ru.noties.markwon.sample.extension; import android.support.annotation.NonNull; import android.text.TextUtils; -import android.widget.TextView; import org.commonmark.node.CustomNode; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.renderer.SpannableMarkdownVisitor; @SuppressWarnings("WeakerAccess") @@ -18,7 +17,7 @@ public class IconVisitor extends SpannableMarkdownVisitor { private final IconSpanProvider iconSpanProvider; public IconVisitor( - @NonNull SpannableConfiguration configuration, + @NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull IconSpanProvider iconSpanProvider ) { diff --git a/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/MainActivity.java b/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/MainActivity.java index 19a69704..b104e88e 100644 --- a/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/MainActivity.java +++ b/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/MainActivity.java @@ -12,9 +12,9 @@ import org.commonmark.parser.Parser; import java.util.Arrays; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; -import ru.noties.markwon.spans.SpannableTheme; +import ru.noties.markwon.spans.MarkwonTheme; import ru.noties.markwon.tasklist.TaskListExtension; public class MainActivity extends Activity { @@ -53,8 +53,8 @@ public class MainActivity extends Activity { final IconSpanProvider spanProvider = IconSpanProvider.create(this, 0); final float[] textSizeMultipliers = new float[]{3f, 2f, 1.5f, 1f, .5f, .25f}; - SpannableConfiguration configuration = SpannableConfiguration.builder(this) - .theme(SpannableTheme.builder() + MarkwonConfiguration configuration = MarkwonConfiguration.builder(this) + .theme(MarkwonTheme.builder() .headingTypeface(Typeface.MONOSPACE) .headingTextSizeMultipliers(textSizeMultipliers) .build()) diff --git a/sample-latex-math/src/main/java/ru/noties/markwon/sample/jlatexmath/MainActivity.java b/sample-latex-math/src/main/java/ru/noties/markwon/sample/jlatexmath/MainActivity.java index dee84ee4..b613eac5 100644 --- a/sample-latex-math/src/main/java/ru/noties/markwon/sample/jlatexmath/MainActivity.java +++ b/sample-latex-math/src/main/java/ru/noties/markwon/sample/jlatexmath/MainActivity.java @@ -10,8 +10,8 @@ import org.commonmark.parser.Parser; import ru.noties.jlatexmath.JLatexMathAndroid; import ru.noties.markwon.Markwon; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.SpannableBuilder; -import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.il.AsyncDrawableLoader; import ru.noties.markwon.renderer.ImageSize; import ru.noties.markwon.renderer.SpannableMarkdownVisitor; @@ -55,7 +55,7 @@ public class MainActivity extends Activity { .mediaDecoders(jLatexMathMedia.mediaDecoder()) .build(); - final SpannableConfiguration configuration = SpannableConfiguration.builder(this) + final MarkwonConfiguration configuration = MarkwonConfiguration.builder(this) .asyncDrawableLoader(asyncDrawableLoader) .build(); @@ -68,7 +68,7 @@ public class MainActivity extends Activity { final Node node = parser.parse(markdown); final SpannableBuilder builder = new SpannableBuilder(); - final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(SpannableConfiguration.create(this), builder) { + final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(MarkwonConfiguration.create(this), builder) { @Override public void visit(CustomBlock customBlock) {