diff --git a/app/src/main/assets/test.md b/app/src/main/assets/test.md
index 55aaab47..9957a19f 100644
--- a/app/src/main/assets/test.md
+++ b/app/src/main/assets/test.md
@@ -13,9 +13,15 @@
Yo!
Omg
+
ddffdg
+1. First
+2. Second
+3. Third
+* Interesting
+4. Forth
## Unordered list
@@ -35,6 +41,41 @@ ddffdg
* it's also here
2. and this
3. and that
+ 1. Another one nested this time and a lot of text here, well, at least some to check how multiline will be handled
+ 1. And it goes on and on
+ 2. And it goes on and on
+ 3. And it goes on and on
+ 4. And it goes on and on
+ 5. And it goes on and on
+ 6. And it goes on and on
+ 7. And it goes on and on
+ 8. And it goes on and on
+ 9. And it goes on and on
+ 10. And it goes on and on
+ 11. And it goes on and on
+ 12. And it goes on and on
+ 13. And it goes on and on
+ 14. And it goes on and on
+ 15. And it goes on and on
+ 16. And it goes on and on
+ 17. And it goes on and on
+ 18. And it goes on and on
+ 19. And it goes on and on
+ 20. And it goes on and on
+ 21. And it goes on and on
+ 22. And it goes on and on
+ 23. And it goes on and on
+ 24. And it goes on and on
+ 25. And it goes on and on
+ 26. And it goes on and on
+ 27. And it goes on and on
+ 28. And it goes on and on
+ 29. And it goes on and on
+ 30. And it goes on and on
+ 31. And it goes on and on
+ 32. And it goes on and on
+ 33. And it goes on and on
+
### Quoted list
diff --git a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableConfiguration.java b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableConfiguration.java
index 13f53f26..58a0225b 100644
--- a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableConfiguration.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableConfiguration.java
@@ -7,6 +7,7 @@ import ru.noties.markwon.spans.BlockQuoteSpan;
import ru.noties.markwon.spans.BulletListItemSpan;
import ru.noties.markwon.spans.CodeSpan;
import ru.noties.markwon.spans.HeadingSpan;
+import ru.noties.markwon.spans.OrderedListItemSpan;
import ru.noties.markwon.spans.ThematicBreakSpan;
public class SpannableConfiguration {
@@ -25,6 +26,7 @@ public class SpannableConfiguration {
private final BulletListItemSpan.Config bulletListConfig;
private final HeadingSpan.Config headingConfig;
private final ThematicBreakSpan.Config thematicConfig;
+ private final OrderedListItemSpan.Config orderedListConfig;
private SpannableConfiguration(Builder builder) {
this.blockQuoteConfig = builder.blockQuoteConfig;
@@ -32,6 +34,7 @@ public class SpannableConfiguration {
this.bulletListConfig = builder.bulletListConfig;
this.headingConfig = builder.headingConfig;
this.thematicConfig = builder.thematicConfig;
+ this.orderedListConfig = builder.orderedListConfig;
}
public BlockQuoteSpan.Config getBlockQuoteConfig() {
@@ -54,6 +57,10 @@ public class SpannableConfiguration {
return thematicConfig;
}
+ public OrderedListItemSpan.Config getOrderedListConfig() {
+ return orderedListConfig;
+ }
+
public static class Builder {
private final Context context;
@@ -62,6 +69,7 @@ public class SpannableConfiguration {
private BulletListItemSpan.Config bulletListConfig;
private HeadingSpan.Config headingConfig;
private ThematicBreakSpan.Config thematicConfig;
+ private OrderedListItemSpan.Config orderedListConfig;
public Builder(Context context) {
this.context = context;
@@ -92,11 +100,17 @@ public class SpannableConfiguration {
return this;
}
+ public Builder setOrderedListConfig(@NonNull OrderedListItemSpan.Config orderedListConfig) {
+ this.orderedListConfig = orderedListConfig;
+ return this;
+ }
+
// todo, change to something more reliable
+ // todo, must mention that bullet/ordered/quote must have the same margin (or maybe we can just enforce it?)
public SpannableConfiguration build() {
if (blockQuoteConfig == null) {
blockQuoteConfig = new BlockQuoteSpan.Config(
- px(16),
+ px(24),
0,
0
);
@@ -107,7 +121,7 @@ public class SpannableConfiguration {
.build();
}
if (bulletListConfig == null) {
- bulletListConfig = new BulletListItemSpan.Config(0, px(16), px(1));
+ bulletListConfig = new BulletListItemSpan.Config(px(24), 0, px(8), px(1));
}
if (headingConfig == null) {
headingConfig = new HeadingSpan.Config(px(1), 0);
@@ -115,6 +129,9 @@ public class SpannableConfiguration {
if (thematicConfig == null) {
thematicConfig = new ThematicBreakSpan.Config(0, px(2));
}
+ if (orderedListConfig == null) {
+ orderedListConfig = new OrderedListItemSpan.Config(px(24), 0);
+ }
return new SpannableConfiguration(this);
}
diff --git a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
index 26c09d24..dea44e6f 100644
--- a/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
+++ b/library-renderer/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java
@@ -16,7 +16,6 @@ import org.commonmark.node.FencedCodeBlock;
import org.commonmark.node.HardLineBreak;
import org.commonmark.node.Heading;
import org.commonmark.node.HtmlBlock;
-import org.commonmark.node.Image;
import org.commonmark.node.ListBlock;
import org.commonmark.node.ListItem;
import org.commonmark.node.Node;
@@ -33,6 +32,8 @@ import ru.noties.markwon.spans.BulletListItemSpan;
import ru.noties.markwon.spans.CodeSpan;
import ru.noties.markwon.spans.EmphasisSpan;
import ru.noties.markwon.spans.HeadingSpan;
+import ru.noties.markwon.spans.OrderedListItemSpan;
+import ru.noties.markwon.spans.SimpleLeadingMarginSpan;
import ru.noties.markwon.spans.StrongEmphasisSpan;
import ru.noties.markwon.spans.ThematicBreakSpan;
@@ -54,13 +55,13 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
@Override
public void visit(Text text) {
- Debug.i(text);
+// Debug.i(text);
builder.append(text.getLiteral());
}
@Override
public void visit(StrongEmphasis strongEmphasis) {
- Debug.i(strongEmphasis);
+// Debug.i(strongEmphasis);
final int length = builder.length();
visitChildren(strongEmphasis);
setSpan(length, new StrongEmphasisSpan());
@@ -68,7 +69,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
@Override
public void visit(Emphasis emphasis) {
- Debug.i(emphasis);
+// Debug.i(emphasis);
final int length = builder.length();
visitChildren(emphasis);
setSpan(length, new EmphasisSpan());
@@ -77,7 +78,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
@Override
public void visit(BlockQuote blockQuote) {
- Debug.i(blockQuote);
+// Debug.i(blockQuote);
newLine();
if (blockQuoteIndent != 0) {
@@ -106,7 +107,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
@Override
public void visit(Code code) {
- Debug.i(code);
+// Debug.i(code);
final int length = builder.length();
@@ -125,7 +126,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
@Override
public void visit(FencedCodeBlock fencedCodeBlock) {
- Debug.i(fencedCodeBlock);
+// Debug.i(fencedCodeBlock);
newLine();
@@ -141,33 +142,35 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
builder.append('\n');
}
- @Override
- public void visit(Image image) {
-
- Debug.i(image);
-
- final int length = builder.length();
-
- visitChildren(image);
-
- if (length == builder.length()) {
- // nothing is added, and we need at least one symbol
- builder.append(' ');
- }
-
-
-//// final int length = builder.length();
-// final TestDrawable drawable = new TestDrawable();
-// final DrawableSpan span = new DrawableSpan(drawable);
-// builder.append(" ");
-// builder.setSpan(span, length, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
+// @Override
+// public void visit(Image image) {
+//
+// Debug.i(image);
+//
+//// final int length = builder.length();
+//
+// visitChildren(image);
+//
+//// if (length == builder.length()) {
+//// // nothing is added, and we need at least one symbol
+//// builder.append(' ');
+//// }
+// }
@Override
public void visit(BulletList bulletList) {
- Debug.i(bulletList);
+ visitList(bulletList);
+ }
+
+ @Override
+ public void visit(OrderedList orderedList) {
+ visitList(orderedList);
+ }
+
+ private void visitList(Node node) {
+ Debug.i(node);
newLine();
- visitChildren(bulletList);
+ visitChildren(node);
newLine();
if (listLevel == 0 && blockQuoteIndent == 0) {
builder.append('\n');
@@ -180,16 +183,67 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
Debug.i(listItem);
final int length = builder.length();
+
blockQuoteIndent += 1;
listLevel += 1;
- visitChildren(listItem);
+
// todo, can be a bullet list & ordered list (with leading numbers... looks like we need to `draw` numbers...
- setSpan(length, new BulletListItemSpan(
- configuration.getBulletListConfig(),
- blockQuoteIndent,
- listLevel - 1,
- length
- ));
+
+ final Node parent = listItem.getParent();
+ if (parent instanceof OrderedList) {
+
+// // let's build ordered number
+// final StringBuilder lead = new StringBuilder();
+// Node p = parent;
+// while (p != null && p instanceof OrderedList) {
+// lead.insert(0, ((OrderedList) p).getDelimiter());
+// lead.insert(0, ((OrderedList) p).getStartNumber());
+// p = p.getParent();
+// if (p instanceof ListItem) {
+// p = p.getParent();
+// }
+// }
+//
+// builder.append(lead)
+// .append('\u00a0');
+//
+// blockQuoteIndent -= 1;
+
+ final int start = ((OrderedList) parent).getStartNumber();
+
+ visitChildren(listItem);
+
+ setSpan(length, new OrderedListItemSpan(
+ configuration.getOrderedListConfig(),
+ String.valueOf(start) + "." + '\u00a0',
+ blockQuoteIndent,
+ length
+ ));
+
+// blockQuoteIndent += 1;
+
+// if (listLevel != 1) {
+// setSpan(length, new SimpleLeadingMarginSpan(32));
+// }
+
+ // after we have visited the children increment start number
+ final OrderedList orderedList = (OrderedList) parent;
+ orderedList.setStartNumber(orderedList.getStartNumber() + 1);
+
+ } else {
+
+ visitChildren(listItem);
+
+ // if we are inside orderedList increase the margin?
+
+ setSpan(length, new BulletListItemSpan(
+ configuration.getBulletListConfig(),
+ blockQuoteIndent,
+ listLevel - 1,
+ length
+ ));
+ }
+
blockQuoteIndent -= 1;
listLevel -= 1;
@@ -199,7 +253,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
@Override
public void visit(ThematicBreak thematicBreak) {
- Debug.i(thematicBreak);
+// Debug.i(thematicBreak);
newLine();
@@ -211,27 +265,10 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
builder.append('\n');
}
- @Override
- public void visit(OrderedList orderedList) {
-
- Debug.i(orderedList);
-
- newLine();
-
-// Debug.i(orderedList, orderedList.getDelimiter(), orderedList.getStartNumber());
- // todo, ordering numbers
- super.visit(orderedList);
-
- newLine();
- if (listLevel == 0 && blockQuoteIndent == 0) {
- builder.append('\n');
- }
- }
-
@Override
public void visit(Heading heading) {
- Debug.i(heading);
+// Debug.i(heading);
newLine();
@@ -264,7 +301,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
@Override
public void visit(CustomNode customNode) {
- Debug.i(customNode);
+// Debug.i(customNode);
if (customNode instanceof Strikethrough) {
final int length = builder.length();
@@ -280,7 +317,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
final boolean inTightList = isInTightList(paragraph);
- Debug.i(paragraph, inTightList, listLevel);
+// Debug.i(paragraph, inTightList, listLevel);
if (!inTightList) {
newLine();
@@ -326,4 +363,23 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
}
return false;
}
+
+ private static String dump(Node node) {
+ final StringBuilder builder = new StringBuilder();
+ node.accept(new DumpVisitor(builder));
+ return builder.toString();
+ }
+
+ private static class DumpVisitor extends AbstractVisitor {
+ private final StringBuilder builder;
+
+ DumpVisitor(StringBuilder builder) {
+ this.builder = builder;
+ }
+
+ @Override
+ public void visit(Text text) {
+ builder.append(text.getLiteral());
+ }
+ }
}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java
index f6c52b38..1aa6b89a 100644
--- a/library-spans/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java
+++ b/library-spans/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java
@@ -17,14 +17,20 @@ public class BulletListItemSpan implements LeadingMarginSpan {
public static class Config {
- final int bulletColor; // by default uses text color
final int marginWidth;
+ final int bulletColor; // by default uses text color
+ final int bulletSide;
final int bulletStrokeWidth;
// from 0 but it makes sense to provide something wider
- public Config(@ColorInt int bulletColor, @IntRange(from = 0) int marginWidth, int bulletStrokeWidth) {
- this.bulletColor = bulletColor;
+ public Config(
+ @IntRange(from = 0) int marginWidth,
+ @ColorInt int bulletColor,
+ @IntRange(from = 0) int bulletSide,
+ @IntRange(from = 0) int bulletStrokeWidth) {
this.marginWidth = marginWidth;
+ this.bulletColor = bulletColor;
+ this.bulletSide = bulletSide;
this.bulletStrokeWidth = bulletStrokeWidth;
}
}
@@ -58,7 +64,7 @@ public class BulletListItemSpan implements LeadingMarginSpan {
@Override
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
- // if there was a line break, we don't need to draw it
+ // if there was a line break, we don't need to draw anything
if (this.start != start) {
return;
}
@@ -88,7 +94,14 @@ public class BulletListItemSpan implements LeadingMarginSpan {
final int width = config.marginWidth;
final int height = bottom - top;
- final int side = Math.min(config.marginWidth, height) / 2;
+ final int min = Math.min(config.marginWidth, height) / 2;
+ final int side;
+ if (config.bulletSide == 0
+ || config.bulletSide > min) {
+ side = min;
+ } else {
+ side = config.bulletSide;
+ }
final int marginLeft = (width - side) / 2;
final int marginTop = (height - side) / 2;
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java
new file mode 100644
index 00000000..4d1e0451
--- /dev/null
+++ b/library-spans/src/main/java/ru/noties/markwon/spans/OrderedListItemSpan.java
@@ -0,0 +1,66 @@
+package ru.noties.markwon.spans;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.support.annotation.ColorInt;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.text.Layout;
+import android.text.style.LeadingMarginSpan;
+
+public class OrderedListItemSpan implements LeadingMarginSpan {
+
+ public static class Config {
+
+ final int marginWidth; // by default 0
+ final int numberColor; // by default color of the main text
+
+ public Config(@IntRange(from = 0) int marginWidth, @ColorInt int numberColor) {
+ this.marginWidth = marginWidth;
+ this.numberColor = numberColor;
+ }
+ }
+
+ private final Config config;
+ private final String number;
+ private final int blockIndent;
+ private final int start;
+
+ public OrderedListItemSpan(
+ @NonNull Config config,
+ @NonNull String number,
+ @IntRange(from = 0) int blockIndent,
+ @IntRange(from = 0) int start
+ ) {
+ this.config = config;
+ this.number = number;
+ this.blockIndent = blockIndent;
+ this.start = start;
+ }
+
+ @Override
+ public int getLeadingMargin(boolean first) {
+ return config.marginWidth;
+ }
+
+ @Override
+ public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
+
+ // if there was a line break, we don't need to draw anything
+ if (this.start != start) {
+ return;
+ }
+
+ if (config.numberColor != 0) {
+ p.setColor(config.numberColor);
+ }
+
+ final int width = config.marginWidth;
+ final int numberWidth = (int) (p.measureText(number) + .5F);
+ final int numberX = (width * blockIndent) - numberWidth;
+
+ final int numberY = bottom - ((bottom - top) / 2) - (int) ((p.descent() + p.ascent()) / 2);
+
+ c.drawText(number, numberX, numberY, p);
+ }
+}
diff --git a/library-spans/src/main/java/ru/noties/markwon/spans/SimpleLeadingMarginSpan.java b/library-spans/src/main/java/ru/noties/markwon/spans/SimpleLeadingMarginSpan.java
new file mode 100644
index 00000000..b442adba
--- /dev/null
+++ b/library-spans/src/main/java/ru/noties/markwon/spans/SimpleLeadingMarginSpan.java
@@ -0,0 +1,25 @@
+package ru.noties.markwon.spans;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.text.Layout;
+import android.text.style.LeadingMarginSpan;
+
+public class SimpleLeadingMarginSpan implements LeadingMarginSpan {
+
+ private final int margin;
+
+ public SimpleLeadingMarginSpan(int margin) {
+ this.margin = margin;
+ }
+
+ @Override
+ public int getLeadingMargin(boolean first) {
+ return margin;
+ }
+
+ @Override
+ public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) {
+ // no op
+ }
+}