diff --git a/CHANGELOG.md b/CHANGELOG.md index ee18c59a..655ae84d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ # 4.2.0-SNAPSHOT * `MarkwonEditor` to highlight markdown input whilst editing (new module: `markwon-editor`) +* `MarkwonInlineParser` to customize inline parsing (new module: `markwon-inline-parser`) * `Markwon#configuration` method to expose `MarkwonConfiguration` via public API * `HeadingSpan#getLevel` getter * Add `SvgPictureMediaDecoder` in `image` module to deal with SVG without dimensions ([#165]) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index f8db7ba5..bd44aa90 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -104,6 +104,7 @@ module.exports = { '/docs/v4/image/', '/docs/v4/image-glide/', '/docs/v4/image-picasso/', + '/docs/v4/inline-parser/', '/docs/v4/linkify/', '/docs/v4/recycler/', '/docs/v4/recycler-table/', diff --git a/docs/docs/v4/inline-parser/README.md b/docs/docs/v4/inline-parser/README.md new file mode 100644 index 00000000..4c5471a1 --- /dev/null +++ b/docs/docs/v4/inline-parser/README.md @@ -0,0 +1,78 @@ +# Inline Parser + +**Experimental** commonmark-java inline parser that allows customizing +core features and/or extend with own. + +Usage of _internal_ classes: +```java +import org.commonmark.internal.Bracket; +import org.commonmark.internal.Delimiter; +import org.commonmark.internal.ReferenceParser; +import org.commonmark.internal.util.Escaping; +import org.commonmark.internal.util.Html5Entities; +import org.commonmark.internal.util.Parsing; +import org.commonmark.internal.inline.AsteriskDelimiterProcessor; +import org.commonmark.internal.inline.UnderscoreDelimiterProcessor; +``` + +--- + +```java +// all default (like current commonmark-java InlineParserImpl) +final InlineParserFactory factory = MarkwonInlineParser.factoryBuilder() + .includeDefaults() + .build(); +``` + +```java +// disable images (current markdown images will be considered as links): +final InlineParserFactory factory = MarkwonInlineParser.factoryBuilder() + .includeDefaults() + .excludeInlineProcessor(BangInlineProcessor.class) + .build(); +``` + +```java +// disable core delimiter processors for `*`|`_` and `**`|`__` +final InlineParserFactory factory = MarkwonInlineParser.factoryBuilder() + .includeDefaults() + .excludeDelimiterProcessor(AsteriskDelimiterProcessor.class) + .excludeDelimiterProcessor(UnderscoreDelimiterProcessor.class) + .build(); +``` + +```java +// disable _all_ markdown inlines except for links (open and close bracket handling `[` & `]`) +final InlineParserFactory inlineParserFactory = MarkwonInlineParser.factoryBuilder() + // note that there is no `includeDefaults` method call + .referencesEnabled(true) + .addInlineProcessor(new OpenBracketInlineProcessor()) + .addInlineProcessor(new CloseBracketInlineProcessor()) + .build(); +``` + +To use custom InlineParser: +```java +final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureParser(@NonNull Parser.Builder builder) { + builder.inlineParserFactory(inlineParserFactory); + } + }) + .build(); +``` + +--- + +The list of available inline processors: + +* `AutolinkInlineProcessor` (`<` => ``) +* `BackslashInlineProcessor` (`\\`) +* `BackticksInlineProcessor` (` => `code`) +* `BangInlineProcessor` (`!` => `![alt](#src)`) +* `CloseBracketInlineProcessor` (`]` => `[link](#href)`, `![alt](#src)`) +* `EntityInlineProcessor` (`&` => `&`) +* `HtmlInlineProcessor` (`<` => ``) +* `NewLineInlineProcessor` (`\n`) +* `OpenBracketInlineProcessor` (`[` => `[link](#href)`) \ No newline at end of file diff --git a/markwon-inline-parser/README.md b/markwon-inline-parser/README.md index 5b0e1335..bcfa3802 100644 --- a/markwon-inline-parser/README.md +++ b/markwon-inline-parser/README.md @@ -4,17 +4,13 @@ ```java import org.commonmark.internal.Bracket; +import org.commonmark.internal.Delimiter; +import org.commonmark.internal.ReferenceParser; import org.commonmark.internal.util.Escaping; import org.commonmark.internal.util.Html5Entities; import org.commonmark.internal.util.Parsing; -import org.commonmark.internal.Bracket; -import org.commonmark.internal.Delimiter; -import org.commonmark.internal.ReferenceParser; import org.commonmark.internal.inline.AsteriskDelimiterProcessor; import org.commonmark.internal.inline.UnderscoreDelimiterProcessor; -import org.commonmark.internal.util.Escaping; -import org.commonmark.internal.Bracket; -import org.commonmark.internal.Delimiter; ``` `StaggeredDelimiterProcessor` class source is copied (required for InlineParser) \ No newline at end of file diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/AsteriskDelimiterProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/AsteriskDelimiterProcessor.java deleted file mode 100644 index 3a8d570e..00000000 --- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/AsteriskDelimiterProcessor.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.noties.markwon.inlineparser; - -/** - * @since 4.2.0-SNAPSHOT - */ -public class AsteriskDelimiterProcessor extends org.commonmark.internal.inline.AsteriskDelimiterProcessor { -} diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParser.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParser.java index 5bdda362..89bb18c5 100644 --- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParser.java +++ b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParser.java @@ -6,6 +6,8 @@ import androidx.annotation.Nullable; import org.commonmark.internal.Bracket; import org.commonmark.internal.Delimiter; import org.commonmark.internal.ReferenceParser; +import org.commonmark.internal.inline.AsteriskDelimiterProcessor; +import org.commonmark.internal.inline.UnderscoreDelimiterProcessor; import org.commonmark.internal.util.Escaping; import org.commonmark.node.Link; import org.commonmark.node.Node; diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/UnderscoreDelimiterProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/UnderscoreDelimiterProcessor.java deleted file mode 100644 index 83f7771f..00000000 --- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/UnderscoreDelimiterProcessor.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.noties.markwon.inlineparser; - -/** - * @since 4.2.0-SNAPSHOT - */ -public class UnderscoreDelimiterProcessor extends org.commonmark.internal.inline.UnderscoreDelimiterProcessor { -} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 6bc6ef02..ee887f8c 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -33,6 +33,8 @@ android:name=".editor.EditorActivity" android:windowSoftInputMode="adjustResize" /> + + \ No newline at end of file diff --git a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java index 59c6049f..db937d19 100644 --- a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -24,6 +24,7 @@ import io.noties.markwon.sample.customextension.CustomExtensionActivity; import io.noties.markwon.sample.customextension2.CustomExtensionActivity2; import io.noties.markwon.sample.editor.EditorActivity; import io.noties.markwon.sample.html.HtmlActivity; +import io.noties.markwon.sample.inlineparser.InlineParserActivity; import io.noties.markwon.sample.latex.LatexActivity; import io.noties.markwon.sample.precomputed.PrecomputedActivity; import io.noties.markwon.sample.recycler.RecyclerActivity; @@ -122,6 +123,10 @@ public class MainActivity extends Activity { activity = EditorActivity.class; break; + case INLINE_PARSER: + activity = InlineParserActivity.class; + break; + default: throw new IllegalStateException("No Activity is associated with sample-item: " + item); } diff --git a/sample/src/main/java/io/noties/markwon/sample/Sample.java b/sample/src/main/java/io/noties/markwon/sample/Sample.java index c2a2add3..221ee0bc 100644 --- a/sample/src/main/java/io/noties/markwon/sample/Sample.java +++ b/sample/src/main/java/io/noties/markwon/sample/Sample.java @@ -23,7 +23,9 @@ public enum Sample { PRECOMPUTED_TEXT(R.string.sample_precomputed_text), - EDITOR(R.string.sample_editor); + EDITOR(R.string.sample_editor), + + INLINE_PARSER(R.string.sample_inline_parser); private final int textResId; diff --git a/sample/src/main/java/io/noties/markwon/sample/inlineparser/InlineParserActivity.java b/sample/src/main/java/io/noties/markwon/sample/inlineparser/InlineParserActivity.java new file mode 100644 index 00000000..955d6db2 --- /dev/null +++ b/sample/src/main/java/io/noties/markwon/sample/inlineparser/InlineParserActivity.java @@ -0,0 +1,119 @@ +package io.noties.markwon.sample.inlineparser; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.commonmark.node.Block; +import org.commonmark.node.BlockQuote; +import org.commonmark.node.Heading; +import org.commonmark.node.HtmlBlock; +import org.commonmark.node.ListBlock; +import org.commonmark.node.ThematicBreak; +import org.commonmark.parser.InlineParserFactory; +import org.commonmark.parser.Parser; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.inlineparser.BackticksInlineProcessor; +import io.noties.markwon.inlineparser.CloseBracketInlineProcessor; +import io.noties.markwon.inlineparser.MarkwonInlineParser; +import io.noties.markwon.inlineparser.OpenBracketInlineProcessor; +import io.noties.markwon.sample.R; + +public class InlineParserActivity extends Activity { + + private TextView textView; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_text_view); + + this.textView = findViewById(R.id.text_view); + +// links_only(); + + disable_code(); + } + + private void links_only() { + + // create an inline-parser-factory that will _ONLY_ parse links + // this would mean: + // * no emphasises (strong and regular aka bold and italics), + // * no images, + // * no code, + // * no HTML entities (&) + // * no HTML tags + // markdown blocks are still parsed + final InlineParserFactory inlineParserFactory = MarkwonInlineParser.factoryBuilder() + .referencesEnabled(true) + .addInlineProcessor(new OpenBracketInlineProcessor()) + .addInlineProcessor(new CloseBracketInlineProcessor()) + .build(); + + final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureParser(@NonNull Parser.Builder builder) { + builder.inlineParserFactory(inlineParserFactory); + } + }) + .build(); + + // note that image is considered a link now + final String md = "**bold_bold-italic_** html-u, [link](#) ![alt](#image) `code`"; + markwon.setMarkdown(textView, md); + } + + private void disable_code() { + // parses all as usual, but ignores code (inline and block) + + final InlineParserFactory inlineParserFactory = MarkwonInlineParser.factoryBuilder() + .includeDefaults() + .excludeInlineProcessor(BackticksInlineProcessor.class) + .build(); + + // unfortunately there is no _exclude_ method for parser-builder + final Set> enabledBlocks = new HashSet>() {{ + // IndentedCodeBlock.class and FencedCodeBlock.class are missing + // this is full list (including above) that can be passed to `enabledBlockTypes` method + addAll(Arrays.asList( + BlockQuote.class, + Heading.class, + HtmlBlock.class, + ThematicBreak.class, + ListBlock.class)); + }}; + + final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureParser(@NonNull Parser.Builder builder) { + builder + .inlineParserFactory(inlineParserFactory) + .enabledBlockTypes(enabledBlocks); + } + }) + .build(); + + final String md = "# Head!\n\n" + + "* one\n" + + "+ two\n\n" + + "and **bold** to `you`!\n\n" + + "> a quote _em_\n\n" + + "```java\n" + + "final int i = 0;\n" + + "```\n\n" + + "**Good day!**"; + markwon.setMarkdown(textView, md); + } +} diff --git a/sample/src/main/res/values/strings-samples.xml b/sample/src/main/res/values/strings-samples.xml index 7cf55ed2..a26f62c5 100644 --- a/sample/src/main/res/values/strings-samples.xml +++ b/sample/src/main/res/values/strings-samples.xml @@ -27,4 +27,6 @@ # \# Editor\n\n`MarkwonEditor` sample usage to highlight user input in EditText + # \# Inline Parser\n\nUsage of custom inline parser + \ No newline at end of file