Allow customizing the CommonMark Parser (#444)

This is required by one of our customers, and it allows them to
customize the handling of standard tags (e.g., remove images).

It is an opt-in behaviour and it does not impact existing Markdown
handling code or behaviour.
GitOrigin-RevId: 81cb5b7f45f84b1d5946eb5d9da4ba94e91f3fd1
This commit is contained in:
Sebastiano Poggi
2024-07-10 18:38:41 +02:00
committed by intellij-monorepo-bot
parent 6df91718f0
commit f1a6ac3478
3 changed files with 72 additions and 20 deletions

View File

@@ -442,12 +442,20 @@ public abstract interface class org/jetbrains/jewel/markdown/extensions/Markdown
public abstract fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
}
public final class org/jetbrains/jewel/markdown/processing/MarkdownParserFactory {
public static final field $stable I
public static final field INSTANCE Lorg/jetbrains/jewel/markdown/processing/MarkdownParserFactory;
public final fun create (ZLjava/util/List;Lkotlin/jvm/functions/Function1;)Lorg/commonmark/parser/Parser;
public static synthetic fun create$default (Lorg/jetbrains/jewel/markdown/processing/MarkdownParserFactory;ZLjava/util/List;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lorg/commonmark/parser/Parser;
}
public final class org/jetbrains/jewel/markdown/processing/MarkdownProcessor {
public static final field $stable I
public fun <init> ()V
public fun <init> (Ljava/util/List;Z)V
public synthetic fun <init> (Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> ([Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)V
public fun <init> (Ljava/util/List;ZLorg/commonmark/parser/Parser;)V
public synthetic fun <init> (Ljava/util/List;ZLorg/commonmark/parser/Parser;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Z[Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;)V
public synthetic fun <init> (Z[Lorg/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun processChildren (Lorg/commonmark/node/Node;)Ljava/util/List;
public final fun processMarkdownDocument (Ljava/lang/String;)Ljava/util/List;
}

View File

@@ -0,0 +1,50 @@
package org.jetbrains.jewel.markdown.processing
import org.commonmark.parser.IncludeSourceSpans
import org.commonmark.parser.Parser
import org.jetbrains.jewel.markdown.extensions.MarkdownProcessorExtension
/**
* Simplifies creating a [CommonMark `Parser`][Parser] while also
* supporting Jewel's [MarkdownProcessorExtension]s and the `optimizeEdits`
* flag.
*/
public object MarkdownParserFactory {
/**
* Create a [CommonMark `Parser`][Parser] with the provided [extensions].
* The parser's [Builder][Parser.Builder] can be customized by providing a
* non-null [customizeBuilder] lambda.
*
* Make sure to provide the right value for [optimizeEdits], matching the
* one provided to the [MarkdownProcessor], or this parser will not be set
* up correctly.
*
* @param optimizeEdits If true, sets up the [Parser] to allow for edits
* optimization in the [MarkdownProcessor].
* @param extensions A list of [MarkdownProcessorExtension] to attach.
* @param customizeBuilder Allows customizing the [Parser.Builder] before
* its [build()][Parser.Builder.build] method is called.
*/
public fun create(
optimizeEdits: Boolean,
extensions: List<MarkdownProcessorExtension> = emptyList(),
customizeBuilder: (Parser.Builder.() -> Parser.Builder)? = null,
): Parser =
Parser.builder()
.extensions(extensions.map(MarkdownProcessorExtension::parserExtension))
.run {
val builder =
if (optimizeEdits) {
includeSourceSpans(IncludeSourceSpans.BLOCKS)
} else {
this
}
if (customizeBuilder != null) {
builder.customizeBuilder()
} else {
builder
}
}
.build()
}

View File

@@ -14,7 +14,6 @@ import org.commonmark.node.Node
import org.commonmark.node.OrderedList
import org.commonmark.node.Paragraph
import org.commonmark.node.ThematicBreak
import org.commonmark.parser.IncludeSourceSpans
import org.commonmark.parser.Parser
import org.intellij.lang.annotations.Language
import org.jetbrains.annotations.TestOnly
@@ -30,25 +29,20 @@ import org.jetbrains.jewel.markdown.rendering.DefaultInlineMarkdownRenderer
import org.commonmark.node.ListBlock as CMListBlock
/**
* @param optimizeEdits Optional. Indicates whether the processing should only update the changed blocks
* by keeping a previous state in memory. Default is `true`, use `false` for immutable data.
* @param optimizeEdits Optional. Indicates whether the processing should
* only update the changed blocks by keeping a previous state in memory.
* Default is `true`, use `false` for immutable data.
*/
@ExperimentalJewelApi
public class MarkdownProcessor(
private val extensions: List<MarkdownProcessorExtension> = emptyList(),
private val optimizeEdits: Boolean = true,
private val commonMarkParser: Parser = MarkdownParserFactory.create(optimizeEdits, extensions),
) {
public constructor(vararg extensions: MarkdownProcessorExtension) : this(extensions.toList())
private val commonMarkParser =
Parser.builder()
.let { builder ->
builder.extensions(extensions.map(MarkdownProcessorExtension::parserExtension))
if (optimizeEdits) {
builder.includeSourceSpans(IncludeSourceSpans.BLOCKS)
}
builder.build()
}
public constructor(
optimizeEdits: Boolean = true,
vararg extensions: MarkdownProcessorExtension,
) : this(extensions.toList(), optimizeEdits)
private data class State(val lines: List<String>, val blocks: List<Block>, val indexes: List<Pair<Int, Int>>)
@@ -58,9 +52,9 @@ public class MarkdownProcessor(
internal fun getCurrentIndexesInTest() = currentState.indexes
/**
* Parses a Markdown document, translating from CommonMark 0.31.2
* to a list of [MarkdownBlock]. Inline Markdown in leaf nodes
* is contained in [InlineMarkdown], which can be rendered
* Parses a Markdown document, translating from CommonMark
* 0.31.2 to a list of [MarkdownBlock]. Inline Markdown in leaf
* nodes is contained in [InlineMarkdown], which can be rendered
* to an [androidx.compose.ui.text.AnnotatedString] by using
* [DefaultInlineMarkdownRenderer.renderAsAnnotatedString].
*