Merge pull request #162 from noties/develop
* `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
This commit is contained in:
commit
4348555b75
20
.github/workflows/release.yml
vendored
Normal file
20
.github/workflows/release.yml
vendored
Normal file
@ -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
|
20
.github/workflows/snapshot.yml
vendored
Normal file
20
.github/workflows/snapshot.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,5 +1,16 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
# 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])
|
||||||
|
* 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
|
# 4.1.0
|
||||||
* Add `Markwon.TextSetter` interface to be able to use PrecomputedText/PrecomputedTextCompat
|
* Add `Markwon.TextSetter` interface to be able to use PrecomputedText/PrecomputedTextCompat
|
||||||
* Add `PrecomputedTextSetterCompat` and `compileOnly` dependency on `androidx.core:core`
|
* Add `PrecomputedTextSetterCompat` and `compileOnly` dependency on `androidx.core:core`
|
||||||
|
@ -4,7 +4,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
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'
|
classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ task clean(type: Delete) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wrapper {
|
wrapper {
|
||||||
gradleVersion '5.1.1'
|
gradleVersion '5.5.1'
|
||||||
distributionType 'all'
|
distributionType 'all'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="warning custom-block">
|
<div class="warning custom-block">
|
||||||
<p class="custom-block-title">WARNING</p>
|
<p class="custom-block-title">WARNING</p>
|
||||||
<p>This is documentation for <u>legacy 2.x.x</u> versions. For the most current version <a :href="$withBase('/')">click here.</a></p>
|
<p>This is documentation for <u>legacy</u> versions. For the most current version <a :href="$withBase('/')">click here.</a></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -16,9 +16,17 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
text: 'API Version',
|
text: 'API Version',
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Current (4.x.x)', link: '/' },
|
{
|
||||||
{ text: 'Legacy (3.x.x)', link: '/docs/v3/install.md' },
|
text: 'Latest', items: [
|
||||||
{ text: 'Legacy (2.x.x)', link: '/docs/v2/' }
|
{ 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' },
|
{ 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/spans-factory.md',
|
||||||
'/docs/v4/core/core-plugin.md',
|
'/docs/v4/core/core-plugin.md',
|
||||||
'/docs/v4/core/movement-method-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/',
|
'/docs/v4/ext-latex/',
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
`MarkwonConfiguration` class holds common Markwon functionality.
|
`MarkwonConfiguration` class holds common Markwon functionality.
|
||||||
These are _configurable_ properties:
|
These are _configurable_ properties:
|
||||||
* `SyntaxHighlight`
|
* `SyntaxHighlight`
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Core plugin <Badge text="3.0.0" />
|
# Core plugin <Badge text="3.0.0" />
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
Since <Badge text="3.0.0" /> with introduction of _plugins_, Markwon
|
Since <Badge text="3.0.0" /> with introduction of _plugins_, Markwon
|
||||||
**core** functionality was moved to a dedicated plugin.
|
**core** functionality was moved to a dedicated plugin.
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Getting started
|
# Getting started
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
:::tip Installation
|
:::tip Installation
|
||||||
Please follow [installation](/docs/v3/install.md) instructions
|
Please follow [installation](/docs/v3/install.md) instructions
|
||||||
to learn how to add `Markwon` to your project
|
to learn how to add `Markwon` to your project
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# HTML Renderer
|
# HTML Renderer
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
Starting with <Badge text="3.0.0" /> `MarkwonHtmlRenderer` controls how HTML
|
Starting with <Badge text="3.0.0" /> `MarkwonHtmlRenderer` controls how HTML
|
||||||
is rendered:
|
is rendered:
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Images
|
# Images
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
Starting with <Badge text="3.0.0" /> `Markwon` comes with `ImagesPlugin`
|
Starting with <Badge text="3.0.0" /> `Markwon` comes with `ImagesPlugin`
|
||||||
which supports `http(s)`, `file` and `data` schemes and default media
|
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
|
decoder (for simple images, no [SVG](/docs/v3/image/svg.md) or [GIF](/docs/v3/image/gif.md) which
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Movement method plugin
|
# Movement method plugin
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
`MovementMethodPlugin` can be used to apply a `MovementMethod` to a TextView
|
`MovementMethodPlugin` can be used to apply a `MovementMethod` to a TextView
|
||||||
(important if you have links inside your markdown). By default `CorePlugin`
|
(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
|
will set a `LinkMovementMethod` on a TextView if one is missing. If you have
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Plugins <Badge text="3.0.0" />
|
# Plugins <Badge text="3.0.0" />
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
Since <Badge text="3.0.0" /> `MarkwonPlugin` takes the key role in
|
Since <Badge text="3.0.0" /> `MarkwonPlugin` takes the key role in
|
||||||
processing and rendering markdown. Even **core** functionaly is abstracted
|
processing and rendering markdown. Even **core** functionaly is abstracted
|
||||||
into a `CorePlugin`. So it's still possible to use `Markwon` with a completely
|
into a `CorePlugin`. So it's still possible to use `Markwon` with a completely
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# RenderProps <Badge text="3.0.0" />
|
# RenderProps <Badge text="3.0.0" />
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
`RenderProps` encapsulates passing arguments from a node visitor to a node renderer.
|
`RenderProps` encapsulates passing arguments from a node visitor to a node renderer.
|
||||||
Without hardcoding arguments into an API method calls.
|
Without hardcoding arguments into an API method calls.
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Spans Factory
|
# Spans Factory
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
Starting with <Badge text="3.0.0" /> `MarkwonSpansFactory` controls what spans are displayed
|
Starting with <Badge text="3.0.0" /> `MarkwonSpansFactory` controls what spans are displayed
|
||||||
for markdown nodes.
|
for markdown nodes.
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Theme
|
# Theme
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
Here is the list of properties that can be configured via `MarkwonTheme.Builder` class.
|
Here is the list of properties that can be configured via `MarkwonTheme.Builder` class.
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Visitor
|
# Visitor
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
Starting with <Badge text="3.0.0" /> _visiting_ of parsed markdown
|
Starting with <Badge text="3.0.0" /> _visiting_ of parsed markdown
|
||||||
nodes does not require creating own instance of commonmark-java `Visitor`,
|
nodes does not require creating own instance of commonmark-java `Visitor`,
|
||||||
instead a composable/configurable `MarkwonVisitor` is used.
|
instead a composable/configurable `MarkwonVisitor` is used.
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# LaTeX extension
|
# LaTeX extension
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'ext-latex'" />
|
<MavenBadge :artifact="'ext-latex'" />
|
||||||
|
|
||||||
This is an extension that will help you display LaTeX formulas in your markdown.
|
This is an extension that will help you display LaTeX formulas in your markdown.
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Strikethrough extension
|
# Strikethrough extension
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'ext-strikethrough'" />
|
<MavenBadge :artifact="'ext-strikethrough'" />
|
||||||
|
|
||||||
This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`:
|
This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`:
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Tables extension
|
# Tables extension
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'ext-tables'" />
|
<MavenBadge :artifact="'ext-tables'" />
|
||||||
|
|
||||||
This extension adds support for GFM tables.
|
This extension adds support for GFM tables.
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Task list extension
|
# Task list extension
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'ext-tasklist'" />
|
<MavenBadge :artifact="'ext-tasklist'" />
|
||||||
|
|
||||||
Adds support for GFM (Github-flavored markdown) task-lists:
|
Adds support for GFM (Github-flavored markdown) task-lists:
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# HTML
|
# HTML
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
This artifact encapsulates HTML parsing from the core artifact and provides
|
This artifact encapsulates HTML parsing from the core artifact and provides
|
||||||
few predefined `TagHandlers`
|
few predefined `TagHandlers`
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Image GIF
|
# Image GIF
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'image-gif'" />
|
<MavenBadge :artifact="'image-gif'" />
|
||||||
|
|
||||||
Adds support for GIF images inside markdown.
|
Adds support for GIF images inside markdown.
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Image OkHttp
|
# Image OkHttp
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'image-okhttp'" />
|
<MavenBadge :artifact="'image-okhttp'" />
|
||||||
|
|
||||||
Uses [okhttp library](https://github.com/square/okhttp) as the network transport fro images. Since <Badge text="3.0.0" />
|
Uses [okhttp library](https://github.com/square/okhttp) as the network transport fro images. Since <Badge text="3.0.0" />
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Image SVG
|
# Image SVG
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'image-svg'" />
|
<MavenBadge :artifact="'image-svg'" />
|
||||||
|
|
||||||
Adds support for SVG images inside markdown.
|
Adds support for SVG images inside markdown.
|
||||||
|
@ -3,6 +3,8 @@ prev: false
|
|||||||
next: /docs/v3/core/getting-started.md
|
next: /docs/v3/core/getting-started.md
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||

|

|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Migration 2.x.x -> 3.x.x
|
# Migration 2.x.x -> 3.x.x
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
* strikethrough moved to standalone module
|
* strikethrough moved to standalone module
|
||||||
* tables moved to standalone module
|
* tables moved to standalone module
|
||||||
* core functionality of `AsyncDrawableLoader` moved to `core` module
|
* core functionality of `AsyncDrawableLoader` moved to `core` module
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Recycler Table <Badge text="3.0.0" />
|
# Recycler Table <Badge text="3.0.0" />
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'recycler-table'" />
|
<MavenBadge :artifact="'recycler-table'" />
|
||||||
|
|
||||||
Artifact that provides [MarkwonAdapter.Entry](/docs/v3/recycler/) to render `TableBlock` inside
|
Artifact that provides [MarkwonAdapter.Entry](/docs/v3/recycler/) to render `TableBlock` inside
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Recycler <Badge text="3.0.0" />
|
# Recycler <Badge text="3.0.0" />
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'recycler'" />
|
<MavenBadge :artifact="'recycler'" />
|
||||||
|
|
||||||
This artifact allows displaying markdown in a set of Android widgets
|
This artifact allows displaying markdown in a set of Android widgets
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Syntax highlight
|
# Syntax highlight
|
||||||
|
|
||||||
|
<LegacyWarning />
|
||||||
|
|
||||||
<MavenBadge :artifact="'syntax-highlight'" />
|
<MavenBadge :artifact="'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.
|
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.
|
||||||
|
40
docs/docs/v4/core/text-setter.md
Normal file
40
docs/docs/v4/core/text-setter.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# TextSetter <Badge text="4.1.0" />
|
||||||
|
|
||||||
|
Since <Badge text="4.1.0" /> 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
|
@ -8,7 +8,7 @@ android.enableJetifier=true
|
|||||||
android.enableBuildCache=true
|
android.enableBuildCache=true
|
||||||
android.buildCacheDir=build/pre-dex-cache
|
android.buildCacheDir=build/pre-dex-cache
|
||||||
|
|
||||||
VERSION_NAME=4.1.0
|
VERSION_NAME=4.1.1
|
||||||
|
|
||||||
GROUP=io.noties.markwon
|
GROUP=io.noties.markwon
|
||||||
POM_DESCRIPTION=Markwon markdown for Android
|
POM_DESCRIPTION=Markwon markdown for Android
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -104,11 +104,17 @@ class MarkwonBuilderImpl implements Markwon.Builder {
|
|||||||
|
|
||||||
final RenderProps renderProps = new RenderPropsImpl();
|
final RenderProps renderProps = new RenderPropsImpl();
|
||||||
|
|
||||||
|
// @since 4.1.1
|
||||||
|
final MarkwonVisitorFactory visitorFactory = MarkwonVisitorFactory.create(
|
||||||
|
visitorBuilder,
|
||||||
|
configuration,
|
||||||
|
renderProps);
|
||||||
|
|
||||||
return new MarkwonImpl(
|
return new MarkwonImpl(
|
||||||
bufferType,
|
bufferType,
|
||||||
textSetter,
|
textSetter,
|
||||||
parserBuilder.build(),
|
parserBuilder.build(),
|
||||||
visitorBuilder.build(configuration, renderProps),
|
visitorFactory,
|
||||||
Collections.unmodifiableList(plugins)
|
Collections.unmodifiableList(plugins)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class MarkwonImpl extends Markwon {
|
|||||||
|
|
||||||
private final TextView.BufferType bufferType;
|
private final TextView.BufferType bufferType;
|
||||||
private final Parser parser;
|
private final Parser parser;
|
||||||
private final MarkwonVisitor visitor;
|
private final MarkwonVisitorFactory visitorFactory; // @since 4.1.1
|
||||||
private final List<MarkwonPlugin> plugins;
|
private final List<MarkwonPlugin> plugins;
|
||||||
|
|
||||||
// @since 4.1.0
|
// @since 4.1.0
|
||||||
@ -31,12 +31,12 @@ class MarkwonImpl extends Markwon {
|
|||||||
@NonNull TextView.BufferType bufferType,
|
@NonNull TextView.BufferType bufferType,
|
||||||
@Nullable TextSetter textSetter,
|
@Nullable TextSetter textSetter,
|
||||||
@NonNull Parser parser,
|
@NonNull Parser parser,
|
||||||
@NonNull MarkwonVisitor visitor,
|
@NonNull MarkwonVisitorFactory visitorFactory,
|
||||||
@NonNull List<MarkwonPlugin> plugins) {
|
@NonNull List<MarkwonPlugin> plugins) {
|
||||||
this.bufferType = bufferType;
|
this.bufferType = bufferType;
|
||||||
this.textSetter = textSetter;
|
this.textSetter = textSetter;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
this.visitor = visitor;
|
this.visitorFactory = visitorFactory;
|
||||||
this.plugins = plugins;
|
this.plugins = plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,16 +60,22 @@ class MarkwonImpl extends Markwon {
|
|||||||
plugin.beforeRender(node);
|
plugin.beforeRender(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @since 4.1.1 obtain visitor via factory
|
||||||
|
final MarkwonVisitor visitor = visitorFactory.create();
|
||||||
|
|
||||||
node.accept(visitor);
|
node.accept(visitor);
|
||||||
|
|
||||||
for (MarkwonPlugin plugin : plugins) {
|
for (MarkwonPlugin plugin : plugins) {
|
||||||
plugin.afterRender(node, visitor);
|
plugin.afterRender(node, visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection UnnecessaryLocalVariable
|
||||||
final Spanned spanned = visitor.builder().spannableStringBuilder();
|
final Spanned spanned = visitor.builder().spannableStringBuilder();
|
||||||
|
|
||||||
// clear render props and builder after rendering
|
// clear render props and builder after rendering
|
||||||
visitor.clear();
|
// @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();
|
||||||
|
|
||||||
return spanned;
|
return spanned;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package io.noties.markwon;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.1.1
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -269,6 +269,11 @@ class MarkwonVisitorImpl implements MarkwonVisitor {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public <N extends Node> Builder on(@NonNull Class<N> node, @Nullable NodeVisitor<? super N> nodeVisitor) {
|
public <N extends Node> Builder on(@NonNull Class<N> node, @Nullable NodeVisitor<? super N> nodeVisitor) {
|
||||||
|
|
||||||
|
// @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
|
||||||
|
|
||||||
// we should allow `null` to exclude node from being visited (for example to disable
|
// we should allow `null` to exclude node from being visited (for example to disable
|
||||||
// some functionality)
|
// some functionality)
|
||||||
if (nodeVisitor == null) {
|
if (nodeVisitor == null) {
|
||||||
|
@ -328,6 +328,9 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
visitor.builder().append('\u00a0');
|
visitor.builder().append('\u00a0');
|
||||||
|
|
||||||
|
// @since 4.1.1
|
||||||
|
CoreProps.CODE_BLOCK_INFO.set(visitor.renderProps(), info);
|
||||||
|
|
||||||
visitor.setSpansForNodeOptional(node, length);
|
visitor.setSpansForNodeOptional(node, length);
|
||||||
|
|
||||||
if (visitor.hasNext(node)) {
|
if (visitor.hasNext(node)) {
|
||||||
|
@ -19,6 +19,11 @@ public abstract class CoreProps {
|
|||||||
|
|
||||||
public static final Prop<Boolean> PARAGRAPH_IS_IN_TIGHT_LIST = Prop.of("paragraph-is-in-tight-list");
|
public static final Prop<Boolean> PARAGRAPH_IS_IN_TIGHT_LIST = Prop.of("paragraph-is-in-tight-list");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.1.1
|
||||||
|
*/
|
||||||
|
public static final Prop<String> CODE_BLOCK_INFO = Prop.of("code-block-info");
|
||||||
|
|
||||||
public enum ListItemType {
|
public enum ListItemType {
|
||||||
BULLET,
|
BULLET,
|
||||||
ORDERED
|
ORDERED
|
||||||
|
@ -31,6 +31,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
|||||||
import static org.mockito.Mockito.RETURNS_MOCKS;
|
import static org.mockito.Mockito.RETURNS_MOCKS;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@ -47,7 +48,7 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.SPANNABLE,
|
TextView.BufferType.SPANNABLE,
|
||||||
null,
|
null,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
mock(MarkwonVisitor.class),
|
mock(MarkwonVisitorFactory.class),
|
||||||
Collections.singletonList(plugin));
|
Collections.singletonList(plugin));
|
||||||
|
|
||||||
impl.parse("whatever");
|
impl.parse("whatever");
|
||||||
@ -70,7 +71,7 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.SPANNABLE,
|
TextView.BufferType.SPANNABLE,
|
||||||
null,
|
null,
|
||||||
parser,
|
parser,
|
||||||
mock(MarkwonVisitor.class),
|
mock(MarkwonVisitorFactory.class),
|
||||||
Arrays.asList(first, second));
|
Arrays.asList(first, second));
|
||||||
|
|
||||||
impl.parse("zero");
|
impl.parse("zero");
|
||||||
@ -89,6 +90,7 @@ public class MarkwonImplTest {
|
|||||||
|
|
||||||
final MarkwonPlugin plugin = mock(MarkwonPlugin.class);
|
final MarkwonPlugin plugin = mock(MarkwonPlugin.class);
|
||||||
|
|
||||||
|
final MarkwonVisitorFactory visitorFactory = mock(MarkwonVisitorFactory.class);
|
||||||
final MarkwonVisitor visitor = mock(MarkwonVisitor.class);
|
final MarkwonVisitor visitor = mock(MarkwonVisitor.class);
|
||||||
final SpannableBuilder builder = mock(SpannableBuilder.class);
|
final SpannableBuilder builder = mock(SpannableBuilder.class);
|
||||||
|
|
||||||
@ -96,9 +98,10 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.SPANNABLE,
|
TextView.BufferType.SPANNABLE,
|
||||||
null,
|
null,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
visitor,
|
visitorFactory,
|
||||||
Collections.singletonList(plugin));
|
Collections.singletonList(plugin));
|
||||||
|
|
||||||
|
when(visitorFactory.create()).thenReturn(visitor);
|
||||||
when(visitor.builder()).thenReturn(builder);
|
when(visitor.builder()).thenReturn(builder);
|
||||||
|
|
||||||
final Node node = mock(Node.class);
|
final Node node = mock(Node.class);
|
||||||
@ -132,24 +135,30 @@ public class MarkwonImplTest {
|
|||||||
public void render_clears_visitor() {
|
public void render_clears_visitor() {
|
||||||
// each render call should have empty-state visitor (no previous rendering info)
|
// 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);
|
final MarkwonVisitor visitor = mock(MarkwonVisitor.class, RETURNS_MOCKS);
|
||||||
|
|
||||||
|
when(visitorFactory.create()).thenReturn(visitor);
|
||||||
|
|
||||||
final MarkwonImpl impl = new MarkwonImpl(
|
final MarkwonImpl impl = new MarkwonImpl(
|
||||||
TextView.BufferType.SPANNABLE,
|
TextView.BufferType.SPANNABLE,
|
||||||
null,
|
null,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
visitor,
|
visitorFactory,
|
||||||
Collections.<MarkwonPlugin>emptyList());
|
Collections.<MarkwonPlugin>emptyList());
|
||||||
|
|
||||||
impl.render(mock(Node.class));
|
impl.render(mock(Node.class));
|
||||||
|
|
||||||
verify(visitor, times(1)).clear();
|
// obsolete starting with 4.1.1
|
||||||
|
// verify(visitor, times(1)).clear();
|
||||||
|
verify(visitor, never()).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void render_props() {
|
public void render_props() {
|
||||||
// render props are configured properly and cleared after render function
|
// 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 MarkwonVisitor visitor = mock(MarkwonVisitor.class, RETURNS_MOCKS);
|
||||||
|
|
||||||
final RenderProps renderProps = mock(RenderProps.class);
|
final RenderProps renderProps = mock(RenderProps.class);
|
||||||
@ -161,6 +170,7 @@ public class MarkwonImplTest {
|
|||||||
}
|
}
|
||||||
}).when(visitor).clear();
|
}).when(visitor).clear();
|
||||||
|
|
||||||
|
when(visitorFactory.create()).thenReturn(visitor);
|
||||||
when(visitor.renderProps()).thenReturn(renderProps);
|
when(visitor.renderProps()).thenReturn(renderProps);
|
||||||
|
|
||||||
final MarkwonPlugin plugin = mock(MarkwonPlugin.class);
|
final MarkwonPlugin plugin = mock(MarkwonPlugin.class);
|
||||||
@ -169,7 +179,7 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.SPANNABLE,
|
TextView.BufferType.SPANNABLE,
|
||||||
null,
|
null,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
visitor,
|
visitorFactory,
|
||||||
Collections.singletonList(plugin));
|
Collections.singletonList(plugin));
|
||||||
|
|
||||||
final AtomicBoolean flag = new AtomicBoolean(false);
|
final AtomicBoolean flag = new AtomicBoolean(false);
|
||||||
@ -191,7 +201,9 @@ public class MarkwonImplTest {
|
|||||||
|
|
||||||
assertTrue(flag.get());
|
assertTrue(flag.get());
|
||||||
|
|
||||||
verify(renderProps, times(1)).clearAll();
|
// obsolete starting with 4.1.1
|
||||||
|
// verify(renderProps, times(1)).clearAll();
|
||||||
|
verify(renderProps, never()).clearAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -205,7 +217,7 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.EDITABLE,
|
TextView.BufferType.EDITABLE,
|
||||||
null,
|
null,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
mock(MarkwonVisitor.class, RETURNS_MOCKS),
|
mock(MarkwonVisitorFactory.class, RETURNS_MOCKS),
|
||||||
Collections.singletonList(plugin));
|
Collections.singletonList(plugin));
|
||||||
|
|
||||||
final TextView textView = mock(TextView.class);
|
final TextView textView = mock(TextView.class);
|
||||||
@ -252,7 +264,7 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.SPANNABLE,
|
TextView.BufferType.SPANNABLE,
|
||||||
null,
|
null,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
mock(MarkwonVisitor.class),
|
mock(MarkwonVisitorFactory.class),
|
||||||
plugins);
|
plugins);
|
||||||
|
|
||||||
assertTrue("First", impl.hasPlugin(First.class));
|
assertTrue("First", impl.hasPlugin(First.class));
|
||||||
@ -274,7 +286,7 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.EDITABLE,
|
TextView.BufferType.EDITABLE,
|
||||||
textSetter,
|
textSetter,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
mock(MarkwonVisitor.class),
|
mock(MarkwonVisitorFactory.class),
|
||||||
Collections.singletonList(plugin));
|
Collections.singletonList(plugin));
|
||||||
|
|
||||||
final TextView textView = mock(TextView.class);
|
final TextView textView = mock(TextView.class);
|
||||||
@ -317,7 +329,8 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.SPANNABLE,
|
TextView.BufferType.SPANNABLE,
|
||||||
null,
|
null,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
mock(MarkwonVisitor.class), plugins);
|
mock(MarkwonVisitorFactory.class),
|
||||||
|
plugins);
|
||||||
|
|
||||||
// should be returned
|
// should be returned
|
||||||
assertNotNull(impl.requirePlugin(MarkwonPlugin.class));
|
assertNotNull(impl.requirePlugin(MarkwonPlugin.class));
|
||||||
@ -346,7 +359,7 @@ public class MarkwonImplTest {
|
|||||||
TextView.BufferType.SPANNABLE,
|
TextView.BufferType.SPANNABLE,
|
||||||
null,
|
null,
|
||||||
mock(Parser.class),
|
mock(Parser.class),
|
||||||
mock(MarkwonVisitor.class),
|
mock(MarkwonVisitorFactory.class),
|
||||||
plugins);
|
plugins);
|
||||||
|
|
||||||
final List<? extends MarkwonPlugin> list = impl.getPlugins();
|
final List<? extends MarkwonPlugin> list = impl.getPlugins();
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package io.noties.markwon.core;
|
package io.noties.markwon.core;
|
||||||
|
|
||||||
|
import android.text.method.MovementMethod;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
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.BlockQuote;
|
||||||
import org.commonmark.node.BulletList;
|
import org.commonmark.node.BulletList;
|
||||||
@ -38,15 +38,15 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import ix.Ix;
|
|
||||||
import ix.IxFunction;
|
|
||||||
import ix.IxPredicate;
|
|
||||||
import io.noties.markwon.MarkwonConfiguration;
|
import io.noties.markwon.MarkwonConfiguration;
|
||||||
import io.noties.markwon.MarkwonSpansFactory;
|
import io.noties.markwon.MarkwonSpansFactory;
|
||||||
import io.noties.markwon.MarkwonVisitor;
|
import io.noties.markwon.MarkwonVisitor;
|
||||||
import io.noties.markwon.RenderProps;
|
import io.noties.markwon.RenderProps;
|
||||||
import io.noties.markwon.SpanFactory;
|
import io.noties.markwon.SpanFactory;
|
||||||
import io.noties.markwon.SpannableBuilder;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
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.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.RETURNS_MOCKS;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@ -300,4 +301,45 @@ public class CorePluginTest {
|
|||||||
|
|
||||||
verify(textView, times(0)).setMovementMethod(any(MovementMethod.class));
|
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<MarkwonVisitor.NodeVisitor> fencedCaptor =
|
||||||
|
ArgumentCaptor.forClass(MarkwonVisitor.NodeVisitor.class);
|
||||||
|
final ArgumentCaptor<MarkwonVisitor.NodeVisitor> 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -6,6 +6,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.ext.gfm.tables.TableBlock;
|
||||||
import org.commonmark.ext.gfm.tables.TableBody;
|
import org.commonmark.ext.gfm.tables.TableBody;
|
||||||
import org.commonmark.ext.gfm.tables.TableCell;
|
import org.commonmark.ext.gfm.tables.TableCell;
|
||||||
import org.commonmark.ext.gfm.tables.TableHead;
|
import org.commonmark.ext.gfm.tables.TableHead;
|
||||||
@ -115,19 +116,26 @@ public class TablePlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
void configure(@NonNull MarkwonVisitor.Builder builder) {
|
void configure(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
builder
|
builder
|
||||||
.on(TableBody.class, new MarkwonVisitor.NodeVisitor<TableBody>() {
|
// @since 4.1.1 we use TableBlock instead of TableBody to add new lines
|
||||||
|
.on(TableBlock.class, new MarkwonVisitor.NodeVisitor<TableBlock>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableBody tableBody) {
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableBlock tableBlock) {
|
||||||
|
|
||||||
visitor.visitChildren(tableBody);
|
visitor.visitChildren(tableBlock);
|
||||||
tableRows = 0;
|
|
||||||
|
|
||||||
if (visitor.hasNext(tableBody)) {
|
if (visitor.hasNext(tableBlock)) {
|
||||||
visitor.ensureNewLine();
|
visitor.ensureNewLine();
|
||||||
visitor.forceNewLine();
|
visitor.forceNewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.on(TableBody.class, new MarkwonVisitor.NodeVisitor<TableBody>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableBody tableBody) {
|
||||||
|
visitor.visitChildren(tableBody);
|
||||||
|
tableRows = 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
.on(TableRow.class, new MarkwonVisitor.NodeVisitor<TableRow>() {
|
.on(TableRow.class, new MarkwonVisitor.NodeVisitor<TableRow>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableRow tableRow) {
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TableRow tableRow) {
|
||||||
|
@ -11,7 +11,6 @@ import java.io.InputStream;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import io.noties.markwon.image.DrawableUtils;
|
|
||||||
import io.noties.markwon.image.MediaDecoder;
|
import io.noties.markwon.image.MediaDecoder;
|
||||||
import pl.droidsonroids.gif.GifDrawable;
|
import pl.droidsonroids.gif.GifDrawable;
|
||||||
|
|
||||||
@ -97,9 +96,7 @@ public class GifMediaDecoder extends MediaDecoder {
|
|||||||
|
|
||||||
private static void validate() {
|
private static void validate() {
|
||||||
if (!GifSupport.hasGifSupport()) {
|
if (!GifSupport.hasGifSupport()) {
|
||||||
throw new IllegalStateException("`pl.droidsonroids.gif:android-gif-drawable:*` " +
|
throw new IllegalStateException(GifSupport.missingMessage());
|
||||||
"dependency is missing, please add to your project explicitly if you " +
|
|
||||||
"wish to use GIF media decoder");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package io.noties.markwon.image.gif;
|
package io.noties.markwon.image.gif;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@ -13,7 +17,9 @@ public abstract class GifSupport {
|
|||||||
pl.droidsonroids.gif.GifDrawable.class.getName();
|
pl.droidsonroids.gif.GifDrawable.class.getName();
|
||||||
result = true;
|
result = true;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
// @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;
|
result = false;
|
||||||
}
|
}
|
||||||
HAS_GIF = result;
|
HAS_GIF = result;
|
||||||
@ -23,6 +29,16 @@ public abstract class GifSupport {
|
|||||||
return HAS_GIF;
|
return HAS_GIF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.1.1
|
||||||
|
*/
|
||||||
|
@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() {
|
private GifSupport() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,8 +83,7 @@ public class SvgMediaDecoder extends MediaDecoder {
|
|||||||
|
|
||||||
private static void validate() {
|
private static void validate() {
|
||||||
if (!SvgSupport.hasSvgSupport()) {
|
if (!SvgSupport.hasSvgSupport()) {
|
||||||
throw new IllegalStateException("`com.caverock:androidsvg:*` dependency is missing, " +
|
throw new IllegalStateException(SvgSupport.missingMessage());
|
||||||
"please add to your project explicitly if you wish to use SVG media decoder");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package io.noties.markwon.image.svg;
|
package io.noties.markwon.image.svg;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@ -13,7 +17,9 @@ public abstract class SvgSupport {
|
|||||||
com.caverock.androidsvg.SVG.class.getName();
|
com.caverock.androidsvg.SVG.class.getName();
|
||||||
result = true;
|
result = true;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
// @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;
|
result = false;
|
||||||
}
|
}
|
||||||
HAS_SVG = result;
|
HAS_SVG = result;
|
||||||
@ -23,6 +29,15 @@ public abstract class SvgSupport {
|
|||||||
return HAS_SVG;
|
return HAS_SVG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.1.1
|
||||||
|
*/
|
||||||
|
@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() {
|
private SvgSupport() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user