Skip to content

Commit

Permalink
seperate normal and formatting elements, remove SingleTagMultiElement
Browse files Browse the repository at this point in the history
  • Loading branch information
DeDiamondPro committed Jun 30, 2024
1 parent 3cf79bb commit 90d2860
Show file tree
Hide file tree
Showing 27 changed files with 374 additions and 283 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ plugins {
}

group = "dev.dediamondpro"
version = "1.1.0"
version = "1.2.0"

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package dev.dediamondpro.minemark.elementa.elements
import dev.dediamondpro.minemark.LayoutStyle
import dev.dediamondpro.minemark.elementa.style.MarkdownStyle
import dev.dediamondpro.minemark.elements.Element
import dev.dediamondpro.minemark.elements.impl.formatting.HeadingElement
import dev.dediamondpro.minemark.elements.impl.HeadingElement
import gg.essential.elementa.components.UIBlock
import gg.essential.universal.UMatrixStack
import org.xml.sax.Attributes
Expand Down
2 changes: 1 addition & 1 deletion minecraft/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Mod Configuration
mod_name=MineMark
mod_id=minemark
mod_version=1.1.0
mod_version=1.2.0
mod_description=Markdown rendering library
mod_license=LGPL
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import dev.dediamondpro.minemark.LayoutStyle;
import dev.dediamondpro.minemark.elements.Element;
import dev.dediamondpro.minemark.elements.impl.CodeBlockElement;
import dev.dediamondpro.minemark.elements.impl.formatting.HeadingElement;
import dev.dediamondpro.minemark.minecraft.platform.MarkdownRenderer;
import dev.dediamondpro.minemark.minecraft.style.MarkdownStyle;
import org.jetbrains.annotations.NotNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import dev.dediamondpro.minemark.LayoutStyle;
import dev.dediamondpro.minemark.elements.Element;
import dev.dediamondpro.minemark.elements.impl.formatting.HeadingElement;
import dev.dediamondpro.minemark.elements.impl.HeadingElement;
import dev.dediamondpro.minemark.minecraft.platform.MarkdownRenderer;
import dev.dediamondpro.minemark.minecraft.style.MarkdownStyle;
import org.jetbrains.annotations.NotNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public void close() {
public static MarkdownDynamicImage of(NativeImage image) throws IOException {
NativeImageBackedTexture texture = new NativeImageBackedTexture(image);
Identifier identifier = MinecraftClient.getInstance().getTextureManager().registerDynamicTexture("minemark", texture);
System.out.println("Created dynamic image " + identifier);
return new MarkdownDynamicImage(identifier);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
Expand All @@ -43,14 +45,10 @@ public void getImage(String src, Consumer<Dimension> dimensionCallback, Consumer
BufferedImage bufferedImage = ImageIO.read(getInputStream(src));
dimensionCallback.accept(new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight()));

NativeImage image = new NativeImage(bufferedImage.getWidth(), bufferedImage.getHeight(), true);
for (int y = 0; y < bufferedImage.getHeight(); y++) {
for (int x = 0; x < bufferedImage.getWidth(); x++) {
image.setColor(x, y, bufferedImage.getRGB(x, y));
}
}

imageCallback.accept(MarkdownDynamicImage.of(image));
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", out);
NativeImage nativeImage = NativeImage.read(new ByteArrayInputStream(out.toByteArray()));
imageCallback.accept(MarkdownDynamicImage.of(nativeImage));
} catch (IOException e) {
e.printStackTrace();
}
Expand Down
28 changes: 15 additions & 13 deletions src/main/java/dev/dediamondpro/minemark/MineMarkCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import dev.dediamondpro.minemark.elements.MineMarkElement;
import dev.dediamondpro.minemark.elements.creators.ElementCreator;
import dev.dediamondpro.minemark.elements.creators.TextElementCreator;
import dev.dediamondpro.minemark.elements.formatting.FormattingElement;
import dev.dediamondpro.minemark.style.Style;
import org.commonmark.Extension;
import org.commonmark.node.Node;
Expand Down Expand Up @@ -51,42 +52,43 @@ public class MineMarkCore<S extends Style, R> {
private final ReentrantLock parsingLock = new ReentrantLock();

/**
* @param textElement The text element for this core
* @param elements Elements supported to create a layout and render
* @param extensions Markdown extensions that should be used when parsing
* @param urlSanitizer An optional urlSanitizer
* @param textElement The text element for this core
* @param elements Elements supported to create a layout and render
* @param formattingElements Elements that apply a formatting style
* @param extensions Markdown extensions that should be used when parsing
* @param urlSanitizer An optional urlSanitizer
*/
protected MineMarkCore(TextElementCreator<S, R> textElement, List<ElementCreator<S, R>> elements, Iterable<? extends Extension> extensions, @Nullable UrlSanitizer urlSanitizer) {
protected MineMarkCore(TextElementCreator<S, R> textElement, List<ElementCreator<S, R>> elements, List<FormattingElement<S, R>> formattingElements, Iterable<? extends Extension> extensions, @Nullable UrlSanitizer urlSanitizer) {
this.markdownParser = Parser.builder().extensions(extensions).build();
HtmlRenderer.Builder htmlRendererBuilder = HtmlRenderer.builder().extensions(extensions);
if (urlSanitizer != null) {
htmlRendererBuilder.urlSanitizer(urlSanitizer).sanitizeUrls(true);
}
this.htmlRenderer = htmlRendererBuilder.build();
this.htmlParser = new MineMarkHtmlParser<>(textElement, elements);
this.htmlParser = new MineMarkHtmlParser<>(textElement, elements, formattingElements);
xmlParser = new org.ccil.cowan.tagsoup.Parser();
xmlParser.setContentHandler(htmlParser);
}

/**
* Parse markdown to an element used to render it
*
* @param markdown The markdown text to parse
* @param markdown The Markdown text to parse
* @param style The style passed to all elements
* @param charSet The charset to use when parsing the markdown
* @return The parsed markdown element
* @throws SAXException An exception during SAX parsing
* @throws IOException An IOException during parsing
*/
public MineMarkElement<S, R> parse(@NotNull S style, @NotNull String markdown, Charset charSet) throws SAXException, IOException {
public MineMarkElement<S, R> parse(@NotNull S style, @NotNull String markdown, @NotNull Charset charSet) throws SAXException, IOException {
Node document = markdownParser.parse(markdown);
return parseDocument(style, document, charSet);
}

/**
* Parse markdown to an element used to render it
*
* @param markdown The markdown text to parse
* @param markdown The Markdown text to parse
* @param style The style passed to all elements
* @return The parsed markdown element
* @throws SAXException An exception during SAX parsing
Expand All @@ -99,22 +101,22 @@ public MineMarkElement<S, R> parse(@NotNull S style, @NotNull String markdown) t
/**
* Parse markdown to an element used to render it
*
* @param markdown The markdown text to parse
* @param markdown The Markdown text to parse
* @param style The style passed to all elements
* @param charSet The charset to use when parsing the markdown
* @return The parsed markdown element
* @throws SAXException An exception during SAX parsing
* @throws IOException An IOException during parsing
*/
public MineMarkElement<S, R> parse(@NotNull S style, @NotNull Reader markdown, Charset charSet) throws SAXException, IOException {
public MineMarkElement<S, R> parse(@NotNull S style, @NotNull Reader markdown, @NotNull Charset charSet) throws SAXException, IOException {
Node document = markdownParser.parseReader(markdown);
return parseDocument(style, document, charSet);
}

/**
* Parse markdown to an element used to render it
*
* @param markdown The markdown text to parse
* @param markdown The Markdown text to parse
* @param style The style passed to all elements
* @return The parsed markdown element
* @throws SAXException An exception during SAX parsing
Expand All @@ -124,7 +126,7 @@ public MineMarkElement<S, R> parse(@NotNull S style, @NotNull Reader markdown) t
return parse(style, markdown, StandardCharsets.UTF_8);
}

private MineMarkElement<S, R> parseDocument(@NotNull S style, Node document, Charset charSet) throws SAXException, IOException {
private MineMarkElement<S, R> parseDocument(@NotNull S style, Node document, @NotNull Charset charSet) throws SAXException, IOException {
String html = "<minemark>\n" + htmlRenderer.render(document) + "</minemark>";
// Acquire the lock to make sure this thread is the only one using the parser
parsingLock.lock();
Expand Down
73 changes: 59 additions & 14 deletions src/main/java/dev/dediamondpro/minemark/MineMarkCoreBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
package dev.dediamondpro.minemark;

import dev.dediamondpro.minemark.elements.Elements;
import dev.dediamondpro.minemark.elements.formatting.FormattingElement;
import dev.dediamondpro.minemark.elements.impl.LinkElement;
import dev.dediamondpro.minemark.elements.impl.ParagraphElement;
import dev.dediamondpro.minemark.elements.impl.formatting.AlignmentElement;
import dev.dediamondpro.minemark.elements.impl.formatting.CssStyleElement;
import dev.dediamondpro.minemark.elements.impl.formatting.FormattingElement;
import dev.dediamondpro.minemark.elements.formatting.impl.AlignmentElement;
import dev.dediamondpro.minemark.elements.formatting.impl.CssStyleElement;
import dev.dediamondpro.minemark.elements.formatting.impl.TextFormattingElement;
import dev.dediamondpro.minemark.elements.impl.list.ListHolderElement;
import dev.dediamondpro.minemark.elements.impl.table.TableHolderElement;
import dev.dediamondpro.minemark.elements.impl.table.TableRowElement;
Expand All @@ -40,8 +41,10 @@ public class MineMarkCoreBuilder<S extends Style, R> {
protected MineMarkCoreBuilder() {
}

private final ArrayList<FormattingElement<S, R>> formattingElements = new ArrayList<>();
private final ArrayList<ElementCreator<S, R>> elements = new ArrayList<>();
private final ArrayList<Extension> extensions = new ArrayList<>();
private boolean withDefaultFormattingElements = true;
private TextElementCreator<S, R> textElement = null;
private boolean withDefaultElements = true;
private UrlSanitizer urlSanitizer = null;
Expand Down Expand Up @@ -143,7 +146,7 @@ public MineMarkCoreBuilder<S, R> addElement(int position, @NotNull Elements elem
/**
* Add supported elements to be used
*
* @param elements A Map with all elements that should be added
* @param elements A List with all elements that should be added
*/
public MineMarkCoreBuilder<S, R> addElements(@NotNull List<ElementCreator<S, R>> elements) {
for (ElementCreator<S, R> element : elements) {
Expand All @@ -152,6 +155,39 @@ public MineMarkCoreBuilder<S, R> addElements(@NotNull List<ElementCreator<S, R>>
return this;
}

/**
* Add a formatting element to be used
*
* @param element The formatting element
*/
public MineMarkCoreBuilder<S, R> addFormatingElement(@NotNull FormattingElement<S, R> element) {
this.formattingElements.add(element);
return this;
}

/**
* Add a formatting element to be used
*
* @param position The position the element should be added at
* @param element The formatting element
*/
public MineMarkCoreBuilder<S, R> addFormatingElement(int position, @NotNull FormattingElement<S, R> element) {
this.formattingElements.add(position, element);
return this;
}

/**
* Add formatting elements to be used
*
* @param elements A List of formatting elements that should be added
*/
public MineMarkCoreBuilder<S, R> addFormatingElements(@NotNull List<FormattingElement<S, R>> elements) {
for (FormattingElement<S, R> element : elements) {
addFormatingElement(element);
}
return this;
}

/**
* Add a commonmark extension to the Markdown parser
*
Expand All @@ -170,6 +206,14 @@ public MineMarkCoreBuilder<S, R> withoutDefaultElements() {
return this;
}

/**
* Disable default formatting elements
*/
public MineMarkCoreBuilder<S, R> withoutDefaultFormattingElements() {
withDefaultFormattingElements = false;
return this;
}

/**
* Make the core use an url sanitizer and enable url sanitization
*
Expand All @@ -188,16 +232,17 @@ public MineMarkCore<S, R> build() {
throw new IllegalArgumentException("A text element has to be provided by using \"setTextElement(textElement\"");
}
if (withDefaultElements) {
// Add default (formatting) elements, these are added first so they take priority and their formatting applies properly
addElement(0, Elements.PARAGRAPH, ParagraphElement::new);
addElement(0, Elements.FORMATTING, FormattingElement::new);
addElement(0, Elements.LINK, LinkElement::new);
addElement(0, Elements.LIST_PARENT, ListHolderElement::new);
addElement(0, Elements.TABLE, TableHolderElement::new);
addElement(0, Elements.TABLE_ROW, TableRowElement::new);
addElement(0, new AlignmentElement.AlignmentElementCreator<>());
addElement(0, new CssStyleElement.CssStyleElementCreator<>());
addElement(Elements.PARAGRAPH, ParagraphElement::new);
addElement(Elements.LINK, LinkElement::new);
addElement(Elements.LIST_PARENT, ListHolderElement::new);
addElement(Elements.TABLE, TableHolderElement::new);
addElement(Elements.TABLE_ROW, TableRowElement::new);
}
if (withDefaultFormattingElements) {
addFormatingElement(new AlignmentElement<>());
addFormatingElement(new CssStyleElement<>());
addFormatingElement(new TextFormattingElement<>());
}
return new MineMarkCore<>(textElement, elements, extensions, urlSanitizer);
return new MineMarkCore<>(textElement, elements, formattingElements, extensions, urlSanitizer);
}
}
52 changes: 30 additions & 22 deletions src/main/java/dev/dediamondpro/minemark/MineMarkHtmlParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
import dev.dediamondpro.minemark.elements.Element;
import dev.dediamondpro.minemark.elements.EmptyElement;
import dev.dediamondpro.minemark.elements.MineMarkElement;
import dev.dediamondpro.minemark.elements.SingleTagMultiElement;
import dev.dediamondpro.minemark.elements.creators.ElementCreator;
import dev.dediamondpro.minemark.elements.creators.TextElementCreator;
import dev.dediamondpro.minemark.elements.formatting.FormattingElement;
import dev.dediamondpro.minemark.style.Style;
import org.jetbrains.annotations.NotNull;
import org.xml.sax.Attributes;
Expand All @@ -32,6 +32,7 @@

public class MineMarkHtmlParser<S extends Style, R> extends DefaultHandler {
private final List<ElementCreator<S, R>> elements;
private final List<FormattingElement<S, R>> formattingElements;
private final TextElementCreator<S, R> textElementCreator;
private MineMarkElement<S, R> markDown;
private Element<S, R> currentElement;
Expand All @@ -40,9 +41,10 @@ public class MineMarkHtmlParser<S extends Style, R> extends DefaultHandler {
private StringBuilder textBuilder = new StringBuilder();
private boolean isPreFormatted = false;

protected MineMarkHtmlParser(TextElementCreator<S, R> textElementCreator, List<ElementCreator<S, R>> elements) {
protected MineMarkHtmlParser(TextElementCreator<S, R> textElementCreator, List<ElementCreator<S, R>> elements, List<FormattingElement<S, R>> formattingElements) {
this.textElementCreator = textElementCreator;
this.elements = elements;
this.formattingElements = formattingElements;
}

@Override
Expand All @@ -59,8 +61,29 @@ public void startElement(String uri, String localName, String qName, Attributes
break;
}
addText();
Element<S, R> newElement = createElement(style, currentElement.getLayoutStyle(), currentElement, qName, attributes);
currentElement = newElement != null ? newElement : new EmptyElement<>(style, currentElement.getLayoutStyle(), currentElement, qName, attributes);

LayoutStyle originalLayoutStyle = currentElement.getLayoutStyle();
LayoutStyle layoutStyle = originalLayoutStyle;
boolean canBeInline = true;
for (FormattingElement<S, R> element : formattingElements) {
if (!element.appliesTo(style, layoutStyle, currentElement, qName, attributes)) {
continue;
}
// If a formatting element applies, clone the layout style. This should only be done once
if (layoutStyle == originalLayoutStyle) {
layoutStyle = layoutStyle.clone();
}

element.applyStyle(style, layoutStyle, currentElement, qName, attributes);

canBeInline = canBeInline && element.canBeInline(style, layoutStyle, currentElement, qName, attributes);
}

Element<S, R> newElement = createElement(style, layoutStyle, currentElement, qName, attributes);
currentElement = newElement != null ? newElement : new EmptyElement<>(style, layoutStyle, currentElement, qName, attributes);
if (!canBeInline) {
currentElement.setInline(false);
}
}

@Override
Expand Down Expand Up @@ -121,31 +144,16 @@ private void addText() {
* @param parent The parent element, null if top level element
* @param qName The name of the HTML tag
* @param attributes The attributes of the HTML tag, null for text
* @return If only one element applies to the given parameters, return that element,
* otherwise return a TagMultiElement with all elements that apply. If no element applies, return null.
* @return The first element that applies to the parameters, if none apply returns null
*/
private Element<S, R> createElement(S style, LayoutStyle layoutStyle, @NotNull Element<S, R> parent, @NotNull String qName, @NotNull Attributes attributes) {
ElementCreator<S, R> elementCreator = null;
SingleTagMultiElement<S, R> multipleElement = null;

for (ElementCreator<S, R> element : elements) {
if (!element.appliesTo(style, layoutStyle, parent, qName, attributes)) {
continue;
}

if (elementCreator == null) {
elementCreator = element;
continue;
}

if (multipleElement == null) {
multipleElement = new SingleTagMultiElement<>(style, layoutStyle, parent, qName, attributes);
multipleElement.addElement(elementCreator);
}
multipleElement.addElement(element);

return element.createElement(style, layoutStyle, parent, qName, attributes);
}
return multipleElement != null ? multipleElement : elementCreator != null ? elementCreator.createElement(style, layoutStyle, parent, qName, attributes) : null;
return null;
}

protected void setStyle(S style, LayoutStyle layoutStyle) {
Expand Down
Loading

0 comments on commit 90d2860

Please sign in to comment.