Improve TagHandler to allow direct set of spans
This commit is contained in:
parent
019ed61e69
commit
23b95e70b9
@ -145,11 +145,11 @@ Please refer to [SpannableConfiguration] document for more info
|
|||||||
|
|
||||||
## Syntax highlight
|
## Syntax highlight
|
||||||
|
|
||||||
Starting with version `1.1.0` there is an artifact (`markwon-syntax`) that allows you to have syntax highlight functionality.
|
Starting with version `1.1.0` there is an artifact (`markwon-syntax-highlight`) that allows you to have syntax highlight functionality.
|
||||||
It is based on [Prism4j](https://github.com/noties/Prism4j) project. It contains 2 builtin themes:
|
It is based on [Prism4j](https://github.com/noties/Prism4j) project. It contains 2 builtin themes:
|
||||||
`Default` (light, `Prism4jThemeDefault`) and `Darkula` (dark, `Prism4jThemeDarkula`).
|
`Default` (light, `Prism4jThemeDefault`) and `Darkula` (dark, `Prism4jThemeDarkula`).
|
||||||
|
|
||||||
[library-syntax](./library-syntax/)
|
[markwon-syntax-highlight](./markwon-syntax-highlight/)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -56,7 +56,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
private final SpannableConfiguration configuration;
|
private final SpannableConfiguration configuration;
|
||||||
private final SpannableBuilder builder;
|
private final SpannableBuilder builder;
|
||||||
private final MarkwonHtmlParser htmlParser;
|
private final MarkwonHtmlParser htmlParser;
|
||||||
// private final Deque<HtmlInlineItem> htmlInlineItems;
|
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final SpannableTheme theme;
|
||||||
private final SpannableFactory factory;
|
private final SpannableFactory factory;
|
||||||
@ -75,7 +74,6 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.builder = builder;
|
this.builder = builder;
|
||||||
this.htmlParser = configuration.htmlParser();
|
this.htmlParser = configuration.htmlParser();
|
||||||
// this.htmlInlineItems = new ArrayDeque<>(2);
|
|
||||||
|
|
||||||
this.theme = configuration.theme();
|
this.theme = configuration.theme();
|
||||||
this.factory = configuration.factory();
|
this.factory = configuration.factory();
|
||||||
@ -450,54 +448,12 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(HtmlBlock htmlBlock) {
|
public void visit(HtmlBlock htmlBlock) {
|
||||||
// // http://spec.commonmark.org/0.18/#html-blocks
|
|
||||||
// final Spanned spanned = configuration.htmlParser().getSpanned(null, htmlBlock.getLiteral());
|
|
||||||
// if (!TextUtils.isEmpty(spanned)) {
|
|
||||||
// builder.append(spanned);
|
|
||||||
// }
|
|
||||||
// htmlParser.processFragment(builder, htmlBlock.getLiteral());
|
|
||||||
visitHtml(htmlBlock.getLiteral());
|
visitHtml(htmlBlock.getLiteral());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(HtmlInline htmlInline) {
|
public void visit(HtmlInline htmlInline) {
|
||||||
|
|
||||||
visitHtml(htmlInline.getLiteral());
|
visitHtml(htmlInline.getLiteral());
|
||||||
|
|
||||||
// htmlParser.processFragment(builder, htmlInline.getLiteral());
|
|
||||||
|
|
||||||
// final SpannableHtmlParser htmlParser = configuration.htmlParser();
|
|
||||||
// final SpannableHtmlParser.Tag tag = htmlParser.parseTag(htmlInline.getLiteral());
|
|
||||||
//
|
|
||||||
// if (tag != null) {
|
|
||||||
//
|
|
||||||
// final boolean voidTag = tag.voidTag();
|
|
||||||
// if (!voidTag && tag.opening()) {
|
|
||||||
// // push in stack
|
|
||||||
// htmlInlineItems.push(new HtmlInlineItem(tag, builder.length()));
|
|
||||||
// visitChildren(htmlInline);
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// if (!voidTag) {
|
|
||||||
// if (htmlInlineItems.size() > 0) {
|
|
||||||
// final HtmlInlineItem item = htmlInlineItems.pop();
|
|
||||||
// final Object span = htmlParser.getSpanForTag(item.tag);
|
|
||||||
// setSpan(item.start, span);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// final Spanned html = htmlParser.getSpanned(tag, htmlInline.getLiteral());
|
|
||||||
// if (!TextUtils.isEmpty(html)) {
|
|
||||||
// builder.append(html);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // todo, should we append just literal?
|
|
||||||
//// builder.append(htmlInline.getLiteral());
|
|
||||||
// visitChildren(htmlInline);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitHtml(@Nullable String html) {
|
private void visitHtml(@Nullable String html) {
|
||||||
@ -568,15 +524,4 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static class HtmlInlineItem {
|
|
||||||
//
|
|
||||||
// final SpannableHtmlParser.Tag tag;
|
|
||||||
// final int start;
|
|
||||||
//
|
|
||||||
// HtmlInlineItem(SpannableHtmlParser.Tag tag, int start) {
|
|
||||||
// this.tag = tag;
|
|
||||||
// this.start = start;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import ru.noties.markwon.SpannableBuilder;
|
|||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||||
import ru.noties.markwon.renderer.html2.tag.EmphasisHandler;
|
import ru.noties.markwon.renderer.html2.tag.EmphasisHandler;
|
||||||
|
import ru.noties.markwon.renderer.html2.tag.ImageHandler;
|
||||||
import ru.noties.markwon.renderer.html2.tag.LinkHandler;
|
import ru.noties.markwon.renderer.html2.tag.LinkHandler;
|
||||||
import ru.noties.markwon.renderer.html2.tag.ListHandler;
|
import ru.noties.markwon.renderer.html2.tag.ListHandler;
|
||||||
import ru.noties.markwon.renderer.html2.tag.StrikeHandler;
|
import ru.noties.markwon.renderer.html2.tag.StrikeHandler;
|
||||||
@ -46,6 +47,7 @@ public abstract class MarkwonHtmlRenderer {
|
|||||||
final EmphasisHandler emphasisHandler = new EmphasisHandler();
|
final EmphasisHandler emphasisHandler = new EmphasisHandler();
|
||||||
final StrongEmphasisHandler strongEmphasisHandler = new StrongEmphasisHandler();
|
final StrongEmphasisHandler strongEmphasisHandler = new StrongEmphasisHandler();
|
||||||
final StrikeHandler strikeHandler = new StrikeHandler();
|
final StrikeHandler strikeHandler = new StrikeHandler();
|
||||||
|
final UnderlineHandler underlineHandler = new UnderlineHandler();
|
||||||
final ListHandler listHandler = new ListHandler();
|
final ListHandler listHandler = new ListHandler();
|
||||||
|
|
||||||
return builder()
|
return builder()
|
||||||
@ -57,13 +59,15 @@ public abstract class MarkwonHtmlRenderer {
|
|||||||
.handler("strong", strongEmphasisHandler)
|
.handler("strong", strongEmphasisHandler)
|
||||||
.handler("sup", new SuperScriptHandler())
|
.handler("sup", new SuperScriptHandler())
|
||||||
.handler("sub", new SubScriptHandler())
|
.handler("sub", new SubScriptHandler())
|
||||||
.handler("u", new UnderlineHandler())
|
.handler("u", underlineHandler)
|
||||||
|
.handler("ins", underlineHandler)
|
||||||
.handler("del", strikeHandler)
|
.handler("del", strikeHandler)
|
||||||
.handler("s", strikeHandler)
|
.handler("s", strikeHandler)
|
||||||
.handler("strike", strikeHandler)
|
.handler("strike", strikeHandler)
|
||||||
.handler("a", new LinkHandler())
|
.handler("a", new LinkHandler())
|
||||||
.handler("ul", listHandler)
|
.handler("ul", listHandler)
|
||||||
.handler("ol", listHandler);
|
.handler("ol", listHandler)
|
||||||
|
.handler("img", new ImageHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -82,9 +86,7 @@ public abstract class MarkwonHtmlRenderer {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public MarkwonHtmlRenderer build() {
|
public MarkwonHtmlRenderer build() {
|
||||||
return new MarkwonHtmlRendererImpl(
|
return new MarkwonHtmlRendererImpl(Collections.unmodifiableMap(tagHandlers));
|
||||||
Collections.unmodifiableMap(tagHandlers)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
package ru.noties.markwon.renderer.html2.tag;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
import ru.noties.markwon.renderer.ImageSize;
|
||||||
|
|
||||||
|
public class ImageHandler extends SimpleTagHandler {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||||
|
|
||||||
|
final Map<String, String> attributes = tag.attributes();
|
||||||
|
final String src = attributes.get("src");
|
||||||
|
if (TextUtils.isEmpty(src)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String destination = configuration.urlProcessor().process(src);
|
||||||
|
|
||||||
|
// todo: replacement text is link... as we are not at block level
|
||||||
|
// and cannot inspect the parent of this node... (img and a are both inlines)
|
||||||
|
|
||||||
|
return configuration.factory().image(
|
||||||
|
configuration.theme(),
|
||||||
|
destination,
|
||||||
|
configuration.asyncDrawableLoader(),
|
||||||
|
configuration.imageSizeResolver(),
|
||||||
|
parseImageSize(attributes),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static ImageSize parseImageSize(@NonNull Map<String, String> attributes) {
|
||||||
|
// strictly speaking percents when specified directly on an attribute
|
||||||
|
// are not part of the HTML spec (I couldn't find any reference)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ import ru.noties.markwon.SpannableBuilder;
|
|||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class ListHandler implements TagHandler {
|
public class ListHandler extends TagHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(
|
public void handle(
|
||||||
@ -53,23 +53,6 @@ public class ListHandler implements TagHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitChildren(
|
|
||||||
@NonNull SpannableConfiguration configuration,
|
|
||||||
@NonNull SpannableBuilder builder,
|
|
||||||
@NonNull HtmlTag.Block block) {
|
|
||||||
|
|
||||||
TagHandler handler;
|
|
||||||
|
|
||||||
for (HtmlTag.Block child : block.children()) {
|
|
||||||
handler = configuration.htmlRenderer().tagHandler(child.name());
|
|
||||||
if (handler != null) {
|
|
||||||
handler.handle(configuration, builder, child);
|
|
||||||
} else {
|
|
||||||
visitChildren(configuration, builder, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int currentBulletListLevel(@NonNull HtmlTag.Block block) {
|
private static int currentBulletListLevel(@NonNull HtmlTag.Block block) {
|
||||||
int level = 0;
|
int level = 0;
|
||||||
while ((block = block.parent()) != null) {
|
while ((block = block.parent()) != null) {
|
||||||
|
@ -7,7 +7,7 @@ import ru.noties.markwon.SpannableBuilder;
|
|||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public abstract class SimpleTagHandler implements TagHandler {
|
public abstract class SimpleTagHandler extends TagHandler {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag);
|
public abstract Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag);
|
||||||
|
@ -1,15 +1,28 @@
|
|||||||
package ru.noties.markwon.renderer.html2.tag;
|
package ru.noties.markwon.renderer.html2.tag;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
|
|
||||||
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class StrikeHandler extends SimpleTagHandler {
|
public class StrikeHandler extends TagHandler {
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public void handle(
|
||||||
return configuration.factory().strikethrough();
|
@NonNull SpannableConfiguration configuration,
|
||||||
|
@NonNull SpannableBuilder builder,
|
||||||
|
@NonNull HtmlTag tag) {
|
||||||
|
|
||||||
|
if (tag.isBlock()) {
|
||||||
|
visitChildren(configuration, builder, tag.getAsBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
SpannableBuilder.setSpans(
|
||||||
|
builder,
|
||||||
|
configuration.factory().strikethrough(),
|
||||||
|
tag.start(),
|
||||||
|
tag.end()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,28 @@ import ru.noties.markwon.SpannableBuilder;
|
|||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public interface TagHandler {
|
public abstract class TagHandler {
|
||||||
|
|
||||||
void handle(
|
public abstract void handle(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull SpannableConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull HtmlTag tag
|
@NonNull HtmlTag tag
|
||||||
);
|
);
|
||||||
|
|
||||||
|
protected static void visitChildren(
|
||||||
|
@NonNull SpannableConfiguration configuration,
|
||||||
|
@NonNull SpannableBuilder builder,
|
||||||
|
@NonNull HtmlTag.Block block) {
|
||||||
|
|
||||||
|
TagHandler handler;
|
||||||
|
|
||||||
|
for (HtmlTag.Block child : block.children()) {
|
||||||
|
handler = configuration.htmlRenderer().tagHandler(child.name());
|
||||||
|
if (handler != null) {
|
||||||
|
handler.handle(configuration, builder, child);
|
||||||
|
} else {
|
||||||
|
visitChildren(configuration, builder, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,31 @@
|
|||||||
package ru.noties.markwon.renderer.html2.tag;
|
package ru.noties.markwon.renderer.html2.tag;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
|
|
||||||
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class UnderlineHandler extends SimpleTagHandler {
|
public class UnderlineHandler extends TagHandler {
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public void handle(
|
||||||
return configuration.factory().underline();
|
@NonNull SpannableConfiguration configuration,
|
||||||
|
@NonNull SpannableBuilder builder,
|
||||||
|
@NonNull HtmlTag tag) {
|
||||||
|
|
||||||
|
// as parser doesn't treat U tag as an inline one,
|
||||||
|
// thus doesn't allow children, we must visit them first
|
||||||
|
|
||||||
|
if (tag.isBlock()) {
|
||||||
|
visitChildren(configuration, builder, tag.getAsBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
SpannableBuilder.setSpans(
|
||||||
|
builder,
|
||||||
|
configuration.factory().underline(),
|
||||||
|
tag.start(),
|
||||||
|
tag.end()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user