diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index fd1904ab31..7a9999f195 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -3,6 +3,7 @@
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 2d0cd0e3b5..7bfc30d649 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -16,6 +16,7 @@ poko = "0.13.1"
[libraries]
commonmark-core = { module = "org.commonmark:commonmark", 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" }
diff --git a/markdown/extension/gfm-tables/api/gfm-tables.api b/markdown/extension/gfm-tables/api/gfm-tables.api
new file mode 100644
index 0000000000..1a374c9ca9
--- /dev/null
+++ b/markdown/extension/gfm-tables/api/gfm-tables.api
@@ -0,0 +1,35 @@
+public final class org/jetbrains/jewel/markdown/extensions/tables/GitHubTableBlockRenderer : org/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension {
+ public static final field $stable I
+ public fun (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;)V
+ public fun canRender-oaZXzmo (Lorg/commonmark/node/CustomBlock;)Z
+ public fun render-WESUQbY (Lorg/commonmark/node/CustomBlock;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Lorg/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer;Landroidx/compose/runtime/Composer;I)V
+}
+
+public final class org/jetbrains/jewel/markdown/extensions/tables/GitHubTableProcessorExtension : org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExtension {
+ public static final field $stable I
+ public static final field INSTANCE Lorg/jetbrains/jewel/markdown/extensions/tables/GitHubTableProcessorExtension;
+ public fun getParserExtension ()Lorg/commonmark/parser/Parser$ParserExtension;
+ public fun getProcessorExtension ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension;
+ public fun getTextRendererExtension ()Lorg/commonmark/renderer/text/TextContentRenderer$TextContentRendererExtension;
+}
+
+public final class org/jetbrains/jewel/markdown/extensions/tables/GitHubTableRendererExtension : org/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension {
+ public static final field $stable I
+ public fun (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;)V
+ public fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
+}
+
+public final class org/jetbrains/jewel/markdown/extensions/tables/TableStyling {
+ public static final field $stable I
+ public static final field Companion Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;
+ public synthetic fun (JJLkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getBorderColor-0d7_KjU ()J
+ public final fun getHeadColor-0d7_KjU ()J
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class org/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion {
+}
+
diff --git a/markdown/extension/gfm-tables/build.gradle.kts b/markdown/extension/gfm-tables/build.gradle.kts
new file mode 100644
index 0000000000..6503f2df62
--- /dev/null
+++ b/markdown/extension/gfm-tables/build.gradle.kts
@@ -0,0 +1,23 @@
+plugins {
+ jewel
+ `jewel-publish`
+ `jewel-check-public-api`
+ alias(libs.plugins.composeDesktop)
+}
+
+dependencies {
+ implementation(projects.markdown.core)
+ implementation(libs.commonmark.ext.gfm.tables)
+
+ testImplementation(compose.desktop.uiTestJUnit4)
+}
+
+publicApiValidation {
+ // TODO Oleg remove this once migrated to value classes
+ excludedClassRegexes = setOf("org.jetbrains.jewel.markdown.extensions.github.alerts.*")
+}
+
+publishing.publications.named("main") {
+ val ijpTarget = project.property("ijp.target") as String
+ artifactId = "jewel-markdown-extension-${project.name}-$ijpTarget"
+}
diff --git a/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableBlockRenderer.kt b/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableBlockRenderer.kt
new file mode 100644
index 0000000000..37eb6a717e
--- /dev/null
+++ b/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableBlockRenderer.kt
@@ -0,0 +1,95 @@
+package org.jetbrains.jewel.markdown.extensions.tables
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import org.commonmark.ext.gfm.tables.TableBlock
+import org.commonmark.ext.gfm.tables.TableBody
+import org.commonmark.ext.gfm.tables.TableHead
+import org.commonmark.node.Node
+import org.jetbrains.jewel.markdown.InlineMarkdown
+import org.jetbrains.jewel.markdown.MarkdownBlock.CustomBlock
+import org.jetbrains.jewel.markdown.extensions.MarkdownBlockRendererExtension
+import org.jetbrains.jewel.markdown.rendering.InlineMarkdownRenderer
+import org.jetbrains.jewel.markdown.rendering.MarkdownBlockRenderer
+import org.jetbrains.jewel.markdown.rendering.MarkdownStyling
+import org.jetbrains.jewel.markdown.toInlineNode
+import org.jetbrains.jewel.ui.component.Text
+
+public class GitHubTableBlockRenderer(
+ private val styling: TableStyling,
+ private val rootStyling: MarkdownStyling,
+) : MarkdownBlockRendererExtension {
+
+ override fun canRender(block: CustomBlock): Boolean =
+ block.value is TableBlock
+
+ @Composable
+ private fun RowScope.TableCell(
+ text: List,
+ inlineRenderer: InlineMarkdownRenderer,
+ ) {
+ Text(
+ text = inlineRenderer.renderAsAnnotatedString(text, rootStyling.paragraph.inlinesStyling),
+ Modifier
+ .border(1.dp, styling.borderColor)
+ .weight(1.0f)
+ .padding(8.dp),
+ )
+ }
+
+ @Composable
+ override fun render(
+ block: CustomBlock,
+ blockRenderer: MarkdownBlockRenderer,
+ inlineRenderer: InlineMarkdownRenderer,
+ ) {
+ val head = block.value.firstChild as TableHead
+ val body = block.value.lastChild as TableBody
+
+ Column(Modifier.fillMaxSize().padding(16.dp)) {
+ head.forEachChild { row ->
+ Row(Modifier.background(styling.headColor)) {
+ row.forEachChild { cell ->
+ TableCell(text = cell.children().map { it.toInlineNode() }, inlineRenderer)
+ }
+ }
+ }
+ body.forEachChild { row ->
+ Row(Modifier.fillMaxWidth()) {
+ row.forEachChild { cell ->
+ TableCell(text = cell.children().map { it.toInlineNode() }, inlineRenderer)
+ }
+ }
+ }
+ }
+ }
+
+ @Composable
+ private fun Node.children(): List = buildList {
+ var child = firstChild
+
+ while (child != null) {
+ add(child)
+ child = child.next
+ }
+ }
+}
+
+@Composable
+private fun Node.forEachChild(action: @Composable (Node) -> Unit) {
+ var child = firstChild
+
+ while (child != null) {
+ action(child)
+ child = child.next
+ }
+}
diff --git a/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableProcessorExtension.kt b/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableProcessorExtension.kt
new file mode 100644
index 0000000000..b131adb8b2
--- /dev/null
+++ b/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableProcessorExtension.kt
@@ -0,0 +1,28 @@
+package org.jetbrains.jewel.markdown.extensions.tables
+
+import org.commonmark.ext.gfm.tables.TableBlock
+import org.commonmark.ext.gfm.tables.TablesExtension
+import org.commonmark.node.CustomBlock
+import org.commonmark.parser.Parser.ParserExtension
+import org.commonmark.renderer.text.TextContentRenderer.TextContentRendererExtension
+import org.jetbrains.jewel.markdown.MarkdownBlock
+import org.jetbrains.jewel.markdown.extensions.MarkdownBlockProcessorExtension
+import org.jetbrains.jewel.markdown.extensions.MarkdownProcessorExtension
+import org.jetbrains.jewel.markdown.processing.MarkdownProcessor
+
+public object GitHubTableProcessorExtension : MarkdownProcessorExtension {
+
+ override val parserExtension: ParserExtension = TablesExtension.create() as ParserExtension
+ override val textRendererExtension: TextContentRendererExtension = TablesExtension.create() as TextContentRendererExtension
+
+ override val processorExtension: MarkdownBlockProcessorExtension = GitHubTablesProcessorExtension
+
+ private object GitHubTablesProcessorExtension : MarkdownBlockProcessorExtension {
+
+ override fun canProcess(block: CustomBlock): Boolean = block is TableBlock
+
+ override fun processMarkdownBlock(block: CustomBlock, processor: MarkdownProcessor): MarkdownBlock.CustomBlock? {
+ error("should use CustomNode parser instead")
+ }
+ }
+}
diff --git a/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableRendererExtension.kt b/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableRendererExtension.kt
new file mode 100644
index 0000000000..6f4ae9d6fa
--- /dev/null
+++ b/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/GitHubTableRendererExtension.kt
@@ -0,0 +1,14 @@
+package org.jetbrains.jewel.markdown.extensions.tables
+
+import org.jetbrains.jewel.markdown.extensions.MarkdownBlockRendererExtension
+import org.jetbrains.jewel.markdown.extensions.MarkdownRendererExtension
+import org.jetbrains.jewel.markdown.rendering.MarkdownStyling
+
+public class GitHubTableRendererExtension(
+ alertStyling: TableStyling,
+ rootStyling: MarkdownStyling,
+) : MarkdownRendererExtension {
+
+ override val blockRenderer: MarkdownBlockRendererExtension =
+ GitHubTableBlockRenderer(alertStyling, rootStyling)
+}
diff --git a/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/TableStyling.kt b/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/TableStyling.kt
new file mode 100644
index 0000000000..0ef64ef572
--- /dev/null
+++ b/markdown/extension/gfm-tables/src/main/kotlin/org/jetbrains/jewel/markdown/extensions/tables/TableStyling.kt
@@ -0,0 +1,13 @@
+package org.jetbrains.jewel.markdown.extensions.tables
+
+import androidx.compose.ui.graphics.Color
+import org.jetbrains.jewel.foundation.GenerateDataFunctions
+
+@GenerateDataFunctions
+public class TableStyling(
+ public val headColor: Color,
+ public val borderColor: Color,
+) {
+
+ public companion object
+}
diff --git a/markdown/int-ui-standalone-styling/api/int-ui-standalone-styling.api b/markdown/int-ui-standalone-styling/api/int-ui-standalone-styling.api
index c70cd09739..8eafd826f2 100644
--- a/markdown/int-ui-standalone-styling/api/int-ui-standalone-styling.api
+++ b/markdown/int-ui-standalone-styling/api/int-ui-standalone-styling.api
@@ -113,3 +113,10 @@ public final class org/jetbrains/jewel/intui/markdown/styling/extension/github/a
public static synthetic fun light-gaOEZmc$default (Lorg/jetbrains/jewel/markdown/extensions/github/alerts/WarningAlertStyling$Companion;Landroidx/compose/foundation/layout/PaddingValues;FJLandroidx/compose/ui/graphics/PathEffect;ILandroidx/compose/ui/text/TextStyle;Ljava/lang/String;JJILjava/lang/Object;)Lorg/jetbrains/jewel/markdown/extensions/github/alerts/WarningAlertStyling;
}
+public final class org/jetbrains/jewel/intui/markdown/styling/extension/github/alerts/GitHubTableDefaultStylingKt {
+ public static final fun dark-WkMS-hQ (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;JJ)Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;
+ public static synthetic fun dark-WkMS-hQ$default (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;JJILjava/lang/Object;)Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;
+ public static final fun light-WkMS-hQ (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;JJ)Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;
+ public static synthetic fun light-WkMS-hQ$default (Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling$Companion;JJILjava/lang/Object;)Lorg/jetbrains/jewel/markdown/extensions/tables/TableStyling;
+}
+
diff --git a/markdown/int-ui-standalone-styling/build.gradle.kts b/markdown/int-ui-standalone-styling/build.gradle.kts
index 57a0ae2ae0..17dbdb446d 100644
--- a/markdown/int-ui-standalone-styling/build.gradle.kts
+++ b/markdown/int-ui-standalone-styling/build.gradle.kts
@@ -9,6 +9,7 @@ dependencies {
api(projects.markdown.core)
api(projects.intUi.intUiStandalone)
compileOnly(projects.markdown.extension.gfmAlerts)
+ compileOnly(projects.markdown.extension.gfmTables)
testImplementation(compose.desktop.uiTestJUnit4)
}
diff --git a/markdown/int-ui-standalone-styling/src/main/kotlin/org/jetbrains/jewel/intui/markdown/styling/extension/github/alerts/GitHubTableDefaultStyling.kt b/markdown/int-ui-standalone-styling/src/main/kotlin/org/jetbrains/jewel/intui/markdown/styling/extension/github/alerts/GitHubTableDefaultStyling.kt
new file mode 100644
index 0000000000..d32fd8dbd6
--- /dev/null
+++ b/markdown/int-ui-standalone-styling/src/main/kotlin/org/jetbrains/jewel/intui/markdown/styling/extension/github/alerts/GitHubTableDefaultStyling.kt
@@ -0,0 +1,20 @@
+package org.jetbrains.jewel.intui.markdown.styling.extension.github.alerts
+
+import androidx.compose.ui.graphics.Color
+import org.jetbrains.jewel.markdown.extensions.tables.TableStyling
+
+public fun TableStyling.Companion.dark(
+ headColor: Color = Color.DarkGray,
+ borderColor: Color = Color.Gray,
+): TableStyling = TableStyling(
+ headColor,
+ borderColor,
+)
+
+public fun TableStyling.Companion.light(
+ headColor: Color = Color.LightGray,
+ borderColor: Color = Color.Gray,
+): TableStyling = TableStyling(
+ headColor,
+ borderColor,
+)
diff --git a/samples/standalone/build.gradle.kts b/samples/standalone/build.gradle.kts
index 6cff7ddff0..c7741190b1 100644
--- a/samples/standalone/build.gradle.kts
+++ b/samples/standalone/build.gradle.kts
@@ -14,6 +14,7 @@ dependencies {
implementation(projects.intUi.intUiDecoratedWindow)
implementation(projects.markdown.intUiStandaloneStyling)
implementation(projects.markdown.extension.gfmAlerts)
+ implementation(projects.markdown.extension.gfmTables)
implementation(compose.desktop.currentOs) {
exclude(group = "org.jetbrains.compose.material")
diff --git a/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/markdown/JewelReadme.kt b/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/markdown/JewelReadme.kt
index 54afa08865..f30619a432 100644
--- a/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/markdown/JewelReadme.kt
+++ b/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/markdown/JewelReadme.kt
@@ -11,6 +11,10 @@ internal val JewelReadme = """
Jewel aims at recreating the IntelliJ Platform's _New UI_ Swing Look and Feel in Compose for Desktop, providing a
desktop-optimized theme and set of components.
+| foo | bar |
+| --- | --- |
+| baz | bim |
+
> [!WARNING]
>
> This project is in active development, and caution is advised when considering it for production uses. You _can_ use
diff --git a/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/markdown/MarkdownPreview.kt b/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/markdown/MarkdownPreview.kt
index 8baa7ed879..8fdc952b3b 100644
--- a/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/markdown/MarkdownPreview.kt
+++ b/samples/standalone/src/main/kotlin/org/jetbrains/jewel/samples/standalone/view/markdown/MarkdownPreview.kt
@@ -34,6 +34,9 @@ import org.jetbrains.jewel.markdown.MarkdownBlock
import org.jetbrains.jewel.markdown.extensions.github.alerts.AlertStyling
import org.jetbrains.jewel.markdown.extensions.github.alerts.GitHubAlertProcessorExtension
import org.jetbrains.jewel.markdown.extensions.github.alerts.GitHubAlertRendererExtension
+import org.jetbrains.jewel.markdown.extensions.tables.GitHubTableProcessorExtension
+import org.jetbrains.jewel.markdown.extensions.tables.GitHubTableRendererExtension
+import org.jetbrains.jewel.markdown.extensions.tables.TableStyling
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor
import org.jetbrains.jewel.markdown.rendering.InlineMarkdownRenderer
import org.jetbrains.jewel.markdown.rendering.MarkdownBlockRenderer
@@ -50,7 +53,7 @@ internal fun MarkdownPreview(rawMarkdown: String, modifier: Modifier = Modifier)
remember(isDark) { if (isDark) MarkdownStyling.dark() else MarkdownStyling.light() }
var markdownBlocks by remember { mutableStateOf(emptyList()) }
- val extensions = listOf(GitHubAlertProcessorExtension)
+ val extensions = listOf(GitHubAlertProcessorExtension, GitHubTableProcessorExtension)
val processor = remember { MarkdownProcessor(extensions) }
LaunchedEffect(rawMarkdown) {
@@ -65,7 +68,10 @@ internal fun MarkdownPreview(rawMarkdown: String, modifier: Modifier = Modifier)
if (isDark) {
MarkdownBlockRenderer.dark(
styling = markdownStyling,
- rendererExtensions = listOf(GitHubAlertRendererExtension(AlertStyling.dark(), markdownStyling)),
+ rendererExtensions = listOf(
+ GitHubAlertRendererExtension(AlertStyling.dark(), markdownStyling),
+ GitHubTableRendererExtension(TableStyling.dark(), markdownStyling),
+ ),
inlineRenderer = InlineMarkdownRenderer.default(extensions),
) { url ->
Desktop.getDesktop().browse(URI.create(url))
@@ -73,7 +79,10 @@ internal fun MarkdownPreview(rawMarkdown: String, modifier: Modifier = Modifier)
} else {
MarkdownBlockRenderer.light(
styling = markdownStyling,
- rendererExtensions = listOf(GitHubAlertRendererExtension(AlertStyling.light(), markdownStyling)),
+ rendererExtensions = listOf(
+ GitHubAlertRendererExtension(AlertStyling.light(), markdownStyling),
+ GitHubTableRendererExtension(TableStyling.light(), markdownStyling),
+ ),
inlineRenderer = InlineMarkdownRenderer.default(extensions),
) { url ->
Desktop.getDesktop().browse(URI.create(url))
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 7d7e33b089..43c8c5df1f 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -37,6 +37,7 @@ include(
":int-ui:int-ui-standalone",
":markdown:core",
":markdown:extension:gfm-alerts",
+ ":markdown:extension:gfm-tables",
":markdown:int-ui-standalone-styling",
":markdown:ide-laf-bridge-styling",
":samples:ide-plugin",