diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1cf83a05..96db5266 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -41,17 +41,17 @@ - + - + - + diff --git a/app/src/main/java/ru/noties/markwon/MainActivity.java b/app/src/main/java/ru/noties/markwon/MainActivity.java index a14caf2e..bd477bcd 100644 --- a/app/src/main/java/ru/noties/markwon/MainActivity.java +++ b/app/src/main/java/ru/noties/markwon/MainActivity.java @@ -71,7 +71,7 @@ public class MainActivity extends Activity { .use(new CorePlugin()) .use(TaskListPlugin.create(new TaskListDrawable(0xffff0000, 0xffff0000, -1))) .build(); - final CharSequence markdown = markwon2.markdown("**hello _dear_** `code`\n\n- [ ] first\n- [x] second"); + final CharSequence markdown = markwon2.toMarkdown("**hello _dear_** `code`\n\n- [ ] first\n- [x] second"); textView.setText(markdown); return; } diff --git a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java index 9151b115..f0eb38e5 100644 --- a/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java +++ b/app/src/main/java/ru/noties/markwon/MarkdownRenderer.java @@ -104,7 +104,7 @@ public class MarkdownRenderer { final long end = SystemClock.uptimeMillis(); - Debug.i("markdown rendered: %d ms", end - start); + Debug.i("toMarkdown rendered: %d ms", end - start); if (!isCancelled()) { handler.post(new Runnable() { diff --git a/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewHelper.java b/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewHelper.java index f3669b77..95518023 100644 --- a/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewHelper.java +++ b/markwon-view/src/main/java/ru/noties/markwon/view/MarkwonViewHelper.java @@ -60,7 +60,7 @@ public class MarkwonViewHelper implements IMarkwonView { this.provider = provider; this.configuration = provider.provide(textView.getContext()); if (!TextUtils.isEmpty(markdown)) { - // invalidate rendered markdown + // invalidate rendered toMarkdown setMarkdown(markdown); } } diff --git a/markwon/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java b/markwon/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java index d96e2a6d..d0187fac 100644 --- a/markwon/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java +++ b/markwon/src/main/java/ru/noties/markwon/AbstractMarkwonPlugin.java @@ -35,12 +35,12 @@ public abstract class AbstractMarkwonPlugin implements MarkwonPlugin { } @Override - public void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) { + public void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown) { } @Override - public void afterSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) { + public void afterSetText(@NonNull TextView textView, @NonNull CharSequence markdown) { } } diff --git a/markwon/src/main/java/ru/noties/markwon/Markwon.java b/markwon/src/main/java/ru/noties/markwon/Markwon.java index c7fdf550..5728f21a 100644 --- a/markwon/src/main/java/ru/noties/markwon/Markwon.java +++ b/markwon/src/main/java/ru/noties/markwon/Markwon.java @@ -48,12 +48,12 @@ public abstract class Markwon { } /** - * Parses submitted raw markdown, converts it to CharSequence (with Spannables) + * Parses submitted raw toMarkdown, converts it to CharSequence (with Spannables) * and applies it to view * - * @param view {@link TextView} to set markdown into + * @param view {@link TextView} to set toMarkdown into * @param configuration a {@link MarkwonConfiguration} instance - * @param markdown raw markdown String (for example: {@code `**Hello**`}) + * @param markdown raw toMarkdown String (for example: {@code `**Hello**`}) * @see #markdown(MarkwonConfiguration, String) * @see #setText(TextView, CharSequence) * @see MarkwonConfiguration @@ -69,13 +69,13 @@ public abstract class Markwon { } /** - * Helper method to apply parsed markdown. + * Helper method to apply parsed toMarkdown. *

* Since 1.0.6 redirects it\'s call to {@link #setText(TextView, CharSequence, MovementMethod)} * with LinkMovementMethod as an argument to preserve current API. * - * @param view {@link TextView} to set markdown into - * @param text parsed markdown + * @param view {@link TextView} to set toMarkdown into + * @param text parsed toMarkdown * @see #setText(TextView, CharSequence, MovementMethod) * @since 1.0.0 */ @@ -84,13 +84,13 @@ public abstract class Markwon { } /** - * Helper method to apply parsed markdown with additional argument of a MovementMethod. Used + * Helper method to apply parsed toMarkdown with additional argument of a MovementMethod. Used * to workaround problems that occur when using system LinkMovementMethod (for example: * https://issuetracker.google.com/issues/37068143). As a better alternative to it consider * using: https://github.com/saket/Better-Link-Movement-Method * - * @param view TextView to set markdown into - * @param text parsed markdown + * @param view TextView to set toMarkdown into + * @param text parsed toMarkdown * @param movementMethod an implementation if MovementMethod or null * @see #scheduleDrawables(TextView) * @see #scheduleTableRows(TextView) @@ -102,7 +102,7 @@ public abstract class Markwon { unscheduleTableRows(view); // @since 2.0.1 we must measure ordered-list-item-spans before applying text to a TextView. - // if markdown has a lot of ordered list items (or text size is relatively big, or block-margin + // if toMarkdown has a lot of ordered list items (or text size is relatively big, or block-margin // is relatively small) then this list won't be rendered properly: it will take correct // layout (width and margin) but will be clipped if margin is not _consistent_ between calls. OrderedListItemSpan.measure(view, text); @@ -117,11 +117,11 @@ public abstract class Markwon { } /** - * Returns parsed markdown with default {@link MarkwonConfiguration} obtained from {@link Context} + * Returns parsed toMarkdown with default {@link MarkwonConfiguration} obtained from {@link Context} * * @param context {@link Context} - * @param markdown raw markdown - * @return parsed markdown + * @param markdown raw toMarkdown + * @return parsed toMarkdown * @since 1.0.0 */ @NonNull @@ -131,11 +131,11 @@ public abstract class Markwon { } /** - * Returns parsed markdown with provided {@link MarkwonConfiguration} + * Returns parsed toMarkdown with provided {@link MarkwonConfiguration} * * @param configuration a {@link MarkwonConfiguration} - * @param markdown raw markdown - * @return parsed markdown + * @param markdown raw toMarkdown + * @return parsed toMarkdown * @see MarkwonConfiguration * @since 1.0.0 */ diff --git a/markwon/src/main/java/ru/noties/markwon/Markwon2.java b/markwon/src/main/java/ru/noties/markwon/Markwon2.java index 59feb9a5..734a9ee3 100644 --- a/markwon/src/main/java/ru/noties/markwon/Markwon2.java +++ b/markwon/src/main/java/ru/noties/markwon/Markwon2.java @@ -2,6 +2,7 @@ package ru.noties.markwon; import android.content.Context; import android.support.annotation.NonNull; +import android.widget.TextView; import org.commonmark.node.Node; @@ -18,8 +19,13 @@ public abstract class Markwon2 { @NonNull public abstract CharSequence render(@NonNull Node node); + // parse + render @NonNull - public abstract CharSequence markdown(@NonNull String input); + public abstract CharSequence toMarkdown(@NonNull String input); + + public abstract void setMarkdown(@NonNull TextView textView, @NonNull String markdown); + + public abstract void setParsedMarkdown(@NonNull TextView textView, @NonNull CharSequence markdown); public interface Builder { diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java b/markwon/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java index 635e3138..841c70d4 100644 --- a/markwon/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonBuilderImpl.java @@ -46,7 +46,7 @@ class MarkwonBuilderImpl implements Markwon2.Builder { return new MarkwonImpl( parserBuilder.build(), - visitorBuilder.build(themeBuilder.build(), configurationBuilder.build()), + visitorBuilder.build(configurationBuilder.build(themeBuilder.build())), Collections.unmodifiableList(plugins) ); } diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonConfiguration.java b/markwon/src/main/java/ru/noties/markwon/MarkwonConfiguration.java index 510f10b1..82d48f4f 100644 --- a/markwon/src/main/java/ru/noties/markwon/MarkwonConfiguration.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonConfiguration.java @@ -20,7 +20,7 @@ public class MarkwonConfiguration { // creates default configuration @NonNull public static MarkwonConfiguration create(@NonNull Context context) { - return new Builder(context).build(); + return new Builder(context).build(MarkwonTheme.create(context)); } @NonNull @@ -28,9 +28,8 @@ public class MarkwonConfiguration { return new Builder(context); } - @Deprecated - private final MarkwonTheme theme; + private final MarkwonTheme theme; private final AsyncDrawable.Loader asyncDrawableLoader; private final SyntaxHighlight syntaxHighlight; private final LinkSpan.Resolver linkResolver; @@ -65,7 +64,6 @@ public class MarkwonConfiguration { } @NonNull - @Deprecated public MarkwonTheme theme() { return theme; } @@ -137,7 +135,6 @@ public class MarkwonConfiguration { private final Context context; - @Deprecated private MarkwonTheme theme; private AsyncDrawable.Loader asyncDrawableLoader; private SyntaxHighlight syntaxHighlight; @@ -169,12 +166,12 @@ public class MarkwonConfiguration { this.htmlAllowNonClosedTags = configuration.htmlAllowNonClosedTags; } - @NonNull - @Deprecated - public Builder theme(@NonNull MarkwonTheme theme) { - this.theme = theme; - return this; - } +// @NonNull +// @Deprecated +// public Builder theme(@NonNull MarkwonTheme theme) { +// this.theme = theme; +// return this; +// } @NonNull public Builder asyncDrawableLoader(@NonNull AsyncDrawable.Loader asyncDrawableLoader) { @@ -263,11 +260,9 @@ public class MarkwonConfiguration { } @NonNull - public MarkwonConfiguration build() { + public MarkwonConfiguration build(@NonNull MarkwonTheme theme) { - if (theme == null) { - theme = MarkwonTheme.create(context); - } + this.theme = theme; if (asyncDrawableLoader == null) { asyncDrawableLoader = new AsyncDrawableLoaderNoOp(); diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java b/markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java index 0252568e..db38e183 100644 --- a/markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java @@ -1,6 +1,7 @@ package ru.noties.markwon; import android.support.annotation.NonNull; +import android.widget.TextView; import org.commonmark.node.Node; import org.commonmark.parser.Parser; @@ -42,7 +43,26 @@ class MarkwonImpl extends Markwon2 { @NonNull @Override - public CharSequence markdown(@NonNull String input) { + public CharSequence toMarkdown(@NonNull String input) { return render(parse(input)); } + + @Override + public void setMarkdown(@NonNull TextView textView, @NonNull String markdown) { + setParsedMarkdown(textView, toMarkdown(markdown)); + } + + @Override + public void setParsedMarkdown(@NonNull TextView textView, @NonNull CharSequence markdown) { + + for (MarkwonPlugin plugin : plugins) { + plugin.beforeSetText(textView, markdown); + } + + textView.setText(markdown); + + for (MarkwonPlugin plugin : plugins) { + plugin.afterSetText(textView, markdown); + } + } } diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java b/markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java index 48e3674e..bd54d1d0 100644 --- a/markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java @@ -23,7 +23,7 @@ public interface MarkwonPlugin { @NonNull String processMarkdown(@NonNull String markdown); - void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder); + void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown); - void afterSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder); + void afterSetText(@NonNull TextView textView, @NonNull CharSequence markdown); } diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java index 58c28111..12a912fc 100644 --- a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java @@ -20,14 +20,17 @@ public interface MarkwonVisitor extends Visitor { Builder on(@NonNull Class node, @NonNull NodeVisitor nodeVisitor); @NonNull - MarkwonVisitor build(@NonNull MarkwonTheme theme, @NonNull MarkwonConfiguration configuration); + MarkwonVisitor build(@NonNull MarkwonConfiguration configuration); } + @NonNull + MarkwonConfiguration configuration(); + @NonNull MarkwonTheme theme(); @NonNull - MarkwonConfiguration configuration(); + SpannableFactory factory(); @NonNull SpannableBuilder builder(); diff --git a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java index 55971a38..c4f98d04 100644 --- a/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java +++ b/markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java @@ -37,19 +37,21 @@ class MarkwonVisitorImpl implements MarkwonVisitor { private final Map, NodeVisitor> nodes; - private final MarkwonTheme theme; private final MarkwonConfiguration configuration; + private final MarkwonTheme theme; + private final SpannableFactory factory; + private final SpannableBuilder builder = new SpannableBuilder(); private int blockQuoteIndent; private int listLevel; private MarkwonVisitorImpl( - @NonNull MarkwonTheme theme, @NonNull MarkwonConfiguration configuration, @NonNull Map, NodeVisitor> nodes) { - this.theme = theme; this.configuration = configuration; + this.theme = configuration.theme(); + this.factory = configuration.factory(); this.nodes = nodes; } @@ -173,6 +175,12 @@ class MarkwonVisitorImpl implements MarkwonVisitor { } } + @NonNull + @Override + public MarkwonConfiguration configuration() { + return configuration; + } + @NonNull @Override public MarkwonTheme theme() { @@ -181,8 +189,8 @@ class MarkwonVisitorImpl implements MarkwonVisitor { @NonNull @Override - public MarkwonConfiguration configuration() { - return configuration; + public SpannableFactory factory() { + return factory; } @NonNull @@ -280,9 +288,8 @@ class MarkwonVisitorImpl implements MarkwonVisitor { @NonNull @Override - public MarkwonVisitor build(@NonNull MarkwonTheme theme, @NonNull MarkwonConfiguration configuration) { + public MarkwonVisitor build(@NonNull MarkwonConfiguration configuration) { return new MarkwonVisitorImpl( - theme, configuration, Collections.unmodifiableMap(nodes)); } diff --git a/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java b/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java index a1495c67..3d4ef0c4 100644 --- a/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java +++ b/markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java @@ -9,17 +9,24 @@ import org.commonmark.node.BulletList; import org.commonmark.node.Code; import org.commonmark.node.Emphasis; import org.commonmark.node.FencedCodeBlock; +import org.commonmark.node.HardLineBreak; +import org.commonmark.node.Heading; +import org.commonmark.node.Image; import org.commonmark.node.IndentedCodeBlock; +import org.commonmark.node.Link; +import org.commonmark.node.ListBlock; import org.commonmark.node.ListItem; import org.commonmark.node.Node; import org.commonmark.node.OrderedList; +import org.commonmark.node.Paragraph; +import org.commonmark.node.SoftLineBreak; import org.commonmark.node.StrongEmphasis; import org.commonmark.node.Text; import org.commonmark.node.ThematicBreak; import ru.noties.markwon.AbstractMarkwonPlugin; +import ru.noties.markwon.MarkwonConfiguration; import ru.noties.markwon.MarkwonVisitor; -import ru.noties.markwon.SpannableBuilder; import ru.noties.markwon.spans.OrderedListItemSpan; public class CorePlugin extends AbstractMarkwonPlugin { @@ -30,6 +37,25 @@ public class CorePlugin extends AbstractMarkwonPlugin { // todo: softBreak adds new line should be here (or maybe removed even?) + // todo: add a simple HTML handler + // todo: configure primitive images (without okhttp -> just HttpUrlConnection and simple types (static, data) + + @NonNull + public static CorePlugin create() { + return create(false); + } + + @NonNull + public static CorePlugin create(boolean softBreakAddsNewLine) { + return new CorePlugin(softBreakAddsNewLine); + } + + private final boolean softBreakAddsNewLine; + + protected CorePlugin(boolean softBreakAddsNewLine) { + this.softBreakAddsNewLine = softBreakAddsNewLine; + } + @Override public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { text(builder); @@ -43,11 +69,17 @@ public class CorePlugin extends AbstractMarkwonPlugin { orderedList(builder); listItem(builder); thematicBreak(builder); + heading(builder); + softLineBreak(builder); + hardLineBreak(builder); + paragraph(builder); + image(builder); + link(builder); } @Override - public void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) { - OrderedListItemSpan.measure(textView, builder); + public void beforeSetText(@NonNull TextView textView, @NonNull CharSequence markdown) { + OrderedListItemSpan.measure(textView, markdown); } protected void text(@NonNull MarkwonVisitor.Builder builder) { @@ -65,7 +97,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { public void visit(@NonNull MarkwonVisitor visitor, @NonNull StrongEmphasis strongEmphasis) { final int length = visitor.length(); visitor.visitChildren(strongEmphasis); - visitor.setSpans(length, visitor.configuration().factory().strongEmphasis()); + visitor.setSpans(length, visitor.factory().strongEmphasis()); } }); } @@ -76,7 +108,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { public void visit(@NonNull MarkwonVisitor visitor, @NonNull Emphasis emphasis) { final int length = visitor.length(); visitor.visitChildren(emphasis); - visitor.setSpans(length, visitor.configuration().factory().emphasis()); + visitor.setSpans(length, visitor.factory().emphasis()); } }); } @@ -95,7 +127,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { final int length = visitor.length(); visitor.incrementBlockQuoteIndent(); visitor.visitChildren(blockQuote); - visitor.setSpans(length, visitor.configuration().factory().blockQuote(visitor.theme())); + visitor.setSpans(length, visitor.factory().blockQuote(visitor.theme())); visitor.decrementBlockQuoteIndent(); if (visitor.hasNext(blockQuote)) { @@ -122,7 +154,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { .append(code.getLiteral()) .append('\u00a0'); - visitor.setSpans(length, visitor.configuration().factory().code(visitor.theme(), false)); + visitor.setSpans(length, visitor.factory().code(visitor.theme(), false)); } }); } @@ -163,7 +195,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { visitor.builder().append('\u00a0'); - visitor.setSpans(length, visitor.configuration().factory().code(visitor.theme(), true)); + visitor.setSpans(length, visitor.factory().code(visitor.theme(), true)); if (visitor.hasNext(node)) { visitor.ensureNewLine(); @@ -220,7 +252,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { final int start = ((OrderedList) parent).getStartNumber(); visitor.visitChildren(listItem); - visitor.setSpans(length, visitor.configuration().factory().orderedListItem(visitor.theme(), start)); + visitor.setSpans(length, visitor.factory().orderedListItem(visitor.theme(), start)); // after we have visited the children increment start number @@ -230,7 +262,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { } else { visitor.visitChildren(listItem); - visitor.setSpans(length, visitor.configuration().factory().bulletListItem(visitor.theme(), visitor.listLevel() - 1)); + visitor.setSpans(length, visitor.factory().bulletListItem(visitor.theme(), visitor.listLevel() - 1)); } @@ -256,7 +288,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { // without space it won't render visitor.builder().append('\u00a0'); - visitor.setSpans(length, visitor.configuration().factory().thematicBreak(visitor.theme())); + visitor.setSpans(length, visitor.factory().thematicBreak(visitor.theme())); if (visitor.hasNext(thematicBreak)) { visitor.ensureNewLine(); @@ -265,4 +297,132 @@ public class CorePlugin extends AbstractMarkwonPlugin { } }); } + + protected void heading(@NonNull MarkwonVisitor.Builder builder) { + builder.on(Heading.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) { + + visitor.ensureNewLine(); + + final int length = visitor.length(); + visitor.visitChildren(heading); + visitor.setSpans(length, visitor.factory().heading(visitor.theme(), heading.getLevel())); + + if (visitor.hasNext(heading)) { + visitor.ensureNewLine(); + visitor.forceNewLine(); + } + } + }); + } + + protected 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(' '); + } + } + }); + } + + protected void hardLineBreak(@NonNull MarkwonVisitor.Builder builder) { + builder.on(HardLineBreak.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull HardLineBreak hardLineBreak) { + visitor.ensureNewLine(); + } + }); + } + + protected void paragraph(@NonNull MarkwonVisitor.Builder builder) { + builder.on(Paragraph.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Paragraph paragraph) { + + final boolean inTightList = isInTightList(paragraph); + + if (!inTightList) { + visitor.ensureNewLine(); + } + + final int length = visitor.length(); + visitor.visitChildren(paragraph); + + // @since 1.1.1 apply paragraph span + visitor.setSpans(length, visitor.factory().paragraph(inTightList)); + + if (!inTightList && visitor.hasNext(paragraph)) { + visitor.ensureNewLine(); + if (visitor.blockQuoteIndent() == 0) { + visitor.forceNewLine(); + } + } + } + }); + } + + protected void image(@NonNull MarkwonVisitor.Builder builder) { + builder.on(Image.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) { + + final int length = visitor.length(); + + visitor.visitChildren(image); + + // we must check if anything _was_ added, as we need at least one char to render + if (length == visitor.length()) { + visitor.builder().append('\uFFFC'); + } + + final MarkwonConfiguration configuration = visitor.configuration(); + + final Node parent = image.getParent(); + final boolean link = parent instanceof Link; + final String destination = configuration + .urlProcessor() + .process(image.getDestination()); + + final Object spans = visitor.factory().image( + visitor.theme(), + destination, + configuration.asyncDrawableLoader(), + configuration.imageSizeResolver(), + null, + link); + + visitor.setSpans(length, spans); + } + }); + } + + protected void link(@NonNull MarkwonVisitor.Builder builder) { + builder.on(Link.class, new MarkwonVisitor.NodeVisitor() { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Link link) { + final int length = visitor.length(); + visitor.visitChildren(link); + final MarkwonConfiguration configuration = visitor.configuration(); + final String destination = configuration.urlProcessor().process(link.getDestination()); + visitor.setSpans(length, visitor.factory().link(visitor.theme(), destination, configuration.linkResolver())); + } + }); + } + + private static boolean isInTightList(@NonNull Paragraph paragraph) { + final Node parent = paragraph.getParent(); + if (parent != null) { + final Node gramps = parent.getParent(); + if (gramps instanceof ListBlock) { + ListBlock list = (ListBlock) gramps; + return list.isTight(); + } + } + return false; + } } diff --git a/markwon/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java b/markwon/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java index e2bc1fb0..f7bacfeb 100644 --- a/markwon/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java +++ b/markwon/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java @@ -20,8 +20,8 @@ public class OrderedListItemSpan implements LeadingMarginSpan { * NB, this method must be called before setting text to a TextView (`TextView#setText` * internally can trigger new Layout creation which will ask for leading margins right away) * - * @param textView to which markdown will be applied - * @param text parsed markdown to process + * @param textView to which toMarkdown will be applied + * @param text parsed toMarkdown to process * @since 2.0.1 */ public static void measure(@NonNull TextView textView, @NonNull CharSequence text) { diff --git a/markwon/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java b/markwon/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java index f783fcae..bc18a140 100644 --- a/markwon/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java +++ b/markwon/src/main/java/ru/noties/markwon/utils/LeadingMarginUtils.java @@ -4,6 +4,7 @@ import android.text.Spanned; public abstract class LeadingMarginUtils { + @SuppressWarnings("BooleanMethodIsAlwaysInverted") public static boolean selfStart(int start, CharSequence text, Object span) { return text instanceof Spanned && ((Spanned) text).getSpanStart(span) == start; } diff --git a/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/MainActivity.java b/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/MainActivity.java index b104e88e..9cb46349 100644 --- a/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/MainActivity.java +++ b/sample-custom-extension/src/main/java/ru/noties/markwon/sample/extension/MainActivity.java @@ -47,7 +47,7 @@ public class MainActivity extends Activity { final SpannableBuilder builder = new SpannableBuilder(); - // please note that here I am passing `0` as fallback it means that if markdown references + // please note that here I am passing `0` as fallback it means that if toMarkdown references // unknown icon, it will try to load fallback one and will fail with ResourceNotFound. It's // better to provide a valid fallback option final IconSpanProvider spanProvider = IconSpanProvider.create(this, 0); @@ -59,7 +59,7 @@ public class MainActivity extends Activity { .headingTextSizeMultipliers(textSizeMultipliers) .build()) .build(); - // create an instance of visitor to process parsed markdown + // create an instance of visitor to process parsed toMarkdown final IconVisitor visitor = new IconVisitor( configuration, builder,