Add trimWhiteSpaceEnd configuration option
This commit is contained in:
parent
359fd8699d
commit
4a6e5002e8
@ -96,6 +96,7 @@ public class MarkdownRenderer {
|
||||
.codeTextColor(prism4jTheme.textColor())
|
||||
.build())
|
||||
.factory(new GifAwareSpannableFactory(gifPlaceholder))
|
||||
.trimWhiteSpaceEnd(false)
|
||||
.build();
|
||||
|
||||
final long start = SystemClock.uptimeMillis();
|
||||
|
@ -26,7 +26,8 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
|
||||
// we will be using SpannableStringBuilder anyway as a backing store
|
||||
// as it has tight connection with system (implements some hidden methods, etc)
|
||||
private final SpannableStringBuilder builder;
|
||||
// private final SpannableStringBuilder builder;
|
||||
private final StringBuilder builder;
|
||||
|
||||
// actually we might be just using ArrayList
|
||||
private final Deque<Span> spans = new ArrayDeque<>(8);
|
||||
@ -36,7 +37,8 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
}
|
||||
|
||||
public SpannableBuilder(@NonNull CharSequence cs) {
|
||||
this.builder = new SpannableStringBuilderImpl(cs.toString());
|
||||
// this.builder = new SpannableStringBuilderImpl(cs.toString());
|
||||
this.builder = new StringBuilder(cs);
|
||||
copySpans(0, cs);
|
||||
}
|
||||
|
||||
@ -65,7 +67,7 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
|
||||
copySpans(length(), cs);
|
||||
|
||||
builder.append(cs.toString());
|
||||
builder.append(cs);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -80,7 +82,7 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
final CharSequence cs = csq.subSequence(start, end);
|
||||
copySpans(length(), cs);
|
||||
|
||||
builder.append(cs.toString());
|
||||
builder.append(cs);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -172,8 +174,73 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
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
|
||||
public CharSequence text() {
|
||||
// @since 2.0.0 redirects this call to `#spannableStringBuilder()`
|
||||
return spannableStringBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple method to create a SpannableStringBuilder, which is created anyway. Unlike {@link #text()}
|
||||
* method which returns the same SpannableStringBuilder there is no need to cast the resulting
|
||||
* CharSequence
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@NonNull
|
||||
public SpannableStringBuilder spannableStringBuilder() {
|
||||
|
||||
// okay, in order to not allow external modification and keep our spans order
|
||||
// we should not return our builder
|
||||
@ -183,30 +250,13 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
// so, we will defensively copy builder
|
||||
|
||||
// as we do not expose builder and do no apply spans to it, we are safe to NOT to convert to String
|
||||
|
||||
final SpannableStringBuilderImpl impl = new SpannableStringBuilderImpl(builder);
|
||||
|
||||
for (Span span : spans) {
|
||||
impl.setSpan(span.what, span.start, span.end, span.flags);
|
||||
}
|
||||
|
||||
// now, let's remove trailing newLines (so small amounts of text are displayed correctly)
|
||||
// @since 1.0.2
|
||||
|
||||
final int length = impl.length();
|
||||
if (length > 0) {
|
||||
int amount = 0;
|
||||
for (int i = length - 1; i >= 0; i--) {
|
||||
if (Character.isWhitespace(impl.charAt(i))) {
|
||||
amount += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (amount > 0) {
|
||||
impl.replace(length - amount, length, "");
|
||||
}
|
||||
}
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ public class SpannableConfiguration {
|
||||
private final SpannableHtmlParser htmlParser;
|
||||
private final ImageSizeResolver imageSizeResolver;
|
||||
private final SpannableFactory factory; // @since 1.1.0
|
||||
private final boolean trimWhiteSpaceEnd; // @since 2.0.0
|
||||
|
||||
private SpannableConfiguration(@NonNull Builder builder) {
|
||||
this.theme = builder.theme;
|
||||
@ -42,6 +43,7 @@ public class SpannableConfiguration {
|
||||
this.htmlParser = builder.htmlParser;
|
||||
this.imageSizeResolver = builder.imageSizeResolver;
|
||||
this.factory = builder.factory;
|
||||
this.trimWhiteSpaceEnd = builder.trimWhiteSpaceEnd;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -84,6 +86,13 @@ public class SpannableConfiguration {
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public boolean trimWhiteSpaceEnd() {
|
||||
return trimWhiteSpaceEnd;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class Builder {
|
||||
|
||||
@ -96,6 +105,7 @@ public class SpannableConfiguration {
|
||||
private SpannableHtmlParser htmlParser;
|
||||
private ImageSizeResolver imageSizeResolver;
|
||||
private SpannableFactory factory;
|
||||
private boolean trimWhiteSpaceEnd = true;
|
||||
|
||||
Builder(@NonNull Context context) {
|
||||
this.context = context;
|
||||
@ -155,6 +165,18 @@ public class SpannableConfiguration {
|
||||
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;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public SpannableConfiguration build() {
|
||||
|
||||
|
@ -15,6 +15,7 @@ import org.commonmark.node.BulletList;
|
||||
import org.commonmark.node.Code;
|
||||
import org.commonmark.node.CustomBlock;
|
||||
import org.commonmark.node.CustomNode;
|
||||
import org.commonmark.node.Document;
|
||||
import org.commonmark.node.Emphasis;
|
||||
import org.commonmark.node.FencedCodeBlock;
|
||||
import org.commonmark.node.HardLineBreak;
|
||||
@ -77,6 +78,15 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
this.factory = configuration.factory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Document document) {
|
||||
super.visit(document);
|
||||
|
||||
if (configuration.trimWhiteSpaceEnd()) {
|
||||
builder.trimWhiteSpaceEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Text text) {
|
||||
builder.append(text.getLiteral());
|
||||
|
Loading…
x
Reference in New Issue
Block a user