Feature/white space (#63)
* Deal with white spaces by checking for next node * Update documentation about remove trimWhiteSpaceEnd * Update app module layout
This commit is contained in:
parent
b5c87d957e
commit
3ef4dc61fa
@ -158,8 +158,6 @@ Or leave it empty and use the [link text itself].
|
|||||||
|
|
||||||
Inline `code` has `back-ticks around` it.
|
Inline `code` has `back-ticks around` it.
|
||||||
|
|
||||||
<sup>*</sup>*Please note, that syntax highlighting is supported but library provides no means to do it automatically*
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var s = "JavaScript syntax highlighting";
|
var s = "JavaScript syntax highlighting";
|
||||||
alert(s);
|
alert(s);
|
||||||
|
@ -96,7 +96,6 @@ public class MarkdownRenderer {
|
|||||||
.codeTextColor(prism4jTheme.textColor())
|
.codeTextColor(prism4jTheme.textColor())
|
||||||
.build())
|
.build())
|
||||||
.factory(new GifAwareSpannableFactory(gifPlaceholder))
|
.factory(new GifAwareSpannableFactory(gifPlaceholder))
|
||||||
.trimWhiteSpaceEnd(false)
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final long start = SystemClock.uptimeMillis();
|
final long start = SystemClock.uptimeMillis();
|
||||||
|
@ -8,13 +8,16 @@
|
|||||||
android:id="@+id/scroll_view"
|
android:id="@+id/scroll_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dip"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:scrollbarStyle="outsideOverlay"
|
||||||
android:layout_marginTop="?android:attr/actionBarSize">
|
android:layout_marginTop="?android:attr/actionBarSize">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text"
|
android:id="@+id/text"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="16dip"
|
|
||||||
android:lineSpacingExtra="2dip"
|
android:lineSpacingExtra="2dip"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
tools:context="ru.noties.markwon.MainActivity"
|
tools:context="ru.noties.markwon.MainActivity"
|
||||||
|
@ -183,25 +183,6 @@ If not provided explicitly, default `false` value will be used.
|
|||||||
|
|
||||||
<Link name="commonmark-spec#soft-break" displayName="Commonmark specification" />
|
<Link name="commonmark-spec#soft-break" displayName="Commonmark specification" />
|
||||||
|
|
||||||
## Trim white space from end <Badge text="2.0.0" />
|
|
||||||
|
|
||||||
`trimWhiteSpaceEnd` option controls whether or not to trim white spaces from the
|
|
||||||
end of a document.
|
|
||||||
|
|
||||||
```java
|
|
||||||
SpannableConfiguration.builder(context)
|
|
||||||
.trimWhiteSpaceEnd(boolean)
|
|
||||||
.build();
|
|
||||||
```
|
|
||||||
|
|
||||||
If not provided explicitly, default `true` value will be used.
|
|
||||||
|
|
||||||
:::tip Before <Badge text="2.0.0" />
|
|
||||||
Before `2.0.0` version this functionality was _implicitly_ included in
|
|
||||||
`SpannableBuilder#text` method. This is no longer true and now `SpannableBuilder`
|
|
||||||
does not trim white spaces (which was by default and non-configurable)
|
|
||||||
:::
|
|
||||||
|
|
||||||
## HTML <Badge text="2.0.0" />
|
## HTML <Badge text="2.0.0" />
|
||||||
|
|
||||||
### Parser
|
### Parser
|
||||||
|
@ -61,7 +61,6 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SpannableBuilder(@NonNull CharSequence cs) {
|
public SpannableBuilder(@NonNull CharSequence cs) {
|
||||||
// this.builder = new SpannableStringBuilderImpl(cs.toString());
|
|
||||||
this.builder = new StringBuilder(cs);
|
this.builder = new StringBuilder(cs);
|
||||||
copySpans(0, cs);
|
copySpans(0, cs);
|
||||||
}
|
}
|
||||||
@ -198,58 +197,6 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Moved from {@link #text()} method
|
|
||||||
*
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
public void trimWhiteSpaceEnd() {
|
|
||||||
|
|
||||||
// now, let's remove trailing & leading newLines (so small amounts of text are displayed correctly)
|
|
||||||
// @since 1.0.2
|
|
||||||
|
|
||||||
int length = builder.length();
|
|
||||||
|
|
||||||
if (length > 0) {
|
|
||||||
|
|
||||||
length = builder.length();
|
|
||||||
int amount = 0;
|
|
||||||
for (int i = length - 1; i >= 0; i--) {
|
|
||||||
if (Character.isWhitespace(builder.charAt(i))) {
|
|
||||||
amount += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amount > 0) {
|
|
||||||
|
|
||||||
final int newLength = length - amount;
|
|
||||||
builder.replace(newLength, length, "");
|
|
||||||
|
|
||||||
// additionally we should apply new length to the spans (otherwise
|
|
||||||
// sometimes system cannot handle spans with length greater than total length
|
|
||||||
// which causes some internal failure (no exceptions, no logs) in Layout class
|
|
||||||
// and no markdown is displayed at all
|
|
||||||
if (spans.size() > 0) {
|
|
||||||
Span span;
|
|
||||||
final Iterator<Span> iterator = spans.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
span = iterator.next();
|
|
||||||
// if span start is greater than newLength, then remove it... one should
|
|
||||||
// not use white space for spanning resulting text
|
|
||||||
if (span.start > newLength) {
|
|
||||||
iterator.remove();
|
|
||||||
} else if (span.end > newLength) {
|
|
||||||
span.end = newLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public CharSequence text() {
|
public CharSequence text() {
|
||||||
// @since 2.0.0 redirects this call to `#spannableStringBuilder()`
|
// @since 2.0.0 redirects this call to `#spannableStringBuilder()`
|
||||||
|
@ -3,7 +3,6 @@ package ru.noties.markwon;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
|
||||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.renderer.ImageSizeResolver;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolverDef;
|
import ru.noties.markwon.renderer.ImageSizeResolverDef;
|
||||||
@ -34,7 +33,6 @@ public class SpannableConfiguration {
|
|||||||
private final ImageSizeResolver imageSizeResolver;
|
private final ImageSizeResolver imageSizeResolver;
|
||||||
private final SpannableFactory factory; // @since 1.1.0
|
private final SpannableFactory factory; // @since 1.1.0
|
||||||
private final boolean softBreakAddsNewLine; // @since 1.1.1
|
private final boolean softBreakAddsNewLine; // @since 1.1.1
|
||||||
private final boolean trimWhiteSpaceEnd; // @since 2.0.0
|
|
||||||
private final MarkwonHtmlParser htmlParser; // @since 2.0.0
|
private final MarkwonHtmlParser htmlParser; // @since 2.0.0
|
||||||
private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
||||||
private final boolean htmlAllowNonClosedTags; // @since 2.0.0
|
private final boolean htmlAllowNonClosedTags; // @since 2.0.0
|
||||||
@ -48,7 +46,6 @@ public class SpannableConfiguration {
|
|||||||
this.imageSizeResolver = builder.imageSizeResolver;
|
this.imageSizeResolver = builder.imageSizeResolver;
|
||||||
this.factory = builder.factory;
|
this.factory = builder.factory;
|
||||||
this.softBreakAddsNewLine = builder.softBreakAddsNewLine;
|
this.softBreakAddsNewLine = builder.softBreakAddsNewLine;
|
||||||
this.trimWhiteSpaceEnd = builder.trimWhiteSpaceEnd;
|
|
||||||
this.htmlParser = builder.htmlParser;
|
this.htmlParser = builder.htmlParser;
|
||||||
this.htmlRenderer = builder.htmlRenderer;
|
this.htmlRenderer = builder.htmlRenderer;
|
||||||
this.htmlAllowNonClosedTags = builder.htmlAllowNonClosedTags;
|
this.htmlAllowNonClosedTags = builder.htmlAllowNonClosedTags;
|
||||||
@ -98,13 +95,6 @@ public class SpannableConfiguration {
|
|||||||
return softBreakAddsNewLine;
|
return softBreakAddsNewLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
public boolean trimWhiteSpaceEnd() {
|
|
||||||
return trimWhiteSpaceEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@ -140,7 +130,6 @@ public class SpannableConfiguration {
|
|||||||
private ImageSizeResolver imageSizeResolver;
|
private ImageSizeResolver imageSizeResolver;
|
||||||
private SpannableFactory factory; // @since 1.1.0
|
private SpannableFactory factory; // @since 1.1.0
|
||||||
private boolean softBreakAddsNewLine; // @since 1.1.1
|
private boolean softBreakAddsNewLine; // @since 1.1.1
|
||||||
private boolean trimWhiteSpaceEnd = true; // @since 2.0.0
|
|
||||||
private MarkwonHtmlParser htmlParser; // @since 2.0.0
|
private MarkwonHtmlParser htmlParser; // @since 2.0.0
|
||||||
private MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
private MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
||||||
private boolean htmlAllowNonClosedTags; // @since 2.0.0
|
private boolean htmlAllowNonClosedTags; // @since 2.0.0
|
||||||
@ -210,18 +199,6 @@ public class SpannableConfiguration {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Will trim white space(s) from the end from resulting text.
|
|
||||||
* By default `true`
|
|
||||||
*
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public Builder trimWhiteSpaceEnd(boolean trimWhiteSpaceEnd) {
|
|
||||||
this.trimWhiteSpaceEnd = trimWhiteSpaceEnd;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
|
@ -6,6 +6,7 @@ import android.support.annotation.Nullable;
|
|||||||
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
||||||
import org.commonmark.ext.gfm.tables.TableBody;
|
import org.commonmark.ext.gfm.tables.TableBody;
|
||||||
import org.commonmark.ext.gfm.tables.TableCell;
|
import org.commonmark.ext.gfm.tables.TableCell;
|
||||||
|
import org.commonmark.ext.gfm.tables.TableHead;
|
||||||
import org.commonmark.ext.gfm.tables.TableRow;
|
import org.commonmark.ext.gfm.tables.TableRow;
|
||||||
import org.commonmark.node.AbstractVisitor;
|
import org.commonmark.node.AbstractVisitor;
|
||||||
import org.commonmark.node.BlockQuote;
|
import org.commonmark.node.BlockQuote;
|
||||||
@ -79,10 +80,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
super.visit(document);
|
super.visit(document);
|
||||||
|
|
||||||
configuration.htmlRenderer().render(configuration, builder, htmlParser);
|
configuration.htmlRenderer().render(configuration, builder, htmlParser);
|
||||||
|
|
||||||
if (configuration.trimWhiteSpaceEnd()) {
|
|
||||||
builder.trimWhiteSpaceEnd();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -122,11 +119,13 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
|
|
||||||
blockQuoteIndent -= 1;
|
blockQuoteIndent -= 1;
|
||||||
|
|
||||||
|
if (hasNext(blockQuote)) {
|
||||||
newLine();
|
newLine();
|
||||||
if (blockQuoteIndent == 0) {
|
if (blockQuoteIndent == 0) {
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Code code) {
|
public void visit(Code code) {
|
||||||
@ -145,7 +144,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
@Override
|
@Override
|
||||||
public void visit(FencedCodeBlock fencedCodeBlock) {
|
public void visit(FencedCodeBlock fencedCodeBlock) {
|
||||||
// @since 1.0.4
|
// @since 1.0.4
|
||||||
visitCodeBlock(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral());
|
visitCodeBlock(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral(), fencedCodeBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,7 +152,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visit(IndentedCodeBlock indentedCodeBlock) {
|
public void visit(IndentedCodeBlock indentedCodeBlock) {
|
||||||
visitCodeBlock(null, indentedCodeBlock.getLiteral());
|
visitCodeBlock(null, indentedCodeBlock.getLiteral(), indentedCodeBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,7 +160,8 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
* @param code content of a code block
|
* @param code content of a code block
|
||||||
* @since 1.0.4
|
* @since 1.0.4
|
||||||
*/
|
*/
|
||||||
private void visitCodeBlock(@Nullable String info, @NonNull String code) {
|
private void visitCodeBlock(@Nullable String info, @NonNull String code, @NonNull Node node) {
|
||||||
|
|
||||||
newLine();
|
newLine();
|
||||||
|
|
||||||
final int length = builder.length();
|
final int length = builder.length();
|
||||||
@ -172,13 +172,17 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
configuration.syntaxHighlight()
|
configuration.syntaxHighlight()
|
||||||
.highlight(info, code)
|
.highlight(info, code)
|
||||||
);
|
);
|
||||||
builder.append('\u00a0').append('\n');
|
|
||||||
|
newLine();
|
||||||
|
builder.append('\u00a0');
|
||||||
|
|
||||||
setSpan(length, factory.code(theme, true));
|
setSpan(length, factory.code(theme, true));
|
||||||
|
|
||||||
|
if (hasNext(node)) {
|
||||||
newLine();
|
newLine();
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BulletList bulletList) {
|
public void visit(BulletList bulletList) {
|
||||||
@ -191,13 +195,18 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void visitList(Node node) {
|
private void visitList(Node node) {
|
||||||
|
|
||||||
newLine();
|
newLine();
|
||||||
|
|
||||||
visitChildren(node);
|
visitChildren(node);
|
||||||
|
|
||||||
|
if (hasNext(node)) {
|
||||||
newLine();
|
newLine();
|
||||||
if (listLevel == 0 && blockQuoteIndent == 0) {
|
if (listLevel == 0 && blockQuoteIndent == 0) {
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ListItem listItem) {
|
public void visit(ListItem listItem) {
|
||||||
@ -230,8 +239,10 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
blockQuoteIndent -= 1;
|
blockQuoteIndent -= 1;
|
||||||
listLevel -= 1;
|
listLevel -= 1;
|
||||||
|
|
||||||
|
if (hasNext(listItem)) {
|
||||||
newLine();
|
newLine();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ThematicBreak thematicBreak) {
|
public void visit(ThematicBreak thematicBreak) {
|
||||||
@ -243,9 +254,11 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
|
|
||||||
setSpan(length, factory.thematicBreak(theme));
|
setSpan(length, factory.thematicBreak(theme));
|
||||||
|
|
||||||
|
if (hasNext(thematicBreak)) {
|
||||||
newLine();
|
newLine();
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Heading heading) {
|
public void visit(Heading heading) {
|
||||||
@ -256,11 +269,12 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
visitChildren(heading);
|
visitChildren(heading);
|
||||||
setSpan(length, factory.heading(theme, heading.getLevel()));
|
setSpan(length, factory.heading(theme, heading.getLevel()));
|
||||||
|
|
||||||
|
if (hasNext(heading)) {
|
||||||
newLine();
|
newLine();
|
||||||
|
|
||||||
// after heading we add another line anyway (no additional checks)
|
// after heading we add another line anyway (no additional checks)
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SoftLineBreak softLineBreak) {
|
public void visit(SoftLineBreak softLineBreak) {
|
||||||
@ -282,12 +296,17 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visit(CustomBlock customBlock) {
|
public void visit(CustomBlock customBlock) {
|
||||||
|
|
||||||
if (customBlock instanceof TaskListBlock) {
|
if (customBlock instanceof TaskListBlock) {
|
||||||
blockQuoteIndent += 1;
|
blockQuoteIndent += 1;
|
||||||
visitChildren(customBlock);
|
visitChildren(customBlock);
|
||||||
blockQuoteIndent -= 1;
|
blockQuoteIndent -= 1;
|
||||||
|
|
||||||
|
if (hasNext(customBlock)) {
|
||||||
newLine();
|
newLine();
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
super.visit(customBlock);
|
super.visit(customBlock);
|
||||||
}
|
}
|
||||||
@ -316,7 +335,9 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
|
|
||||||
setSpan(length, factory.taskListItem(theme, blockQuoteIndent, listItem.done()));
|
setSpan(length, factory.taskListItem(theme, blockQuoteIndent, listItem.done()));
|
||||||
|
|
||||||
|
if (hasNext(customNode)) {
|
||||||
newLine();
|
newLine();
|
||||||
|
}
|
||||||
|
|
||||||
blockQuoteIndent -= listItem.indent();
|
blockQuoteIndent -= listItem.indent();
|
||||||
|
|
||||||
@ -330,18 +351,37 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
final boolean handled;
|
final boolean handled;
|
||||||
|
|
||||||
if (node instanceof TableBody) {
|
if (node instanceof TableBody) {
|
||||||
|
|
||||||
visitChildren(node);
|
visitChildren(node);
|
||||||
tableRows = 0;
|
tableRows = 0;
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
||||||
|
if (hasNext(node)) {
|
||||||
newLine();
|
newLine();
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
} else if (node instanceof TableRow) {
|
}
|
||||||
|
|
||||||
|
} else if (node instanceof TableRow || node instanceof TableHead) {
|
||||||
|
|
||||||
final int length = builder.length();
|
final int length = builder.length();
|
||||||
|
|
||||||
visitChildren(node);
|
visitChildren(node);
|
||||||
|
|
||||||
if (pendingTableRow != null) {
|
if (pendingTableRow != null) {
|
||||||
|
|
||||||
|
// @since 2.0.0
|
||||||
|
// we cannot rely on hasNext(TableHead) as it's not reliable
|
||||||
|
// we must apply new line manually and then exclude it from tableRow span
|
||||||
|
final boolean addNewLine;
|
||||||
|
{
|
||||||
|
final int builderLength = builder.length();
|
||||||
|
addNewLine = builderLength > 0
|
||||||
|
&& '\n' != builder.charAt(builderLength - 1);
|
||||||
|
}
|
||||||
|
if (addNewLine) {
|
||||||
|
builder.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
// @since 1.0.4 Replace table char with non-breakable space
|
// @since 1.0.4 Replace table char with non-breakable space
|
||||||
// we need this because if table is at the end of the text, then it will be
|
// we need this because if table is at the end of the text, then it will be
|
||||||
// trimmed from the final result
|
// trimmed from the final result
|
||||||
@ -357,12 +397,13 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
? 0
|
? 0
|
||||||
: tableRows + 1;
|
: tableRows + 1;
|
||||||
|
|
||||||
setSpan(length, span);
|
setSpan(addNewLine ? length + 1 : length, span);
|
||||||
newLine();
|
|
||||||
pendingTableRow = null;
|
pendingTableRow = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
||||||
} else if (node instanceof TableCell) {
|
} else if (node instanceof TableCell) {
|
||||||
|
|
||||||
final TableCell cell = (TableCell) node;
|
final TableCell cell = (TableCell) node;
|
||||||
@ -383,11 +424,13 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
} else {
|
} else {
|
||||||
handled = false;
|
handled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Paragraph paragraph) {
|
public void visit(Paragraph paragraph) {
|
||||||
|
|
||||||
final boolean inTightList = isInTightList(paragraph);
|
final boolean inTightList = isInTightList(paragraph);
|
||||||
|
|
||||||
if (!inTightList) {
|
if (!inTightList) {
|
||||||
@ -400,9 +443,8 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
// @since 1.1.1 apply paragraph span
|
// @since 1.1.1 apply paragraph span
|
||||||
setSpan(length, factory.paragraph(inTightList));
|
setSpan(length, factory.paragraph(inTightList));
|
||||||
|
|
||||||
if (!inTightList) {
|
if (hasNext(paragraph) && !inTightList) {
|
||||||
newLine();
|
newLine();
|
||||||
|
|
||||||
if (blockQuoteIndent == 0) {
|
if (blockQuoteIndent == 0) {
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
}
|
}
|
||||||
@ -518,4 +560,11 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
protected static boolean hasNext(@NonNull Node node) {
|
||||||
|
return node.getNext() != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ public class SpannableMarkdownVisitorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// assert that the whole thing is processed
|
// assert that the whole thing is processed
|
||||||
assertEquals(stringBuilder.length(), index);
|
assertEquals("`" + stringBuilder + "`", stringBuilder.length(), index);
|
||||||
|
|
||||||
final Object[] spans = stringBuilder.getSpans(0, stringBuilder.length(), Object.class);
|
final Object[] spans = stringBuilder.getSpans(0, stringBuilder.length(), Object.class);
|
||||||
final int length = spans != null
|
final int length = spans != null
|
||||||
|
@ -5,7 +5,6 @@ import android.support.annotation.Nullable;
|
|||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import ix.Ix;
|
import ix.Ix;
|
||||||
@ -68,7 +67,10 @@ abstract class TestValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(text, builder.subSequence(index, index + text.length()).toString());
|
assertEquals(
|
||||||
|
String.format("text: %s, position: {%d-%d}", text, index, index + text.length()),
|
||||||
|
text,
|
||||||
|
builder.subSequence(index, index + text.length()).toString());
|
||||||
|
|
||||||
return index + text.length();
|
return index + text.length();
|
||||||
}
|
}
|
||||||
@ -106,6 +108,7 @@ abstract class TestValidator {
|
|||||||
.filter(new IxPredicate<TestSpan>() {
|
.filter(new IxPredicate<TestSpan>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean test(TestSpan testSpan) {
|
public boolean test(TestSpan testSpan) {
|
||||||
|
|
||||||
// in case of nested spans with the same name (lists)
|
// in case of nested spans with the same name (lists)
|
||||||
// we also must validate attributes
|
// we also must validate attributes
|
||||||
// and thus we are moving most of assertions to this filter method
|
// and thus we are moving most of assertions to this filter method
|
||||||
@ -170,16 +173,21 @@ abstract class TestValidator {
|
|||||||
spansText = "[]";
|
spansText = "[]";
|
||||||
} else {
|
} else {
|
||||||
final StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
for (Object o: spans) {
|
for (Object o : spans) {
|
||||||
final TestSpan testSpan = (TestSpan) o;
|
final TestSpan testSpan = (TestSpan) o;
|
||||||
if (builder.length() > 0) {
|
if (builder.length() > 0) {
|
||||||
builder.append(", ");
|
builder.append(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.append("{name: '").append(testSpan.name()).append('\'')
|
.append("{name: '").append(testSpan.name()).append('\'')
|
||||||
.append(", position{").append(start).append(", ").append(end).append('}')
|
.append(", position{").append(start).append(", ").append(end).append('}');
|
||||||
.append(", attributes: ").append(testSpan.attributes())
|
|
||||||
.append('}');
|
if (testSpan.attributes().size() > 0) {
|
||||||
|
builder.append(", attributes: ").append(testSpan.attributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append('}');
|
||||||
}
|
}
|
||||||
spansText = builder.toString();
|
spansText = builder.toString();
|
||||||
}
|
}
|
||||||
|
17
markwon/src/test/resources/tests/code-blocks.yaml
Normal file
17
markwon/src/test/resources/tests/code-blocks.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
input: |-
|
||||||
|
```java
|
||||||
|
final String s = null;
|
||||||
|
```
|
||||||
|
```html
|
||||||
|
<html></html>
|
||||||
|
```
|
||||||
|
```
|
||||||
|
nothing here
|
||||||
|
```
|
||||||
|
|
||||||
|
output:
|
||||||
|
- code-block: "final String s = null;"
|
||||||
|
- "\n\n"
|
||||||
|
- code-block: "<html></html>"
|
||||||
|
- "\n\n"
|
||||||
|
- code-block: "nothing here"
|
@ -21,8 +21,8 @@ output:
|
|||||||
- text: " "
|
- text: " "
|
||||||
- s: "strike"
|
- s: "strike"
|
||||||
- text: " down\n\n"
|
- text: " down\n\n"
|
||||||
- blockquote: "Some quote here!\n"
|
- blockquote: "Some quote here!"
|
||||||
- text: "\n"
|
- text: "\n\n"
|
||||||
- h1: "Header 1"
|
- h1: "Header 1"
|
||||||
- text: "\n\n"
|
- text: "\n\n"
|
||||||
- h2: "Header 2"
|
- h2: "Header 2"
|
||||||
|
@ -10,8 +10,8 @@ output:
|
|||||||
- ul:
|
- ul:
|
||||||
- ul: "Second"
|
- ul: "Second"
|
||||||
level: 1
|
level: 1
|
||||||
- text: "\n"
|
|
||||||
level: 0
|
level: 0
|
||||||
|
- text: "\n"
|
||||||
- ul:
|
- ul:
|
||||||
- ul:
|
- ul:
|
||||||
- ul: "Third"
|
- ul: "Third"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user