Skip to content

Commit

Permalink
Define delimited inlines extension API, implement strikethrough
Browse files Browse the repository at this point in the history
This includes a bunch of changes to the Markdown inline APIs to better
align with CommonMark and our actual needs; a clean-up of the previous
half-hearted attempt at supporting custom inline nodes (it did not and
could never have worked in the way it was implemented), and some misc
tweaks and cleanup.
  • Loading branch information
rock3r authored and hamen committed Jan 30, 2025
1 parent 1ebba7a commit 34d01b5
Show file tree
Hide file tree
Showing 43 changed files with 995 additions and 290 deletions.
3 changes: 2 additions & 1 deletion .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions platform/jewel/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ poko = "0.17.1"
[libraries]
commonmark-core = { module = "org.commonmark:commonmark", version.ref = "commonmark" }
commonmark-ext-autolink = { module = "org.commonmark:commonmark-ext-autolink", version.ref = "commonmark" }
commonmark-ext-gfm-strikethrough = { module = "org.commonmark:commonmark-ext-gfm-strikethrough", version.ref = "commonmark" }
commonmark-ext-gfm-tables = { module = "org.commonmark:commonmark-ext-gfm-tables", version.ref = "commonmark" }

filePicker = { module = "com.darkrockstudios:mpfilepicker", version = "3.1.0" }
Expand Down
41 changes: 22 additions & 19 deletions platform/jewel/markdown/core/api/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ public final class org/jetbrains/jewel/markdown/InlineMarkdown$Code : org/jetbra
public fun toString ()Ljava/lang/String;
}

public abstract interface class org/jetbrains/jewel/markdown/InlineMarkdown$CustomNode : org/jetbrains/jewel/markdown/InlineMarkdown {
public abstract fun contentOrNull ()Ljava/lang/String;
public abstract interface class org/jetbrains/jewel/markdown/InlineMarkdown$CustomDelimitedNode : org/jetbrains/jewel/markdown/InlineMarkdown, org/jetbrains/jewel/markdown/WithInlineMarkdown {
public abstract fun getClosingDelimiter ()Ljava/lang/String;
public abstract fun getOpeningDelimiter ()Ljava/lang/String;
}

public final class org/jetbrains/jewel/markdown/InlineMarkdown$CustomNode$DefaultImpls {
public static fun contentOrNull (Lorg/jetbrains/jewel/markdown/InlineMarkdown$CustomNode;)Ljava/lang/String;
public final class org/jetbrains/jewel/markdown/InlineMarkdown$CustomDelimitedNode$DefaultImpls {
public static fun getClosingDelimiter (Lorg/jetbrains/jewel/markdown/InlineMarkdown$CustomDelimitedNode;)Ljava/lang/String;
}

public final class org/jetbrains/jewel/markdown/InlineMarkdown$Emphasis : org/jetbrains/jewel/markdown/InlineMarkdown, org/jetbrains/jewel/markdown/WithInlineMarkdown {
Expand Down Expand Up @@ -264,14 +265,14 @@ public abstract interface class org/jetbrains/jewel/markdown/extensions/Markdown
public abstract fun render (Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Lorg/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer;ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
}

public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownInlineProcessorExtension {
public abstract fun canProcess (Lorg/commonmark/node/CustomNode;)Z
public abstract fun processInlineMarkdown (Lorg/commonmark/node/CustomNode;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;)Lorg/jetbrains/jewel/markdown/InlineMarkdown$CustomNode;
public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineProcessorExtension {
public abstract fun canProcess (Lorg/commonmark/node/Delimited;)Z
public abstract fun processDelimitedInline (Lorg/commonmark/node/Delimited;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;)Lorg/jetbrains/jewel/markdown/InlineMarkdown$CustomDelimitedNode;
}

public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownInlineRendererExtension {
public abstract fun canRender (Lorg/jetbrains/jewel/markdown/InlineMarkdown$CustomNode;)Z
public abstract fun render (Lorg/jetbrains/jewel/markdown/InlineMarkdown$CustomNode;Lorg/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer;Z)V
public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension {
public abstract fun canRender (Lorg/jetbrains/jewel/markdown/InlineMarkdown$CustomDelimitedNode;)Z
public abstract fun render (Lorg/jetbrains/jewel/markdown/InlineMarkdown$CustomDelimitedNode;Lorg/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer;Lorg/jetbrains/jewel/markdown/rendering/InlinesStyling;ZLkotlin/jvm/functions/Function1;)Landroidx/compose/ui/text/AnnotatedString;
}

public final class org/jetbrains/jewel/markdown/extensions/MarkdownKt {
Expand All @@ -287,26 +288,26 @@ public final class org/jetbrains/jewel/markdown/extensions/MarkdownKt {

public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension {
public abstract fun getBlockProcessorExtension ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension;
public abstract fun getInlineProcessorExtension ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownInlineProcessorExtension;
public abstract fun getDelimitedInlineProcessorExtension ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineProcessorExtension;
public abstract fun getParserExtension ()Lorg/commonmark/parser/Parser$ParserExtension;
public abstract fun getTextRendererExtension ()Lorg/commonmark/renderer/text/TextContentRenderer$TextContentRendererExtension;
}

public final class org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension$DefaultImpls {
public static fun getBlockProcessorExtension (Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension;
public static fun getInlineProcessorExtension (Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)Lorg/jetbrains/jewel/markdown/extensions/MarkdownInlineProcessorExtension;
public static fun getDelimitedInlineProcessorExtension (Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineProcessorExtension;
public static fun getParserExtension (Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)Lorg/commonmark/parser/Parser$ParserExtension;
public static fun getTextRendererExtension (Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)Lorg/commonmark/renderer/text/TextContentRenderer$TextContentRendererExtension;
}

public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension {
public abstract fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
public abstract fun getInlineRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownInlineRendererExtension;
public abstract fun getDelimitedInlineRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension;
}

public final class org/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension$DefaultImpls {
public static fun getBlockRenderer (Lorg/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension;)Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
public static fun getInlineRenderer (Lorg/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension;)Lorg/jetbrains/jewel/markdown/extensions/MarkdownInlineRendererExtension;
public static fun getDelimitedInlineRenderer (Lorg/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension;)Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension;
}

public final class org/jetbrains/jewel/markdown/processing/MarkdownParserFactory {
Expand All @@ -321,26 +322,27 @@ public final class org/jetbrains/jewel/markdown/processing/MarkdownProcessor {
public fun <init> ()V
public fun <init> (Ljava/util/List;Lorg/jetbrains/jewel/markdown/MarkdownMode;Lorg/commonmark/parser/Parser;)V
public synthetic fun <init> (Ljava/util/List;Lorg/jetbrains/jewel/markdown/MarkdownMode;Lorg/commonmark/parser/Parser;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getBlockExtensions ()Ljava/util/List;
public final fun getDelimitedInlineExtensions ()Ljava/util/List;
public final fun getExtensions ()Ljava/util/List;
public final fun plus (Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;
public final fun processChildren (Lorg/commonmark/node/Node;)Ljava/util/List;
public final fun processMarkdownDocument (Ljava/lang/String;)Ljava/util/List;
public final fun withExtension (Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;
}

public final class org/jetbrains/jewel/markdown/processing/ProcessingUtilKt {
public static final fun readInlineContent (Lorg/commonmark/node/Node;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;)Ljava/util/List;
public static final fun readInlineMarkdown (Lorg/commonmark/node/Node;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;)Ljava/util/List;
public static final fun toInlineMarkdownOrNull (Lorg/commonmark/node/Node;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;)Lorg/jetbrains/jewel/markdown/InlineMarkdown;
}

public class org/jetbrains/jewel/markdown/rendering/DefaultInlineMarkdownRenderer : org/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer {
public static final field $stable I
public static final field Companion Lorg/jetbrains/jewel/markdown/rendering/DefaultInlineMarkdownRenderer$Companion;
public fun <init> (Ljava/util/List;)V
protected final fun getDelimitedNodeRendererExtensions ()Ljava/util/List;
public fun renderAsAnnotatedString (Ljava/lang/Iterable;Lorg/jetbrains/jewel/markdown/rendering/InlinesStyling;ZLkotlin/jvm/functions/Function1;)Landroidx/compose/ui/text/AnnotatedString;
}

public final class org/jetbrains/jewel/markdown/rendering/DefaultInlineMarkdownRenderer$Companion {
}

public class org/jetbrains/jewel/markdown/rendering/DefaultMarkdownBlockRenderer : org/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer {
public static final field $stable I
public fun <init> (Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;Ljava/util/List;Lorg/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer;)V
Expand Down Expand Up @@ -437,6 +439,7 @@ public final class org/jetbrains/jewel/markdown/rendering/MarkdownStyling {
public static final field Companion Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$Companion;
public synthetic fun <init> (FLorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$Paragraph;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$Heading;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$BlockQuote;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$Code;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$List;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$Image;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$ThematicBreak;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$HtmlBlock;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getBaseInlinesStyling ()Lorg/jetbrains/jewel/markdown/rendering/InlinesStyling;
public final fun getBlockQuote ()Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$BlockQuote;
public final fun getBlockVerticalSpacing-D9Ej5fM ()F
public final fun getCode ()Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$Code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,33 @@ package org.jetbrains.jewel.markdown

import org.jetbrains.jewel.foundation.GenerateDataFunctions

/** A run of inline Markdown used as content for [block-level elements][MarkdownBlock]. */
/**
* An inline Markdown node, usually found as content for [block-level elements][MarkdownBlock] or other inline nodes
* annotated with the [WithInlineMarkdown] interface.
*/
public sealed interface InlineMarkdown {
@GenerateDataFunctions public class Code(override val content: String) : InlineMarkdown, WithTextContent

public interface CustomNode : InlineMarkdown {
/**
* An inline node that is delimited by a fixed delimiter, and can be rendered directly into an
* [androidx.compose.ui.text.AnnotatedString].
*
* This type of node can be parsed by a
* [org.jetbrains.jewel.markdown.extensions.MarkdownDelimitedInlineProcessorExtension] and rendered by a
* [org.jetbrains.jewel.markdown.extensions.MarkdownDelimitedInlineRendererExtension].
*/
public interface CustomDelimitedNode : InlineMarkdown, WithInlineMarkdown {
/**
* If this custom node has a text-based representation, this function should return it. Otherwise, it should
* return null.
* The string used to indicate the beginning of this type of inline node. Can be identical to the
* [closingDelimiter].
*/
public fun contentOrNull(): String? = null
public val openingDelimiter: String

/**
* The string used to indicate the end of this type of inline node. Can be identical to the [openingDelimiter].
*/
public val closingDelimiter: String
get() = openingDelimiter
}

@GenerateDataFunctions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jetbrains.jewel.markdown

/** An inline Markdown node that contains other [InlineMarkdown] nodes. */
public interface WithInlineMarkdown {
/** Child inline Markdown nodes. */
public val inlineContent: List<InlineMarkdown>
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jetbrains.jewel.markdown

/** An inline Markdown node that has a plain text content, or can be rendered as plain text. */
public interface WithTextContent {
/** The plain text content or representation of this node. */
public val content: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,24 @@ import org.commonmark.node.CustomBlock
import org.jetbrains.jewel.markdown.MarkdownBlock
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor

/** Extension that can process a custom block-level [CustomBlock]. */
public interface MarkdownBlockProcessorExtension {
/**
* Returns true if the [block] can be processed by this extension instance.
*
* @param block The [CustomBlock] to parse
* @return True if this extension can process the provided [CustomBlock], false otherwise.
*/
public fun canProcess(block: CustomBlock): Boolean

/**
* Processes the [block] as a [MarkdownBlock.CustomBlock], if possible. Note that you should always check that
* [canProcess] returns true for the same [block], as implementations might throw an exception for unsupported block
* types.
*
* @param block The [CustomBlock] to process, for which this extension's [canProcess] returned true.
* @param processor The [MarkdownProcessor] to use for processing.
* @return null if the processing fails, otherwise the processed [MarkdownBlock.CustomBlock].
*/
public fun processMarkdownBlock(block: CustomBlock, processor: MarkdownProcessor): MarkdownBlock.CustomBlock?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.jetbrains.jewel.markdown.extensions

import org.commonmark.node.Delimited
import org.jetbrains.jewel.markdown.InlineMarkdown
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor

/** An extension for parsing [org.commonmark.node.Delimited] inline nodes. */
public interface MarkdownDelimitedInlineProcessorExtension {
/** Checks whether the [delimited] can be processed by this instance. */
public fun canProcess(delimited: Delimited): Boolean

/**
* Processes a [delimited] for which [canProcess] returned `true` into a [InlineMarkdown.CustomDelimitedNode].
*
* @param delimited A [Delimited] produced by a [MarkdownProcessor].
* @param markdownProcessor The [MarkdownProcessor] to use to parse this [Delimited].
* @return The [InlineMarkdown.CustomDelimitedNode] obtained from [delimited].
*/
public fun processDelimitedInline(
delimited: Delimited,
markdownProcessor: MarkdownProcessor,
): InlineMarkdown.CustomDelimitedNode
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.jetbrains.jewel.markdown.extensions

import androidx.compose.ui.text.AnnotatedString
import org.jetbrains.jewel.markdown.InlineMarkdown
import org.jetbrains.jewel.markdown.InlineMarkdown.CustomDelimitedNode
import org.jetbrains.jewel.markdown.rendering.InlineMarkdownRenderer
import org.jetbrains.jewel.markdown.rendering.InlinesStyling

/**
* An extension for [InlineMarkdownRenderer] that can render [InlineMarkdown.CustomDelimitedNode]s backed by a
* [org.commonmark.node.Delimited] node.
*
* Only `Delimited` nodes that can be rendered as an [AnnotatedString] are supported; other kinds of inline node aren't.
*/
public interface MarkdownDelimitedInlineRendererExtension {
/**
* Check whether the provided [node] node can be rendered by this extension.
*
* @param node The [CustomDelimitedNode] to check.
* @return True if this instance can render [node], false otherwise.
*/
public fun canRender(node: CustomDelimitedNode): Boolean

/**
* Render a [CustomDelimitedNode] into an [AnnotatedString.Builder]. Note that if [canRender] returns `false` for
* [node], the implementation might throw.
*
* @param node The [CustomDelimitedNode] to render.
* @param inlineRenderer The [InlineMarkdownRenderer] to use to render the node and its content.
* @param inlinesStyling The styling to use to render the node and its content.
* @param enabled When false, the node will be rendered with a disabled appearance (e.g., grayed out).
* @param onUrlClicked Lambda that will be invoked when URLs inside this node are clicked.
*/
public fun render(
node: CustomDelimitedNode,
inlineRenderer: InlineMarkdownRenderer,
inlinesStyling: InlinesStyling,
enabled: Boolean,
onUrlClicked: ((String) -> Unit)?,
): AnnotatedString
}
Loading

0 comments on commit 34d01b5

Please sign in to comment.