From a1f12641c3b93c141c13dd72a9816097b077d26d Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 2 Mar 2020 10:22:04 +0300 Subject: [PATCH] JLatexMathPlugin add error handling --- CHANGELOG.md | 6 +- .../markwon/ext/latex/JLatexMathPlugin.java | 83 +++++++++++++++---- .../markwon/sample/latex/LatexActivity.java | 53 ++++++++---- 3 files changed, 110 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64de0ca5..b6983a78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,12 @@ ``` * `JLatexMathPlugin`: add `theme` (to customize both inlines and blocks) * `JLatexMathPlugin`: add `renderMode` to use previous (pre `4.3.0`) LaTeX rendering +* add `JLatexMathPlugin.ErrorHandler` to catch latex rendering errors and (optionally) display error drawable ([#204]) * add `SoftBreakAddsNewLinePlugin` plugin (`core` module) -* `LinkResolverDef` defaults to `https` when a link does not have scheme information +* `LinkResolverDef` defaults to `https` when a link does not have scheme information ([#75]) + +[#75]: https://github.com/noties/Markwon/issues/75 +[#204]: https://github.com/noties/Markwon/issues/204 # 4.2.2 diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java index 5a3d70b9..e83f3bf6 100644 --- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java +++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java @@ -29,6 +29,7 @@ import io.noties.markwon.image.AsyncDrawable; import io.noties.markwon.image.AsyncDrawableLoader; import io.noties.markwon.image.AsyncDrawableScheduler; import io.noties.markwon.image.AsyncDrawableSpan; +import io.noties.markwon.image.DrawableUtils; import io.noties.markwon.image.ImageSizeResolver; import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; import ru.noties.jlatexmath.JLatexMathDrawable; @@ -62,6 +63,22 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { BLOCKS_AND_INLINES } + /** + * @since 4.3.0-SNAPSHOT + */ + public interface ErrorHandler { + + /** + * @param latex that caused the error or null if operated `AsyncDrawable` + * is not an instance of `JLatexAsyncDrawable` + * @param error occurred + * @return (optional) error drawable that will be used instead (if drawable will have bounds + * it will be used, if not intrinsic bounds will be set) + */ + @Nullable + Drawable handleError(@Nullable String latex, @NonNull Throwable error); + } + public interface BuilderConfigure { void configureBuilder(@NonNull Builder builder); } @@ -125,11 +142,15 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { // @since 4.3.0-SNAPSHOT private final RenderMode renderMode; + // @since 4.3.0-SNAPSHOT + private final ErrorHandler errorHandler; + private final ExecutorService executorService; Config(@NonNull Builder builder) { this.theme = builder.theme.build(); this.renderMode = builder.renderMode; + this.errorHandler = builder.errorHandler; // @since 4.0.0 ExecutorService executorService = builder.executorService; if (executorService == null) { @@ -284,6 +305,9 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { // @since 4.3.0-SNAPSHOT private RenderMode renderMode = RenderMode.BLOCKS_AND_INLINES; + // @since 4.3.0-SNAPSHOT + private ErrorHandler errorHandler; + // @since 4.0.0 private ExecutorService executorService; @@ -305,6 +329,12 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { return this; } + @NonNull + public Builder errorHandler(@Nullable ErrorHandler errorHandler) { + this.errorHandler = errorHandler; + return this; + } + /** * @since 4.0.0 */ @@ -351,10 +381,24 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { try { execute(); } catch (Throwable t) { - Log.e( - "JLatexMathPlugin", - "Error displaying latex: `" + drawable.getDestination() + "`", - t); + // @since 4.3.0-SNAPSHOT add error handling + final ErrorHandler errorHandler = config.errorHandler; + if (errorHandler == null) { + // as before + Log.e( + "JLatexMathPlugin", + "Error displaying latex: `" + drawable.getDestination() + "`", + t); + } else { + final Drawable errorDrawable = errorHandler.handleError( + drawable.getDestination(), + t + ); + if (errorDrawable != null) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(errorDrawable); + setResult(drawable, errorDrawable); + } + } } } @@ -370,19 +414,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { jLatexMathDrawable = createInlineDrawable(jLatextAsyncDrawable.getDestination()); } - // we must post to handler, but also have a way to identify the drawable - // for which we are posting (in case of cancellation) - handler.postAtTime(new Runnable() { - @Override - public void run() { - // remove entry from cache (it will be present if task is not cancelled) - if (cache.remove(drawable) != null - && drawable.isAttached()) { - drawable.setResult(jLatexMathDrawable); - } - - } - }, drawable, SystemClock.uptimeMillis()); + setResult(drawable, jLatexMathDrawable); } })); } @@ -456,6 +488,23 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin { return builder.build(); } + + // @since 4.3.0-SNAPSHOT + private void setResult(@NonNull final AsyncDrawable drawable, @NonNull final Drawable result) { + // we must post to handler, but also have a way to identify the drawable + // for which we are posting (in case of cancellation) + handler.postAtTime(new Runnable() { + @Override + public void run() { + // remove entry from cache (it will be present if task is not cancelled) + if (cache.remove(drawable) != null + && drawable.isAttached()) { + drawable.setResult(result); + } + + } + }, drawable, SystemClock.uptimeMillis()); + } } private static class InlineImageSizeResolver extends ImageSizeResolver { diff --git a/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java index 48f052c2..24d87da3 100644 --- a/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/latex/LatexActivity.java @@ -2,12 +2,15 @@ package io.noties.markwon.sample.latex; import android.content.res.Resources; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import io.noties.debug.Debug; import io.noties.markwon.Markwon; import io.noties.markwon.ext.latex.JLatexMathPlugin; import io.noties.markwon.ext.latex.JLatexMathTheme; @@ -57,6 +60,7 @@ public class LatexActivity extends ActivityWithMenuOptions { .add("bangle", this::bangle) .add("boxes", this::boxes) .add("insideBlockQuote", this::insideBlockQuote) + .add("error", this::error) .add("legacy", this::legacy); } @@ -95,6 +99,27 @@ public class LatexActivity extends ActivityWithMenuOptions { render(md); } + private void error() { + final String md = wrapLatexInSampleMarkdown("\\sum_{i=0}^\\infty x \\cdot 0 \\rightarrow \\iMightNotExist{0}"); + + final Markwon markwon = Markwon.builder(this) + .usePlugin(MarkwonInlineParserPlugin.create()) + .usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> { + //noinspection Convert2Lambda + builder.errorHandler(new JLatexMathPlugin.ErrorHandler() { + @Nullable + @Override + public Drawable handleError(@Nullable String latex, @NonNull Throwable error) { + Debug.e(error, latex); + return ContextCompat.getDrawable(LatexActivity.this, R.drawable.ic_android_black_24dp); + } + }); + })) + .build(); + + markwon.setMarkdown(textView, md); + } + private void legacy() { final String md = wrapLatexInSampleMarkdown(LATEX_BANGLE); @@ -127,22 +152,22 @@ public class LatexActivity extends ActivityWithMenuOptions { final float textSize = textView.getTextSize(); final Resources r = getResources(); -final Markwon markwon = Markwon.builder(this) - // NB! `MarkwonInlineParserPlugin` is required in order to parse inlines - .usePlugin(MarkwonInlineParserPlugin.create()) - .usePlugin(JLatexMathPlugin.create(textSize, textSize * 1.25F, builder -> { - builder.theme() - .inlineBackgroundProvider(() -> new ColorDrawable(0x1000ff00)) - .blockBackgroundProvider(() -> new ColorDrawable(0x10ff0000)) - .blockPadding(JLatexMathTheme.Padding.symmetric( - r.getDimensionPixelSize(R.dimen.latex_block_padding_vertical), - r.getDimensionPixelSize(R.dimen.latex_block_padding_horizontal) - )); + final Markwon markwon = Markwon.builder(this) + // NB! `MarkwonInlineParserPlugin` is required in order to parse inlines + .usePlugin(MarkwonInlineParserPlugin.create()) + .usePlugin(JLatexMathPlugin.create(textSize, textSize * 1.25F, builder -> { + builder.theme() + .inlineBackgroundProvider(() -> new ColorDrawable(0x1000ff00)) + .blockBackgroundProvider(() -> new ColorDrawable(0x10ff0000)) + .blockPadding(JLatexMathTheme.Padding.symmetric( + r.getDimensionPixelSize(R.dimen.latex_block_padding_vertical), + r.getDimensionPixelSize(R.dimen.latex_block_padding_horizontal) + )); - // explicitly request LEGACY rendering mode + // explicitly request LEGACY rendering mode // builder.renderMode(JLatexMathPlugin.RenderMode.LEGACY); - })) - .build(); + })) + .build(); markwon.setMarkdown(textView, markdown); }