| Author | DaveJarvis <email> |
|---|---|
| Date | 2021-01-01 10:23:39 GMT-0800 |
| Commit | 84ac84ab0d55aab9a0eac2412be5882af1347760 |
| Parent | e02499e |
| Delta | 124 lines added, 206 lines removed, 82-line decrease |
| import com.keenwrite.preferences.Workspace; | ||
| +import com.keenwrite.processors.markdown.extensions.ImageLinkExtension; | ||
| import com.vladsch.flexmark.html.HtmlRenderer; | ||
| import com.vladsch.flexmark.parser.Parser; |
| /** | ||
| - * Dialog to enter a markdown link. | ||
| + * Dialog to enter a Markdown link. | ||
| */ | ||
| public class LinkDialog extends AbstractDialog<String> { |
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| -package com.keenwrite.processors.markdown.tex; | ||
| - | ||
| -import com.keenwrite.ExportFormat; | ||
| -import com.keenwrite.preview.SvgRasterizer; | ||
| -import com.vladsch.flexmark.html.HtmlWriter; | ||
| -import com.vladsch.flexmark.html.renderer.NodeRenderer; | ||
| -import com.vladsch.flexmark.html.renderer.NodeRendererContext; | ||
| -import com.vladsch.flexmark.html.renderer.NodeRendererFactory; | ||
| -import com.vladsch.flexmark.html.renderer.NodeRenderingHandler; | ||
| -import com.vladsch.flexmark.util.ast.Node; | ||
| -import com.vladsch.flexmark.util.data.DataHolder; | ||
| -import org.jetbrains.annotations.NotNull; | ||
| -import org.jetbrains.annotations.Nullable; | ||
| - | ||
| -import java.util.Set; | ||
| - | ||
| -import static com.keenwrite.preview.MathRenderer.MATH_RENDERER; | ||
| -import static com.keenwrite.processors.markdown.tex.TexNode.*; | ||
| - | ||
| -public class TexNodeRenderer { | ||
| - | ||
| - public static class Factory implements NodeRendererFactory { | ||
| - private final ExportFormat mExportFormat; | ||
| - | ||
| - public Factory( final ExportFormat exportFormat ) { | ||
| - mExportFormat = exportFormat; | ||
| - } | ||
| - | ||
| - @NotNull | ||
| - @Override | ||
| - public NodeRenderer apply( @NotNull DataHolder options ) { | ||
| - return switch( mExportFormat ) { | ||
| - case HTML_TEX_SVG -> new TexSvgNodeRenderer(); | ||
| - case HTML_TEX_DELIMITED, MARKDOWN_PLAIN -> new TexDelimNodeRenderer(); | ||
| - case NONE -> new TexElementNodeRenderer(); | ||
| - }; | ||
| - } | ||
| - } | ||
| - | ||
| - private static abstract class AbstractTexNodeRenderer | ||
| - implements NodeRenderer { | ||
| - | ||
| - @Override | ||
| - public @Nullable Set<NodeRenderingHandler<?>> getNodeRenderingHandlers() { | ||
| - final var h = new NodeRenderingHandler<>( TexNode.class, this::render ); | ||
| - return Set.of( h ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Subclasses implement this method to render the content of {@link TexNode} | ||
| - * instances as per their associated {@link ExportFormat}. | ||
| - * | ||
| - * @param node {@link Node} containing text content of a math formula. | ||
| - * @param context Configuration information (unused). | ||
| - * @param html Where to write the rendered output. | ||
| - */ | ||
| - abstract void render( final TexNode node, | ||
| - final NodeRendererContext context, | ||
| - final HtmlWriter html ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Responsible for rendering a TeX node as an HTML {@code <tex>} | ||
| - * element. This is the default behaviour. | ||
| - */ | ||
| - private static class TexElementNodeRenderer extends AbstractTexNodeRenderer { | ||
| - void render( final TexNode node, | ||
| - final NodeRendererContext context, | ||
| - final HtmlWriter html ) { | ||
| - html.tag( HTML_TEX ); | ||
| - html.raw( node.getText() ); | ||
| - html.closeTag( HTML_TEX ); | ||
| - } | ||
| - } | ||
| - | ||
| - /** | ||
| - * Responsible for rendering a TeX node as an HTML {@code <svg>} | ||
| - * element. | ||
| - */ | ||
| - private static class TexSvgNodeRenderer extends AbstractTexNodeRenderer { | ||
| - void render( final TexNode node, | ||
| - final NodeRendererContext context, | ||
| - final HtmlWriter html ) { | ||
| - final var tex = node.getText().toStringOrNull(); | ||
| - final var doc = MATH_RENDERER.render( tex == null ? "" : tex ); | ||
| - final var svg = SvgRasterizer.toSvg( doc.getDocumentElement() ); | ||
| - html.raw( svg ); | ||
| - } | ||
| - } | ||
| - | ||
| - /** | ||
| - * Responsible for rendering a TeX node as text bracketed by $ tokens. | ||
| - */ | ||
| - private static class TexDelimNodeRenderer extends AbstractTexNodeRenderer { | ||
| - void render( final TexNode node, | ||
| - final NodeRendererContext context, | ||
| - final HtmlWriter html ) { | ||
| - html.raw( TOKEN_OPEN ); | ||
| - html.raw( node.getText() ); | ||
| - html.raw( TOKEN_CLOSE ); | ||
| - } | ||
| - } | ||
| -} | ||
| +/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| +package com.keenwrite.processors.markdown.extensions.tex; | ||
| + | ||
| +import com.keenwrite.ExportFormat; | ||
| +import com.keenwrite.preview.SvgRasterizer; | ||
| +import com.vladsch.flexmark.html.HtmlWriter; | ||
| +import com.vladsch.flexmark.html.renderer.NodeRenderer; | ||
| +import com.vladsch.flexmark.html.renderer.NodeRendererContext; | ||
| +import com.vladsch.flexmark.html.renderer.NodeRendererFactory; | ||
| +import com.vladsch.flexmark.html.renderer.NodeRenderingHandler; | ||
| +import com.vladsch.flexmark.util.ast.Node; | ||
| +import com.vladsch.flexmark.util.data.DataHolder; | ||
| +import org.jetbrains.annotations.NotNull; | ||
| +import org.jetbrains.annotations.Nullable; | ||
| + | ||
| +import java.util.Set; | ||
| + | ||
| +import static com.keenwrite.preview.MathRenderer.MATH_RENDERER; | ||
| +import static com.keenwrite.processors.markdown.extensions.tex.TexNode.*; | ||
| + | ||
| +public class TexNodeRenderer { | ||
| + | ||
| + public static class Factory implements NodeRendererFactory { | ||
| + private final ExportFormat mExportFormat; | ||
| + | ||
| + public Factory( final ExportFormat exportFormat ) { | ||
| + mExportFormat = exportFormat; | ||
| + } | ||
| + | ||
| + @NotNull | ||
| + @Override | ||
| + public NodeRenderer apply( @NotNull DataHolder options ) { | ||
| + return switch( mExportFormat ) { | ||
| + case HTML_TEX_SVG -> new TexSvgNodeRenderer(); | ||
| + case HTML_TEX_DELIMITED, MARKDOWN_PLAIN -> new TexDelimNodeRenderer(); | ||
| + case NONE -> new TexElementNodeRenderer(); | ||
| + }; | ||
| + } | ||
| + } | ||
| + | ||
| + private static abstract class AbstractTexNodeRenderer | ||
| + implements NodeRenderer { | ||
| + | ||
| + @Override | ||
| + public @Nullable Set<NodeRenderingHandler<?>> getNodeRenderingHandlers() { | ||
| + final var h = new NodeRenderingHandler<>( TexNode.class, this::render ); | ||
| + return Set.of( h ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Subclasses implement this method to render the content of {@link TexNode} | ||
| + * instances as per their associated {@link ExportFormat}. | ||
| + * | ||
| + * @param node {@link Node} containing text content of a math formula. | ||
| + * @param context Configuration information (unused). | ||
| + * @param html Where to write the rendered output. | ||
| + */ | ||
| + abstract void render( final TexNode node, | ||
| + final NodeRendererContext context, | ||
| + final HtmlWriter html ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Responsible for rendering a TeX node as an HTML {@code <tex>} | ||
| + * element. This is the default behaviour. | ||
| + */ | ||
| + private static class TexElementNodeRenderer extends AbstractTexNodeRenderer { | ||
| + void render( final TexNode node, | ||
| + final NodeRendererContext context, | ||
| + final HtmlWriter html ) { | ||
| + html.tag( HTML_TEX ); | ||
| + html.raw( node.getText() ); | ||
| + html.closeTag( HTML_TEX ); | ||
| + } | ||
| + } | ||
| + | ||
| + /** | ||
| + * Responsible for rendering a TeX node as an HTML {@code <svg>} | ||
| + * element. | ||
| + */ | ||
| + private static class TexSvgNodeRenderer extends AbstractTexNodeRenderer { | ||
| + void render( final TexNode node, | ||
| + final NodeRendererContext context, | ||
| + final HtmlWriter html ) { | ||
| + final var tex = node.getText().toStringOrNull(); | ||
| + final var doc = MATH_RENDERER.render( tex == null ? "" : tex ); | ||
| + final var svg = SvgRasterizer.toSvg( doc.getDocumentElement() ); | ||
| + html.raw( svg ); | ||
| + } | ||
| + } | ||
| + | ||
| + /** | ||
| + * Responsible for rendering a TeX node as text bracketed by $ tokens. | ||
| + */ | ||
| + private static class TexDelimNodeRenderer extends AbstractTexNodeRenderer { | ||
| + void render( final TexNode node, | ||
| + final NodeRendererContext context, | ||
| + final HtmlWriter html ) { | ||
| + html.raw( TOKEN_OPEN ); | ||
| + html.raw( node.getText() ); | ||
| + html.raw( TOKEN_CLOSE ); | ||
| + } | ||
| + } | ||
| +} | ||
| import com.keenwrite.io.MediaType; | ||
| import com.keenwrite.processors.ExecutorProcessor; | ||
| -import com.keenwrite.processors.IdentityProcessor; | ||
| import com.keenwrite.processors.Processor; | ||
| import com.keenwrite.processors.ProcessorContext; | ||
| -import com.keenwrite.processors.markdown.r.RExtension; | ||
| +import com.keenwrite.processors.markdown.extensions.caret.CaretExtension; | ||
| +import com.keenwrite.processors.markdown.extensions.FencedBlockExtension; | ||
| +import com.keenwrite.processors.markdown.extensions.ImageLinkExtension; | ||
| +import com.keenwrite.processors.markdown.extensions.tex.TeXExtension; | ||
| +import com.keenwrite.processors.markdown.extensions.r.RExtension; | ||
| import com.vladsch.flexmark.ext.definition.DefinitionExtension; | ||
| import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughSubscriptExtension; | ||
| import static com.keenwrite.io.MediaType.TEXT_R_MARKDOWN; | ||
| import static com.keenwrite.io.MediaType.TEXT_R_XML; | ||
| +import static com.keenwrite.processors.IdentityProcessor.IDENTITY; | ||
| /** | ||
| public static MarkdownProcessor create( final ProcessorContext context ) { | ||
| - return create( IdentityProcessor.INSTANCE, context ); | ||
| + return create( IDENTITY, context ); | ||
| } | ||
| final ProcessorContext context ) { | ||
| final var extensions = createDefaultExtensions(); | ||
| - final var format = context.getExportFormat(); | ||
| - final var workspace = context.getWorkspace(); | ||
| final var editorFile = context.getPath(); | ||
| - final var linkDir = context.getBasePath(); | ||
| final var mediaType = MediaType.valueFrom( editorFile ); | ||
| if( mediaType == TEXT_R_MARKDOWN || mediaType == TEXT_R_XML ) { | ||
| - extensions.add( RExtension.create() ); | ||
| + extensions.add( RExtension.create( context ) ); | ||
| } | ||
| - extensions.add( ImageLinkExtension.create( linkDir, workspace ) ); | ||
| - extensions.add( TeXExtension.create( format ) ); | ||
| + extensions.add( ImageLinkExtension.create( context ) ); | ||
| + extensions.add( TeXExtension.create( context ) ); | ||
| extensions.add( FencedBlockExtension.create( context ) ); | ||
| - extensions.add( CaretExtension.create( context.getCaret() ) ); | ||
| + extensions.add( CaretExtension.create( context ) ); | ||
| return extensions; | ||
| @Override | ||
| public String apply( final String markdown ) { | ||
| - return toHtml( markdown ); | ||
| + return toHtml( parse( markdown ) ); | ||
| } | ||
| /** | ||
| - * Returns the AST in the form of a node for the given markdown document. This | ||
| + * Returns the AST in the form of a node for the given Markdown document. This | ||
| * can be used, for example, to determine if a hyperlink exists inside of a | ||
| * paragraph. | ||
| * | ||
| - * @param markdown The markdown to convert into an AST. | ||
| - * @return The markdown AST for the given text (usually a paragraph). | ||
| + * @param markdown The Markdown to convert into an AST. | ||
| + * @return The Markdown AST for the given text (usually a paragraph). | ||
| */ | ||
| public Node toNode( final String markdown ) { | ||
| /** | ||
| - * Helper method to create an AST given some markdown. | ||
| + * Helper method to create an AST given some Markdown. | ||
| * | ||
| - * @param markdown The markdown to parse. | ||
| - * @return The root node of the markdown tree. | ||
| + * @param markdown The Markdown to parse. | ||
| + * @return The root node of the Markdown tree. | ||
| */ | ||
| private Node parse( final String markdown ) { | ||
| return getParser().parse( markdown ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Converts a string of markdown into HTML. | ||
| - * | ||
| - * @param markdown The markdown text to convert to HTML, must not be null. | ||
| - * @return The markdown rendered as an HTML document. | ||
| - */ | ||
| - private String toHtml( final String markdown ) { | ||
| - return toHtml( parse( markdown ) ); | ||
| } | ||
| -/* Copyright 2020 White Magic Software, Ltd. -- All rights reserved. */ | ||
| -package com.keenwrite.processors.markdown; | ||
| - | ||
| -import com.keenwrite.ExportFormat; | ||
| -import com.keenwrite.processors.markdown.tex.TeXInlineDelimiterProcessor; | ||
| -import com.keenwrite.processors.markdown.tex.TexNodeRenderer.Factory; | ||
| -import com.vladsch.flexmark.html.HtmlRenderer; | ||
| -import com.vladsch.flexmark.parser.Parser; | ||
| -import com.vladsch.flexmark.util.data.MutableDataHolder; | ||
| -import com.vladsch.flexmark.util.misc.Extension; | ||
| -import org.jetbrains.annotations.NotNull; | ||
| - | ||
| -import static com.vladsch.flexmark.html.HtmlRenderer.HtmlRendererExtension; | ||
| -import static com.vladsch.flexmark.parser.Parser.ParserExtension; | ||
| - | ||
| -/** | ||
| - * Responsible for wrapping delimited TeX code in Markdown into an XML element | ||
| - * that the HTML renderer can handle. For example, {@code $E=mc^2$} becomes | ||
| - * {@code <tex>E=mc^2</tex>} when passed to HTML renderer. The HTML renderer | ||
| - * is responsible for converting the TeX code for display. This avoids inserting | ||
| - * SVG code into the Markdown document, which the parser would then have to | ||
| - * iterate---a <em>very</em> wasteful operation that impacts front-end | ||
| - * performance. | ||
| - */ | ||
| -public class TeXExtension implements ParserExtension, HtmlRendererExtension { | ||
| - /** | ||
| - * Controls how the node renderer produces TeX code within HTML output. | ||
| - */ | ||
| - private final ExportFormat mExportFormat; | ||
| - | ||
| - /** | ||
| - * Creates an extension capable of handling delimited TeX code in Markdown. | ||
| - * | ||
| - * @return The new {@link TeXExtension}, never {@code null}. | ||
| - */ | ||
| - public static TeXExtension create( final ExportFormat format ) { | ||
| - return new TeXExtension( format ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Force using the {@link #create(ExportFormat)} method for consistency with | ||
| - * the other {@link Extension} creation invocations. | ||
| - */ | ||
| - private TeXExtension( final ExportFormat exportFormat ) { | ||
| - mExportFormat = exportFormat; | ||
| - } | ||
| - | ||
| - /** | ||
| - * Adds the TeX extension for HTML document export types. | ||
| - * | ||
| - * @param builder The document builder. | ||
| - * @param rendererType Indicates the document type to be built. | ||
| - */ | ||
| - @Override | ||
| - public void extend( @NotNull final HtmlRenderer.Builder builder, | ||
| - @NotNull final String rendererType ) { | ||
| - if( "HTML".equalsIgnoreCase( rendererType ) ) { | ||
| - builder.nodeRendererFactory( new Factory( mExportFormat ) ); | ||
| - } | ||
| - } | ||
| - | ||
| - @Override | ||
| - public void extend( final Parser.Builder builder ) { | ||
| - builder.customDelimiterProcessor( new TeXInlineDelimiterProcessor() ); | ||
| - } | ||
| - | ||
| - @Override | ||
| - public void rendererOptions( @NotNull final MutableDataHolder options ) { | ||
| - } | ||
| - | ||
| - @Override | ||
| - public void parserOptions( final MutableDataHolder options ) { | ||
| - } | ||
| -} | ||