From 18fd56a97c16a676972be2d34ed01390cae61be2 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Sun, 20 Jan 2019 16:04:28 +0300 Subject: [PATCH] Working with documentation --- docs/.vuepress/config.js | 17 +-- docs/README.md | 15 +-- docs/docs/core/core-plugin.md | 103 ++++++++++++++++++ docs/docs/core/movement-method-plugin.md | 17 +++ .../{strikethrough.md => README.md} | 0 docs/docs/ext-tables/{tables.md => README.md} | 13 +++ .../ext-tasklist/{tasklist.md => README.md} | 0 docs/docs/html/{html.md => README.md} | 0 docs/docs/html/custom-tag-handler.md | 1 + docs/docs/recycler/{recycler.md => README.md} | 0 .../{syntax-highlight.md => README.md} | 0 .../ru/noties/markwon/core/CorePlugin.java | 22 +--- .../markwon/MarkwonBuilderImplTest.java | 2 +- .../noties/markwon/core/CorePluginTest.java | 69 +++++++----- .../markwon/core/suite/BaseSuiteTest.java | 6 +- .../core/suite/SoftBreakAddsNewLineTest.java | 39 ------- .../markwon/core/suite/SoftBreakTest.java | 23 ++-- .../priority/PriorityProcessorTest.java | 2 +- .../markwon/ext/tables/TablePlugin.java | 7 ++ .../sample/recycler/RecyclerActivity.java | 2 + 20 files changed, 217 insertions(+), 121 deletions(-) create mode 100644 docs/docs/core/core-plugin.md create mode 100644 docs/docs/core/movement-method-plugin.md rename docs/docs/ext-strikethrough/{strikethrough.md => README.md} (100%) rename docs/docs/ext-tables/{tables.md => README.md} (85%) rename docs/docs/ext-tasklist/{tasklist.md => README.md} (100%) rename docs/docs/html/{html.md => README.md} (100%) create mode 100644 docs/docs/html/custom-tag-handler.md rename docs/docs/recycler/{recycler.md => README.md} (100%) rename docs/docs/syntax-highlight/{syntax-highlight.md => README.md} (100%) delete mode 100644 markwon-core/src/test/java/ru/noties/markwon/core/suite/SoftBreakAddsNewLineTest.java 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() {