From 6c8f1c04bbe27d752701a5e88e67fe391e26e39b Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 6 Aug 2019 19:27:20 +0300 Subject: [PATCH 01/13] Update documentation web-site --- .../noties/markwon/app/MarkdownRenderer.java | 7 ++++ docs/.vuepress/components/LegacyWarning.vue | 2 +- docs/.vuepress/config.js | 17 ++++++-- docs/docs/v3/core/configuration.md | 2 + docs/docs/v3/core/core-plugin.md | 2 + docs/docs/v3/core/getting-started.md | 2 + docs/docs/v3/core/html-renderer.md | 2 + docs/docs/v3/core/images.md | 2 + docs/docs/v3/core/movement-method-plugin.md | 2 + docs/docs/v3/core/plugins.md | 2 + docs/docs/v3/core/render-props.md | 2 + docs/docs/v3/core/spans-factory.md | 2 + docs/docs/v3/core/theme.md | 2 + docs/docs/v3/core/visitor.md | 2 + docs/docs/v3/ext-latex/README.md | 2 + docs/docs/v3/ext-strikethrough/README.md | 2 + docs/docs/v3/ext-tables/README.md | 2 + docs/docs/v3/ext-tasklist/README.md | 2 + docs/docs/v3/html/README.md | 2 + docs/docs/v3/image/gif.md | 2 + docs/docs/v3/image/okhttp.md | 2 + docs/docs/v3/image/svg.md | 2 + docs/docs/v3/install.md | 2 + docs/docs/v3/migration-2-3.md | 2 + docs/docs/v3/recycler-table/README.md | 2 + docs/docs/v3/recycler/README.md | 2 + docs/docs/v3/syntax-highlight/README.md | 2 + docs/docs/v4/core/text-setter.md | 40 +++++++++++++++++++ .../main/java/io/noties/markwon/Markwon.java | 30 +++++++------- 29 files changed, 124 insertions(+), 20 deletions(-) create mode 100644 docs/docs/v4/core/text-setter.md diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index 9bcb8e0f..15583b65 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -10,6 +10,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.inject.Inject; @@ -18,6 +19,7 @@ import io.noties.debug.Debug; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.Markwon; import io.noties.markwon.MarkwonConfiguration; +import io.noties.markwon.PrecomputedTextSetterCompat; import io.noties.markwon.app.gif.GifAwarePlugin; import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.ext.tables.TablePlugin; @@ -73,6 +75,11 @@ public class MarkdownRenderer { cancel(); +final Markwon markwon = Markwon.builder(context) + .usePlugin(/**/) + .textSetter(PrecomputedTextSetterCompat.create(Executors.newCachedThreadPool())) + .build(); + task = service.submit(new Runnable() { @Override diff --git a/docs/.vuepress/components/LegacyWarning.vue b/docs/.vuepress/components/LegacyWarning.vue index b84e9cea..5f1d585f 100644 --- a/docs/.vuepress/components/LegacyWarning.vue +++ b/docs/.vuepress/components/LegacyWarning.vue @@ -1,7 +1,7 @@ diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index de897e67..cd58b64c 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -16,9 +16,17 @@ module.exports = { { text: 'API Version', items: [ - { text: 'Current (4.x.x)', link: '/' }, - { text: 'Legacy (3.x.x)', link: '/docs/v3/install.md' }, - { text: 'Legacy (2.x.x)', link: '/docs/v2/' } + { + text: 'Latest', items: [ + { text: '4.x.x', link: '/' }, + ] + }, + { + text: 'Legacy', items: [ + { text: '3.x.x', link: '/docs/v3/install.md' }, + { text: '2.x.x', link: '/docs/v2/' } + ] + } ] }, { text: 'Changelog', link: 'https://github.com/noties/Markwon/blob/master/CHANGELOG.md' }, @@ -83,7 +91,8 @@ module.exports = { '/docs/v4/core/spans-factory.md', '/docs/v4/core/core-plugin.md', '/docs/v4/core/movement-method-plugin.md', - '/docs/v4/core/render-props.md' + '/docs/v4/core/render-props.md', + '/docs/v4/core/text-setter.md' ] }, '/docs/v4/ext-latex/', diff --git a/docs/docs/v3/core/configuration.md b/docs/docs/v3/core/configuration.md index 245b3310..db5d3f96 100644 --- a/docs/docs/v3/core/configuration.md +++ b/docs/docs/v3/core/configuration.md @@ -1,5 +1,7 @@ # Configuration + + `MarkwonConfiguration` class holds common Markwon functionality. These are _configurable_ properties: * `SyntaxHighlight` diff --git a/docs/docs/v3/core/core-plugin.md b/docs/docs/v3/core/core-plugin.md index 3a63c2c5..41c92a45 100644 --- a/docs/docs/v3/core/core-plugin.md +++ b/docs/docs/v3/core/core-plugin.md @@ -1,5 +1,7 @@ # Core plugin + + Since with introduction of _plugins_, Markwon **core** functionality was moved to a dedicated plugin. diff --git a/docs/docs/v3/core/getting-started.md b/docs/docs/v3/core/getting-started.md index 652cfb7c..60dc0451 100644 --- a/docs/docs/v3/core/getting-started.md +++ b/docs/docs/v3/core/getting-started.md @@ -1,5 +1,7 @@ # Getting started + + :::tip Installation Please follow [installation](/docs/v3/install.md) instructions to learn how to add `Markwon` to your project diff --git a/docs/docs/v3/core/html-renderer.md b/docs/docs/v3/core/html-renderer.md index 17ef63e3..1b5e4761 100644 --- a/docs/docs/v3/core/html-renderer.md +++ b/docs/docs/v3/core/html-renderer.md @@ -1,5 +1,7 @@ # HTML Renderer + + Starting with `MarkwonHtmlRenderer` controls how HTML is rendered: diff --git a/docs/docs/v3/core/images.md b/docs/docs/v3/core/images.md index 4aa675e2..75361d86 100644 --- a/docs/docs/v3/core/images.md +++ b/docs/docs/v3/core/images.md @@ -1,5 +1,7 @@ # Images + + Starting with `Markwon` comes with `ImagesPlugin` which supports `http(s)`, `file` and `data` schemes and default media decoder (for simple images, no [SVG](/docs/v3/image/svg.md) or [GIF](/docs/v3/image/gif.md) which diff --git a/docs/docs/v3/core/movement-method-plugin.md b/docs/docs/v3/core/movement-method-plugin.md index 6bb50c87..86fe43d2 100644 --- a/docs/docs/v3/core/movement-method-plugin.md +++ b/docs/docs/v3/core/movement-method-plugin.md @@ -1,5 +1,7 @@ # Movement method plugin + + `MovementMethodPlugin` can be used to apply a `MovementMethod` to a TextView (important if you have links inside your markdown). By default `CorePlugin` will set a `LinkMovementMethod` on a TextView if one is missing. If you have diff --git a/docs/docs/v3/core/plugins.md b/docs/docs/v3/core/plugins.md index dd83ab76..62052c32 100644 --- a/docs/docs/v3/core/plugins.md +++ b/docs/docs/v3/core/plugins.md @@ -1,5 +1,7 @@ # Plugins + + Since `MarkwonPlugin` takes the key role in processing and rendering markdown. Even **core** functionaly is abstracted into a `CorePlugin`. So it's still possible to use `Markwon` with a completely diff --git a/docs/docs/v3/core/render-props.md b/docs/docs/v3/core/render-props.md index 9dd18004..fb75479d 100644 --- a/docs/docs/v3/core/render-props.md +++ b/docs/docs/v3/core/render-props.md @@ -1,5 +1,7 @@ # RenderProps + + `RenderProps` encapsulates passing arguments from a node visitor to a node renderer. Without hardcoding arguments into an API method calls. diff --git a/docs/docs/v3/core/spans-factory.md b/docs/docs/v3/core/spans-factory.md index 6044de9a..e6536dd0 100644 --- a/docs/docs/v3/core/spans-factory.md +++ b/docs/docs/v3/core/spans-factory.md @@ -1,5 +1,7 @@ # Spans Factory + + Starting with `MarkwonSpansFactory` controls what spans are displayed for markdown nodes. diff --git a/docs/docs/v3/core/theme.md b/docs/docs/v3/core/theme.md index 672babc6..1b7d524f 100644 --- a/docs/docs/v3/core/theme.md +++ b/docs/docs/v3/core/theme.md @@ -1,5 +1,7 @@ # Theme + + Here is the list of properties that can be configured via `MarkwonTheme.Builder` class. :::tip diff --git a/docs/docs/v3/core/visitor.md b/docs/docs/v3/core/visitor.md index f0cce0f2..ef0ffee6 100644 --- a/docs/docs/v3/core/visitor.md +++ b/docs/docs/v3/core/visitor.md @@ -1,5 +1,7 @@ # Visitor + + Starting with _visiting_ of parsed markdown nodes does not require creating own instance of commonmark-java `Visitor`, instead a composable/configurable `MarkwonVisitor` is used. diff --git a/docs/docs/v3/ext-latex/README.md b/docs/docs/v3/ext-latex/README.md index ea1256f0..a0f1b601 100644 --- a/docs/docs/v3/ext-latex/README.md +++ b/docs/docs/v3/ext-latex/README.md @@ -1,5 +1,7 @@ # LaTeX extension + + This is an extension that will help you display LaTeX formulas in your markdown. diff --git a/docs/docs/v3/ext-strikethrough/README.md b/docs/docs/v3/ext-strikethrough/README.md index 9bbfc0e5..ce0d9f4d 100644 --- a/docs/docs/v3/ext-strikethrough/README.md +++ b/docs/docs/v3/ext-strikethrough/README.md @@ -1,5 +1,7 @@ # Strikethrough extension + + This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`: diff --git a/docs/docs/v3/ext-tables/README.md b/docs/docs/v3/ext-tables/README.md index 49282a05..dc0813b0 100644 --- a/docs/docs/v3/ext-tables/README.md +++ b/docs/docs/v3/ext-tables/README.md @@ -1,5 +1,7 @@ # Tables extension + + This extension adds support for GFM tables. diff --git a/docs/docs/v3/ext-tasklist/README.md b/docs/docs/v3/ext-tasklist/README.md index 3fb332f4..cda66aa5 100644 --- a/docs/docs/v3/ext-tasklist/README.md +++ b/docs/docs/v3/ext-tasklist/README.md @@ -1,5 +1,7 @@ # Task list extension + + Adds support for GFM (Github-flavored markdown) task-lists: diff --git a/docs/docs/v3/html/README.md b/docs/docs/v3/html/README.md index 12f66400..36e08abc 100644 --- a/docs/docs/v3/html/README.md +++ b/docs/docs/v3/html/README.md @@ -1,5 +1,7 @@ # HTML + + This artifact encapsulates HTML parsing from the core artifact and provides few predefined `TagHandlers` diff --git a/docs/docs/v3/image/gif.md b/docs/docs/v3/image/gif.md index 56ce081c..f3d3b5a6 100644 --- a/docs/docs/v3/image/gif.md +++ b/docs/docs/v3/image/gif.md @@ -1,5 +1,7 @@ # Image GIF + + Adds support for GIF images inside markdown. diff --git a/docs/docs/v3/image/okhttp.md b/docs/docs/v3/image/okhttp.md index 4a7c159d..fc61b1d9 100644 --- a/docs/docs/v3/image/okhttp.md +++ b/docs/docs/v3/image/okhttp.md @@ -1,5 +1,7 @@ # Image OkHttp + + Uses [okhttp library](https://github.com/square/okhttp) as the network transport fro images. Since diff --git a/docs/docs/v3/image/svg.md b/docs/docs/v3/image/svg.md index 538c524c..cf060251 100644 --- a/docs/docs/v3/image/svg.md +++ b/docs/docs/v3/image/svg.md @@ -1,5 +1,7 @@ # Image SVG + + Adds support for SVG images inside markdown. diff --git a/docs/docs/v3/install.md b/docs/docs/v3/install.md index 19c28cba..1d76b5c2 100644 --- a/docs/docs/v3/install.md +++ b/docs/docs/v3/install.md @@ -3,6 +3,8 @@ prev: false next: /docs/v3/core/getting-started.md --- + + # Installation ![stable](https://img.shields.io/maven-central/v/ru.noties.markwon/core.svg?label=stable) diff --git a/docs/docs/v3/migration-2-3.md b/docs/docs/v3/migration-2-3.md index aeb045c6..2fdcd884 100644 --- a/docs/docs/v3/migration-2-3.md +++ b/docs/docs/v3/migration-2-3.md @@ -1,5 +1,7 @@ # Migration 2.x.x -> 3.x.x + + * strikethrough moved to standalone module * tables moved to standalone module * core functionality of `AsyncDrawableLoader` moved to `core` module diff --git a/docs/docs/v3/recycler-table/README.md b/docs/docs/v3/recycler-table/README.md index e7287649..a377b041 100644 --- a/docs/docs/v3/recycler-table/README.md +++ b/docs/docs/v3/recycler-table/README.md @@ -1,5 +1,7 @@ # Recycler Table + + Artifact that provides [MarkwonAdapter.Entry](/docs/v3/recycler/) to render `TableBlock` inside diff --git a/docs/docs/v3/recycler/README.md b/docs/docs/v3/recycler/README.md index 73b05826..635fbcf4 100644 --- a/docs/docs/v3/recycler/README.md +++ b/docs/docs/v3/recycler/README.md @@ -1,5 +1,7 @@ # Recycler + + This artifact allows displaying markdown in a set of Android widgets diff --git a/docs/docs/v3/syntax-highlight/README.md b/docs/docs/v3/syntax-highlight/README.md index a5203cf6..cc47f6f5 100644 --- a/docs/docs/v3/syntax-highlight/README.md +++ b/docs/docs/v3/syntax-highlight/README.md @@ -1,5 +1,7 @@ # Syntax highlight + + This is a simple module to add **syntax highlight** functionality to your markdown rendered with `Markwon` library. It is based on [Prism4j](https://github.com/noties/Prism4j) so lead there to understand how to configure `Prism4j` instance. diff --git a/docs/docs/v4/core/text-setter.md b/docs/docs/v4/core/text-setter.md new file mode 100644 index 00000000..c69d0e58 --- /dev/null +++ b/docs/docs/v4/core/text-setter.md @@ -0,0 +1,40 @@ +# TextSetter + +Since it is possible to control how text is applied to a `TextView`. +This is done via `Markwon.TextSetter` interface. + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(/**/) + .textSetter(PrecomputedTextSetterCompat.create(Executors.newCachedThreadPool())) + .build(); +``` + +```java +public interface TextSetter { + /** + * @param textView TextView + * @param markdown prepared markdown + * @param bufferType BufferType specified when building {@link Markwon} instance + * via {@link Builder#bufferType(TextView.BufferType)} + * @param onComplete action to run when set-text is finished (required to call in order + * to execute {@link MarkwonPlugin#afterSetText(TextView)}) + */ + void setText( + @NonNull TextView textView, + @NonNull Spanned markdown, + @NonNull TextView.BufferType bufferType, + @NonNull Runnable onComplete); +} +``` + +Primary target for this functionality is to use [PrecomputedText] and [PrecomputedTextCompat]. +`Markwon` comes with `PrecomputedTextSetterCompat` implementation. + +:::tip Note +Please note that `PrecomputedTextCompat` belongs to the `androidx.core:core` artifact. Make +sure that you have it in your project's dependencies (explicitly or implicitly) +::: + +[PrecomputedText]: https://developer.android.com/reference/android/text/PrecomputedText +[PrecomputedTextCompat]: https://developer.android.com/reference/androidx/core/text/PrecomputedTextCompat \ No newline at end of file diff --git a/markwon-core/src/main/java/io/noties/markwon/Markwon.java b/markwon-core/src/main/java/io/noties/markwon/Markwon.java index 9277688b..ce8f956a 100644 --- a/markwon-core/src/main/java/io/noties/markwon/Markwon.java +++ b/markwon-core/src/main/java/io/noties/markwon/Markwon.java @@ -141,21 +141,21 @@ public abstract class Markwon { * @see PrecomputedTextSetterCompat * @since 4.1.0 */ - public interface TextSetter { - /** - * @param textView TextView - * @param markdown prepared markdown - * @param bufferType BufferType specified when building {@link Markwon} instance - * via {@link Builder#bufferType(TextView.BufferType)} - * @param onComplete action to run when set-text is finished (required to call in order - * to execute {@link MarkwonPlugin#afterSetText(TextView)}) - */ - void setText( - @NonNull TextView textView, - @NonNull Spanned markdown, - @NonNull TextView.BufferType bufferType, - @NonNull Runnable onComplete); - } +public interface TextSetter { + /** + * @param textView TextView + * @param markdown prepared markdown + * @param bufferType BufferType specified when building {@link Markwon} instance + * via {@link Builder#bufferType(TextView.BufferType)} + * @param onComplete action to run when set-text is finished (required to call in order + * to execute {@link MarkwonPlugin#afterSetText(TextView)}) + */ + void setText( + @NonNull TextView textView, + @NonNull Spanned markdown, + @NonNull TextView.BufferType bufferType, + @NonNull Runnable onComplete); +} /** * Builder for {@link Markwon}. From 6a06e56c1ca06c239d78bcabdb648c91b1bf76d9 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Tue, 6 Aug 2019 19:30:25 +0300 Subject: [PATCH 02/13] Fix MarkdownRenderer --- .../main/java/io/noties/markwon/app/MarkdownRenderer.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index 15583b65..9bcb8e0f 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -10,7 +10,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.inject.Inject; @@ -19,7 +18,6 @@ import io.noties.debug.Debug; import io.noties.markwon.AbstractMarkwonPlugin; import io.noties.markwon.Markwon; import io.noties.markwon.MarkwonConfiguration; -import io.noties.markwon.PrecomputedTextSetterCompat; import io.noties.markwon.app.gif.GifAwarePlugin; import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.ext.tables.TablePlugin; @@ -75,11 +73,6 @@ public class MarkdownRenderer { cancel(); -final Markwon markwon = Markwon.builder(context) - .usePlugin(/**/) - .textSetter(PrecomputedTextSetterCompat.create(Executors.newCachedThreadPool())) - .build(); - task = service.submit(new Runnable() { @Override From b3e7749c7aa6f5e1c602cd3e084ad39b02296af6 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sat, 24 Aug 2019 13:22:44 +0300 Subject: [PATCH 03/13] Fix missing subsequent table-blocks spacing --- gradle.properties | 2 +- .../noties/markwon/ext/tables/TablePlugin.java | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index b76c9e11..aea3b99f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ android.enableJetifier=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=4.1.0 +VERSION_NAME=4.1.1-SNAPSHOT GROUP=io.noties.markwon POM_DESCRIPTION=Markwon markdown for Android diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java index 4d931e9a..e1950d59 100644 --- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java @@ -6,6 +6,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import org.commonmark.ext.gfm.tables.TableBlock; import org.commonmark.ext.gfm.tables.TableBody; import org.commonmark.ext.gfm.tables.TableCell; import org.commonmark.ext.gfm.tables.TableHead; @@ -115,19 +116,26 @@ public class TablePlugin extends AbstractMarkwonPlugin { void configure(@NonNull MarkwonVisitor.Builder builder) { builder - .on(TableBody.class, new MarkwonVisitor.NodeVisitor() { + // @since 4.1.1-SNAPSHOT we use TableBlock instead of TableBody to add new lines + .on(TableBlock.class, new MarkwonVisitor.NodeVisitor() { @Override - public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableBody tableBody) { + public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableBlock tableBlock) { - visitor.visitChildren(tableBody); - tableRows = 0; + visitor.visitChildren(tableBlock); - if (visitor.hasNext(tableBody)) { + if (visitor.hasNext(tableBlock)) { visitor.ensureNewLine(); visitor.forceNewLine(); } } }) + .on(TableBody.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableBody tableBody) { + visitor.visitChildren(tableBody); + tableRows = 0; + } + }) .on(TableRow.class, new MarkwonVisitor.NodeVisitor() { @Override public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableRow tableRow) { From fa01a50ae8033f9ca4418473cf37896ae251f6e2 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 26 Aug 2019 13:06:21 +0300 Subject: [PATCH 04/13] ImagesPlugin remove stacktrace printing when checking for SVG and GIF dependencies --- .../src/main/java/io/noties/markwon/image/gif/GifSupport.java | 3 ++- .../src/main/java/io/noties/markwon/image/svg/SvgSupport.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java index 47624d40..d90a34d5 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java @@ -13,7 +13,8 @@ public abstract class GifSupport { pl.droidsonroids.gif.GifDrawable.class.getName(); result = true; } catch (Throwable t) { - t.printStackTrace(); + // @since 4.1.1-SNAPSHOT do not print stacktrace (it can become noisy) +// t.printStackTrace(); result = false; } HAS_GIF = result; diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java index 70293570..efb6108a 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java @@ -13,7 +13,8 @@ public abstract class SvgSupport { com.caverock.androidsvg.SVG.class.getName(); result = true; } catch (Throwable t) { - t.printStackTrace(); + // @since 4.1.1-SNAPSHOT do not print stacktrace (it can become noisy) +// t.printStackTrace(); result = false; } HAS_SVG = result; From 1b7fbfb77f7b3cd29c88cc8e970afba4cbe928af Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 26 Aug 2019 13:53:39 +0300 Subject: [PATCH 05/13] ImagesPlugin print a warning for SVG and GIF instead of full stacktrace --- .../markwon/image/gif/GifMediaDecoder.java | 5 +---- .../noties/markwon/image/gif/GifSupport.java | 19 +++++++++++++++++-- .../markwon/image/svg/SvgMediaDecoder.java | 3 +-- .../noties/markwon/image/svg/SvgSupport.java | 18 ++++++++++++++++-- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java index e8ac616e..2efd9f93 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifMediaDecoder.java @@ -11,7 +11,6 @@ import java.io.InputStream; import java.util.Collection; import java.util.Collections; -import io.noties.markwon.image.DrawableUtils; import io.noties.markwon.image.MediaDecoder; import pl.droidsonroids.gif.GifDrawable; @@ -97,9 +96,7 @@ public class GifMediaDecoder extends MediaDecoder { private static void validate() { if (!GifSupport.hasGifSupport()) { - throw new IllegalStateException("`pl.droidsonroids.gif:android-gif-drawable:*` " + - "dependency is missing, please add to your project explicitly if you " + - "wish to use GIF media decoder"); + throw new IllegalStateException(GifSupport.missingMessage()); } } } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java index d90a34d5..b8d91bb5 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java @@ -1,5 +1,9 @@ package io.noties.markwon.image.gif; +import android.util.Log; + +import androidx.annotation.NonNull; + /** * @since 4.0.0 */ @@ -13,8 +17,9 @@ public abstract class GifSupport { pl.droidsonroids.gif.GifDrawable.class.getName(); result = true; } catch (Throwable t) { - // @since 4.1.1-SNAPSHOT do not print stacktrace (it can become noisy) -// t.printStackTrace(); + // @since 4.1.1-SNAPSHOT instead of printing full stacktrace of the exception, + // just print a warning to the console + Log.w("MarkwonImagesPlugin", missingMessage()); result = false; } HAS_GIF = result; @@ -24,6 +29,16 @@ public abstract class GifSupport { return HAS_GIF; } + /** + * @since 4.1.1-SNAPSHOT + */ + @NonNull + static String missingMessage() { + return "`pl.droidsonroids.gif:android-gif-drawable:*` " + + "dependency is missing, please add to your project explicitly if you " + + "wish to use GIF media-decoder"; + } + private GifSupport() { } } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java index b307a105..fc5da090 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgMediaDecoder.java @@ -83,8 +83,7 @@ public class SvgMediaDecoder extends MediaDecoder { private static void validate() { if (!SvgSupport.hasSvgSupport()) { - throw new IllegalStateException("`com.caverock:androidsvg:*` dependency is missing, " + - "please add to your project explicitly if you wish to use SVG media decoder"); + throw new IllegalStateException(SvgSupport.missingMessage()); } } } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java index efb6108a..775cde3d 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java @@ -1,5 +1,9 @@ package io.noties.markwon.image.svg; +import android.util.Log; + +import androidx.annotation.NonNull; + /** * @since 4.0.0 */ @@ -13,8 +17,9 @@ public abstract class SvgSupport { com.caverock.androidsvg.SVG.class.getName(); result = true; } catch (Throwable t) { - // @since 4.1.1-SNAPSHOT do not print stacktrace (it can become noisy) -// t.printStackTrace(); + // @since 4.1.1-SNAPSHOT instead of printing full stacktrace of the exception, + // just print a warning to the console + Log.w("MarkwonImagesPlugin", missingMessage()); result = false; } HAS_SVG = result; @@ -24,6 +29,15 @@ public abstract class SvgSupport { return HAS_SVG; } + /** + * @since 4.1.1-SNAPSHOT + */ + @NonNull + static String missingMessage() { + return "`com.caverock:androidsvg:*` dependency is missing, " + + "please add to your project explicitly if you wish to use SVG media-decoder"; + } + private SvgSupport() { } } From 1ab1b8b87a6f9cd597a0be1fc3f88ef57d4a22ff Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 26 Aug 2019 14:28:48 +0300 Subject: [PATCH 06/13] Add code block info prop --- .../io/noties/markwon/core/CorePlugin.java | 3 ++ .../io/noties/markwon/core/CoreProps.java | 5 ++ .../noties/markwon/core/CorePluginTest.java | 54 ++++++++++++++++--- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java index 194882e3..783dadc0 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java @@ -328,6 +328,9 @@ public class CorePlugin extends AbstractMarkwonPlugin { visitor.builder().append('\u00a0'); + // @since 4.1.1-SNAPSHOT + CoreProps.CODE_BLOCK_INFO.set(visitor.renderProps(), info); + visitor.setSpansForNodeOptional(node, length); if (visitor.hasNext(node)) { diff --git a/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java b/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java index 1da57e24..5b2140ed 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java @@ -19,6 +19,11 @@ public abstract class CoreProps { public static final Prop PARAGRAPH_IS_IN_TIGHT_LIST = Prop.of("paragraph-is-in-tight-list"); + /** + * @since 4.1.1-SNAPSHOT + */ + public static final Prop CODE_BLOCK_INFO = Prop.of("code-block-info"); + public enum ListItemType { BULLET, ORDERED diff --git a/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java index e21a8ded..4137b83e 100644 --- a/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/core/CorePluginTest.java @@ -1,10 +1,10 @@ package io.noties.markwon.core; +import android.text.method.MovementMethod; +import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import android.text.method.MovementMethod; -import android.widget.ImageView; -import android.widget.TextView; import org.commonmark.node.BlockQuote; import org.commonmark.node.BulletList; @@ -38,15 +38,15 @@ import java.util.List; import java.util.Map; import java.util.Set; -import ix.Ix; -import ix.IxFunction; -import ix.IxPredicate; import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonSpansFactory; import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.RenderProps; import io.noties.markwon.SpanFactory; import io.noties.markwon.SpannableBuilder; +import ix.Ix; +import ix.IxFunction; +import ix.IxPredicate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -54,6 +54,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.RETURNS_MOCKS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -300,4 +301,45 @@ public class CorePluginTest { verify(textView, times(0)).setMovementMethod(any(MovementMethod.class)); } + + @Test + public void code_block_info_prop() { + final CorePlugin plugin = CorePlugin.create(); + final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class); + plugin.configureVisitor(builder); + + final ArgumentCaptor fencedCaptor = + ArgumentCaptor.forClass(MarkwonVisitor.NodeVisitor.class); + final ArgumentCaptor indendedCaptor = + ArgumentCaptor.forClass(MarkwonVisitor.NodeVisitor.class); + + //noinspection unchecked + verify(builder, times(1)).on(eq(FencedCodeBlock.class), fencedCaptor.capture()); + //noinspection unchecked + verify(builder, times(1)).on(eq(IndentedCodeBlock.class), indendedCaptor.capture()); + + final RenderProps renderProps = mock(RenderProps.class); + final MarkwonVisitor visitor = mock(MarkwonVisitor.class, RETURNS_MOCKS); + + when(visitor.renderProps()).thenReturn(renderProps); + + // fenced + { + final FencedCodeBlock block = new FencedCodeBlock(); + block.setInfo("testing-fenced"); + //noinspection unchecked + fencedCaptor.getValue().visit(visitor, block); + + verify(renderProps, times(1)).set(eq(CoreProps.CODE_BLOCK_INFO), eq("testing-fenced")); + } + + // indended + { + final IndentedCodeBlock block = new IndentedCodeBlock(); + //noinspection unchecked + indendedCaptor.getValue().visit(visitor, block); + + verify(renderProps, times(1)).set(eq(CoreProps.CODE_BLOCK_INFO), eq((String) null)); + } + } } \ No newline at end of file From 3c7744868218655643553a1fbe5c69db82c0ea7b Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 28 Aug 2019 13:07:25 +0300 Subject: [PATCH 07/13] Update android gradle plugin 3.5.0 --- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 57cc1bab..cfb9c01e 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.1' + classpath 'com.android.tools.build:gradle:3.5.0' classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0' } } @@ -30,7 +30,7 @@ task clean(type: Delete) { } wrapper { - gradleVersion '5.1.1' + gradleVersion '5.5.1' distributionType 'all' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c4486d47..430dfabc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 4406a5faafe6797ae2b809cbfed66f989397d9c5 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 28 Aug 2019 13:24:55 +0300 Subject: [PATCH 08/13] Introduce MarkwonVisitorFactory --- .../io/noties/markwon/MarkwonBuilderImpl.java | 8 +++- .../java/io/noties/markwon/MarkwonImpl.java | 14 +++++-- .../noties/markwon/MarkwonVisitorFactory.java | 26 +++++++++++++ .../io/noties/markwon/MarkwonVisitorImpl.java | 5 +++ .../io/noties/markwon/MarkwonImplTest.java | 37 +++++++++++++------ 5 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorFactory.java diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java index 77de961f..1fe21edb 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java @@ -104,11 +104,17 @@ class MarkwonBuilderImpl implements Markwon.Builder { final RenderProps renderProps = new RenderPropsImpl(); + // @since 4.1.1-SNAPSHOT + final MarkwonVisitorFactory visitorFactory = MarkwonVisitorFactory.create( + visitorBuilder, + configuration, + renderProps); + return new MarkwonImpl( bufferType, textSetter, parserBuilder.build(), - visitorBuilder.build(configuration, renderProps), + visitorFactory, Collections.unmodifiableList(plugins) ); } diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java index 9080527f..9d7ffee0 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java @@ -20,7 +20,7 @@ class MarkwonImpl extends Markwon { private final TextView.BufferType bufferType; private final Parser parser; - private final MarkwonVisitor visitor; + private final MarkwonVisitorFactory visitorFactory; // @since 4.1.1-SNAPSHOT private final List plugins; // @since 4.1.0 @@ -31,12 +31,12 @@ class MarkwonImpl extends Markwon { @NonNull TextView.BufferType bufferType, @Nullable TextSetter textSetter, @NonNull Parser parser, - @NonNull MarkwonVisitor visitor, + @NonNull MarkwonVisitorFactory visitorFactory, @NonNull List plugins) { this.bufferType = bufferType; this.textSetter = textSetter; this.parser = parser; - this.visitor = visitor; + this.visitorFactory = visitorFactory; this.plugins = plugins; } @@ -60,16 +60,22 @@ class MarkwonImpl extends Markwon { plugin.beforeRender(node); } + // @since 4.1.1-SNAPSHOT obtain visitor via factory + final MarkwonVisitor visitor = visitorFactory.create(); + node.accept(visitor); for (MarkwonPlugin plugin : plugins) { plugin.afterRender(node, visitor); } + //noinspection UnnecessaryLocalVariable final Spanned spanned = visitor.builder().spannableStringBuilder(); // clear render props and builder after rendering - visitor.clear(); + // @since 4.1.1-SNAPSHOT as we no longer reuse visitor - there is no need to clean it + // we might still do it if we introduce a thread-local storage though +// visitor.clear(); return spanned; } diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorFactory.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorFactory.java new file mode 100644 index 00000000..429e5080 --- /dev/null +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorFactory.java @@ -0,0 +1,26 @@ +package io.noties.markwon; + +import androidx.annotation.NonNull; + +/** + * @since 4.1.1-SNAPSHOT + */ +abstract class MarkwonVisitorFactory { + + @NonNull + abstract MarkwonVisitor create(); + + @NonNull + static MarkwonVisitorFactory create( + @NonNull final MarkwonVisitorImpl.Builder builder, + @NonNull final MarkwonConfiguration configuration, + @NonNull final RenderProps renderProps) { + return new MarkwonVisitorFactory() { + @NonNull + @Override + MarkwonVisitor create() { + return builder.build(configuration, renderProps); + } + }; + } +} diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java index 42db74ac..ea4d6118 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java @@ -269,6 +269,11 @@ class MarkwonVisitorImpl implements MarkwonVisitor { @NonNull @Override public Builder on(@NonNull Class node, @Nullable NodeVisitor nodeVisitor) { + + // @since 4.1.1-SNAPSHOT we might actually introduce a local flag to check if it's been built + // and throw an exception here if some modification is requested + // NB, as we might be built from different threads this flag must be synchronized + // we should allow `null` to exclude node from being visited (for example to disable // some functionality) if (nodeVisitor == null) { diff --git a/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java index 8e24e578..c557cdb7 100644 --- a/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java @@ -31,6 +31,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.RETURNS_MOCKS; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -47,7 +48,7 @@ public class MarkwonImplTest { TextView.BufferType.SPANNABLE, null, mock(Parser.class), - mock(MarkwonVisitor.class), + mock(MarkwonVisitorFactory.class), Collections.singletonList(plugin)); impl.parse("whatever"); @@ -70,7 +71,7 @@ public class MarkwonImplTest { TextView.BufferType.SPANNABLE, null, parser, - mock(MarkwonVisitor.class), + mock(MarkwonVisitorFactory.class), Arrays.asList(first, second)); impl.parse("zero"); @@ -89,6 +90,7 @@ public class MarkwonImplTest { final MarkwonPlugin plugin = mock(MarkwonPlugin.class); + final MarkwonVisitorFactory visitorFactory = mock(MarkwonVisitorFactory.class); final MarkwonVisitor visitor = mock(MarkwonVisitor.class); final SpannableBuilder builder = mock(SpannableBuilder.class); @@ -96,9 +98,10 @@ public class MarkwonImplTest { TextView.BufferType.SPANNABLE, null, mock(Parser.class), - visitor, + visitorFactory, Collections.singletonList(plugin)); + when(visitorFactory.create()).thenReturn(visitor); when(visitor.builder()).thenReturn(builder); final Node node = mock(Node.class); @@ -132,24 +135,30 @@ public class MarkwonImplTest { public void render_clears_visitor() { // each render call should have empty-state visitor (no previous rendering info) + final MarkwonVisitorFactory visitorFactory = mock(MarkwonVisitorFactory.class); final MarkwonVisitor visitor = mock(MarkwonVisitor.class, RETURNS_MOCKS); + when(visitorFactory.create()).thenReturn(visitor); + final MarkwonImpl impl = new MarkwonImpl( TextView.BufferType.SPANNABLE, null, mock(Parser.class), - visitor, + visitorFactory, Collections.emptyList()); impl.render(mock(Node.class)); - verify(visitor, times(1)).clear(); + // obsolete starting with 4.1.1-SNAPSHOT +// verify(visitor, times(1)).clear(); + verify(visitor, never()).clear(); } @Test public void render_props() { // render props are configured properly and cleared after render function + final MarkwonVisitorFactory visitorFactory = mock(MarkwonVisitorFactory.class); final MarkwonVisitor visitor = mock(MarkwonVisitor.class, RETURNS_MOCKS); final RenderProps renderProps = mock(RenderProps.class); @@ -161,6 +170,7 @@ public class MarkwonImplTest { } }).when(visitor).clear(); + when(visitorFactory.create()).thenReturn(visitor); when(visitor.renderProps()).thenReturn(renderProps); final MarkwonPlugin plugin = mock(MarkwonPlugin.class); @@ -169,7 +179,7 @@ public class MarkwonImplTest { TextView.BufferType.SPANNABLE, null, mock(Parser.class), - visitor, + visitorFactory, Collections.singletonList(plugin)); final AtomicBoolean flag = new AtomicBoolean(false); @@ -191,7 +201,9 @@ public class MarkwonImplTest { assertTrue(flag.get()); - verify(renderProps, times(1)).clearAll(); + // obsolete starting with 4.1.1-SNAPSHOT +// verify(renderProps, times(1)).clearAll(); + verify(renderProps, never()).clearAll(); } @Test @@ -205,7 +217,7 @@ public class MarkwonImplTest { TextView.BufferType.EDITABLE, null, mock(Parser.class), - mock(MarkwonVisitor.class, RETURNS_MOCKS), + mock(MarkwonVisitorFactory.class, RETURNS_MOCKS), Collections.singletonList(plugin)); final TextView textView = mock(TextView.class); @@ -252,7 +264,7 @@ public class MarkwonImplTest { TextView.BufferType.SPANNABLE, null, mock(Parser.class), - mock(MarkwonVisitor.class), + mock(MarkwonVisitorFactory.class), plugins); assertTrue("First", impl.hasPlugin(First.class)); @@ -274,7 +286,7 @@ public class MarkwonImplTest { TextView.BufferType.EDITABLE, textSetter, mock(Parser.class), - mock(MarkwonVisitor.class), + mock(MarkwonVisitorFactory.class), Collections.singletonList(plugin)); final TextView textView = mock(TextView.class); @@ -317,7 +329,8 @@ public class MarkwonImplTest { TextView.BufferType.SPANNABLE, null, mock(Parser.class), - mock(MarkwonVisitor.class), plugins); + mock(MarkwonVisitorFactory.class), + plugins); // should be returned assertNotNull(impl.requirePlugin(MarkwonPlugin.class)); @@ -346,7 +359,7 @@ public class MarkwonImplTest { TextView.BufferType.SPANNABLE, null, mock(Parser.class), - mock(MarkwonVisitor.class), + mock(MarkwonVisitorFactory.class), plugins); final List list = impl.getPlugins(); From 02e83a62db0154907cdafadaf523c28083926125 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 28 Aug 2019 13:33:05 +0300 Subject: [PATCH 09/13] Update 4.1.1-SNAPSHOT changelog --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60e2c357..2232b3fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +# 4.1.1-SNAPSHOT +* `markwon-ext-tables`: fix padding between subsequent table blocks ([#159]) +* `markwon-images`: print a single warning instead full stacktrace in case when SVG or GIF +are not present in the classpath ([#160]) +* Make `Markwon` instance thread-safe by using a single `MarkwonVisitor` for each `render` call ([#157]) +* Add `CoreProps.CODE_BLOCK_INFO` with code-block info (language) + +[#159]: https://github.com/noties/Markwon/issues/159 +[#160]: https://github.com/noties/Markwon/issues/160 +[#157]: https://github.com/noties/Markwon/issues/157 + # 4.1.0 * Add `Markwon.TextSetter` interface to be able to use PrecomputedText/PrecomputedTextCompat * Add `PrecomputedTextSetterCompat` and `compileOnly` dependency on `androidx.core:core` From 008faa6f4997ff9c82f560479dc0ce92e5e9a086 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 29 Aug 2019 13:53:34 +0300 Subject: [PATCH 10/13] Define release and snapshot github workflows --- .github/workflows/release.yml | 20 ++++++++++++++++++++ .github/workflows/snapshot.yml | 25 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/snapshot.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..962e76ed --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,20 @@ +name: Release + +on: + push: + branches: + - master + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Gradle + run: ./gradlew build diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 00000000..97274d38 --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,25 @@ +name: Snapshot + +on: + push: + branches: + - develop + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Gradle + run: ./gradlew build + - name: Publish snapshot + env: + username: ${{ secrets.NEXUS_USERNAME }} + password: ${{ secrets.NEXUS_PASSSWORD }} + run: ./gradlew upA -Prelease -PNEXUS_USERNAME=$username -PNEXUS_PASSWORD=$password From 0a7356ecf871c13470b5ff07919ec7fbb0b62d15 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 29 Aug 2019 13:54:53 +0300 Subject: [PATCH 11/13] Prepare 4.1.1 release --- CHANGELOG.md | 2 +- gradle.properties | 2 +- .../src/main/java/io/noties/markwon/MarkwonBuilderImpl.java | 2 +- .../src/main/java/io/noties/markwon/MarkwonImpl.java | 6 +++--- .../main/java/io/noties/markwon/MarkwonVisitorFactory.java | 2 +- .../src/main/java/io/noties/markwon/MarkwonVisitorImpl.java | 2 +- .../src/main/java/io/noties/markwon/core/CorePlugin.java | 2 +- .../src/main/java/io/noties/markwon/core/CoreProps.java | 2 +- .../src/test/java/io/noties/markwon/MarkwonImplTest.java | 4 ++-- .../main/java/io/noties/markwon/ext/tables/TablePlugin.java | 2 +- .../main/java/io/noties/markwon/image/gif/GifSupport.java | 4 ++-- .../main/java/io/noties/markwon/image/svg/SvgSupport.java | 4 ++-- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2232b3fc..e8992853 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -# 4.1.1-SNAPSHOT +# 4.1.1 * `markwon-ext-tables`: fix padding between subsequent table blocks ([#159]) * `markwon-images`: print a single warning instead full stacktrace in case when SVG or GIF are not present in the classpath ([#160]) diff --git a/gradle.properties b/gradle.properties index aea3b99f..bc71ace9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ android.enableJetifier=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=4.1.1-SNAPSHOT +VERSION_NAME=4.1.1 GROUP=io.noties.markwon POM_DESCRIPTION=Markwon markdown for Android diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java index 1fe21edb..a14002f1 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java @@ -104,7 +104,7 @@ class MarkwonBuilderImpl implements Markwon.Builder { final RenderProps renderProps = new RenderPropsImpl(); - // @since 4.1.1-SNAPSHOT + // @since 4.1.1 final MarkwonVisitorFactory visitorFactory = MarkwonVisitorFactory.create( visitorBuilder, configuration, diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java index 9d7ffee0..3f0ee18c 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java @@ -20,7 +20,7 @@ class MarkwonImpl extends Markwon { private final TextView.BufferType bufferType; private final Parser parser; - private final MarkwonVisitorFactory visitorFactory; // @since 4.1.1-SNAPSHOT + private final MarkwonVisitorFactory visitorFactory; // @since 4.1.1 private final List plugins; // @since 4.1.0 @@ -60,7 +60,7 @@ class MarkwonImpl extends Markwon { plugin.beforeRender(node); } - // @since 4.1.1-SNAPSHOT obtain visitor via factory + // @since 4.1.1 obtain visitor via factory final MarkwonVisitor visitor = visitorFactory.create(); node.accept(visitor); @@ -73,7 +73,7 @@ class MarkwonImpl extends Markwon { final Spanned spanned = visitor.builder().spannableStringBuilder(); // clear render props and builder after rendering - // @since 4.1.1-SNAPSHOT as we no longer reuse visitor - there is no need to clean it + // @since 4.1.1 as we no longer reuse visitor - there is no need to clean it // we might still do it if we introduce a thread-local storage though // visitor.clear(); diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorFactory.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorFactory.java index 429e5080..98b0187e 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorFactory.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorFactory.java @@ -3,7 +3,7 @@ package io.noties.markwon; import androidx.annotation.NonNull; /** - * @since 4.1.1-SNAPSHOT + * @since 4.1.1 */ abstract class MarkwonVisitorFactory { diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java index ea4d6118..c6361a00 100644 --- a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java +++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java @@ -270,7 +270,7 @@ class MarkwonVisitorImpl implements MarkwonVisitor { @Override public Builder on(@NonNull Class node, @Nullable NodeVisitor nodeVisitor) { - // @since 4.1.1-SNAPSHOT we might actually introduce a local flag to check if it's been built + // @since 4.1.1 we might actually introduce a local flag to check if it's been built // and throw an exception here if some modification is requested // NB, as we might be built from different threads this flag must be synchronized diff --git a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java index 783dadc0..dffa215d 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java @@ -328,7 +328,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { visitor.builder().append('\u00a0'); - // @since 4.1.1-SNAPSHOT + // @since 4.1.1 CoreProps.CODE_BLOCK_INFO.set(visitor.renderProps(), info); visitor.setSpansForNodeOptional(node, length); diff --git a/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java b/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java index 5b2140ed..23d8d374 100644 --- a/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java +++ b/markwon-core/src/main/java/io/noties/markwon/core/CoreProps.java @@ -20,7 +20,7 @@ public abstract class CoreProps { public static final Prop PARAGRAPH_IS_IN_TIGHT_LIST = Prop.of("paragraph-is-in-tight-list"); /** - * @since 4.1.1-SNAPSHOT + * @since 4.1.1 */ public static final Prop CODE_BLOCK_INFO = Prop.of("code-block-info"); diff --git a/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java b/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java index c557cdb7..2eb4f3f8 100644 --- a/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java +++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java @@ -149,7 +149,7 @@ public class MarkwonImplTest { impl.render(mock(Node.class)); - // obsolete starting with 4.1.1-SNAPSHOT + // obsolete starting with 4.1.1 // verify(visitor, times(1)).clear(); verify(visitor, never()).clear(); } @@ -201,7 +201,7 @@ public class MarkwonImplTest { assertTrue(flag.get()); - // obsolete starting with 4.1.1-SNAPSHOT + // obsolete starting with 4.1.1 // verify(renderProps, times(1)).clearAll(); verify(renderProps, never()).clearAll(); } diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java index e1950d59..086afd75 100644 --- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java +++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java @@ -116,7 +116,7 @@ public class TablePlugin extends AbstractMarkwonPlugin { void configure(@NonNull MarkwonVisitor.Builder builder) { builder - // @since 4.1.1-SNAPSHOT we use TableBlock instead of TableBody to add new lines + // @since 4.1.1 we use TableBlock instead of TableBody to add new lines .on(TableBlock.class, new MarkwonVisitor.NodeVisitor() { @Override public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableBlock tableBlock) { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java index b8d91bb5..70a143fc 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/gif/GifSupport.java @@ -17,7 +17,7 @@ public abstract class GifSupport { pl.droidsonroids.gif.GifDrawable.class.getName(); result = true; } catch (Throwable t) { - // @since 4.1.1-SNAPSHOT instead of printing full stacktrace of the exception, + // @since 4.1.1 instead of printing full stacktrace of the exception, // just print a warning to the console Log.w("MarkwonImagesPlugin", missingMessage()); result = false; @@ -30,7 +30,7 @@ public abstract class GifSupport { } /** - * @since 4.1.1-SNAPSHOT + * @since 4.1.1 */ @NonNull static String missingMessage() { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java index 775cde3d..4afe2506 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/svg/SvgSupport.java @@ -17,7 +17,7 @@ public abstract class SvgSupport { com.caverock.androidsvg.SVG.class.getName(); result = true; } catch (Throwable t) { - // @since 4.1.1-SNAPSHOT instead of printing full stacktrace of the exception, + // @since 4.1.1 instead of printing full stacktrace of the exception, // just print a warning to the console Log.w("MarkwonImagesPlugin", missingMessage()); result = false; @@ -30,7 +30,7 @@ public abstract class SvgSupport { } /** - * @since 4.1.1-SNAPSHOT + * @since 4.1.1 */ @NonNull static String missingMessage() { From 5cbdbe1759a1a5351e76644b575afab439b34fd3 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 29 Aug 2019 14:07:51 +0300 Subject: [PATCH 12/13] Change snapshot workflow env variables names (uppercase) --- .github/workflows/snapshot.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 97274d38..3ebbb091 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -20,6 +20,6 @@ jobs: run: ./gradlew build - name: Publish snapshot env: - username: ${{ secrets.NEXUS_USERNAME }} - password: ${{ secrets.NEXUS_PASSSWORD }} - run: ./gradlew upA -Prelease -PNEXUS_USERNAME=$username -PNEXUS_PASSWORD=$password + USERNAME: ${{ secrets.NEXUS_USERNAME }} + PASSWORD: ${{ secrets.NEXUS_PASSSWORD }} + run: ./gradlew upA -Prelease -PNEXUS_USERNAME=$USERNAME -PNEXUS_PASSWORD=$PASSWORD From 529e9a88ca65cb48894479628e1f441312b6e93c Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 29 Aug 2019 14:16:27 +0300 Subject: [PATCH 13/13] Remove snapshot publishing on push to develop --- .github/workflows/snapshot.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 3ebbb091..7d38df2b 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -18,8 +18,3 @@ jobs: java-version: 1.8 - name: Build with Gradle run: ./gradlew build - - name: Publish snapshot - env: - USERNAME: ${{ secrets.NEXUS_USERNAME }} - PASSWORD: ${{ secrets.NEXUS_PASSSWORD }} - run: ./gradlew upA -Prelease -PNEXUS_USERNAME=$USERNAME -PNEXUS_PASSWORD=$PASSWORD