Working with documentation
This commit is contained in:
parent
c390cb0502
commit
e1d5530962
@ -40,7 +40,8 @@ module.exports = {
|
||||
'/docs/v3/core/spans-factory.md',
|
||||
'/docs/v3/core/html-renderer.md',
|
||||
'/docs/v3/core/core-plugin.md',
|
||||
'/docs/v3/core/movement-method-plugin.md'
|
||||
'/docs/v3/core/movement-method-plugin.md',
|
||||
'/docs/v3/core/render-props.md'
|
||||
]
|
||||
},
|
||||
'/docs/v3/ext-latex/',
|
||||
|
@ -86,7 +86,7 @@ and 2 themes included: Light & Dark. It can be downloaded from [releases](ht
|
||||
|
||||
---
|
||||
|
||||
[Help to improve][awesome_link] this section by submitting your application/library/anything
|
||||
[Help to improve][awesome_link] this section by submitting your application or library
|
||||
that is using `Markwon`
|
||||
|
||||
|
||||
|
@ -1 +1,181 @@
|
||||
# Configuration
|
||||
# Configuration
|
||||
|
||||
`MarkwonConfiguration` class holds common Markwon functionality.
|
||||
These are _configurable_ properties:
|
||||
* `SyntaxHighlight`
|
||||
* `LinkSpan.Resolver`
|
||||
* `UrlProcessor`
|
||||
* `ImageSizeResolver`
|
||||
* `MarkwonHtmlParser`
|
||||
|
||||
:::tip
|
||||
Additionally `MarkwonConfiguration` holds:
|
||||
* `MarkwonTheme`
|
||||
* `AsyncDrawableLoader`
|
||||
* `MarkwonHtmlRenderer`
|
||||
* `MarkwonSpansFactory`
|
||||
|
||||
Please note that these values can be retrieved from `MarkwonConfiguration`
|
||||
instance, but their _configuration_ must be done by a `Plugin` by overriding
|
||||
one of the methods:
|
||||
* `Plugin#configureTheme`
|
||||
* `Plugin#configureImages`
|
||||
* `Plugin#configureHtmlRenderer`
|
||||
* `Plugin#configureSpansFactory`
|
||||
:::
|
||||
|
||||
## SyntaxHighlight
|
||||
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(this)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||
builder.syntaxHighlight(new SyntaxHighlightNoOp());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
```
|
||||
|
||||
:::tip
|
||||
Use [syntax-highlight](/docs/v3/syntax-highlight/) to add syntax highlighting
|
||||
to your application
|
||||
:::
|
||||
|
||||
## LinkSpan.Resolver
|
||||
|
||||
React to a link click event. By default `LinkResolverDef` is used,
|
||||
which tries to start an Activity given the `link` argument. If no
|
||||
Activity can handle `link` `LinkResolverDef` silently ignores click event
|
||||
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(this)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||
builder.linkResolver(new LinkSpan.Resolver() {
|
||||
@Override
|
||||
public void resolve(View view, @NonNull String link) {
|
||||
// react to link click here
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
```
|
||||
|
||||
:::tip
|
||||
Please note that `Markwon` will apply `LinkMovementMethod` to a resulting TextView
|
||||
if there is none registered. if you wish to register own instance of a `MovementMethod`
|
||||
apply it directly to a TextView or use [MovementMethodPlugin](/docs/v3/core/movement-method-plugin.md)
|
||||
:::
|
||||
|
||||
## UrlProcessor
|
||||
|
||||
Process URLs in your markdown (for links and images). If not provided explicitly,
|
||||
default **no-op** implementation will be used, which does not modify URLs (keeping them as-is).
|
||||
|
||||
`Markwon` provides 2 implementations of `UrlProcessor`:
|
||||
* `UrlProcessorRelativeToAbsolute`
|
||||
* `UrlProcessorAndroidAssets`
|
||||
|
||||
### UrlProcessorRelativeToAbsolute
|
||||
|
||||
`UrlProcessorRelativeToAbsolute` can be used to make relative URL absolute. For example if an image is
|
||||
defined like this: `` and `UrlProcessorRelativeToAbsolute`
|
||||
is created with `https://github.com/noties/Markwon/raw/master/` as the base:
|
||||
`new UrlProcessorRelativeToAbsolute("https://github.com/noties/Markwon/raw/master/")`,
|
||||
then final image will have `https://github.com/noties/Markwon/raw/master/art/image.JPG`
|
||||
as the destination.
|
||||
|
||||
### UrlProcessorAndroidAssets
|
||||
|
||||
`UrlProcessorAndroidAssets` can be used to make processed links to point to Android assets folder.
|
||||
So an image: `` will have `file:///android_asset/art/image.JPG` as the
|
||||
destination.
|
||||
|
||||
:::tip
|
||||
Please note that `UrlProcessorAndroidAssets` will process only URLs that have no `scheme` information,
|
||||
so a `./art/image.png` will become `file:///android_asset/art/image.JPG` whilst `https://so.me/where.png`
|
||||
will be kept as-is.
|
||||
:::
|
||||
|
||||
:::warning
|
||||
In order to display an image from assets you still need to register `ImagesPlugin#createWithAssets(Context)`
|
||||
plugin in resulting `Markwon` instance. As `UrlProcessorAndroidAssets` only
|
||||
_processes_ URLs and doesn't take any part in displaying an image.
|
||||
:::
|
||||
|
||||
|
||||
## ImageSizeResolver
|
||||
|
||||
`ImageSizeResolver` controls the size of an image to be displayed. Currently it
|
||||
handles only HTML images (specified via `img` tag).
|
||||
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(this)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||
builder.imageSizeResolver(new ImageSizeResolver() {
|
||||
@NonNull
|
||||
@Override
|
||||
public Rect resolveImageSize(
|
||||
@Nullable ImageSize imageSize,
|
||||
@NonNull Rect imageBounds,
|
||||
int canvasWidth,
|
||||
float textSize) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
```
|
||||
|
||||
If not provided explicitly, default `ImageSizeResolverDef` implementation will be used.
|
||||
It handles 3 dimension units:
|
||||
* `%` (percent, relative to Canvas width)
|
||||
* `em` (relative to text size)
|
||||
* `px` (absolute size, every dimension that is not `%` or `em` is considered to be _absolute_)
|
||||
|
||||
```html
|
||||
<img width="100%">
|
||||
<img width="2em" height="10px">
|
||||
<img style="{width: 100%; height: 8em;}">
|
||||
```
|
||||
|
||||
`ImageSizeResolverDef` keeps the ratio of original image if one of the dimensions is missing.
|
||||
|
||||
:::warning Height%
|
||||
There is no support for `%` units for `height` dimension. This is due to the fact that
|
||||
height of an TextView in which markdown is displayed is non-stable and changes with time
|
||||
(for example when image is loaded and applied to a TextView it will _increase_ TextView's height),
|
||||
so we will have no point-of-reference from which to _calculate_ image height.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
`ImageSizeResolverDef` also takes care for an image to **not** exceed
|
||||
canvas width. If an image has greater width than a TextView Canvas, then
|
||||
image will be _scaled-down_ to fit the canvas. Please note that this rule
|
||||
applies only if image has no absolute sizes (for example width is specified
|
||||
in pixels).
|
||||
:::
|
||||
|
||||
## MarkwonHtmlParser
|
||||
|
||||
Specify which HTML parser to use. Default implementation is **no-op**.
|
||||
|
||||
:::warning
|
||||
One must explicitly use [HtmlPlugin](/docs/v3/html/) in order to display
|
||||
HTML content in markdown. Without specified HTML parser **no HTML content
|
||||
will be rendered**.
|
||||
|
||||
```java
|
||||
Markwon.builder(context)
|
||||
.usePlugin(HtmlPlugin.create())
|
||||
```
|
||||
|
||||
Please note that adding `HtmlPlugin` will take care of initializing parser,
|
||||
so after `HtmlPlugin` is used, no additional configuration steps are required.
|
||||
:::
|
@ -75,6 +75,8 @@ Beware of this if you would like to override only one of the list types. This is
|
||||
done to correspond to `commonmark-java` implementation.
|
||||
:::
|
||||
|
||||
More information about props can be found [here](/docs/v3/core/render-props.md)
|
||||
|
||||
---
|
||||
|
||||
:::tip Soft line break
|
||||
|
@ -113,6 +113,40 @@ be used.
|
||||
|
||||
## MediaDecoder
|
||||
|
||||
By default `core` artifact comes with _default image decoder_ only. It's called
|
||||
`ImageMediaDecoder` and it can decode all the formats that `BitmapFactory#decodeStream(InputStream)`
|
||||
can.
|
||||
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(this)
|
||||
.usePlugin(ImagesPlugin.create(this))
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
||||
builder.addMediaDecoder("text/plain", new TextPlainMediaDecoder());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
```
|
||||
|
||||
`MediaDecoder` is a class to turn `InputStream` into a `Drawable`:
|
||||
|
||||
```java
|
||||
public abstract class MediaDecoder {
|
||||
|
||||
@Nullable
|
||||
public abstract Drawable decode(@NonNull InputStream inputStream);
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
If you want to display GIF or SVG images also, you can use [image-gif](/docs/v3/image/gif.md)
|
||||
and [image-svg](/docs/v3/image/svg.md) modules.
|
||||
:::
|
||||
|
||||
##
|
||||
|
||||
:::tip
|
||||
If you are using [html](/docs/v3/html/) you do not have to additionally setup
|
||||
images displayed via `<img>` tag, as `HtmlPlugin` automatically uses configured
|
||||
|
@ -425,7 +425,7 @@ queried directly from a TextView.
|
||||
|
||||
## What happens underneath
|
||||
|
||||
Here is an approximation of how a `Markwon` instance will handle plugins:
|
||||
Here is what happens inside `Markwon` when `setMarkdown` method is called:
|
||||
|
||||
```java
|
||||
// `Markwon#create` implicitly uses CorePlugin
|
||||
|
75
docs/docs/v3/core/render-props.md
Normal file
75
docs/docs/v3/core/render-props.md
Normal file
@ -0,0 +1,75 @@
|
||||
# RenderProps <Badge text="3.0.0" />
|
||||
|
||||
`RenderProps` encapsulates passing arguments from a node visitor to a node renderer.
|
||||
Without hardcoding arguments into an API method calls.
|
||||
|
||||
`RenderProps` is the state collection for `Props` that are set by a node visitor and
|
||||
retrieved by a node renderer.
|
||||
|
||||
```java
|
||||
public class Prop<T> {
|
||||
|
||||
@NonNull
|
||||
public static <T> Prop<T> of(@NonNull String name) {
|
||||
return new Prop<>(name);
|
||||
}
|
||||
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
For example `CorePlugin` defines a _Heading level_ prop (inside `CoreProps` class):
|
||||
|
||||
```java
|
||||
public static final Prop<Integer> HEADING_LEVEL = Prop.of("heading-level");
|
||||
```
|
||||
|
||||
Then CorePlugin registers a `Heading` node visitor and applies heading value:
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.on(Heading.class, new MarkwonVisitor.NodeVisitor<Heading>() {
|
||||
@Override
|
||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) {
|
||||
|
||||
/* Heading node handling logic */
|
||||
|
||||
// set heading level
|
||||
CoreProps.HEADING_LEVEL.set(visitor.renderProps(), heading.getLevel());
|
||||
|
||||
// a helper method to apply span(s) for a node
|
||||
// (internally obtains a SpanFactory for Heading or silently ignores
|
||||
// this call if no factory for a Heading is registered)
|
||||
visitor.setSpansForNodeOptional(heading, start);
|
||||
|
||||
/* Heading node handling logic */
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
And finally `HeadingSpanFactory` (which is also registered by `CorePlugin`):
|
||||
|
||||
```java
|
||||
public class HeadingSpanFactory implements SpanFactory {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
|
||||
return new HeadingSpan(
|
||||
configuration.theme(),
|
||||
CoreProps.HEADING_LEVEL.require(props)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`Prop<T>` has these methods:
|
||||
|
||||
* `@Nullable T get(RenderProps)` - returns value stored in RenderProps or `null` if none is present
|
||||
* `@NonNull T get(RenderProps, @NonNull T defValue)` - returns value stored in RenderProps or default value (this method always return non-null value)
|
||||
* `@NonNull T require(RenderProps)` - returns value stored in RenderProps or _throws an exception_ if none is present
|
||||
* `void set(RenderProps, @Nullable T value)` - updates value stored in RenderProps, passing `null` as value is the same as calling `clear`
|
||||
* `void clear(RenderProps)` - clears value stored in RenderProps
|
@ -1 +1,73 @@
|
||||
# Visitor
|
||||
# Visitor
|
||||
|
||||
Starting with <Badge text="3.0.0" /> _visiting_ of parsed markdown
|
||||
nodes does not require creating own instance of commonmark-java `Visitor`,
|
||||
instead a composable/configurable `MarkwonVisitor` is used.
|
||||
|
||||
## Visitor.Builder
|
||||
There is no need to create own instance of `MarkwonVisitor.Builder` as
|
||||
it is done by `Markwon` itself. One still can configure it as one wishes:
|
||||
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(contex)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.on(SoftLineBreak.class, new MarkwonVisitor.NodeVisitor<SoftLineBreak>() {
|
||||
@Override
|
||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull SoftLineBreak softLineBreak) {
|
||||
visitor.forceNewLine();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`MarkwonVisitor` encapsulates most of the functionality of rendering parsed markdown.
|
||||
|
||||
It holds rendering configuration:
|
||||
* `MarkwonVisitor#configuration` - getter for current [MarkwonConfiguration](/docs/v3/core/configuration.md)
|
||||
* `MarkwonVisitor#renderProps` - getter for current [RenderProps](/docs/v3/core/render-props.md)
|
||||
* `MarkwonVisitor#builder` - getter for current `SpannableBuilder`
|
||||
|
||||
It contains also a number of utility functions:
|
||||
* `visitChildren(Node)` - will visit all children of supplied Node
|
||||
* `hasNext(Node)` - utility function to check if supplied Node has a Node after it (useful for white-space management, so there should be no blank new line after last BlockNode)
|
||||
* `ensureNewLine` - will insert a new line at current `SpannableBuilder` position only if current (last) character is not a new-line
|
||||
* `forceNewLine` - will insert a new line character without any condition checking
|
||||
* `length` - helper function to call `visitor.builder().length()`, returns current length of `SpannableBuilder`
|
||||
* `clear` - will clear state for `RenderProps` and `SpannableBuilder`, this is done by `Markwon` automatically after each render call
|
||||
|
||||
And some utility functions to control the spans:
|
||||
* `setSpans(int start, Object spans)` - will apply supplied `spans` on `SpannableBuilder` starting at `start` position and ending at `SpannableBuilder#length`. `spans` can be `null` (no spans will be applied) or an array of spans (each span of this array will be applied)
|
||||
* `setSpansForNodeOptional(N node, int start)` - helper method to set spans for specified `node` (internally obtains `SpanFactory` for that node and uses it to apply spans)
|
||||
* `setSpansForNode(N node, int start)` - almost the same as `setSpansForNodeOptional` but instead of silently ignoring call if none `SpanFactory` is registered, this method will throw an exception.
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.on(Heading.class, new MarkwonVisitor.NodeVisitor<Heading>() {
|
||||
@Override
|
||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) {
|
||||
|
||||
// or just `visitor.length()`
|
||||
final int start = visitor.builder().length();
|
||||
|
||||
visitor.visitChildren(heading);
|
||||
|
||||
// or just `visitor.setSpansForNodeOptional(heading, start)`
|
||||
final SpanFactory factory = visitor.configuration().spansFactory().get(heading.getClass());
|
||||
if (factory != null) {
|
||||
visitor.setSpans(start, factory.getSpans(visitor.configuration(), visitor.renderProps()));
|
||||
}
|
||||
|
||||
if (visitor.hasNext(heading)) {
|
||||
visitor.ensureNewLine();
|
||||
visitor.forceNewLine();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
@ -79,6 +79,11 @@ public interface MarkwonVisitor extends Visitor {
|
||||
*/
|
||||
int length();
|
||||
|
||||
/**
|
||||
* Clears state of visitor (both {@link RenderProps} and {@link SpannableBuilder} will be cleared
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Sets <code>spans</code> to underlying {@link SpannableBuilder} from <em>start</em>
|
||||
* to <em>{@link SpannableBuilder#length()}</em>.
|
||||
@ -88,11 +93,6 @@ public interface MarkwonVisitor extends Visitor {
|
||||
*/
|
||||
void setSpans(int start, @Nullable Object spans);
|
||||
|
||||
/**
|
||||
* Clears state of visitor (both {@link RenderProps} and {@link SpannableBuilder} will be cleared
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Helper method to obtain and apply spans for supplied Node. Internally queries {@link SpanFactory}
|
||||
* for the node (via {@link MarkwonSpansFactory#require(Class)} thus throwing an exception
|
||||
|
@ -0,0 +1,110 @@
|
||||
package ru.noties.markwon.utils;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.commonmark.node.Block;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.node.Visitor;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
// utility class to print parsed Nodes hierarchy
|
||||
public abstract class DumpNodes {
|
||||
|
||||
public interface NodeProcessor {
|
||||
@NonNull
|
||||
String process(@NonNull Node node);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String dump(@NonNull Node node) {
|
||||
return dump(node, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String dump(@NonNull Node node, @Nullable NodeProcessor nodeProcessor) {
|
||||
|
||||
final NodeProcessor processor = nodeProcessor != null
|
||||
? nodeProcessor
|
||||
: new NodeProcessorToString();
|
||||
|
||||
final Indent indent = new Indent();
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final Visitor visitor = (Visitor) Proxy.newProxyInstance(
|
||||
Visitor.class.getClassLoader(),
|
||||
new Class[]{Visitor.class},
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
|
||||
final Node argument = (Node) args[0];
|
||||
|
||||
// initial indent
|
||||
indent.appendTo(builder);
|
||||
|
||||
// node info
|
||||
builder.append(processor.process(argument));
|
||||
|
||||
if (argument instanceof Block) {
|
||||
builder.append(" [\n");
|
||||
indent.increment();
|
||||
visitChildren((Visitor) proxy, argument);
|
||||
indent.decrement();
|
||||
indent.appendTo(builder);
|
||||
builder.append("]\n");
|
||||
} else {
|
||||
builder.append('\n');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
node.accept(visitor);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private DumpNodes() {
|
||||
}
|
||||
|
||||
private static class Indent {
|
||||
|
||||
private int count;
|
||||
|
||||
void increment() {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
void decrement() {
|
||||
count -= 1;
|
||||
}
|
||||
|
||||
void appendTo(@NonNull StringBuilder builder) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
builder
|
||||
.append(' ')
|
||||
.append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void visitChildren(@NonNull Visitor visitor, @NonNull Node parent) {
|
||||
Node node = parent.getFirstChild();
|
||||
while (node != null) {
|
||||
// A subclass of this visitor might modify the node, resulting in getNext returning a different node or no
|
||||
// node after visiting it. So get the next node before visiting.
|
||||
Node next = node.getNext();
|
||||
node.accept(visitor);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NodeProcessorToString implements NodeProcessor {
|
||||
@NonNull
|
||||
@Override
|
||||
public String process(@NonNull Node node) {
|
||||
return node.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,8 @@ import android.text.TextUtils;
|
||||
import org.commonmark.ext.gfm.tables.TableBlock;
|
||||
import org.commonmark.ext.gfm.tables.TablesExtension;
|
||||
import org.commonmark.node.FencedCodeBlock;
|
||||
import org.commonmark.node.Heading;
|
||||
import org.commonmark.node.SoftLineBreak;
|
||||
import org.commonmark.parser.Parser;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@ -27,7 +29,9 @@ import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||
import ru.noties.markwon.Markwon;
|
||||
import ru.noties.markwon.MarkwonConfiguration;
|
||||
import ru.noties.markwon.MarkwonVisitor;
|
||||
import ru.noties.markwon.SpanFactory;
|
||||
import ru.noties.markwon.core.CorePlugin;
|
||||
import ru.noties.markwon.core.CoreProps;
|
||||
import ru.noties.markwon.html.HtmlPlugin;
|
||||
import ru.noties.markwon.image.ImagesPlugin;
|
||||
import ru.noties.markwon.image.svg.SvgPlugin;
|
||||
@ -48,6 +52,36 @@ public class RecyclerActivity extends Activity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_recycler);
|
||||
|
||||
{
|
||||
final Markwon markwon = Markwon.builder(contex)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.on(Heading.class, new MarkwonVisitor.NodeVisitor<Heading>() {
|
||||
@Override
|
||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) {
|
||||
|
||||
// or just `visitor.length()`
|
||||
final int start = visitor.builder().length();
|
||||
|
||||
visitor.visitChildren(heading);
|
||||
|
||||
// or just `visitor.setSpansForNodeOptional(heading, start)`
|
||||
final SpanFactory factory = visitor.configuration().spansFactory().get(heading.getClass());
|
||||
if (factory != null) {
|
||||
visitor.setSpans(start, factory.getSpans(visitor.configuration(), visitor.renderProps()));
|
||||
}
|
||||
|
||||
if (visitor.hasNext(heading)) {
|
||||
visitor.ensureNewLine();
|
||||
visitor.forceNewLine();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// create MarkwonAdapter and register two blocks that will be rendered differently
|
||||
// * fenced code block (can also specify the same Entry for indended code block)
|
||||
// * table block
|
||||
|
Loading…
x
Reference in New Issue
Block a user