diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
index d372d9d5..98885d7a 100644
--- a/docs/.vuepress/config.js
+++ b/docs/.vuepress/config.js
@@ -49,17 +49,20 @@ module.exports = {
'/docs/core/configuration.md',
'/docs/core/visitor.md',
'/docs/core/spans-factory.md',
- '/docs/core/html-renderer.md'
+ '/docs/core/html-renderer.md',
+ '/docs/core/core-plugin.md',
+ '/docs/core/movement-method-plugin.md'
]
},
'/docs/ext-latex/',
- '/docs/ext-strikethrough/strikethrough.md',
- '/docs/ext-tables/tables.md',
- '/docs/ext-tasklist/tasklist.md',
+ '/docs/ext-strikethrough/',
+ '/docs/ext-tables/',
+ '/docs/ext-tasklist/',
{
title: 'HTML',
children: [
- '/docs/html/html.md'
+ '/docs/html/',
+ '/docs/html/custom-tag-handler.md'
]
},
{
@@ -70,8 +73,8 @@ module.exports = {
'/docs/image/svg.md'
]
},
- '/docs/recycler/recycler.md',
- '/docs/syntax-highlight/syntax-highlight.md',
+ '/docs/recycler/',
+ '/docs/syntax-highlight/',
'/docs/migration-2-3.md'
]
},
diff --git a/docs/README.md b/docs/README.md
index a2752665..e930c4bf 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -25,18 +25,19 @@ listed in are supported (including support for *
* Emphasis (`*`, `_`)
* Strong emphasis (`**`, `__`)
-* Strike-through (`~~`)
* Headers (`#{1,6}`)
* Links (`[]()` && `[][]`)
-* [Images](/docs/image-loader.md)
+* [Images](/docs/core/images.md)
* Thematic break (`---`, `***`, `___`)
* Quotes & nested quotes (`>{1,}`)
* Ordered & non-ordered lists & nested ones
* Inline code
* Code blocks
-* Tables (*with limitations*)
-* [Syntax highlight](/docs/syntax-highlight.md)
-* [HTML](/docs/html.md)
+* [Strike-through](/docs/ext-strikethrough/) (`~~`)
+* [Tables](/docs/ext-tables/) (*with limitations*)
+* [Syntax highlight](/docs/syntax-highlight/)
+* [LaTeX](/docs/ext-latex/) formulas
+* [HTML](/docs/html/)
* Emphasis (``, ``, ``, ``)
* Strong emphasis (``, ``)
* SuperScript (``)
@@ -49,8 +50,8 @@ listed in are supported (including support for *
* Blockquote (`blockquote`)
* Heading (`h1`, `h2`, `h3`, `h4`, `h5`, `h6`)
* there is support to render any HTML tag, but it will require to create a special `TagHandler`,
- more information can be found in [HTML section](/docs/html.md#custom-tag-handler)
-* Task lists:
+ more information can be found in [HTML section](/docs/html/custom-tag-handler.md)
+* [Task lists](/docs/ext-tasklist/):
- [ ] Not _done_
- [X] **Done** with `X`
- [x] ~~and~~ **or** small `x`
diff --git a/docs/docs/core/core-plugin.md b/docs/docs/core/core-plugin.md
new file mode 100644
index 00000000..13802825
--- /dev/null
+++ b/docs/docs/core/core-plugin.md
@@ -0,0 +1,103 @@
+# Core plugin
+
+Since with introduction of _plugins_, Markwon
+**core** functionality was moved to a dedicated plugin.
+
+```java
+CorePlugin.create();
+```
+
+## Node visitors
+
+`CorePlugin` registers these `commonmark-java` node visitors:
+* `Text`
+* `StrongEmphasis`
+* `Emphasis`
+* `BlockQuote`
+* `Code`
+* `FencedCodeBlock`
+* `IndentedCodeBlock`
+* `BulletList`
+* `OrderedList`
+* `ListItem`
+* `ThematicBreak`
+* `Heading`
+* `SoftLineBreak`
+* `HardLineBreak`
+* `Paragraph`
+* `Link`
+
+## Span factories
+
+`CorePlugin` adds these `SpanFactory`s:
+* `StrongEmphasis`
+* `Emphasis`
+* `BlockQuote`
+* `Code`
+* `FencedCodeBlock`
+* `IndentedCodeBlock`
+* `ListItem`
+* `Heading`
+* `Link`
+* `ThematicBreak`
+
+
+:::tip
+By default `CorePlugin` does not register a `Paragraph` `SpanFactory` but
+this can be done in your custom plugin:
+
+```java
+Markwon.builder(context)
+ .usePlugin(new AbstractMarkwonPlugin() {
+ @Override
+ public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
+ builder.setFactory(Paragraph.class, (configuration, props) ->
+ new ForegroundColorSpan(Color.RED));
+ }
+ })
+```
+:::
+
+## Props
+These props are exported by `CorePlugin` and can be found in `CoreProps`:
+* `Prop LIST_ITEM_TYPE` (BULLET | ORDERED)
+* `Prop BULLET_LIST_ITEM_LEVEL`
+* `Prop ORDERED_LIST_ITEM_NUMBER`
+* `Prop HEADING_LEVEL`
+* `Prop LINK_DESTINATION`
+* `Prop PARAGRAPH_IS_IN_TIGHT_LIST`
+
+:::warning List item type
+Before `Markwon` had 2 distinct lists (bullet and ordered).
+Since a single `SpanFactory` is used, which internally checks
+for `Prop LIST_ITEM_TYPE`.
+Beware of this if you would like to override only one of the list types. This is
+done to correspond to `commonmark-java` implementation.
+:::
+
+---
+
+:::tip Soft line break
+Since Markwon core does not give an option to
+insert a new line when there is a soft line break in markdown. Instead a
+custom plugin can be used:
+
+```java
+final Markwon markwon = Markwon.builder(this)
+ .usePlugin(new AbstractMarkwonPlugin() {
+ @Override
+ public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
+ builder.on(SoftLineBreak.class, (visitor, softLineBreak) ->
+ visitor.forceNewLine());
+ }
+ })
+ .build();
+```
+:::
+
+:::warning
+Please note that `CorePlugin` will implicitly set a `LinkMovementMethod` on a TextView
+if one is not present. If you wish to customize a MovementMethod that is used, apply
+one manually to a TextView (before applying markdown) or use the [MovementMethodPlugin](/docs/core/movement-method-plugin.md)
+which accepts a MovementMethod as an argument.
+:::
\ No newline at end of file
diff --git a/docs/docs/core/movement-method-plugin.md b/docs/docs/core/movement-method-plugin.md
new file mode 100644
index 00000000..6bb50c87
--- /dev/null
+++ b/docs/docs/core/movement-method-plugin.md
@@ -0,0 +1,17 @@
+# 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
+specific needs for a `MovementMethod` and `LinkMovementMethod` doesn't answer
+your needs use `MovementMethodPlugin`:
+
+```java
+Markwon.builder(context)
+ .usePlugin(MovementMethodPlugin.create(ScrollingMovementMethod.getInstance()))
+```
+
+:::tip
+If you are having trouble with system `LinkMovementMethod` as an alternative
+[BetterLinkMovementMethod](https://github.com/saket/Better-Link-Movement-Method) library can be used.
+:::
diff --git a/docs/docs/ext-strikethrough/strikethrough.md b/docs/docs/ext-strikethrough/README.md
similarity index 100%
rename from docs/docs/ext-strikethrough/strikethrough.md
rename to docs/docs/ext-strikethrough/README.md
diff --git a/docs/docs/ext-tables/tables.md b/docs/docs/ext-tables/README.md
similarity index 85%
rename from docs/docs/ext-tables/tables.md
rename to docs/docs/ext-tables/README.md
index afa534ff..a728645c 100644
--- a/docs/docs/ext-tables/tables.md
+++ b/docs/docs/ext-tables/README.md
@@ -24,6 +24,19 @@ final Markwon markwon = Markwon.builder(context)
.usePlugin(TablePlugin.create(tableTheme))
```
+```java
+Markwon.builder(context)
+ .usePlugin(TablePlugin.create(builder ->
+ builder
+ .tableBorderColor(Color.RED)
+ .tableBorderWidth(0)
+ .tableCellPadding(0)
+ .tableHeaderRowBackgroundColor(Color.BLACK)
+ .tableEvenRowBackgroundColor(Color.GREEN)
+ .tableOddRowBackgroundColor(Color.YELLOW)
+))
+```
+
Please note, that _by default_ tables have limitations. For example, there is no support
for images inside table cells. And table contents won't be copied to clipboard if a TextView
has such functionality. Table will always take full width of a TextView in which it is displayed.
diff --git a/docs/docs/ext-tasklist/tasklist.md b/docs/docs/ext-tasklist/README.md
similarity index 100%
rename from docs/docs/ext-tasklist/tasklist.md
rename to docs/docs/ext-tasklist/README.md
diff --git a/docs/docs/html/html.md b/docs/docs/html/README.md
similarity index 100%
rename from docs/docs/html/html.md
rename to docs/docs/html/README.md
diff --git a/docs/docs/html/custom-tag-handler.md b/docs/docs/html/custom-tag-handler.md
new file mode 100644
index 00000000..e5ed0ccc
--- /dev/null
+++ b/docs/docs/html/custom-tag-handler.md
@@ -0,0 +1 @@
+# HTML custom tag handler
\ No newline at end of file
diff --git a/docs/docs/recycler/recycler.md b/docs/docs/recycler/README.md
similarity index 100%
rename from docs/docs/recycler/recycler.md
rename to docs/docs/recycler/README.md
diff --git a/docs/docs/syntax-highlight/syntax-highlight.md b/docs/docs/syntax-highlight/README.md
similarity index 100%
rename from docs/docs/syntax-highlight/syntax-highlight.md
rename to docs/docs/syntax-highlight/README.md
diff --git a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java
index bc3946a4..77fa3653 100644
--- a/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java
+++ b/markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java
@@ -50,18 +50,10 @@ public class CorePlugin extends AbstractMarkwonPlugin {
@NonNull
public static CorePlugin create() {
- return create(false);
+ return new CorePlugin();
}
- @NonNull
- public static CorePlugin create(boolean softBreakAddsNewLine) {
- return new CorePlugin(softBreakAddsNewLine);
- }
-
- private final boolean softBreakAddsNewLine;
-
- protected CorePlugin(boolean softBreakAddsNewLine) {
- this.softBreakAddsNewLine = softBreakAddsNewLine;
+ protected CorePlugin() {
}
@Override
@@ -78,7 +70,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
listItem(builder);
thematicBreak(builder);
heading(builder);
- softLineBreak(builder, softBreakAddsNewLine);
+ softLineBreak(builder);
hardLineBreak(builder);
paragraph(builder);
link(builder);
@@ -341,15 +333,11 @@ public class CorePlugin extends AbstractMarkwonPlugin {
});
}
- private static void softLineBreak(@NonNull MarkwonVisitor.Builder builder, final boolean softBreakAddsNewLine) {
+ private static void softLineBreak(@NonNull MarkwonVisitor.Builder builder) {
builder.on(SoftLineBreak.class, new MarkwonVisitor.NodeVisitor() {
@Override
public void visit(@NonNull MarkwonVisitor visitor, @NonNull SoftLineBreak softLineBreak) {
- if (softBreakAddsNewLine) {
- visitor.ensureNewLine();
- } else {
- visitor.builder().append(' ');
- }
+ visitor.builder().append(' ');
}
});
}
diff --git a/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java b/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java
index 108c43b8..af3d00b1 100644
--- a/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java
+++ b/markwon-core/src/test/java/ru/noties/markwon/MarkwonBuilderImplTest.java
@@ -126,7 +126,7 @@ public class MarkwonBuilderImplTest {
};
// our subclass
- final CorePlugin corePlugin = new CorePlugin(false) {
+ final CorePlugin corePlugin = new CorePlugin() {
};
diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java b/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java
index 64c266b8..681e1f0a 100644
--- a/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java
+++ b/markwon-core/src/test/java/ru/noties/markwon/core/CorePluginTest.java
@@ -2,6 +2,8 @@ package ru.noties.markwon.core;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.text.method.MovementMethod;
+import android.widget.TextView;
import org.commonmark.node.BlockQuote;
import org.commonmark.node.BulletList;
@@ -46,6 +48,7 @@ import ru.noties.markwon.SpannableBuilder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -223,26 +226,9 @@ public class CorePluginTest {
}
@Test
- public void softbreak_adds_new_line_default() {
- // default is false
- softbreak_adds_new_line(CorePlugin.create(), false);
- }
+ public void softbreak() {
- @Test
- public void softbreak_adds_new_line_false() {
- // a space character will be added
- softbreak_adds_new_line(CorePlugin.create(false), false);
- }
-
- @Test
- public void softbreak_adds_new_line_true() {
- // a new line will be added
- softbreak_adds_new_line(CorePlugin.create(true), true);
- }
-
- private static void softbreak_adds_new_line(
- @NonNull CorePlugin plugin,
- boolean softBreakAddsNewLine) {
+ final CorePlugin plugin = CorePlugin.create();
final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
when(builder.on(any(Class.class), any(MarkwonVisitor.NodeVisitor.class))).thenReturn(builder);
@@ -259,21 +245,44 @@ public class CorePluginTest {
final MarkwonVisitor.NodeVisitor nodeVisitor = captor.getValue();
final MarkwonVisitor visitor = mock(MarkwonVisitor.class);
- if (!softBreakAddsNewLine) {
+ // we must mock SpannableBuilder and verify that it has a space character appended
+ final SpannableBuilder spannableBuilder = mock(SpannableBuilder.class);
+ when(visitor.builder()).thenReturn(spannableBuilder);
+ nodeVisitor.visit(visitor, mock(SoftLineBreak.class));
- // we must mock SpannableBuilder and verify that it has a space character appended
- final SpannableBuilder spannableBuilder = mock(SpannableBuilder.class);
- when(visitor.builder()).thenReturn(spannableBuilder);
- nodeVisitor.visit(visitor, mock(SoftLineBreak.class));
+ verify(visitor, times(1)).builder();
+ verify(spannableBuilder, times(1)).append(eq(' '));
+ }
- verify(visitor, times(1)).builder();
- verify(spannableBuilder, times(1)).append(eq(' '));
+ @Test
+ public void implicit_movement_method_after_set_text_added() {
+ // validate that CorePlugin will implicitly add LinkMovementMethod if one is missing
+ final TextView textView = mock(TextView.class);
+ when(textView.getMovementMethod()).thenReturn(null);
- } else {
+ final CorePlugin plugin = CorePlugin.create();
- nodeVisitor.visit(visitor, mock(SoftLineBreak.class));
+ assertNull(textView.getMovementMethod());
- verify(visitor, times(1)).ensureNewLine();
- }
+ plugin.afterSetText(textView);
+
+ final ArgumentCaptor captor = ArgumentCaptor.forClass(MovementMethod.class);
+ verify(textView, times(1)).setMovementMethod(captor.capture());
+
+ assertNotNull(captor.getValue());
+ }
+
+ @Test
+ public void implicit_movement_method_after_set_text_no_op() {
+ // validate that CorePlugin won't change movement method if one is present on a TextView
+
+ final TextView textView = mock(TextView.class);
+ when(textView.getMovementMethod()).thenReturn(mock(MovementMethod.class));
+
+ final CorePlugin plugin = CorePlugin.create();
+
+ plugin.afterSetText(textView);
+
+ verify(textView, times(0)).setMovementMethod(any(MovementMethod.class));
}
}
\ No newline at end of file
diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/BaseSuiteTest.java b/markwon-core/src/test/java/ru/noties/markwon/core/suite/BaseSuiteTest.java
index 98734db7..d434ed99 100644
--- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/BaseSuiteTest.java
+++ b/markwon-core/src/test/java/ru/noties/markwon/core/suite/BaseSuiteTest.java
@@ -73,7 +73,7 @@ abstract class BaseSuiteTest {
@NonNull
Markwon markwon() {
return Markwon.builder(RuntimeEnvironment.application)
- .usePlugin(CorePlugin.create(softBreakAddsNewLine()))
+ .usePlugin(CorePlugin.create())
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
@@ -99,10 +99,6 @@ abstract class BaseSuiteTest {
return false;
}
- boolean softBreakAddsNewLine() {
- return false;
- }
-
private static final Map, SpanFactory> CORE_NODES;
static {
diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakAddsNewLineTest.java b/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakAddsNewLineTest.java
deleted file mode 100644
index 4658dc7d..00000000
--- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakAddsNewLineTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package ru.noties.markwon.core.suite;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import ru.noties.markwon.test.TestSpan.Document;
-
-import static ru.noties.markwon.test.TestSpan.document;
-import static ru.noties.markwon.test.TestSpan.text;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class SoftBreakAddsNewLineTest extends BaseSuiteTest {
-
- /*
-hello there!
-this one is on the next line
-hard break to the full extend
- */
-
- @Test
- public void test() {
-
- final Document document = document(
- text("hello there!\n"),
- text("this one is on the next line\n"),
- text("hard break to the full extend")
- );
-
- matchInput("soft-break-adds-new-line.md", document);
- }
-
- @Override
- boolean softBreakAddsNewLine() {
- return true;
- }
-}
diff --git a/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakTest.java b/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakTest.java
index 25991e4e..b94ab45a 100644
--- a/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakTest.java
+++ b/markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakTest.java
@@ -14,20 +14,15 @@ import static ru.noties.markwon.test.TestSpan.text;
@Config(manifest = Config.NONE)
public class SoftBreakTest extends BaseSuiteTest {
- @Test
- public void test() {
+ @Test
+ public void test() {
- final Document document = document(
- text("First line "),
- text("same line but with space between "),
- text("this is also the first line")
- );
+ final Document document = document(
+ text("First line "),
+ text("same line but with space between "),
+ text("this is also the first line")
+ );
- matchInput("soft-break.md", document);
- }
-
- @Override
- boolean softBreakAddsNewLine() {
- return false;
- }
+ matchInput("soft-break.md", document);
+ }
}
diff --git a/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java b/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java
index 2274a7f6..2a6063ed 100644
--- a/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java
+++ b/markwon-core/src/test/java/ru/noties/markwon/priority/PriorityProcessorTest.java
@@ -109,7 +109,7 @@ public class PriorityProcessorTest {
public void subclass_found() {
// when a plugin comes after another, but _another_ was subclassed and placed in the list
- final MarkwonPlugin core = new CorePlugin(false) {
+ final MarkwonPlugin core = new CorePlugin() {
};
final MarkwonPlugin plugin = new AbstractMarkwonPlugin() {
@NonNull
diff --git a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java
index 67faecb2..ece065bf 100644
--- a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java
+++ b/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java
@@ -30,6 +30,13 @@ public class TablePlugin extends AbstractMarkwonPlugin {
void configureTheme(@NonNull TableTheme.Builder builder);
}
+ /**
+ * Factory method to create a {@link TablePlugin} with default {@link TableTheme} instance
+ * (obtained via {@link TableTheme#create(Context)} method)
+ *
+ * @see #create(TableTheme)
+ * @see #create(ThemeConfigure)
+ */
@NonNull
public static TablePlugin create(@NonNull Context context) {
return new TablePlugin(TableTheme.create(context));
diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java
index 47afb7bd..23c5777e 100644
--- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java
+++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java
@@ -81,6 +81,8 @@ public class RecyclerActivity extends Activity {
.usePlugin(CorePlugin.create())
.usePlugin(ImagesPlugin.createWithAssets(context))
.usePlugin(SvgPlugin.create(context.getResources()))
+ // although we will be rendering table differently we still need
+ // to register commonmark-java tables extension (which TablePlugin does)
.usePlugin(TablePlugin.create(context))
.usePlugin(HtmlPlugin.create())
.usePlugin(new AbstractMarkwonPlugin() {