diff --git a/CHANGELOG.md b/CHANGELOG.md
index 293be7ea..a4607ed5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,11 +9,13 @@
* Expose `enabledBlockTypes` in `CorePlugin`
* Update `jlatexmath-android` dependency ([#225])
* Update `image-coil` module (Coil version `0.10.1`) ([#244])
Thanks to [@tylerbwong]
-* Rename `UrlProcessor` to `ImageDestinationProcessor` (`io.noties.markwon.urlprocessor` -> `io.noties.markwon.image.destination`) and limit its usage to process **only** destination URL of images (was used to also process links before)
+* Rename `UrlProcessor` to `ImageDestinationProcessor` (`io.noties.markwon.urlprocessor` -> `io.noties.markwon.image.destination`) and limit its usage to process **only** destination URL of images (was used to also process links before)
+* `fallbackToRawInputWhenEmpty` `Markwon.Builder` configuration to fallback to raw input if rendered markdown is empty ([#242])
[#235]: https://github.com/noties/Markwon/issues/235
[#225]: https://github.com/noties/Markwon/issues/225
[#244]: https://github.com/noties/Markwon/pull/244
+[#242]: https://github.com/noties/Markwon/issues/242
[@tylerbwong]: https://github.com/tylerbwong
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 cd277e03..1422bf3c 100644
--- a/markwon-core/src/main/java/io/noties/markwon/Markwon.java
+++ b/markwon-core/src/main/java/io/noties/markwon/Markwon.java
@@ -192,6 +192,17 @@ public abstract class Markwon {
@NonNull
Builder usePlugins(@NonNull Iterable extends MarkwonPlugin> plugins);
+ /**
+ * Control if small chunks of non-finished markdown sentences (for example, a single `*` character)
+ * should be displayed/rendered as raw input instead of an empty string.
+ *
+ * Since $nap; {@code true} by default, versions prior - {@code false}
+ *
+ * @since $nap;
+ */
+ @NonNull
+ Builder fallbackToRawInputWhenEmpty(boolean fallbackToRawInputWhenEmpty);
+
@NonNull
Markwon build();
}
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 2ae70e18..9d470f87 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java
@@ -27,6 +27,9 @@ class MarkwonBuilderImpl implements Markwon.Builder {
private Markwon.TextSetter textSetter;
+ // @since $nap;
+ private boolean fallbackToRawInputWhenEmpty = true;
+
MarkwonBuilderImpl(@NonNull Context context) {
this.context = context;
}
@@ -71,6 +74,13 @@ class MarkwonBuilderImpl implements Markwon.Builder {
return this;
}
+ @NonNull
+ @Override
+ public Markwon.Builder fallbackToRawInputWhenEmpty(boolean fallbackToRawInputWhenEmpty) {
+ this.fallbackToRawInputWhenEmpty = fallbackToRawInputWhenEmpty;
+ return this;
+ }
+
@NonNull
@Override
public Markwon build() {
@@ -114,7 +124,8 @@ class MarkwonBuilderImpl implements Markwon.Builder {
parserBuilder.build(),
visitorFactory,
configuration,
- Collections.unmodifiableList(plugins)
+ Collections.unmodifiableList(plugins),
+ fallbackToRawInputWhenEmpty
);
}
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 5aced55c..999e2f68 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java
@@ -1,6 +1,8 @@
package io.noties.markwon;
+import android.text.SpannableStringBuilder;
import android.text.Spanned;
+import android.text.TextUtils;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -28,19 +30,25 @@ class MarkwonImpl extends Markwon {
@Nullable
private final TextSetter textSetter;
+ // @since $nap;
+ private final boolean fallbackToRawInputWhenEmpty;
+
MarkwonImpl(
@NonNull TextView.BufferType bufferType,
@Nullable TextSetter textSetter,
@NonNull Parser parser,
@NonNull MarkwonVisitorFactory visitorFactory,
@NonNull MarkwonConfiguration configuration,
- @NonNull List plugins) {
+ @NonNull List plugins,
+ boolean fallbackToRawInputWhenEmpty
+ ) {
this.bufferType = bufferType;
this.textSetter = textSetter;
this.parser = parser;
this.visitorFactory = visitorFactory;
this.configuration = configuration;
this.plugins = plugins;
+ this.fallbackToRawInputWhenEmpty = fallbackToRawInputWhenEmpty;
}
@NonNull
@@ -86,7 +94,18 @@ class MarkwonImpl extends Markwon {
@NonNull
@Override
public Spanned toMarkdown(@NonNull String input) {
- return render(parse(input));
+ final Spanned spanned = render(parse(input));
+
+ // @since $nap;
+ // if spanned is empty, we are configured to use raw input and input is not empty
+ if (TextUtils.isEmpty(spanned)
+ && fallbackToRawInputWhenEmpty
+ && !TextUtils.isEmpty(input)) {
+ // let's use SpannableStringBuilder in order to keep backward-compatibility
+ return new SpannableStringBuilder(input);
+ }
+
+ return spanned;
}
@Override
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 0d9024d4..599e24d5 100644
--- a/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java
+++ b/markwon-core/src/test/java/io/noties/markwon/MarkwonImplTest.java
@@ -1,6 +1,7 @@
package io.noties.markwon;
import android.text.Spanned;
+import android.text.TextUtils;
import android.widget.TextView;
import org.commonmark.node.Node;
@@ -50,7 +51,9 @@ public class MarkwonImplTest {
mock(Parser.class),
mock(MarkwonVisitorFactory.class),
mock(MarkwonConfiguration.class),
- Collections.singletonList(plugin));
+ Collections.singletonList(plugin),
+ true
+ );
impl.parse("whatever");
@@ -74,7 +77,9 @@ public class MarkwonImplTest {
parser,
mock(MarkwonVisitorFactory.class),
mock(MarkwonConfiguration.class),
- Arrays.asList(first, second));
+ Arrays.asList(first, second),
+ true
+ );
impl.parse("zero");
@@ -102,7 +107,9 @@ public class MarkwonImplTest {
mock(Parser.class),
visitorFactory,
mock(MarkwonConfiguration.class),
- Collections.singletonList(plugin));
+ Collections.singletonList(plugin),
+ true
+ );
when(visitorFactory.create()).thenReturn(visitor);
when(visitor.builder()).thenReturn(builder);
@@ -149,7 +156,9 @@ public class MarkwonImplTest {
mock(Parser.class),
visitorFactory,
mock(MarkwonConfiguration.class),
- Collections.emptyList());
+ Collections.emptyList(),
+ true
+ );
impl.render(mock(Node.class));
@@ -185,7 +194,9 @@ public class MarkwonImplTest {
mock(Parser.class),
visitorFactory,
mock(MarkwonConfiguration.class),
- Collections.singletonList(plugin));
+ Collections.singletonList(plugin),
+ true
+ );
final AtomicBoolean flag = new AtomicBoolean(false);
final Node node = mock(Node.class);
@@ -224,7 +235,9 @@ public class MarkwonImplTest {
mock(Parser.class),
mock(MarkwonVisitorFactory.class, RETURNS_MOCKS),
mock(MarkwonConfiguration.class),
- Collections.singletonList(plugin));
+ Collections.singletonList(plugin),
+ true
+ );
final TextView textView = mock(TextView.class);
final AtomicBoolean flag = new AtomicBoolean(false);
@@ -272,7 +285,9 @@ public class MarkwonImplTest {
mock(Parser.class),
mock(MarkwonVisitorFactory.class),
mock(MarkwonConfiguration.class),
- plugins);
+ plugins,
+ true
+ );
assertTrue("First", impl.hasPlugin(First.class));
assertFalse("Second", impl.hasPlugin(Second.class));
@@ -295,7 +310,9 @@ public class MarkwonImplTest {
mock(Parser.class),
mock(MarkwonVisitorFactory.class),
mock(MarkwonConfiguration.class),
- Collections.singletonList(plugin));
+ Collections.singletonList(plugin),
+ true
+ );
final TextView textView = mock(TextView.class);
final Spanned spanned = mock(Spanned.class);
@@ -339,7 +356,9 @@ public class MarkwonImplTest {
mock(Parser.class),
mock(MarkwonVisitorFactory.class),
mock(MarkwonConfiguration.class),
- plugins);
+ plugins,
+ true
+ );
// should be returned
assertNotNull(impl.requirePlugin(MarkwonPlugin.class));
@@ -370,7 +389,9 @@ public class MarkwonImplTest {
mock(Parser.class),
mock(MarkwonVisitorFactory.class),
mock(MarkwonConfiguration.class),
- plugins);
+ plugins,
+ true
+ );
final List extends MarkwonPlugin> list = impl.getPlugins();
@@ -385,4 +406,42 @@ public class MarkwonImplTest {
assertTrue(e.getMessage(), true);
}
}
+
+ @Test
+ public void fallback_to_raw() {
+ final String md = "*";
+
+ final MarkwonImpl impl = new MarkwonImpl(
+ TextView.BufferType.SPANNABLE,
+ null,
+ mock(Parser.class, RETURNS_MOCKS),
+ // it must be sufficient to just return mocks and thus empty rendering result
+ mock(MarkwonVisitorFactory.class, RETURNS_MOCKS),
+ mock(MarkwonConfiguration.class),
+ Collections.emptyList(),
+ true
+ );
+
+ final Spanned spanned = impl.toMarkdown(md);
+ assertEquals(md, spanned.toString());
+ }
+
+ @Test
+ public void fallback_to_raw_false() {
+ final String md = "*";
+
+ final MarkwonImpl impl = new MarkwonImpl(
+ TextView.BufferType.SPANNABLE,
+ null,
+ mock(Parser.class, RETURNS_MOCKS),
+ // it must be sufficient to just return mocks and thus empty rendering result
+ mock(MarkwonVisitorFactory.class, RETURNS_MOCKS),
+ mock(MarkwonConfiguration.class),
+ Collections.emptyList(),
+ false
+ );
+
+ final Spanned spanned = impl.toMarkdown(md);
+ assertTrue(spanned.toString(), TextUtils.isEmpty(spanned));
+ }
}
\ No newline at end of file