Adding javadoc documentation (work in progress)
This commit is contained in:
parent
ef15ee4bd2
commit
286dd5410a
@ -1,13 +0,0 @@
|
|||||||
apply plugin: 'java-library'
|
|
||||||
|
|
||||||
sourceCompatibility = 1.7
|
|
||||||
targetCompatibility = 1.7
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
|
|
||||||
api deps['support-annotations']
|
|
||||||
|
|
||||||
deps['test'].with {
|
|
||||||
implementation it['commons-io']
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
package ru.noties.markwon.test;
|
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public abstract class TestUtil {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String read(@NonNull String path) {
|
|
||||||
try {
|
|
||||||
return IOUtils.resourceToString(path, StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String read(@NonNull Object who, @NonNull String path) {
|
|
||||||
try {
|
|
||||||
return IOUtils.resourceToString(path, StandardCharsets.UTF_8, who.getClass().getClassLoader());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TestUtil() {
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,17 +23,12 @@ dependencies {
|
|||||||
deps['test'].with {
|
deps['test'].with {
|
||||||
|
|
||||||
testImplementation project(':markwon-test-span')
|
testImplementation project(':markwon-test-span')
|
||||||
testImplementation project(':markwon-test-util')
|
|
||||||
|
|
||||||
testImplementation it['junit']
|
testImplementation it['junit']
|
||||||
testImplementation it['robolectric']
|
testImplementation it['robolectric']
|
||||||
testImplementation it['mockito']
|
testImplementation it['mockito']
|
||||||
|
|
||||||
// to remove after migration
|
|
||||||
testImplementation it['ix-java']
|
testImplementation it['ix-java']
|
||||||
testImplementation it['jackson-yaml']
|
|
||||||
testImplementation it['jackson-databind']
|
|
||||||
testImplementation it['gson']
|
|
||||||
testImplementation it['commons-io']
|
testImplementation it['commons-io']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ru.noties.markwon;
|
package ru.noties.markwon;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
@ -9,63 +10,107 @@ import org.commonmark.parser.Parser;
|
|||||||
import ru.noties.markwon.core.MarkwonTheme;
|
import ru.noties.markwon.core.MarkwonTheme;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that extends {@link MarkwonPlugin} with all methods implemented (empty body)
|
||||||
|
* for easier plugin implementation. Only required methods can be overriden
|
||||||
|
*
|
||||||
|
* @see MarkwonPlugin
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
public abstract class AbstractMarkwonPlugin implements MarkwonPlugin {
|
public abstract class AbstractMarkwonPlugin implements MarkwonPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configureParser(@NonNull Parser.Builder builder) {
|
public void configureParser(@NonNull Parser.Builder builder) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
|
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configureRenderProps(@NonNull RenderProps renderProps) {
|
public void configureRenderProps(@NonNull RenderProps renderProps) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String processMarkdown(@NonNull String markdown) {
|
public String processMarkdown(@NonNull String markdown) {
|
||||||
return markdown;
|
return markdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void beforeRender(@NonNull Node node) {
|
public void beforeRender(@NonNull Node node) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) {
|
public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown) {
|
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterSetText(@NonNull TextView textView) {
|
public void afterSetText(@NonNull TextView textView) {
|
||||||
|
|
||||||
|
@ -7,9 +7,20 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to parse and render markdown. Since version 3.0.0 instance specific (previously consisted
|
||||||
|
* of static stateless methods). An instance of builder can be obtained via {@link #builder(Context)}
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @see #builder(Context)
|
||||||
|
* @see Builder
|
||||||
|
*/
|
||||||
public abstract class Markwon {
|
public abstract class Markwon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Factory method to obtain an instance of {@link Builder}
|
||||||
|
*
|
||||||
|
* @see Builder
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -17,6 +28,14 @@ public abstract class Markwon {
|
|||||||
return new MarkwonBuilderImpl(context);
|
return new MarkwonBuilderImpl(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to simply parse markdown (without rendering)
|
||||||
|
*
|
||||||
|
* @param input markdown input to parse
|
||||||
|
* @return parsed via commonmark-java <code>org.commonmark.node.Node</code>
|
||||||
|
* @see #render(Node)
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public abstract Node parse(@NonNull String input);
|
public abstract Node parse(@NonNull String input);
|
||||||
|
|
||||||
@ -29,9 +48,14 @@ public abstract class Markwon {
|
|||||||
|
|
||||||
public abstract void setMarkdown(@NonNull TextView textView, @NonNull String markdown);
|
public abstract void setMarkdown(@NonNull TextView textView, @NonNull String markdown);
|
||||||
|
|
||||||
public abstract void setParsedMarkdown(@NonNull TextView textView, @NonNull CharSequence markdown);
|
public abstract void setParsedMarkdown(@NonNull TextView textView, @NonNull Spanned markdown);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Builder for {@link Markwon}.
|
||||||
|
* <p>
|
||||||
|
* Please note that the order in which plugins are supplied is important as this order will be
|
||||||
|
* used through the whole usage of built Markwon instance
|
||||||
|
*
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public interface Builder {
|
public interface Builder {
|
||||||
|
@ -80,7 +80,6 @@ class MarkwonBuilderImpl implements Markwon.Builder {
|
|||||||
plugin.configureConfiguration(configurationBuilder);
|
plugin.configureConfiguration(configurationBuilder);
|
||||||
plugin.configureVisitor(visitorBuilder);
|
plugin.configureVisitor(visitorBuilder);
|
||||||
plugin.configureSpansFactory(spanFactoryBuilder);
|
plugin.configureSpansFactory(spanFactoryBuilder);
|
||||||
plugin.configureRenderProps(renderProps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final MarkwonConfiguration configuration = configurationBuilder.build(
|
final MarkwonConfiguration configuration = configurationBuilder.build(
|
||||||
|
@ -9,6 +9,9 @@ import org.commonmark.parser.Parser;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
class MarkwonImpl extends Markwon {
|
class MarkwonImpl extends Markwon {
|
||||||
|
|
||||||
private final TextView.BufferType bufferType;
|
private final TextView.BufferType bufferType;
|
||||||
@ -31,6 +34,7 @@ class MarkwonImpl extends Markwon {
|
|||||||
@Override
|
@Override
|
||||||
public Node parse(@NonNull String input) {
|
public Node parse(@NonNull String input) {
|
||||||
|
|
||||||
|
// make sure that all plugins are called `processMarkdown` before parsing
|
||||||
for (MarkwonPlugin plugin : plugins) {
|
for (MarkwonPlugin plugin : plugins) {
|
||||||
input = plugin.processMarkdown(input);
|
input = plugin.processMarkdown(input);
|
||||||
}
|
}
|
||||||
@ -42,7 +46,14 @@ class MarkwonImpl extends Markwon {
|
|||||||
@Override
|
@Override
|
||||||
public Spanned render(@NonNull Node node) {
|
public Spanned render(@NonNull Node node) {
|
||||||
|
|
||||||
|
final RenderProps renderProps = visitor.renderProps();
|
||||||
|
|
||||||
for (MarkwonPlugin plugin : plugins) {
|
for (MarkwonPlugin plugin : plugins) {
|
||||||
|
|
||||||
|
// let plugins apply render properties before rendering (as we will clear
|
||||||
|
// renderProps after rendering)
|
||||||
|
plugin.configureRenderProps(renderProps);
|
||||||
|
|
||||||
plugin.beforeRender(node);
|
plugin.beforeRender(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +63,9 @@ class MarkwonImpl extends Markwon {
|
|||||||
plugin.afterRender(node, visitor);
|
plugin.afterRender(node, visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear render props after rending
|
||||||
|
renderProps.clearAll();
|
||||||
|
|
||||||
return visitor.builder().spannableStringBuilder();
|
return visitor.builder().spannableStringBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +81,7 @@ class MarkwonImpl extends Markwon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setParsedMarkdown(@NonNull TextView textView, @NonNull CharSequence markdown) {
|
public void setParsedMarkdown(@NonNull TextView textView, @NonNull Spanned markdown) {
|
||||||
|
|
||||||
for (MarkwonPlugin plugin : plugins) {
|
for (MarkwonPlugin plugin : plugins) {
|
||||||
plugin.beforeSetText(textView, markdown);
|
plugin.beforeSetText(textView, markdown);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ru.noties.markwon;
|
package ru.noties.markwon;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
@ -8,38 +9,137 @@ import org.commonmark.parser.Parser;
|
|||||||
|
|
||||||
import ru.noties.markwon.core.MarkwonTheme;
|
import ru.noties.markwon.core.MarkwonTheme;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
|
import ru.noties.markwon.image.MediaDecoder;
|
||||||
|
import ru.noties.markwon.image.SchemeHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Class represents a plugin (extension) to Markwon to configure how parsing and rendering
|
||||||
|
* of markdown is carried on.
|
||||||
|
*
|
||||||
|
* @see AbstractMarkwonPlugin
|
||||||
|
* @see ru.noties.markwon.core.CorePlugin
|
||||||
|
* @see ru.noties.markwon.image.ImagesPlugin
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public interface MarkwonPlugin {
|
public interface MarkwonPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to configure <code>org.commonmark.parser.Parser</code> (for example register custom
|
||||||
|
* extension, etc).
|
||||||
|
*/
|
||||||
void configureParser(@NonNull Parser.Builder builder);
|
void configureParser(@NonNull Parser.Builder builder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify {@link MarkwonTheme} that is used for rendering of markdown.
|
||||||
|
*
|
||||||
|
* @see MarkwonTheme
|
||||||
|
* @see MarkwonTheme.Builder
|
||||||
|
*/
|
||||||
void configureTheme(@NonNull MarkwonTheme.Builder builder);
|
void configureTheme(@NonNull MarkwonTheme.Builder builder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure image loading functionality. For example add new content-types
|
||||||
|
* {@link AsyncDrawableLoader.Builder#addMediaDecoder(String, MediaDecoder)}, a transport
|
||||||
|
* layer (network, file, etc) {@link AsyncDrawableLoader.Builder#addSchemeHandler(String, SchemeHandler)}
|
||||||
|
* or modify existing properties.
|
||||||
|
*
|
||||||
|
* @see AsyncDrawableLoader
|
||||||
|
* @see AsyncDrawableLoader.Builder
|
||||||
|
*/
|
||||||
void configureImages(@NonNull AsyncDrawableLoader.Builder builder);
|
void configureImages(@NonNull AsyncDrawableLoader.Builder builder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure {@link MarkwonConfiguration}
|
||||||
|
*
|
||||||
|
* @see MarkwonConfiguration
|
||||||
|
* @see MarkwonConfiguration.Builder
|
||||||
|
*/
|
||||||
void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder);
|
void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure {@link MarkwonVisitor} to accept new node types or override already registered nodes.
|
||||||
|
*
|
||||||
|
* @see MarkwonVisitor
|
||||||
|
* @see MarkwonVisitor.Builder
|
||||||
|
*/
|
||||||
void configureVisitor(@NonNull MarkwonVisitor.Builder builder);
|
void configureVisitor(@NonNull MarkwonVisitor.Builder builder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure {@link MarkwonSpansFactory} to change what spans are used for certain node types.
|
||||||
|
*
|
||||||
|
* @see MarkwonSpansFactory
|
||||||
|
* @see MarkwonSpansFactory.Builder
|
||||||
|
*/
|
||||||
void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder);
|
void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder);
|
||||||
|
|
||||||
// can be used to configure own properties and use between plugins
|
// can be used to configure own properties and use between plugins
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method to store some arbitrary data in {@link RenderProps}. Although it won\'t make
|
||||||
|
* much sense to use existing {@link Prop} keys for {@link SpanFactory}, it can be helpful
|
||||||
|
* to establish a communication channel between multiple plugins in decoupled way (provide
|
||||||
|
* some initial properties for example or indicate that certain plugin is registered).
|
||||||
|
* <p>
|
||||||
|
* This method will be called before <em>each</em> rendering step (after rendering {@link RenderProps}
|
||||||
|
* will be cleared. This method <strong>won\'t</strong> be called during initialization stage.
|
||||||
|
*
|
||||||
|
* @see RenderProps
|
||||||
|
*/
|
||||||
void configureRenderProps(@NonNull RenderProps renderProps);
|
void configureRenderProps(@NonNull RenderProps renderProps);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process input markdown and return new string to be used in parsing stage further.
|
||||||
|
* Can be described as <code>pre-processing</code> of markdown String.
|
||||||
|
*
|
||||||
|
* @param markdown String to process
|
||||||
|
* @return processed markdown String
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
String processMarkdown(@NonNull String markdown);
|
String processMarkdown(@NonNull String markdown);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will be called <strong>before</strong> rendering will occur thus making possible
|
||||||
|
* to <code>post-process</code> parsed node (make changes for example).
|
||||||
|
*
|
||||||
|
* @param node root parsed org.commonmark.node.Node
|
||||||
|
*/
|
||||||
void beforeRender(@NonNull Node node);
|
void beforeRender(@NonNull Node node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will be called <strong>after</strong> rendering (but before applying markdown to a
|
||||||
|
* TextView, if such action will happen). It can be used to clean some
|
||||||
|
* internal state, or trigger certain action. Please note that modifying <code>node</code> won\'t
|
||||||
|
* have any effect as it has been already <i>visited</i> at this stage.
|
||||||
|
*
|
||||||
|
* @param node root parsed org.commonmark.node.Node
|
||||||
|
* @param visitor {@link MarkwonVisitor} instance used to render markdown
|
||||||
|
*/
|
||||||
void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor);
|
void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor);
|
||||||
|
|
||||||
void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown);
|
/**
|
||||||
|
* This method will be called <strong>before</strong> calling <code>TextView#setText</code>.
|
||||||
|
* <p>
|
||||||
|
* It can be useful to prepare a TextView for markdown. For example {@link ru.noties.markwon.image.ImagesPlugin}
|
||||||
|
* uses this method to unregister previously registered {@link ru.noties.markwon.image.AsyncDrawableSpan}
|
||||||
|
* (if there are such spans in this TextView at this point). Or {@link ru.noties.markwon.core.CorePlugin}
|
||||||
|
* which measures ordered list numbers
|
||||||
|
*
|
||||||
|
* @param textView TextView to which <code>markdown</code> will be applied
|
||||||
|
* @param markdown Parsed markdown
|
||||||
|
*/
|
||||||
|
void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown);
|
||||||
|
|
||||||
// this method do not receive markdown like `beforeSetText` does because at this
|
/**
|
||||||
// point TextView already has markdown set and to manipulate spans one must
|
* This method will be called <strong>after</strong> markdown was applied.
|
||||||
// request them from TextView (getText())
|
* <p>
|
||||||
|
* It can be useful to trigger certain action on spans/textView. For example {@link ru.noties.markwon.image.ImagesPlugin}
|
||||||
|
* uses this method to register {@link ru.noties.markwon.image.AsyncDrawableSpan} and start
|
||||||
|
* asynchronously loading images.
|
||||||
|
* <p>
|
||||||
|
* Unlike {@link #beforeSetText(TextView, Spanned)} this method does not receive parsed markdown
|
||||||
|
* as at this point spans must be queried by calling <code>TextView#getText#getSpans</code>.
|
||||||
|
*
|
||||||
|
* @param textView TextView to which markdown was applied
|
||||||
|
*/
|
||||||
void afterSetText(@NonNull TextView textView);
|
void afterSetText(@NonNull TextView textView);
|
||||||
}
|
}
|
||||||
|
@ -6,27 +6,46 @@ import android.support.annotation.Nullable;
|
|||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Class that controls what spans are used for certain Nodes.
|
||||||
|
*
|
||||||
|
* @see SpanFactory
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public interface MarkwonSpansFactory {
|
public interface MarkwonSpansFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns registered {@link SpanFactory} or <code>null</code> if a factory for this node type
|
||||||
|
* is not registered. There is {@link #require(Class)} method that will throw an exception
|
||||||
|
* if required {@link SpanFactory} is not registered, thus making return type <code>non-null</code>
|
||||||
|
*
|
||||||
|
* @param node type of the node
|
||||||
|
* @return registered {@link SpanFactory} or null if it\'s not registered
|
||||||
|
* @see #require(Class)
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
<N extends Node, F extends SpanFactory> F get(@NonNull Class<N> node);
|
<N extends Node> SpanFactory get(@NonNull Class<N> node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #get(Class)
|
||||||
|
* @see #require(Node)
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
<N extends Node, F extends SpanFactory> F get(@NonNull N node);
|
<N extends Node> SpanFactory get(@NonNull N node);
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
<N extends Node, F extends SpanFactory> F require(@NonNull Class<N> node);
|
<N extends Node> SpanFactory require(@NonNull Class<N> node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #require(Class)
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
<N extends Node, F extends SpanFactory> F require(@NonNull N node);
|
<N extends Node> SpanFactory require(@NonNull N node);
|
||||||
|
|
||||||
|
|
||||||
interface Builder {
|
interface Builder {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
<N extends Node, F extends SpanFactory> Builder setFactory(@NonNull Class<N> node, @NonNull F factory);
|
<N extends Node> Builder setFactory(@NonNull Class<N> node, @NonNull SpanFactory factory);
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
MarkwonSpansFactory build();
|
MarkwonSpansFactory build();
|
||||||
|
@ -22,21 +22,20 @@ class MarkwonSpansFactoryImpl implements MarkwonSpansFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <N extends Node, F extends SpanFactory> F get(@NonNull Class<N> node) {
|
public <N extends Node> SpanFactory get(@NonNull Class<N> node) {
|
||||||
//noinspection unchecked
|
return factories.get(node);
|
||||||
return (F) factories.get(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <N extends Node, F extends SpanFactory> F get(@NonNull N node) {
|
public <N extends Node> SpanFactory get(@NonNull N node) {
|
||||||
return get(node.getClass());
|
return get(node.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public <N extends Node, F extends SpanFactory> F require(@NonNull Class<N> node) {
|
public <N extends Node> SpanFactory require(@NonNull Class<N> node) {
|
||||||
final F f = get(node);
|
final SpanFactory f = get(node);
|
||||||
if (f == null) {
|
if (f == null) {
|
||||||
throw new NullPointerException();
|
throw new NullPointerException();
|
||||||
}
|
}
|
||||||
@ -45,8 +44,8 @@ class MarkwonSpansFactoryImpl implements MarkwonSpansFactory {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public <N extends Node, F extends SpanFactory> F require(@NonNull N node) {
|
public <N extends Node> SpanFactory require(@NonNull N node) {
|
||||||
final F f = get(node);
|
final SpanFactory f = get(node);
|
||||||
if (f == null) {
|
if (f == null) {
|
||||||
throw new NullPointerException();
|
throw new NullPointerException();
|
||||||
}
|
}
|
||||||
@ -60,7 +59,7 @@ class MarkwonSpansFactoryImpl implements MarkwonSpansFactory {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public <N extends Node, F extends SpanFactory> Builder setFactory(@NonNull Class<N> node, @NonNull F factory) {
|
public <N extends Node> Builder setFactory(@NonNull Class<N> node, @NonNull SpanFactory factory) {
|
||||||
factories.put(node, factory);
|
factories.put(node, factory);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,29 @@ import org.commonmark.node.Node;
|
|||||||
import org.commonmark.node.Visitor;
|
import org.commonmark.node.Visitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Configurable visitor of parsed markdown. Allows visiting certain (registered) nodes without
|
||||||
|
* need to create own instance of this class.
|
||||||
|
*
|
||||||
|
* @see Builder#on(Class, NodeVisitor)
|
||||||
|
* @see MarkwonPlugin#configureVisitor(Builder)
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public interface MarkwonVisitor extends Visitor {
|
public interface MarkwonVisitor extends Visitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Builder#on(Class, NodeVisitor)
|
||||||
|
*/
|
||||||
interface NodeVisitor<N extends Node> {
|
interface NodeVisitor<N extends Node> {
|
||||||
void visit(@NonNull MarkwonVisitor visitor, @NonNull N n);
|
void visit(@NonNull MarkwonVisitor visitor, @NonNull N n);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Builder {
|
interface Builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param node to register
|
||||||
|
* @param nodeVisitor {@link NodeVisitor} to be used or null to ignore previously registered
|
||||||
|
* visitor for this node
|
||||||
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
<N extends Node> Builder on(@NonNull Class<N> node, @Nullable NodeVisitor<? super N> nodeVisitor);
|
<N extends Node> Builder on(@NonNull Class<N> node, @Nullable NodeVisitor<? super N> nodeVisitor);
|
||||||
|
|
||||||
@ -33,26 +46,86 @@ public interface MarkwonVisitor extends Visitor {
|
|||||||
@NonNull
|
@NonNull
|
||||||
SpannableBuilder builder();
|
SpannableBuilder builder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits all children of supplied node.
|
||||||
|
*
|
||||||
|
* @param node to visit
|
||||||
|
*/
|
||||||
void visitChildren(@NonNull Node node);
|
void visitChildren(@NonNull Node node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a check if there is further content available.
|
||||||
|
*
|
||||||
|
* @param node to check
|
||||||
|
* @return boolean indicating if there are more nodes after supplied one
|
||||||
|
*/
|
||||||
boolean hasNext(@NonNull Node node);
|
boolean hasNext(@NonNull Node node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method <strong>ensures</strong> that further content will start at a new line. If current
|
||||||
|
* last character is already a new line, then it won\'t do anything.
|
||||||
|
*/
|
||||||
void ensureNewLine();
|
void ensureNewLine();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method inserts a new line without any condition checking (unlike {@link #ensureNewLine()}).
|
||||||
|
*/
|
||||||
void forceNewLine();
|
void forceNewLine();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to call <code>builder().length()</code>
|
||||||
|
*
|
||||||
|
* @return current length of underlying {@link SpannableBuilder}
|
||||||
|
*/
|
||||||
int length();
|
int length();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets <code>spans</code> to underlying {@link SpannableBuilder} from <em>start</em>
|
||||||
|
* to <em>{@link SpannableBuilder#length()}</em>.
|
||||||
|
*
|
||||||
|
* @param start start position of spans
|
||||||
|
* @param spans to apply
|
||||||
|
*/
|
||||||
void setSpans(int start, @Nullable Object spans);
|
void setSpans(int start, @Nullable Object spans);
|
||||||
|
|
||||||
// will automatically obtain SpanFactory instance and use it, it no SpanFactory is registered,
|
/**
|
||||||
// will throw, if not desired use setSpansForNodeOptional
|
* Helper method to obtain and apply spans for supplied Node. Internally queries {@link SpanFactory}
|
||||||
|
* for the node (via {@link MarkwonSpansFactory#require(Node)} thus throwing an exception
|
||||||
|
* if there is no {@link SpanFactory} registered for the node).
|
||||||
|
*
|
||||||
|
* @param node to retrieve {@link SpanFactory} for
|
||||||
|
* @param start start position for further {@link #setSpans(int, Object)} call
|
||||||
|
* @see #setSpansForNodeOptional(Node, int)
|
||||||
|
*/
|
||||||
<N extends Node> void setSpansForNode(@NonNull N node, int start);
|
<N extends Node> void setSpansForNode(@NonNull N node, int start);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The same as {@link #setSpansForNode(Node, int)} but can be used in situations when there is
|
||||||
|
* no access to a Node instance (for example in HTML rendering which doesn\'t have markdown Nodes).
|
||||||
|
*
|
||||||
|
* @see #setSpansForNode(Node, int)
|
||||||
|
*/
|
||||||
<N extends Node> void setSpansForNode(@NonNull Class<N> node, int start);
|
<N extends Node> void setSpansForNode(@NonNull Class<N> node, int start);
|
||||||
|
|
||||||
// does not throw if there is no SpanFactory registered for this node
|
// does not throw if there is no SpanFactory registered for this node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to apply spans from a {@link SpanFactory} <b>if</b> it\'s registered in
|
||||||
|
* {@link MarkwonSpansFactory} instance. Otherwise ignores this call (no spans will be applied).
|
||||||
|
* If there is a need to ensure that specified <code>node</code> has a {@link SpanFactory} registered,
|
||||||
|
* then {@link #setSpansForNode(Node, int)} can be used. {@link #setSpansForNode(Node, int)} internally
|
||||||
|
* uses {@link MarkwonSpansFactory#require(Node)}. This method uses {@link MarkwonSpansFactory#get(Node)}.
|
||||||
|
*
|
||||||
|
* @see #setSpansForNode(Node, int)
|
||||||
|
*/
|
||||||
<N extends Node> void setSpansForNodeOptional(@NonNull N node, int start);
|
<N extends Node> void setSpansForNodeOptional(@NonNull N node, int start);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The same as {@link #setSpansForNodeOptional(Node, int)} but can be used in situations when
|
||||||
|
* there is no access to a Node instance (for example in HTML rendering).
|
||||||
|
*
|
||||||
|
* @see #setSpansForNodeOptional(Node, int)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
<N extends Node> void setSpansForNodeOptional(@NonNull Class<N> node, int start);
|
<N extends Node> void setSpansForNodeOptional(@NonNull Class<N> node, int start);
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,11 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to hold data in {@link RenderProps}
|
* Class to hold data in {@link RenderProps}. Represents a certain <em>property</em>.
|
||||||
*
|
*
|
||||||
* @param <T> represents the type that this instance holds
|
* @param <T> represents the type that this instance holds
|
||||||
|
* @see #of(String)
|
||||||
|
* @see #of(Class, String)
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public final class Prop<T> {
|
public final class Prop<T> {
|
||||||
|
@ -17,4 +17,6 @@ public interface RenderProps {
|
|||||||
<T> void set(@NonNull Prop<T> prop, @Nullable T value);
|
<T> void set(@NonNull Prop<T> prop, @Nullable T value);
|
||||||
|
|
||||||
<T> void clear(@NonNull Prop<T> prop);
|
<T> void clear(@NonNull Prop<T> prop);
|
||||||
|
|
||||||
|
void clearAll();
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ public class RenderPropsImpl implements RenderProps {
|
|||||||
values.remove(prop);
|
values.remove(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void clearAll() {
|
public void clearAll() {
|
||||||
values.clear();
|
values.clear();
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package ru.noties.markwon.core;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.commonmark.node.BlockQuote;
|
import org.commonmark.node.BlockQuote;
|
||||||
@ -104,7 +105,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown) {
|
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
|
||||||
OrderedListItemSpan.measure(textView, markdown);
|
OrderedListItemSpan.measure(textView, markdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +124,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull StrongEmphasis strongEmphasis) {
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull StrongEmphasis strongEmphasis) {
|
||||||
final int length = visitor.length();
|
final int length = visitor.length();
|
||||||
visitor.visitChildren(strongEmphasis);
|
visitor.visitChildren(strongEmphasis);
|
||||||
visitor.setSpansForNode(strongEmphasis, length);
|
visitor.setSpansForNodeOptional(strongEmphasis, length);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -134,7 +135,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Emphasis emphasis) {
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Emphasis emphasis) {
|
||||||
final int length = visitor.length();
|
final int length = visitor.length();
|
||||||
visitor.visitChildren(emphasis);
|
visitor.visitChildren(emphasis);
|
||||||
visitor.setSpansForNode(emphasis, length);
|
visitor.setSpansForNodeOptional(emphasis, length);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -149,7 +150,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
final int length = visitor.length();
|
final int length = visitor.length();
|
||||||
|
|
||||||
visitor.visitChildren(blockQuote);
|
visitor.visitChildren(blockQuote);
|
||||||
visitor.setSpansForNode(blockQuote, length);
|
visitor.setSpansForNodeOptional(blockQuote, length);
|
||||||
|
|
||||||
if (visitor.hasNext(blockQuote)) {
|
if (visitor.hasNext(blockQuote)) {
|
||||||
visitor.ensureNewLine();
|
visitor.ensureNewLine();
|
||||||
@ -173,7 +174,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
.append(code.getLiteral())
|
.append(code.getLiteral())
|
||||||
.append('\u00a0');
|
.append('\u00a0');
|
||||||
|
|
||||||
visitor.setSpansForNode(code, length);
|
visitor.setSpansForNodeOptional(code, length);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -215,7 +216,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
visitor.builder().append('\u00a0');
|
visitor.builder().append('\u00a0');
|
||||||
|
|
||||||
visitor.setSpansForNode(node, length);
|
visitor.setSpansForNodeOptional(node, length);
|
||||||
|
|
||||||
if (visitor.hasNext(node)) {
|
if (visitor.hasNext(node)) {
|
||||||
visitor.ensureNewLine();
|
visitor.ensureNewLine();
|
||||||
@ -260,7 +261,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
CoreProps.BULLET_LIST_ITEM_LEVEL.set(visitor.renderProps(), listLevel(listItem));
|
CoreProps.BULLET_LIST_ITEM_LEVEL.set(visitor.renderProps(), listLevel(listItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.setSpansForNode(listItem, length);
|
visitor.setSpansForNodeOptional(listItem, length);
|
||||||
|
|
||||||
if (visitor.hasNext(listItem)) {
|
if (visitor.hasNext(listItem)) {
|
||||||
visitor.ensureNewLine();
|
visitor.ensureNewLine();
|
||||||
@ -293,7 +294,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
// without space it won't render
|
// without space it won't render
|
||||||
visitor.builder().append('\u00a0');
|
visitor.builder().append('\u00a0');
|
||||||
|
|
||||||
visitor.setSpansForNode(thematicBreak, length);
|
visitor.setSpansForNodeOptional(thematicBreak, length);
|
||||||
|
|
||||||
if (visitor.hasNext(thematicBreak)) {
|
if (visitor.hasNext(thematicBreak)) {
|
||||||
visitor.ensureNewLine();
|
visitor.ensureNewLine();
|
||||||
@ -315,7 +316,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
CoreProps.HEADING_LEVEL.set(visitor.renderProps(), heading.getLevel());
|
CoreProps.HEADING_LEVEL.set(visitor.renderProps(), heading.getLevel());
|
||||||
|
|
||||||
visitor.setSpansForNode(heading, length);
|
visitor.setSpansForNodeOptional(heading, length);
|
||||||
|
|
||||||
if (visitor.hasNext(heading)) {
|
if (visitor.hasNext(heading)) {
|
||||||
visitor.ensureNewLine();
|
visitor.ensureNewLine();
|
||||||
@ -399,7 +400,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
CoreProps.LINK_DESTINATION.set(visitor.renderProps(), destination);
|
CoreProps.LINK_DESTINATION.set(visitor.renderProps(), destination);
|
||||||
|
|
||||||
visitor.setSpansForNode(link, length);
|
visitor.setSpansForNodeOptional(link, length);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,22 @@ import java.util.Locale;
|
|||||||
import ru.noties.markwon.utils.ColorUtils;
|
import ru.noties.markwon.utils.ColorUtils;
|
||||||
import ru.noties.markwon.utils.Dip;
|
import ru.noties.markwon.utils.Dip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to hold <i>theming</i> information for rending of markdown.
|
||||||
|
* <p>
|
||||||
|
* Since version 3.0.0 this class should be considered as <em>CoreTheme</em> as it\'s
|
||||||
|
* information holds data for core features only. But based on this other components can still use it
|
||||||
|
* to display markdown consistently.
|
||||||
|
* <p>
|
||||||
|
* Since version 3.0.0 this class should not be instantiated manually. Instead a {@link ru.noties.markwon.MarkwonPlugin}
|
||||||
|
* should be used: {@link ru.noties.markwon.MarkwonPlugin#configureTheme(Builder)}
|
||||||
|
* <p>
|
||||||
|
* Since version 3.0.0 properties related to <em>strike-through</em>, <em>tables</em> and <em>HTML</em>
|
||||||
|
* are moved to specific plugins in independent artifacts
|
||||||
|
*
|
||||||
|
* @see CorePlugin
|
||||||
|
* @see ru.noties.markwon.MarkwonPlugin#configureTheme(Builder)
|
||||||
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public class MarkwonTheme {
|
public class MarkwonTheme {
|
||||||
|
|
||||||
@ -41,12 +57,28 @@ public class MarkwonTheme {
|
|||||||
* @see #builderWithDefaults(Context)
|
* @see #builderWithDefaults(Context)
|
||||||
* @see #builder(MarkwonTheme)
|
* @see #builder(MarkwonTheme)
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
|
* @deprecated 3.0.0
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@Deprecated
|
||||||
public static Builder builder() {
|
public static Builder builder() {
|
||||||
return new Builder();
|
return new Builder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an <strong>empty</strong> instance of {@link Builder} with no default values applied
|
||||||
|
* <p>
|
||||||
|
* Since version 3.0.0 manual construction of {@link MarkwonTheme} is not required, instead a
|
||||||
|
* {@link ru.noties.markwon.MarkwonPlugin#configureTheme(Builder)} should be used in order
|
||||||
|
* to change certain theme properties
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static Builder builderNoDefaults() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method to create a {@link Builder} instance and initialize it with values
|
* Factory method to create a {@link Builder} instance and initialize it with values
|
||||||
* from supplied {@link MarkwonTheme}
|
* from supplied {@link MarkwonTheme}
|
||||||
@ -549,6 +581,7 @@ public class MarkwonTheme {
|
|||||||
* @return self
|
* @return self
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
@NonNull
|
@NonNull
|
||||||
public Builder headingTextSizeMultipliers(@Size(6) @NonNull float[] headingTextSizeMultipliers) {
|
public Builder headingTextSizeMultipliers(@Size(6) @NonNull float[] headingTextSizeMultipliers) {
|
||||||
this.headingTextSizeMultipliers = headingTextSizeMultipliers;
|
this.headingTextSizeMultipliers = headingTextSizeMultipliers;
|
||||||
|
@ -2,6 +2,7 @@ package ru.noties.markwon.image;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.commonmark.node.Image;
|
import org.commonmark.node.Image;
|
||||||
@ -15,6 +16,7 @@ import ru.noties.markwon.MarkwonConfiguration;
|
|||||||
import ru.noties.markwon.MarkwonSpansFactory;
|
import ru.noties.markwon.MarkwonSpansFactory;
|
||||||
import ru.noties.markwon.MarkwonVisitor;
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
import ru.noties.markwon.RenderProps;
|
import ru.noties.markwon.RenderProps;
|
||||||
|
import ru.noties.markwon.SpanFactory;
|
||||||
import ru.noties.markwon.image.data.DataUriSchemeHandler;
|
import ru.noties.markwon.image.data.DataUriSchemeHandler;
|
||||||
import ru.noties.markwon.image.file.FileSchemeHandler;
|
import ru.noties.markwon.image.file.FileSchemeHandler;
|
||||||
import ru.noties.markwon.image.network.NetworkSchemeHandler;
|
import ru.noties.markwon.image.network.NetworkSchemeHandler;
|
||||||
@ -68,6 +70,13 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) {
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) {
|
||||||
|
|
||||||
|
// if there is no image spanFactory, ignore
|
||||||
|
final SpanFactory spanFactory = visitor.configuration().spansFactory().get(image);
|
||||||
|
if (spanFactory == null) {
|
||||||
|
visitor.visitChildren(image);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final int length = visitor.length();
|
final int length = visitor.length();
|
||||||
|
|
||||||
visitor.visitChildren(image);
|
visitor.visitChildren(image);
|
||||||
@ -86,22 +95,22 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
|
|||||||
.urlProcessor()
|
.urlProcessor()
|
||||||
.process(image.getDestination());
|
.process(image.getDestination());
|
||||||
|
|
||||||
final RenderProps context = visitor.renderProps();
|
final RenderProps props = visitor.renderProps();
|
||||||
|
|
||||||
// apply image properties
|
// apply image properties
|
||||||
// Please note that we explicitly set IMAGE_SIZE to null as we do not clear
|
// Please note that we explicitly set IMAGE_SIZE to null as we do not clear
|
||||||
// properties after we applied span (we could though)
|
// properties after we applied span (we could though)
|
||||||
ImageProps.DESTINATION.set(context, destination);
|
ImageProps.DESTINATION.set(props, destination);
|
||||||
ImageProps.REPLACEMENT_TEXT_IS_LINK.set(context, link);
|
ImageProps.REPLACEMENT_TEXT_IS_LINK.set(props, link);
|
||||||
ImageProps.IMAGE_SIZE.set(context, null);
|
ImageProps.IMAGE_SIZE.set(props, null);
|
||||||
|
|
||||||
visitor.setSpansForNode(image, length);
|
visitor.setSpans(length, spanFactory.getSpans(configuration, props));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown) {
|
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
|
||||||
AsyncDrawableScheduler.unschedule(textView);
|
AsyncDrawableScheduler.unschedule(textView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.commonmark.node.BlockQuote;
|
import org.commonmark.node.BlockQuote;
|
||||||
import org.commonmark.node.Code;
|
import org.commonmark.node.Code;
|
||||||
import org.commonmark.node.Emphasis;
|
import org.commonmark.node.Emphasis;
|
||||||
@ -18,7 +19,8 @@ import org.commonmark.node.StrongEmphasis;
|
|||||||
import org.commonmark.node.ThematicBreak;
|
import org.commonmark.node.ThematicBreak;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -32,7 +34,6 @@ import ru.noties.markwon.core.CorePlugin;
|
|||||||
import ru.noties.markwon.core.CoreProps;
|
import ru.noties.markwon.core.CoreProps;
|
||||||
import ru.noties.markwon.test.TestSpan;
|
import ru.noties.markwon.test.TestSpan;
|
||||||
import ru.noties.markwon.test.TestSpanMatcher;
|
import ru.noties.markwon.test.TestSpanMatcher;
|
||||||
import ru.noties.markwon.test.TestUtil;
|
|
||||||
|
|
||||||
import static ru.noties.markwon.test.TestSpan.args;
|
import static ru.noties.markwon.test.TestSpan.args;
|
||||||
import static ru.noties.markwon.test.TestSpan.span;
|
import static ru.noties.markwon.test.TestSpan.span;
|
||||||
@ -62,7 +63,11 @@ abstract class BaseSuiteTest {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private String read(@NonNull String name) {
|
private String read(@NonNull String name) {
|
||||||
return TestUtil.read(this, "tests/" + name);
|
try {
|
||||||
|
return IOUtils.resourceToString("tests/" + name, StandardCharsets.UTF_8, getClass().getClassLoader());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -160,12 +165,7 @@ abstract class BaseSuiteTest {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
|
||||||
return span(name, extractArgs(props));
|
return span(name);
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
Map<String, Object> extractArgs(@NonNull RenderProps props) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ public class SyntaxHighlightTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
final MarkwonSpansFactory spansFactory = mock(MarkwonSpansFactory.class);
|
final MarkwonSpansFactory spansFactory = mock(MarkwonSpansFactory.class);
|
||||||
when(spansFactory.require(any(FencedCodeBlock.class))).thenReturn(new SpanFactory() {
|
when(spansFactory.get(any(FencedCodeBlock.class))).thenReturn(new SpanFactory() {
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
|
||||||
return codeSpan;
|
return codeSpan;
|
||||||
@ -103,7 +104,7 @@ public class SyntaxHighlightTest {
|
|||||||
final FencedCodeBlock fencedCodeBlock = new FencedCodeBlock();
|
final FencedCodeBlock fencedCodeBlock = new FencedCodeBlock();
|
||||||
fencedCodeBlock.setLiteral("{code}");
|
fencedCodeBlock.setLiteral("{code}");
|
||||||
|
|
||||||
CorePluginBridge.visitCodeBlock(visitor, null, "{code}", fencedCodeBlock);
|
CorePluginBridge.visitCodeBlock(visitor, null, fencedCodeBlock.getLiteral(), fencedCodeBlock);
|
||||||
|
|
||||||
final int end = builder.length();
|
final int end = builder.length();
|
||||||
|
|
||||||
@ -115,7 +116,7 @@ public class SyntaxHighlightTest {
|
|||||||
|
|
||||||
// each character + code span
|
// each character + code span
|
||||||
final int length = fencedCodeBlock.getLiteral().length() + 1;
|
final int length = fencedCodeBlock.getLiteral().length() + 1;
|
||||||
assertEquals(length, spans.length);
|
assertEquals(Arrays.toString(spans), length, spans.length);
|
||||||
assertEquals(codeSpan, spans[0]);
|
assertEquals(codeSpan, spans[0]);
|
||||||
|
|
||||||
// each character
|
// each character
|
||||||
|
@ -11,6 +11,5 @@ include ':app',
|
|||||||
':markwon-html',
|
':markwon-html',
|
||||||
':markwon-view',
|
':markwon-view',
|
||||||
':markwon-test-span',
|
':markwon-test-span',
|
||||||
':markwon-test-util',
|
|
||||||
':sample-custom-extension',
|
':sample-custom-extension',
|
||||||
':sample-latex-math'
|
':sample-latex-math'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user