Skip to content

Commit

Permalink
Fix Markdown styling usage, and add semantics support (#397)
Browse files Browse the repository at this point in the history
* Fix Markdown functions not using provided styling

* Add semantics support to Markdown, move to right package

Usage in tests:

```kotlin
fun SemanticsNodeInteraction.assertMarkdownEquals(
  expected: String
): SemanticsNodeInteraction =
  assert(hasMarkdownExactly(expected))

private fun hasMarkdownExactly(expected: String): SemanticsMatcher =
  SemanticsMatcher.expectValue(RawMarkdown, expected)
```

* Update API dump
  • Loading branch information
rock3r authored Jun 10, 2024
1 parent 135f009 commit f4a376c
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 132 deletions.
16 changes: 13 additions & 3 deletions markdown/core/api/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,12 @@ public final class org/jetbrains/jewel/markdown/MarkdownBlock$ThematicBreak : or
public static final field INSTANCE Lorg/jetbrains/jewel/markdown/MarkdownBlock$ThematicBreak;
}

public final class org/jetbrains/jewel/markdown/MarkdownKt {
public static final fun LazyMarkdown (Ljava/util/List;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/lazy/LazyListState;ZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Landroidx/compose/runtime/Composer;II)V
public static final fun Markdown (Ljava/lang/String;Landroidx/compose/ui/Modifier;ZZLkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Landroidx/compose/runtime/Composer;II)V
public static final fun Markdown (Ljava/util/List;Ljava/lang/String;Landroidx/compose/ui/Modifier;ZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Landroidx/compose/runtime/Composer;II)V
}

public final class org/jetbrains/jewel/markdown/MimeType {
public static final field ATTR_FOLDER_TYPE Ljava/lang/String;
public static final field ATTR_ROLE Ljava/lang/String;
Expand Down Expand Up @@ -401,6 +407,12 @@ public final class org/jetbrains/jewel/markdown/MimeTypeKt {
public static final fun isXml-K9GpHcc (Ljava/lang/String;)Z
}

public final class org/jetbrains/jewel/markdown/SemanticsKt {
public static final fun getRawMarkdown ()Landroidx/compose/ui/semantics/SemanticsPropertyKey;
public static final fun getRawMarkdown (Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)Ljava/lang/String;
public static final fun setRawMarkdown (Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;Ljava/lang/String;)V
}

public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownBlockProcessorExtension {
public abstract fun canProcess (Lorg/commonmark/node/CustomBlock;)Z
public abstract fun processMarkdownBlock (Lorg/commonmark/node/CustomBlock;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;)Lorg/jetbrains/jewel/markdown/MarkdownBlock$CustomBlock;
Expand All @@ -412,9 +424,6 @@ public abstract interface class org/jetbrains/jewel/markdown/extensions/Markdown
}

public final class org/jetbrains/jewel/markdown/extensions/MarkdownKt {
public static final fun LazyMarkdown (Ljava/util/List;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/layout/PaddingValues;Landroidx/compose/foundation/lazy/LazyListState;ZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Landroidx/compose/runtime/Composer;II)V
public static final fun Markdown (Ljava/lang/String;Landroidx/compose/ui/Modifier;ZZLkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;Lorg/jetbrains/jewel/markdown/processing/MarkdownProcessor;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Landroidx/compose/runtime/Composer;II)V
public static final fun Markdown (Ljava/util/List;Landroidx/compose/ui/Modifier;ZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownBlockRenderer;Landroidx/compose/runtime/Composer;II)V
public static final fun getLocalMarkdownBlockRenderer ()Landroidx/compose/runtime/ProvidableCompositionLocal;
public static final fun getLocalMarkdownProcessor ()Landroidx/compose/runtime/ProvidableCompositionLocal;
public static final fun getLocalMarkdownStyling ()Landroidx/compose/runtime/ProvidableCompositionLocal;
Expand Down Expand Up @@ -457,6 +466,7 @@ public final class org/jetbrains/jewel/markdown/rendering/DefaultInlineMarkdownR
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
public synthetic fun <init> (Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;Ljava/util/List;Lorg/jetbrains/jewel/markdown/rendering/InlineMarkdownRenderer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun render (Ljava/util/List;ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
public fun render (Lorg/jetbrains/jewel/markdown/MarkdownBlock$BlockQuote;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$BlockQuote;ZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
public fun render (Lorg/jetbrains/jewel/markdown/MarkdownBlock$CodeBlock$FencedCodeBlock;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling$Code$Fenced;Landroidx/compose/runtime/Composer;I)V
Expand Down
138 changes: 138 additions & 0 deletions markdown/core/src/main/kotlin/org/jetbrains/jewel/markdown/Markdown.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package org.jetbrains.jewel.markdown

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.intellij.lang.annotations.Language
import org.jetbrains.jewel.foundation.ExperimentalJewelApi
import org.jetbrains.jewel.foundation.theme.JewelTheme
import org.jetbrains.jewel.markdown.extensions.markdownBlockRenderer
import org.jetbrains.jewel.markdown.extensions.markdownProcessor
import org.jetbrains.jewel.markdown.extensions.markdownStyling
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor
import org.jetbrains.jewel.markdown.rendering.DefaultMarkdownBlockRenderer
import org.jetbrains.jewel.markdown.rendering.MarkdownBlockRenderer
import org.jetbrains.jewel.markdown.rendering.MarkdownStyling

@ExperimentalJewelApi
@Composable
public fun Markdown(
@Language("Markdown") markdown: String,
modifier: Modifier = Modifier,
selectable: Boolean = false,
enabled: Boolean = true,
renderingDispatcher: CoroutineDispatcher = Dispatchers.Default,
onUrlClick: (String) -> Unit = {},
onTextClick: () -> Unit = {},
markdownStyling: MarkdownStyling = JewelTheme.markdownStyling,
processor: MarkdownProcessor = JewelTheme.markdownProcessor,
blockRenderer: MarkdownBlockRenderer = DefaultMarkdownBlockRenderer(markdownStyling),
) {
var markdownBlocks by remember { mutableStateOf(emptyList<MarkdownBlock>()) }
LaunchedEffect(markdown, processor) {
markdownBlocks =
withContext(renderingDispatcher) { processor.processMarkdownDocument(markdown) }
}

Markdown(
markdownBlocks = markdownBlocks,
markdown = markdown,
modifier = modifier,
selectable = selectable,
enabled = enabled,
onUrlClick = onUrlClick,
onTextClick = onTextClick,
markdownStyling = markdownStyling,
blockRenderer = blockRenderer,
)
}

@ExperimentalJewelApi
@Composable
public fun Markdown(
markdownBlocks: List<MarkdownBlock>,
markdown: String,
modifier: Modifier = Modifier,
enabled: Boolean = true,
selectable: Boolean = false,
onUrlClick: (String) -> Unit = {},
onTextClick: () -> Unit = {},
markdownStyling: MarkdownStyling = JewelTheme.markdownStyling,
blockRenderer: MarkdownBlockRenderer = DefaultMarkdownBlockRenderer(markdownStyling),
) {
if (selectable) {
SelectionContainer(modifier.semantics { rawMarkdown = markdown }) {
Column(verticalArrangement = Arrangement.spacedBy(markdownStyling.blockVerticalSpacing)) {
for (block in markdownBlocks) {
blockRenderer.render(block, enabled, onUrlClick, onTextClick)
}
}
}
} else {
Column(
modifier.semantics { rawMarkdown = markdown },
verticalArrangement = Arrangement.spacedBy(markdownStyling.blockVerticalSpacing),
) {
for (block in markdownBlocks) {
blockRenderer.render(block, enabled, onUrlClick, onTextClick)
}
}
}
}

@ExperimentalJewelApi
@Composable
public fun LazyMarkdown(
markdownBlocks: List<MarkdownBlock>,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
state: LazyListState = rememberLazyListState(),
enabled: Boolean = true,
selectable: Boolean = false,
onUrlClick: (String) -> Unit = {},
onTextClick: () -> Unit = {},
markdownStyling: MarkdownStyling = JewelTheme.markdownStyling,
blockRenderer: MarkdownBlockRenderer = JewelTheme.markdownBlockRenderer,
) {
if (selectable) {
SelectionContainer(modifier) {
LazyColumn(
state = state,
contentPadding = contentPadding,
verticalArrangement = Arrangement.spacedBy(markdownStyling.blockVerticalSpacing),
) {
items(markdownBlocks) { block ->
blockRenderer.render(block, enabled, onUrlClick, onTextClick)
}
}
}
} else {
LazyColumn(
modifier = modifier,
state = state,
contentPadding = contentPadding,
verticalArrangement = Arrangement.spacedBy(markdownStyling.blockVerticalSpacing),
) {
items(markdownBlocks) { block ->
blockRenderer.render(block, enabled, onUrlClick, onTextClick)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.jetbrains.jewel.markdown

import androidx.compose.ui.semantics.SemanticsPropertyKey
import androidx.compose.ui.semantics.SemanticsPropertyReceiver

public val RawMarkdown: SemanticsPropertyKey<String> = SemanticsPropertyKey("RawMarkdown")
public var SemanticsPropertyReceiver.rawMarkdown: String by RawMarkdown
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
package org.jetbrains.jewel.markdown.extensions

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.intellij.lang.annotations.Language
import org.jetbrains.jewel.foundation.ExperimentalJewelApi
import org.jetbrains.jewel.foundation.theme.JewelTheme
import org.jetbrains.jewel.markdown.MarkdownBlock
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor
import org.jetbrains.jewel.markdown.rendering.MarkdownBlockRenderer
import org.jetbrains.jewel.markdown.rendering.MarkdownStyling
Expand All @@ -49,107 +28,3 @@ public val LocalMarkdownBlockRenderer: ProvidableCompositionLocal<MarkdownBlockR

public val JewelTheme.Companion.markdownBlockRenderer: MarkdownBlockRenderer
@Composable get() = LocalMarkdownBlockRenderer.current

@ExperimentalJewelApi
@Composable
public fun Markdown(
@Language("Markdown") markdown: String,
modifier: Modifier = Modifier,
selectable: Boolean = false,
enabled: Boolean = true,
renderingDispatcher: CoroutineDispatcher = Dispatchers.Default,
onUrlClick: (String) -> Unit = {},
onTextClick: () -> Unit = {},
markdownStyling: MarkdownStyling = JewelTheme.markdownStyling,
processor: MarkdownProcessor = JewelTheme.markdownProcessor,
blockRenderer: MarkdownBlockRenderer = JewelTheme.markdownBlockRenderer,
) {
var markdownBlocks by remember { mutableStateOf(emptyList<MarkdownBlock>()) }
LaunchedEffect(markdown) {
markdownBlocks =
withContext(renderingDispatcher) { processor.processMarkdownDocument(markdown) }
}

Markdown(
markdownBlocks = markdownBlocks,
modifier = modifier,
selectable = selectable,
enabled = enabled,
onUrlClick = onUrlClick,
onTextClick = onTextClick,
markdownStyling = markdownStyling,
blockRenderer = blockRenderer,
)
}

@ExperimentalJewelApi
@Composable
public fun Markdown(
markdownBlocks: List<MarkdownBlock>,
modifier: Modifier = Modifier,
enabled: Boolean = true,
selectable: Boolean = false,
onUrlClick: (String) -> Unit = {},
onTextClick: () -> Unit = {},
markdownStyling: MarkdownStyling = JewelTheme.markdownStyling,
blockRenderer: MarkdownBlockRenderer = JewelTheme.markdownBlockRenderer,
) {
if (selectable) {
SelectionContainer(modifier) {
Column(verticalArrangement = Arrangement.spacedBy(markdownStyling.blockVerticalSpacing)) {
for (block in markdownBlocks) {
blockRenderer.render(block, enabled, onUrlClick, onTextClick)
}
}
}
} else {
Column(
modifier,
verticalArrangement = Arrangement.spacedBy(markdownStyling.blockVerticalSpacing),
) {
for (block in markdownBlocks) {
blockRenderer.render(block, enabled, onUrlClick, onTextClick)
}
}
}
}

@ExperimentalJewelApi
@Composable
public fun LazyMarkdown(
markdownBlocks: List<MarkdownBlock>,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
state: LazyListState = rememberLazyListState(),
enabled: Boolean = true,
selectable: Boolean = false,
onUrlClick: (String) -> Unit = {},
onTextClick: () -> Unit = {},
markdownStyling: MarkdownStyling = JewelTheme.markdownStyling,
blockRenderer: MarkdownBlockRenderer = JewelTheme.markdownBlockRenderer,
) {
if (selectable) {
SelectionContainer(modifier) {
LazyColumn(
state = state,
contentPadding = contentPadding,
verticalArrangement = Arrangement.spacedBy(markdownStyling.blockVerticalSpacing),
) {
items(markdownBlocks) { block ->
blockRenderer.render(block, enabled, onUrlClick, onTextClick)
}
}
}
} else {
LazyColumn(
modifier = modifier,
state = state,
contentPadding = contentPadding,
verticalArrangement = Arrangement.spacedBy(markdownStyling.blockVerticalSpacing),
) {
items(markdownBlocks) { block ->
blockRenderer.render(block, enabled, onUrlClick, onTextClick)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ import org.jetbrains.jewel.ui.component.Text
@ExperimentalJewelApi
public open class DefaultMarkdownBlockRenderer(
private val rootStyling: MarkdownStyling,
private val rendererExtensions: List<MarkdownRendererExtension>,
private val inlineRenderer: InlineMarkdownRenderer,
private val rendererExtensions: List<MarkdownRendererExtension> = emptyList(),
private val inlineRenderer: InlineMarkdownRenderer = DefaultInlineMarkdownRenderer(),
) : MarkdownBlockRenderer {

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import org.jetbrains.jewel.foundation.modifier.trackComponentActivation
import org.jetbrains.jewel.foundation.theme.JewelTheme
import org.jetbrains.jewel.foundation.theme.LocalContentColor
import org.jetbrains.jewel.intui.markdown.bridge.ProvideMarkdownStyling
import org.jetbrains.jewel.markdown.extensions.Markdown
import org.jetbrains.jewel.markdown.Markdown
import org.jetbrains.jewel.ui.Orientation
import org.jetbrains.jewel.ui.Outline
import org.jetbrains.jewel.ui.component.CheckboxRow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import org.jetbrains.jewel.intui.markdown.standalone.styling.dark
import org.jetbrains.jewel.intui.markdown.standalone.styling.extension.github.alerts.dark
import org.jetbrains.jewel.intui.markdown.standalone.styling.extension.github.alerts.light
import org.jetbrains.jewel.intui.markdown.standalone.styling.light
import org.jetbrains.jewel.markdown.LazyMarkdown
import org.jetbrains.jewel.markdown.MarkdownBlock
import org.jetbrains.jewel.markdown.extension.autolink.AutolinkProcessorExtension
import org.jetbrains.jewel.markdown.extensions.LazyMarkdown
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
Expand Down

0 comments on commit f4a376c

Please sign in to comment.