All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vladsch.flexmark.formatter.Formatter Maven / Gradle / Ivy

There is a newer version: 0.50.50
Show newest version
package com.vladsch.flexmark.formatter;

import com.vladsch.flexmark.formatter.internal.CoreNodeFormatter;
import com.vladsch.flexmark.formatter.internal.FormatterOptions;
import com.vladsch.flexmark.formatter.internal.TranslationHandlerImpl;
import com.vladsch.flexmark.html.AttributeProviderFactory;
import com.vladsch.flexmark.html.LinkResolverFactory;
import com.vladsch.flexmark.html.renderer.HeaderIdGenerator;
import com.vladsch.flexmark.html.renderer.HeaderIdGeneratorFactory;
import com.vladsch.flexmark.html.renderer.HtmlIdGeneratorFactory;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.parser.ParserEmulationProfile;
import com.vladsch.flexmark.util.ast.IRender;
import com.vladsch.flexmark.util.ast.Document;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.builder.BuilderBase;
import com.vladsch.flexmark.util.builder.Extension;
import com.vladsch.flexmark.util.ast.NodeCollectingVisitor;
import com.vladsch.flexmark.util.collection.SubClassingBag;
import com.vladsch.flexmark.util.data.*;
import com.vladsch.flexmark.util.format.TableFormatOptions;
import com.vladsch.flexmark.util.format.options.*;
import com.vladsch.flexmark.util.html.LineFormattingAppendable;
import com.vladsch.flexmark.util.mappers.CharWidthProvider;

import java.util.*;

/**
 * Renders a tree of nodes to HTML.
 * 

* Start with the {@link #builder} method to configure the renderer. Example: *


 * HtmlRenderer renderer = HtmlRenderer.builder().escapeHtml(true).build();
 * renderer.render(node);
 * 
*/ @SuppressWarnings("WeakerAccess") public class Formatter implements IRender { /** * output control for FormattingAppendable, see {@link LineFormattingAppendable#setOptions(int)} */ public static final DataKey FORMAT_FLAGS = new DataKey<>("FORMAT_FLAGS", 0); // for convenience or these together and set FORMAT_FLAGS key above to the value, to have HtmlWriter apply these when rendering Html public static final int FORMAT_CONVERT_TABS = LineFormattingAppendable.CONVERT_TABS; public static final int FORMAT_COLLAPSE_WHITESPACE = LineFormattingAppendable.COLLAPSE_WHITESPACE; public static final int FORMAT_SUPPRESS_TRAILING_WHITESPACE = LineFormattingAppendable.SUPPRESS_TRAILING_WHITESPACE; public static final int FORMAT_ALL_OPTIONS = LineFormattingAppendable.FORMAT_ALL; public static final DataKey MAX_BLANK_LINES = new DataKey<>("MAX_BLANK_LINES", 2); public static final DataKey MAX_TRAILING_BLANK_LINES = new DataKey<>("MAX_TRAILING_BLANK_LINES", 1); public static final DataKey SPACE_AFTER_ATX_MARKER = new DataKey<>("SPACE_AFTER_ATX_MARKER", DiscretionaryText.ADD); public static final DataKey SETEXT_HEADER_EQUALIZE_MARKER = new DataKey<>("SETEXT_HEADER_EQUALIZE_MARKER", true); public static final DataKey ATX_HEADER_TRAILING_MARKER = new DataKey<>("ATX_HEADER_TRAILING_MARKER", EqualizeTrailingMarker.AS_IS); public static final DataKey THEMATIC_BREAK = new DataKey<>("THEMATIC_BREAK", (String) null); public static final DataKey BLOCK_QUOTE_BLANK_LINES = new DataKey<>("BLOCK_QUOTE_BLANK_LINES", true); public static final DataKey BLOCK_QUOTE_MARKERS = new DataKey<>("BLOCK_QUOTE_MARKERS", BlockQuoteMarker.ADD_COMPACT_WITH_SPACE); public static final DataKey INDENTED_CODE_MINIMIZE_INDENT = new DataKey<>("INDENTED_CODE_MINIMIZE_INDENT", true); public static final DataKey FENCED_CODE_MINIMIZE_INDENT = new DataKey<>("FENCED_CODE_MINIMIZE_INDENT", true); public static final DataKey FENCED_CODE_MATCH_CLOSING_MARKER = new DataKey<>("FENCED_CODE_MATCH_CLOSING_MARKER", true); public static final DataKey FENCED_CODE_SPACE_BEFORE_INFO = new DataKey<>("FENCED_CODE_SPACE_BEFORE_INFO", false); public static final DataKey FENCED_CODE_MARKER_LENGTH = new DataKey<>("FENCED_CODE_MARKER_LENGTH", 3); public static final DataKey FENCED_CODE_MARKER_TYPE = new DataKey<>("FENCED_CODE_MARKER_TYPE", CodeFenceMarker.ANY); public static final DataKey LIST_ADD_BLANK_LINE_BEFORE = new DataKey<>("LIST_ADD_BLANK_LINE_BEFORE", false); //public static final DataKey LIST_ALIGN_FIRST_LINE_TEXT = new DataKey<>("LIST_ALIGN_FIRST_LINE_TEXT", false); //public static final DataKey LIST_ALIGN_CHILD_BLOCKS = new DataKey<>("LIST_ALIGN_CHILD_BLOCKS", true); public static final DataKey LIST_RENUMBER_ITEMS = new DataKey<>("LIST_RENUMBER_ITEMS", true); public static final DataKey LIST_REMOVE_EMPTY_ITEMS = new DataKey<>("LIST_REMOVE_EMPTY_ITEMS", false); public static final DataKey LIST_BULLET_MARKER = new DataKey<>("LIST_BULLET_MARKER", ListBulletMarker.ANY); public static final DataKey LIST_NUMBERED_MARKER = new DataKey<>("LIST_NUMBERED_MARKER", ListNumberedMarker.ANY); public static final DataKey LIST_SPACING = new DataKey<>("LIST_SPACING", ListSpacing.AS_IS); public static final DataKey REFERENCE_PLACEMENT = new DataKey<>("REFERENCE_PLACEMENT", ElementPlacement.AS_IS); public static final DataKey REFERENCE_SORT = new DataKey<>("REFERENCE_SORT", ElementPlacementSort.AS_IS); public static final DataKey KEEP_IMAGE_LINKS_AT_START = new DataKey<>("KEEP_IMAGE_LINKS_AT_START", false); public static final DataKey KEEP_EXPLICIT_LINKS_AT_START = new DataKey<>("KEEP_EXPLICIT_LINKS_AT_START", false); public static final DataKey OPTIMIZED_INLINE_RENDERING = new DataKey<>("OPTIMIZED_INLINE_RENDERING", false); //public static final DataKey KEEP_TRAILING_SPACES = new DataKey<>("KEEP_TRAILING_SPACES", TrailingSpaces.KEEP_LINE_BREAK); //public static final DataKey CODE_KEEP_TRAILING_SPACES = new DataKey<>("CODE_KEEP_TRAILING_SPACES", TrailingSpaces.KEEP_ALL); public static final DataKey FORMAT_CHAR_WIDTH_PROVIDER = TableFormatOptions.FORMAT_CHAR_WIDTH_PROVIDER; /** * @deprecated use FORMAT_ prefixed name */ @Deprecated public static final DataKey CHAR_WIDTH_PROVIDER = TableFormatOptions.FORMAT_CHAR_WIDTH_PROVIDER; public static final DataKey FORMAT_TABLE_CAPTION = TableFormatOptions.FORMAT_TABLE_CAPTION; public static final DataKey FORMAT_TABLE_CAPTION_SPACES = TableFormatOptions.FORMAT_TABLE_CAPTION_SPACES; public static final DataKey FORMAT_TABLE_INDENT_PREFIX = TableFormatOptions.FORMAT_TABLE_INDENT_PREFIX; // formatter family override public static final DataKey FORMATTER_EMULATION_PROFILE = new DataKey("FORMATTER_EMULATION_PROFILE", Parser.PARSER_EMULATION_PROFILE); // used for translation phases of rendering public static final DataKey TRANSLATION_ID_FORMAT = new DataKey<>("TRANSLATION_ID_FORMAT", "_%d_"); public static final DataKey TRANSLATION_HTML_BLOCK_PREFIX = new DataKey<>("TRANSLATION_HTML_BLOCK_PREFIX", "_"); public static final DataKey TRANSLATION_EXCLUDE_PATTERN = new DataKey<>("TRANSLATION_EXCLUDE_PATTERN", "^[^\\p{IsAlphabetic}]*$"); public static final DataKey TRANSLATION_HTML_BLOCK_TAG_PATTERN = Parser.TRANSLATION_HTML_BLOCK_TAG_PATTERN; public static final DataKey TRANSLATION_HTML_INLINE_TAG_PATTERN = Parser.TRANSLATION_HTML_INLINE_TAG_PATTERN; public static final DataKey KEEP_HARD_LINE_BREAKS = new DataKey<>("KEEP_HARD_LINE_BREAKS", true); public static final DataKey KEEP_SOFT_LINE_BREAKS = new DataKey<>("KEEP_SOFT_LINE_BREAKS", true); public static final DataKey APPEND_TRANSFERRED_REFERENCES = new DataKey<>("APPEND_TRANSFERRED_REFERENCES", false); final List nodeFormatterFactories; final FormatterOptions formatterOptions; private final DataHolder options; private final Builder builder; private Formatter(Builder builder) { this.builder = new Builder(builder); // take a copy to avoid after creation side effects this.options = new DataSet(builder); this.formatterOptions = new FormatterOptions(this.options); this.nodeFormatterFactories = new ArrayList(builder.nodeFormatterFactories.size() + 1); this.nodeFormatterFactories.addAll(builder.nodeFormatterFactories); // Add as last. This means clients can override the rendering of core nodes if they want. this.nodeFormatterFactories.add(new NodeFormatterFactory() { @Override public NodeFormatter create(DataHolder options) { return new CoreNodeFormatter(options); } }); } public TranslationHandler getTranslationHandler(TranslationHandlerFactory translationHandlerFactory, HtmlIdGeneratorFactory idGeneratorFactory) { return translationHandlerFactory.create(options, formatterOptions, idGeneratorFactory); } public TranslationHandler getTranslationHandler(HtmlIdGeneratorFactory idGeneratorFactory) { return new TranslationHandlerImpl(options, formatterOptions, idGeneratorFactory); } public TranslationHandler getTranslationHandler() { return new TranslationHandlerImpl(options, formatterOptions, new HeaderIdGenerator.Factory()); } @Override public DataHolder getOptions() { return new DataSet(builder); } /** * Create a new builder for configuring an {@link Formatter}. * * @return a builder */ public static Builder builder() { return new Builder(); } /** * Create a new builder for configuring an {@link Formatter}. * * @param options initialization options * @return a builder */ public static Builder builder(DataHolder options) { return new Builder(options); } /** * Render a node to the appendable * * @param node node to render * @param output appendable to use for the output */ public void render(Node node, Appendable output) { MainNodeFormatter renderer = new MainNodeFormatter(options, new MarkdownWriter(formatterOptions.formatFlags), node.getDocument(), null); renderer.render(node); renderer.flushTo(output, formatterOptions.maxTrailingBlankLines); } /** * Render a node to the appendable * * @param node node to render * @param output appendable to use for the output */ public void render(Node node, Appendable output, int maxTrailingBlankLines) { MainNodeFormatter renderer = new MainNodeFormatter(options, new MarkdownWriter(formatterOptions.formatFlags), node.getDocument(), null); renderer.render(node); renderer.flushTo(output, maxTrailingBlankLines); } /** * Render the tree of nodes to markdown * * @param node the root node * @return the formatted markdown */ public String render(Node node) { StringBuilder sb = new StringBuilder(); render(node, sb); return sb.toString(); } /** * Render a node to the appendable * * @param node node to render * @param output appendable to use for the output */ public void translationRender(Node node, Appendable output, TranslationHandler translationHandler, RenderPurpose renderPurpose) { translationHandler.setRenderPurpose(renderPurpose); MainNodeFormatter renderer = new MainNodeFormatter(options, new MarkdownWriter(formatterOptions.formatFlags /*| FormattingAppendable.PASS_THROUGH*/), node.getDocument(), translationHandler); renderer.render(node); renderer.flushTo(output, formatterOptions.maxTrailingBlankLines); } /** * Render a node to the appendable * * @param node node to render * @param output appendable to use for the output */ public void translationRender(Node node, Appendable output, int maxTrailingBlankLines, TranslationHandler translationHandler, RenderPurpose renderPurpose) { translationHandler.setRenderPurpose(renderPurpose); MainNodeFormatter renderer = new MainNodeFormatter(options, new MarkdownWriter(formatterOptions.formatFlags /*| FormattingAppendable.PASS_THROUGH*/), node.getDocument(), translationHandler); renderer.render(node); renderer.flushTo(output, maxTrailingBlankLines); } /** * Render the tree of nodes to markdown * * @param node the root node * @return the formatted markdown */ public String translationRender(Node node, TranslationHandler translationHandler, RenderPurpose renderPurpose) { StringBuilder sb = new StringBuilder(); translationRender(node, sb, translationHandler, renderPurpose); return sb.toString(); } public Formatter withOptions(DataHolder options) { return options == null ? this : new Formatter(new Builder(builder, options)); } /** * Builder for configuring an {@link Formatter}. See methods for default configuration. */ public static class Builder extends BuilderBase { List attributeProviderFactories = new ArrayList(); List nodeFormatterFactories = new ArrayList(); List linkResolverFactories = new ArrayList(); HeaderIdGeneratorFactory htmlIdGeneratorFactory = null; public Builder() { super(); } public Builder(DataHolder options) { super(options); loadExtensions(); } public Builder(Builder other) { super(other); this.attributeProviderFactories.addAll(other.attributeProviderFactories); //this.nodeFormatterFactories.addAll(other.nodeFormatterFactories); // not re-used this.linkResolverFactories.addAll(other.linkResolverFactories); //this.htmlIdGeneratorFactory = other.htmlIdGeneratorFactory; } public Builder(Builder other, DataHolder options) { this(other); withOptions(options); } /** * @return the configured {@link Formatter} */ public Formatter build() { return new Formatter(this); } @Override protected void removeApiPoint(final Object apiPoint) { if (apiPoint instanceof AttributeProviderFactory) this.attributeProviderFactories.remove(apiPoint.getClass()); else if (apiPoint instanceof NodeFormatterFactory) this.nodeFormatterFactories.remove(apiPoint); else if (apiPoint instanceof LinkResolverFactory) this.linkResolverFactories.remove(apiPoint); else if (apiPoint instanceof HeaderIdGeneratorFactory) this.htmlIdGeneratorFactory = null; else { throw new IllegalStateException("Unknown data point type: " + apiPoint.getClass().getName()); } } @Override protected void preloadExtension(final Extension extension) { if (extension instanceof FormatterExtension) { FormatterExtension formatterExtension = (FormatterExtension) extension; formatterExtension.rendererOptions(this); } } @Override protected boolean loadExtension(final Extension extension) { if (extension instanceof FormatterExtension) { FormatterExtension formatterExtension = (FormatterExtension) extension; formatterExtension.extend(this); return true; } return false; } /** * Add a factory for instantiating a node renderer (done when rendering). This allows to override the rendering * of node types or define rendering for custom node types. *

* If multiple node renderers for the same node type are created, the one from the factory that was added first * "wins". (This is how the rendering for core node types can be overridden; the default rendering comes last.) * * @param nodeFormatterFactory the factory for creating a node renderer * @return {@code this} */ @SuppressWarnings("UnusedReturnValue") public Builder nodeFormatterFactory(NodeFormatterFactory nodeFormatterFactory) { this.nodeFormatterFactories.add(nodeFormatterFactory); return this; } } /** * Extension for {@link Formatter}. */ public interface FormatterExtension extends Extension { /** * This method is called first on all extensions so that they can adjust the options. * * @param options option set that will be used for the builder */ void rendererOptions(MutableDataHolder options); void extend(Builder builder); } private final static Iterator NULL_ITERATOR = new Iterator() { @Override public boolean hasNext() { return false; } @Override public Node next() { return null; } @Override public void remove() { } }; final public static Iterable NULL_ITERABLE = new Iterable() { @Override public Iterator iterator() { return null; } }; private class MainNodeFormatter extends NodeFormatterSubContext { private final Document document; private final Map, NodeFormattingHandler> renderers; private final SubClassingBag collectedNodes; private final List phasedFormatters; private final Set renderingPhases; private final DataHolder options; private FormattingPhase phase; final TranslationHandler myTranslationHandler; MainNodeFormatter(DataHolder options, MarkdownWriter out, Document document, TranslationHandler translationHandler) { super(out); this.myTranslationHandler = translationHandler; this.options = new ScopedDataSet(document, options); this.document = document; this.renderers = new HashMap, NodeFormattingHandler>(32); this.renderingPhases = new HashSet(FormattingPhase.values().length); final Set collectNodeTypes = new HashSet(100); this.phasedFormatters = new ArrayList(nodeFormatterFactories.size()); out.setContext(this); // The first node renderer for a node type "wins". for (int i = nodeFormatterFactories.size() - 1; i >= 0; i--) { NodeFormatterFactory nodeFormatterFactory = nodeFormatterFactories.get(i); NodeFormatter nodeFormatter = nodeFormatterFactory.create(this.options); final Set> formattingHandlers = nodeFormatter.getNodeFormattingHandlers(); if (formattingHandlers == null) continue; for (NodeFormattingHandler nodeType : formattingHandlers) { // Overwrite existing renderer renderers.put(nodeType.getNodeType(), nodeType); } // get nodes of interest Set> nodeClasses = nodeFormatter.getNodeClasses(); if (nodeClasses != null) { collectNodeTypes.addAll(nodeClasses); } if (nodeFormatter instanceof PhasedNodeFormatter) { Set phases = ((PhasedNodeFormatter) nodeFormatter).getFormattingPhases(); if (phases != null) { if (phases.isEmpty()) throw new IllegalStateException("PhasedNodeFormatter with empty Phases"); this.renderingPhases.addAll(phases); this.phasedFormatters.add((PhasedNodeFormatter) nodeFormatter); } else { throw new IllegalStateException("PhasedNodeFormatter with null Phases"); } } } // collect nodes of interest from document if (!collectNodeTypes.isEmpty()) { NodeCollectingVisitor collectingVisitor = new NodeCollectingVisitor(collectNodeTypes); collectingVisitor.collect(document); collectedNodes = collectingVisitor.getSubClassingBag(); } else { collectedNodes = null; } } @Override public RenderPurpose getRenderPurpose() { return myTranslationHandler == null ? RenderPurpose.FORMAT : myTranslationHandler.getRenderPurpose(); } @Override public boolean isTransformingText() { return myTranslationHandler != null && myTranslationHandler.isTransformingText(); } @Override public CharSequence transformNonTranslating(final CharSequence prefix, final CharSequence nonTranslatingText, final CharSequence suffix, final CharSequence suffix2) { return myTranslationHandler == null ? nonTranslatingText : myTranslationHandler.transformNonTranslating(prefix, nonTranslatingText, suffix, suffix2); } @Override public CharSequence transformTranslating(final CharSequence prefix, final CharSequence translatingText, final CharSequence suffix, final CharSequence suffix2) { return myTranslationHandler == null ? translatingText : myTranslationHandler.transformTranslating(prefix, translatingText, suffix, suffix2); } @Override public CharSequence transformAnchorRef(final CharSequence pageRef, final CharSequence anchorRef) { return myTranslationHandler == null ? anchorRef : myTranslationHandler.transformAnchorRef(pageRef, anchorRef); } @Override public void translatingSpan(final TranslatingSpanRender render) { if (myTranslationHandler != null) { myTranslationHandler.translatingSpan(render); } else { render.render(this, markdown); } } @Override public void nonTranslatingSpan(final TranslatingSpanRender render) { if (myTranslationHandler != null) { myTranslationHandler.nonTranslatingSpan(render); } else { render.render(this, markdown); } } @Override public void translatingRefTargetSpan(Node target, TranslatingSpanRender render) { if (myTranslationHandler != null) { myTranslationHandler.translatingRefTargetSpan(target, render); } else { render.render(this, markdown); } } @Override public MutableDataHolder getTranslationStore() { if (myTranslationHandler != null) { return myTranslationHandler.getTranslationStore(); } else { return document; } } @Override public void customPlaceholderFormat(final TranslationPlaceholderGenerator generator, final TranslatingSpanRender render) { if (myTranslationHandler != null) { myTranslationHandler.customPlaceholderFormat(generator, render); } else { render.render(this, markdown); } } @Override public Node getCurrentNode() { return renderingNode; } @Override public DataHolder getOptions() { return options; } @Override public FormatterOptions getFormatterOptions() { return formatterOptions; } @Override public Document getDocument() { return document; } @Override public FormattingPhase getFormattingPhase() { return phase; } @Override public void render(Node node) { renderNode(node, this); } @Override public final Iterable nodesOfType(final Class[] classes) { return collectedNodes == null ? NULL_ITERABLE : collectedNodes.itemsOfType(Node.class, classes); } @Override public final Iterable nodesOfType(final Collection> classes) { //noinspection unchecked return collectedNodes == null ? NULL_ITERABLE : collectedNodes.itemsOfType(Node.class, classes); } @Override public final Iterable reversedNodesOfType(final Class[] classes) { return collectedNodes == null ? NULL_ITERABLE : collectedNodes.reversedItemsOfType(Node.class, classes); } @Override public final Iterable reversedNodesOfType(final Collection> classes) { //noinspection unchecked return collectedNodes == null ? NULL_ITERABLE : collectedNodes.reversedItemsOfType(Node.class, classes); } @Override public NodeFormatterContext getSubContext(Appendable out) { MarkdownWriter writer = new MarkdownWriter(getMarkdown().getOptions()); writer.setContext(this); //noinspection ReturnOfInnerClass return new SubNodeFormatter(this, writer); } void renderNode(Node node, NodeFormatterSubContext subContext) { if (node instanceof Document) { // here we render multiple phases if (myTranslationHandler != null) { myTranslationHandler.beginRendering((Document) node, subContext, subContext.markdown); } for (FormattingPhase phase : FormattingPhase.values()) { if (phase != FormattingPhase.DOCUMENT && !renderingPhases.contains(phase)) { continue; } this.phase = phase; // here we render multiple phases if (this.phase == FormattingPhase.DOCUMENT) { NodeFormattingHandler nodeRenderer = renderers.get(node.getClass()); if (nodeRenderer != null) { subContext.renderingNode = node; nodeRenderer.render(node, subContext, subContext.markdown); subContext.renderingNode = null; } } else { // go through all renderers that want this phase for (PhasedNodeFormatter phasedFormatter : phasedFormatters) { if (phasedFormatter.getFormattingPhases().contains(phase)) { subContext.renderingNode = node; phasedFormatter.renderDocument(subContext, subContext.markdown, (Document) node, phase); subContext.renderingNode = null; } } } } } else { NodeFormattingHandler nodeRenderer = renderers.get(node.getClass()); if (nodeRenderer == null) { nodeRenderer = renderers.get(Node.class); } if (nodeRenderer != null) { Node oldNode = this.renderingNode; subContext.renderingNode = node; nodeRenderer.render(node, subContext, subContext.markdown); subContext.renderingNode = oldNode; } else { // default behavior is controlled by generic Node.class that is implemented in CoreNodeFormatter throw new IllegalStateException("Core Node Formatter should implement generic Node renderer"); } } } public void renderChildren(Node parent) { renderChildrenNode(parent, this); } @SuppressWarnings("WeakerAccess") protected void renderChildrenNode(Node parent, NodeFormatterSubContext subContext) { Node node = parent.getFirstChild(); while (node != null) { Node next = node.getNext(); renderNode(node, subContext); node = next; } } @SuppressWarnings("WeakerAccess") private class SubNodeFormatter extends NodeFormatterSubContext implements NodeFormatterContext { private final MainNodeFormatter myMainNodeRenderer; public SubNodeFormatter(MainNodeFormatter mainNodeRenderer, MarkdownWriter out) { super(out); myMainNodeRenderer = mainNodeRenderer; } @Override public MutableDataHolder getTranslationStore() { return myMainNodeRenderer.getTranslationStore(); } @Override public final Iterable nodesOfType(final Class[] classes) { return myMainNodeRenderer.nodesOfType(classes); } @Override public final Iterable nodesOfType(final Collection> classes) { return myMainNodeRenderer.nodesOfType(classes); } @Override public final Iterable reversedNodesOfType(final Class[] classes) { return myMainNodeRenderer.reversedNodesOfType(classes); } @Override public final Iterable reversedNodesOfType(final Collection> classes) { //noinspection unchecked return myMainNodeRenderer.reversedNodesOfType(classes); } @Override public DataHolder getOptions() {return myMainNodeRenderer.getOptions();} @Override public FormatterOptions getFormatterOptions() {return myMainNodeRenderer.getFormatterOptions();} @Override public Document getDocument() {return myMainNodeRenderer.getDocument();} @Override public FormattingPhase getFormattingPhase() {return myMainNodeRenderer.getFormattingPhase();} @Override public void render(Node node) { myMainNodeRenderer.renderNode(node, this); } @Override public Node getCurrentNode() { return myMainNodeRenderer.getCurrentNode(); } @Override public NodeFormatterContext getSubContext(Appendable out) { MarkdownWriter htmlWriter = new MarkdownWriter(this.markdown.getOptions()); htmlWriter.setContext(this); //noinspection ReturnOfInnerClass return new SubNodeFormatter(myMainNodeRenderer, htmlWriter); } @Override public void renderChildren(Node parent) { myMainNodeRenderer.renderChildrenNode(parent, this); } @Override public MarkdownWriter getMarkdown() { return markdown; } @Override public RenderPurpose getRenderPurpose() { return myMainNodeRenderer.getRenderPurpose(); } @Override public boolean isTransformingText() { return myMainNodeRenderer.isTransformingText(); } @Override public CharSequence transformNonTranslating(final CharSequence prefix, final CharSequence nonTranslatingText, final CharSequence suffix, final CharSequence suffix2) { return myMainNodeRenderer.transformNonTranslating(prefix, nonTranslatingText, suffix, suffix2); } @Override public CharSequence transformTranslating(final CharSequence prefix, final CharSequence translatingText, final CharSequence suffix, final CharSequence suffix2) { return myMainNodeRenderer.transformTranslating(prefix, translatingText, suffix, suffix2); } @Override public CharSequence transformAnchorRef(final CharSequence pageRef, final CharSequence anchorRef) { return myMainNodeRenderer.transformAnchorRef(pageRef, anchorRef); } @Override public void translatingSpan(final TranslatingSpanRender render) { myMainNodeRenderer.translatingSpan(render); } @Override public void nonTranslatingSpan(final TranslatingSpanRender render) { myMainNodeRenderer.nonTranslatingSpan(render); } @Override public void translatingRefTargetSpan(Node target, final TranslatingSpanRender render) { myMainNodeRenderer.translatingRefTargetSpan(target, render); } @Override public void customPlaceholderFormat(final TranslationPlaceholderGenerator generator, final TranslatingSpanRender render) { myMainNodeRenderer.customPlaceholderFormat(generator, render); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy