mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
[JEWEL-742] Load markdown images using Coil3
It supports every image as an inline node; Using built-in coroutine library and ktor3 from the platform; Added SVG support using a coil dependency. Moved images into an extension so it can be loaded on demand without pushin coil3 dependencies to everyone. Add Coil3ImagesRendererExtension to rendering extensions to render images. Also expose `imageLoader` as a parameter to give fine controls to apps wanting to pass in their global loader. (cherry picked from commit f7b51b8239622c39297aeb8dcfd8fad3435111ec) (cherry picked from commit 59f8cf9d80d1a53267e902f78976c97d24a898b3) IJ-MR-168786 GitOrigin-RevId: 880feae68b283c1fce907557522a0d4e78a8cdd2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
61d1f2fe74
commit
9b0bb9f169
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@@ -834,6 +834,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/jewel/markdown/extensions/gfm-alerts/intellij.platform.jewel.markdown.extensions.gfmAlerts.iml" filepath="$PROJECT_DIR$/platform/jewel/markdown/extensions/gfm-alerts/intellij.platform.jewel.markdown.extensions.gfmAlerts.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/jewel/markdown/extensions/gfm-strikethrough/intellij.platform.jewel.markdown.extensions.gfmStrikethrough.iml" filepath="$PROJECT_DIR$/platform/jewel/markdown/extensions/gfm-strikethrough/intellij.platform.jewel.markdown.extensions.gfmStrikethrough.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/jewel/markdown/extensions/gfm-tables/intellij.platform.jewel.markdown.extensions.gfmTables.iml" filepath="$PROJECT_DIR$/platform/jewel/markdown/extensions/gfm-tables/intellij.platform.jewel.markdown.extensions.gfmTables.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/jewel/markdown/extensions/images/intellij.platform.jewel.markdown.extensions.images.iml" filepath="$PROJECT_DIR$/platform/jewel/markdown/extensions/images/intellij.platform.jewel.markdown.extensions.images.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/jewel/markdown/ide-laf-bridge-styling/intellij.platform.jewel.markdown.ideLafBridgeStyling.iml" filepath="$PROJECT_DIR$/platform/jewel/markdown/ide-laf-bridge-styling/intellij.platform.jewel.markdown.ideLafBridgeStyling.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/jewel/markdown/int-ui-standalone-styling/intellij.platform.jewel.markdown.intUiStandaloneStyling.iml" filepath="$PROJECT_DIR$/platform/jewel/markdown/int-ui-standalone-styling/intellij.platform.jewel.markdown.intUiStandaloneStyling.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/jewel/samples/ide-plugin/intellij.platform.jewel.samples.idePlugin.iml" filepath="$PROJECT_DIR$/platform/jewel/samples/ide-plugin/intellij.platform.jewel.samples.idePlugin.iml" />
|
||||
|
||||
@@ -25,6 +25,7 @@ internal object JewelMavenArtifacts {
|
||||
"intellij.platform.jewel.markdown.extensions.gfmStrikethrough" to "jewel-markdown-extensions-gfm-strikethrough",
|
||||
"intellij.platform.jewel.markdown.extensions.autolink" to "jewel-markdown-extensions-autolink",
|
||||
"intellij.platform.jewel.markdown.extensions.gfmAlerts" to "jewel-markdown-extensions-gfm-alerts",
|
||||
"intellij.platform.jewel.markdown.extensions.images" to "jewel-markdown-extensions-images",
|
||||
)
|
||||
internal val STANDALONE: Map<String, String> = mapOf(
|
||||
"intellij.platform.jewel.markdown.intUiStandaloneStyling" to "jewel-markdown-int-ui-standalone-styling",
|
||||
@@ -46,6 +47,7 @@ internal object JewelMavenArtifacts {
|
||||
"jewel-markdown-extensions-gfm-alerts" to setOf("jewel-foundation", "jewel-ui"),
|
||||
"jewel-markdown-extensions-gfm-strikethrough" to setOf("jewel-foundation", "jewel-ui"),
|
||||
"jewel-markdown-extensions-gfm-tables" to setOf("jewel-foundation", "jewel-ui"),
|
||||
"jewel-markdown-extensions-images" to setOf("jewel-foundation", "jewel-ui"),
|
||||
"jewel-int-ui-standalone" to setOf("jewel-foundation"),
|
||||
"jewel-int-ui-decorated-window" to setOf("jewel-foundation", "jewel-ui", "jewel-int-ui-standalone"),
|
||||
"jewel-markdown-int-ui-standalone-styling" to setOf("jewel-foundation", "jewel-ui"),
|
||||
|
||||
@@ -8208,6 +8208,48 @@ jvm_import(
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "platform-jewel-markdown-extensions-images-io-coil-kt-coil3-compose-core-jvm",
|
||||
jar = "@coil-compose-core-jvm-3_1_0_http//file",
|
||||
source_jar = "@coil-compose-core-jvm-3_1_0-sources_http//file",
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "platform-jewel-markdown-extensions-images-io-coil-kt-coil3-compose-jvm",
|
||||
jar = "@coil-compose-jvm-3_1_0_http//file",
|
||||
source_jar = "@coil-compose-jvm-3_1_0-sources_http//file",
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "platform-jewel-markdown-extensions-images-io-coil-kt-coil3-core-jvm",
|
||||
jar = "@coil-core-jvm-3_1_0_http//file",
|
||||
source_jar = "@coil-core-jvm-3_1_0-sources_http//file",
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "platform-jewel-markdown-extensions-images-io-coil-kt-coil3-network-core-jvm",
|
||||
jar = "@coil-network-core-jvm-3_1_0_http//file",
|
||||
source_jar = "@coil-network-core-jvm-3_1_0-sources_http//file",
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "platform-jewel-markdown-extensions-images-io-coil-kt-coil3-network-ktor3-jvm",
|
||||
jar = "@coil-network-ktor3-jvm-3_1_0_http//file",
|
||||
source_jar = "@coil-network-ktor3-jvm-3_1_0-sources_http//file",
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "platform-jewel-markdown-extensions-images-io-coil-kt-coil3-svg-jvm",
|
||||
jar = "@coil-svg-jvm-3_1_0_http//file",
|
||||
source_jar = "@coil-svg-jvm-3_1_0-sources_http//file",
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
jvm_import(
|
||||
name = "platform-jewel-samples-standalone-com-darkrockstudios-mpfilepicker",
|
||||
jar = "@mpfilepicker-3_1_0_http//file",
|
||||
|
||||
@@ -11660,6 +11660,90 @@ http_file(
|
||||
downloaded_file_path = "commonmark-ext-gfm-tables-0.24.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-compose-core-jvm-3_1_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-compose-core-jvm/3.1.0/coil-compose-core-jvm-3.1.0.jar",
|
||||
sha256 = "8aa1d7ae1d11f969e8cdcc8fee42b7ee6a036e21f70567e3c3486edd9d7dc594",
|
||||
downloaded_file_path = "coil-compose-core-jvm-3.1.0.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-compose-core-jvm-3_1_0-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-compose-core-jvm/3.1.0/coil-compose-core-jvm-3.1.0-sources.jar",
|
||||
sha256 = "70ae99718a081cb53c353f8f60100960ab27c743465781b96fa2b237aa0f5ed2",
|
||||
downloaded_file_path = "coil-compose-core-jvm-3.1.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-compose-jvm-3_1_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-compose-jvm/3.1.0/coil-compose-jvm-3.1.0.jar",
|
||||
sha256 = "d43e0ed4566d30f8ce8e023539240b494be6fa69a1b8c81b4c32f5f465a7cc06",
|
||||
downloaded_file_path = "coil-compose-jvm-3.1.0.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-compose-jvm-3_1_0-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-compose-jvm/3.1.0/coil-compose-jvm-3.1.0-sources.jar",
|
||||
sha256 = "f9f84a9feaff1a4299ce2d4f4ba6d4de9cd36865f10676cdc9e798a58088002f",
|
||||
downloaded_file_path = "coil-compose-jvm-3.1.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-core-jvm-3_1_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-core-jvm/3.1.0/coil-core-jvm-3.1.0.jar",
|
||||
sha256 = "6d44a11188c53f4eea2e87ebadc6aad90069132c9b029fc1b35aeb0added5ef7",
|
||||
downloaded_file_path = "coil-core-jvm-3.1.0.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-core-jvm-3_1_0-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-core-jvm/3.1.0/coil-core-jvm-3.1.0-sources.jar",
|
||||
sha256 = "3a8039b9e8de0755d0889d53816f02d567bd16e6a5548d3a79ead69d9e1e4b50",
|
||||
downloaded_file_path = "coil-core-jvm-3.1.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-network-core-jvm-3_1_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-network-core-jvm/3.1.0/coil-network-core-jvm-3.1.0.jar",
|
||||
sha256 = "8332e45cf792cd24d9814744db84b0e6d33ec6eaf0724bd07ddc1fce7c55591f",
|
||||
downloaded_file_path = "coil-network-core-jvm-3.1.0.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-network-core-jvm-3_1_0-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-network-core-jvm/3.1.0/coil-network-core-jvm-3.1.0-sources.jar",
|
||||
sha256 = "b83d0d40b5f9074240a337fd33b42853c2a92049290623ce3b2c1d84fd1499a9",
|
||||
downloaded_file_path = "coil-network-core-jvm-3.1.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-network-ktor3-jvm-3_1_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-network-ktor3-jvm/3.1.0/coil-network-ktor3-jvm-3.1.0.jar",
|
||||
sha256 = "cc4f9f8d6d447e7559cb9717c3a45dfbd351ddd06a34724001322512160b0215",
|
||||
downloaded_file_path = "coil-network-ktor3-jvm-3.1.0.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-network-ktor3-jvm-3_1_0-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-network-ktor3-jvm/3.1.0/coil-network-ktor3-jvm-3.1.0-sources.jar",
|
||||
sha256 = "8f1a55a9ed282fe77df261aa7e4d57172508a70843951af422cfcbf97e0ab349",
|
||||
downloaded_file_path = "coil-network-ktor3-jvm-3.1.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-svg-jvm-3_1_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-svg-jvm/3.1.0/coil-svg-jvm-3.1.0.jar",
|
||||
sha256 = "413a53b4b6e0a40b851d1a99a01a4cd91ac0dc68facefddd7adfdb2d5456588f",
|
||||
downloaded_file_path = "coil-svg-jvm-3.1.0.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "coil-svg-jvm-3_1_0-sources_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/io/coil-kt/coil3/coil-svg-jvm/3.1.0/coil-svg-jvm-3.1.0-sources.jar",
|
||||
sha256 = "b12fe3352673d00d5b10f6585a456e3bb0a2f19aadf5d9efcb42bf97dbeb856f",
|
||||
downloaded_file_path = "coil-svg-jvm-3.1.0-sources.jar"
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "mpfilepicker-3_1_0_http",
|
||||
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/com/darkrockstudios/mpfilepicker/3.1.0/mpfilepicker-3.1.0.jar",
|
||||
|
||||
@@ -233,6 +233,18 @@ object CommunityLibraryLicenses {
|
||||
LibraryLicense("CMake For VisualStudio Code", version = "0.0.17", attachedTo = "intellij.textmate", url = "https://github.com/twxs/vs.language.cmake")
|
||||
.mit("https://github.com/twxs/vs.language.cmake/blob/master/LICENSE"),
|
||||
|
||||
// For loading images in Compose (used in Markdown preview, for example)
|
||||
LibraryLicense("Coil", libraryName = "io.coil.kt.coil3.core.jvm", url = "https://github.com/coil-kt/coil")
|
||||
.additionalLibraryNames(
|
||||
"io.coil.kt.coil3.svg.jvm",
|
||||
"io.coil.kt.coil3.network.core.jvm",
|
||||
"io.coil.kt.coil3.network.ktor3.jvm",
|
||||
"io.coil.kt.coil3.compose.jvm",
|
||||
"io.coil.kt.coil3.compose.core.jvm",
|
||||
)
|
||||
.apache("https://github.com/coil-kt/coil/blob/main/README.md#license")
|
||||
.copyrightText("Copyright 2025 Coil Contributors"),
|
||||
|
||||
LibraryLicense("Command Line Interface Parser for Java", libraryName = "cli-parser", url = "https://github.com/spullara/cli-parser?tab=readme-ov-file")
|
||||
.apache("https://github.com/spullara/cli-parser/blob/95edeb2d1a21fb13760b4f96f976a7f3108e0942/README.md?plain=1#L65")
|
||||
.copyrightText("Copyright 2012 Sam Pullara"),
|
||||
|
||||
@@ -18,6 +18,7 @@ java_library(
|
||||
"//platform/jewel/markdown/extensions/gfm-alerts",
|
||||
"//platform/jewel/markdown/extensions/gfm-strikethrough",
|
||||
"//platform/jewel/markdown/extensions/gfm-tables",
|
||||
"//platform/jewel/markdown/extensions/images",
|
||||
"//platform/jewel/markdown/ide-laf-bridge-styling",
|
||||
],
|
||||
runtime_deps = [
|
||||
@@ -28,6 +29,7 @@ java_library(
|
||||
"//platform/jewel/markdown/extensions/gfm-alerts",
|
||||
"//platform/jewel/markdown/extensions/gfm-strikethrough",
|
||||
"//platform/jewel/markdown/extensions/gfm-tables",
|
||||
"//platform/jewel/markdown/extensions/images",
|
||||
"//platform/jewel/markdown/ide-laf-bridge-styling",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.extensions.gfmAlerts" exported="" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.extensions.gfmStrikethrough" exported="" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.extensions.gfmTables" exported="" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.extensions.images" exported="" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.ideLafBridgeStyling" exported="" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -17,6 +17,7 @@ dependencies {
|
||||
sarif(projects.markdown.extensions.gfmAlerts)
|
||||
sarif(projects.markdown.extensions.gfmStrikethrough)
|
||||
sarif(projects.markdown.extensions.gfmTables)
|
||||
sarif(projects.markdown.extensions.images)
|
||||
sarif(projects.markdown.ideLafBridgeStyling)
|
||||
sarif(projects.markdown.intUiStandaloneStyling)
|
||||
sarif(projects.samples.idePlugin)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[versions]
|
||||
coil = "3.1.0"
|
||||
commonmark = "0.24.0"
|
||||
composeDesktop = "1.8.1"
|
||||
detekt = "1.23.6"
|
||||
@@ -17,6 +18,11 @@ kotlinxBinaryCompat = "0.17.0"
|
||||
ktfmtGradlePlugin = "0.22.0"
|
||||
|
||||
[libraries]
|
||||
coil-compose-core = { module = "io.coil-kt.coil3:coil-compose-core", version.ref = "coil" }
|
||||
# network is only needed in a standalone non-ide version
|
||||
coil-network-ktor3 = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil" }
|
||||
coil-svg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coil" }
|
||||
|
||||
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" }
|
||||
@@ -27,6 +33,7 @@ filePicker = { module = "com.darkrockstudios:mpfilepicker", version.ref = "filep
|
||||
kotlinSarif = { module = "io.github.detekt.sarif4k:sarif4k", version.ref = "kotlinSarif" }
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
|
||||
ktor-client-java = { module = "io.ktor:ktor-client-java", version = "3.0.3" }
|
||||
|
||||
jna-core = { module = "net.java.dev.jna:jna", version.ref = "jna" }
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ f:org.jetbrains.jewel.markdown.MarkdownBlock$ListItem
|
||||
- <init>(java.util.List,I):V
|
||||
- <init>(org.jetbrains.jewel.markdown.MarkdownBlock[],I):V
|
||||
- f:getLevel():I
|
||||
org.jetbrains.jewel.markdown.extensions.ImageRendererExtension
|
||||
- a:renderImagesContent(org.jetbrains.jewel.markdown.InlineMarkdown$Image,androidx.compose.runtime.Composer,I):androidx.compose.foundation.text.InlineTextContent
|
||||
org.jetbrains.jewel.markdown.extensions.MarkdownRendererExtension
|
||||
- getImageRendererExtension():org.jetbrains.jewel.markdown.extensions.ImageRendererExtension
|
||||
f:org.jetbrains.jewel.markdown.processing.MarkdownProcessor
|
||||
- sf:$stable:I
|
||||
- <init>():V
|
||||
|
||||
@@ -260,6 +260,10 @@ public abstract interface class org/jetbrains/jewel/markdown/WithTextContent {
|
||||
public abstract fun getContent ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract interface class org/jetbrains/jewel/markdown/extensions/ImageRendererExtension {
|
||||
public abstract fun renderImagesContent (Lorg/jetbrains/jewel/markdown/InlineMarkdown$Image;Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/text/InlineTextContent;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -308,11 +312,13 @@ public final class org/jetbrains/jewel/markdown/extensions/MarkdownProcessorExte
|
||||
public abstract interface class org/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension {
|
||||
public abstract fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
|
||||
public abstract fun getDelimitedInlineRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension;
|
||||
public abstract fun getImageRendererExtension ()Lorg/jetbrains/jewel/markdown/extensions/ImageRendererExtension;
|
||||
}
|
||||
|
||||
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 getDelimitedInlineRenderer (Lorg/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension;)Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension;
|
||||
public static fun getImageRendererExtension (Lorg/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension;)Lorg/jetbrains/jewel/markdown/extensions/ImageRendererExtension;
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/markdown/processing/MarkdownParserFactory {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.jewel.markdown.extensions
|
||||
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.jewel.foundation.ExperimentalJewelApi
|
||||
import org.jetbrains.jewel.markdown.InlineMarkdown
|
||||
|
||||
/** An extension for the Jewel images rendering engine. */
|
||||
@ExperimentalJewelApi
|
||||
public interface ImageRendererExtension {
|
||||
@Composable public fun renderImagesContent(image: InlineMarkdown.Image): InlineTextContent
|
||||
}
|
||||
@@ -24,4 +24,10 @@ public interface MarkdownRendererExtension {
|
||||
*/
|
||||
public val delimitedInlineRenderer: MarkdownDelimitedInlineRendererExtension?
|
||||
get() = null
|
||||
|
||||
/**
|
||||
* An extension for handling the rendering of image elements. Can be null if no custom image rendering is provided.
|
||||
*/
|
||||
public val imageRendererExtension: ImageRendererExtension?
|
||||
get() = null
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.jewel.markdown.rendering
|
||||
|
||||
import androidx.compose.foundation.text.appendInlineContent
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.takeOrElse
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
@@ -166,7 +167,8 @@ public open class DefaultInlineMarkdownRenderer(rendererExtensions: List<Markdow
|
||||
enabled: Boolean,
|
||||
currentTextStyle: TextStyle,
|
||||
) {
|
||||
// Not supported yet — see JEWEL-746
|
||||
// Each image source corresponds to one rendered image.
|
||||
appendInlineContent(node.source, "")
|
||||
}
|
||||
|
||||
// The T type parameter is needed to avoid issues with capturing lambdas
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.foundation.text.selection.DisableSelection
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
@@ -42,6 +43,7 @@ import org.jetbrains.jewel.foundation.code.MimeType
|
||||
import org.jetbrains.jewel.foundation.code.highlighting.LocalCodeHighlighter
|
||||
import org.jetbrains.jewel.foundation.modifier.thenIf
|
||||
import org.jetbrains.jewel.foundation.theme.LocalContentColor
|
||||
import org.jetbrains.jewel.markdown.InlineMarkdown
|
||||
import org.jetbrains.jewel.markdown.MarkdownBlock
|
||||
import org.jetbrains.jewel.markdown.MarkdownBlock.BlockQuote
|
||||
import org.jetbrains.jewel.markdown.MarkdownBlock.CodeBlock
|
||||
@@ -150,6 +152,7 @@ public open class DefaultMarkdownBlockRenderer(
|
||||
.clickable(interactionSource = interactionSource, indication = null, onClick = onTextClick),
|
||||
text = renderedContent,
|
||||
style = mergedStyle,
|
||||
inlineContent = renderedImages(block),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -523,6 +526,17 @@ public open class DefaultMarkdownBlockRenderer(
|
||||
inlineRenderer.renderAsAnnotatedString(block.inlineContent, styling, enabled, onUrlClick)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun renderedImages(blockInlineContent: WithInlineMarkdown): Map<String, InlineTextContent> {
|
||||
return rendererExtensions
|
||||
.firstNotNullOfOrNull { it.imageRendererExtension }
|
||||
?.let { imagesRenderer ->
|
||||
getImages(blockInlineContent).associate { image ->
|
||||
image.source to imagesRenderer.renderImagesContent(image)
|
||||
}
|
||||
} ?: emptyMap()
|
||||
}
|
||||
|
||||
@Composable
|
||||
protected fun MaybeScrollingContainer(
|
||||
isScrollable: Boolean,
|
||||
@@ -551,3 +565,21 @@ public open class DefaultMarkdownBlockRenderer(
|
||||
override operator fun plus(extension: MarkdownRendererExtension): MarkdownBlockRenderer =
|
||||
DefaultMarkdownBlockRenderer(rootStyling, rendererExtensions = rendererExtensions + extension, inlineRenderer)
|
||||
}
|
||||
|
||||
private fun getImages(input: WithInlineMarkdown): List<InlineMarkdown.Image> = buildList {
|
||||
fun collectImagesRecursively(items: List<InlineMarkdown>) {
|
||||
for (item in items) {
|
||||
when (item) {
|
||||
is InlineMarkdown.Image -> {
|
||||
if (item.source.isNotBlank()) add(item)
|
||||
}
|
||||
is WithInlineMarkdown -> {
|
||||
collectImagesRecursively(item.inlineContent)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
collectImagesRecursively(input.inlineContent)
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ public final class org/jetbrains/jewel/markdown/extensions/github/alerts/GitHubA
|
||||
public fun <init> (Lorg/jetbrains/jewel/markdown/extensions/github/alerts/AlertStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;)V
|
||||
public fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
|
||||
public fun getDelimitedInlineRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension;
|
||||
public fun getImageRendererExtension ()Lorg/jetbrains/jewel/markdown/extensions/ImageRendererExtension;
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/markdown/extensions/github/alerts/ImportantAlertStyling : org/jetbrains/jewel/markdown/extensions/github/alerts/BaseAlertStyling {
|
||||
|
||||
@@ -44,5 +44,6 @@ public final class org/jetbrains/jewel/markdown/extensions/github/strikethrough/
|
||||
public static final field INSTANCE Lorg/jetbrains/jewel/markdown/extensions/github/strikethrough/GitHubStrikethroughRendererExtension;
|
||||
public fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
|
||||
public fun getDelimitedInlineRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension;
|
||||
public fun getImageRendererExtension ()Lorg/jetbrains/jewel/markdown/extensions/ImageRendererExtension;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ public final class org/jetbrains/jewel/markdown/extensions/github/tables/GitHubT
|
||||
public fun <init> (Lorg/jetbrains/jewel/markdown/extensions/github/tables/GfmTableStyling;Lorg/jetbrains/jewel/markdown/rendering/MarkdownStyling;)V
|
||||
public fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
|
||||
public fun getDelimitedInlineRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension;
|
||||
public fun getImageRendererExtension ()Lorg/jetbrains/jewel/markdown/extensions/ImageRendererExtension;
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/markdown/extensions/github/tables/RowBackgroundStyle : java/lang/Enum {
|
||||
|
||||
51
platform/jewel/markdown/extensions/images/BUILD.bazel
Normal file
51
platform/jewel/markdown/extensions/images/BUILD.bazel
Normal file
@@ -0,0 +1,51 @@
|
||||
### auto-generated section `build intellij.platform.jewel.markdown.extensions.images` start
|
||||
load("//build:compiler-options.bzl", "create_kotlinc_options")
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_library", "jvm_resources")
|
||||
|
||||
create_kotlinc_options(
|
||||
name = "custom",
|
||||
context_receivers = True,
|
||||
opt_in = [
|
||||
"androidx.compose.ui.ExperimentalComposeUiApi",
|
||||
"androidx.compose.foundation.ExperimentalFoundationApi",
|
||||
"org.jetbrains.jewel.foundation.ExperimentalJewelApi",
|
||||
"org.jetbrains.jewel.foundation.InternalJewelApi",
|
||||
]
|
||||
)
|
||||
|
||||
jvm_resources(
|
||||
name = "images_resources",
|
||||
files = glob(["src/main/resources/**/*"]),
|
||||
strip_prefix = "src/main/resources"
|
||||
)
|
||||
|
||||
jvm_library(
|
||||
name = "images",
|
||||
module_name = "intellij.platform.jewel.markdown.extensions.images",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["src/main/kotlin/**/*.kt", "src/main/kotlin/**/*.java"], allow_empty = True),
|
||||
kotlinc_opts = ":custom",
|
||||
deps = [
|
||||
"@lib//:kotlin-stdlib",
|
||||
"@lib//:kotlinx-coroutines-core",
|
||||
"@lib//:jetbrains-annotations",
|
||||
"//platform/jewel/markdown/core",
|
||||
"//platform/jewel/ui",
|
||||
"//platform/jewel/foundation",
|
||||
"//libraries/compose-foundation-desktop",
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-core-jvm",
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-compose-core-jvm",
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-compose-jvm",
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-network-core-jvm",
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-network-ktor3-jvm",
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-svg-jvm",
|
||||
],
|
||||
exports = [
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-compose-core-jvm",
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-compose-jvm",
|
||||
"@lib//:platform-jewel-markdown-extensions-images-io-coil-kt-coil3-svg-jvm",
|
||||
],
|
||||
runtime_deps = [":images_resources"],
|
||||
plugins = ["@lib//:compose-plugin"]
|
||||
)
|
||||
### auto-generated section `build intellij.platform.jewel.markdown.extensions.images` end
|
||||
14
platform/jewel/markdown/extensions/images/README.md
Normal file
14
platform/jewel/markdown/extensions/images/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Images module
|
||||
|
||||
This module adds support for inline images, typically rendered from `` syntax.
|
||||
It's based on core CommonMark but allows users to not depend on Coil if they don't need images support
|
||||
and avoiding runtime image loading dependencies.
|
||||
|
||||
* No Coil or UI image loading logic is included in the image parser module.
|
||||
* Keeps the structure modular, consistent with how other extensions are handled.
|
||||
|
||||
## Usage
|
||||
|
||||
To use the image module, add the `Coil3ImagesRendererExtension` to your `rendererExtensions`.
|
||||
If you don't want to use library-specific image loader, you can pass it as a parameter,
|
||||
but you have to handle its initialization as well as making sure it's the same instance.
|
||||
13
platform/jewel/markdown/extensions/images/api-dump.txt
Normal file
13
platform/jewel/markdown/extensions/images/api-dump.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
f:org.jetbrains.jewel.markdown.extensions.images.Coil3ImagesRendererExtension
|
||||
- org.jetbrains.jewel.markdown.extensions.MarkdownRendererExtension
|
||||
- sf:$stable:I
|
||||
- sf:Companion:org.jetbrains.jewel.markdown.extensions.images.Coil3ImagesRendererExtension$Companion
|
||||
- <init>(coil3.ImageLoader):V
|
||||
- getImageRendererExtension():org.jetbrains.jewel.markdown.extensions.ImageRendererExtension
|
||||
f:org.jetbrains.jewel.markdown.extensions.images.Coil3ImagesRendererExtension$Companion
|
||||
- f:withDefaultLoader(androidx.compose.runtime.Composer,I):org.jetbrains.jewel.markdown.extensions.images.Coil3ImagesRendererExtension
|
||||
f:org.jetbrains.jewel.markdown.extensions.images.Coil3ImagesRendererExtensionImpl
|
||||
- org.jetbrains.jewel.markdown.extensions.ImageRendererExtension
|
||||
- sf:$stable:I
|
||||
- <init>(coil3.ImageLoader):V
|
||||
- renderImagesContent(org.jetbrains.jewel.markdown.InlineMarkdown$Image,androidx.compose.runtime.Composer,I):androidx.compose.foundation.text.InlineTextContent
|
||||
19
platform/jewel/markdown/extensions/images/api/images.api
Normal file
19
platform/jewel/markdown/extensions/images/api/images.api
Normal file
@@ -0,0 +1,19 @@
|
||||
public final class org/jetbrains/jewel/markdown/extensions/images/Coil3ImagesRendererExtension : org/jetbrains/jewel/markdown/extensions/MarkdownRendererExtension {
|
||||
public static final field $stable I
|
||||
public static final field Companion Lorg/jetbrains/jewel/markdown/extensions/images/Coil3ImagesRendererExtension$Companion;
|
||||
public fun <init> (Lcoil3/ImageLoader;)V
|
||||
public fun getBlockRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownBlockRendererExtension;
|
||||
public fun getDelimitedInlineRenderer ()Lorg/jetbrains/jewel/markdown/extensions/MarkdownDelimitedInlineRendererExtension;
|
||||
public fun getImageRendererExtension ()Lorg/jetbrains/jewel/markdown/extensions/ImageRendererExtension;
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/markdown/extensions/images/Coil3ImagesRendererExtension$Companion {
|
||||
public final fun withDefaultLoader (Landroidx/compose/runtime/Composer;I)Lorg/jetbrains/jewel/markdown/extensions/images/Coil3ImagesRendererExtension;
|
||||
}
|
||||
|
||||
public final class org/jetbrains/jewel/markdown/extensions/images/Coil3ImagesRendererExtensionImpl : org/jetbrains/jewel/markdown/extensions/ImageRendererExtension {
|
||||
public static final field $stable I
|
||||
public fun <init> (Lcoil3/ImageLoader;)V
|
||||
public fun renderImagesContent (Lorg/jetbrains/jewel/markdown/InlineMarkdown$Image;Landroidx/compose/runtime/Composer;I)Landroidx/compose/foundation/text/InlineTextContent;
|
||||
}
|
||||
|
||||
23
platform/jewel/markdown/extensions/images/build.gradle.kts
Normal file
23
platform/jewel/markdown/extensions/images/build.gradle.kts
Normal file
@@ -0,0 +1,23 @@
|
||||
plugins {
|
||||
jewel
|
||||
`jewel-publish`
|
||||
`jewel-check-public-api`
|
||||
alias(libs.plugins.composeDesktop)
|
||||
alias(libs.plugins.compose.compiler)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.markdown.core)
|
||||
runtimeOnly(libs.ktor.client.java)
|
||||
implementation(libs.coil.compose.core)
|
||||
implementation(libs.coil.network.ktor3)
|
||||
implementation(libs.coil.svg)
|
||||
testImplementation(compose.desktop.uiTestJUnit4)
|
||||
}
|
||||
|
||||
publishing.publications.named<MavenPublication>("main") {
|
||||
val ijpTarget = project.property("ijp.target") as String
|
||||
artifactId = "jewel-markdown-extension-${project.name}-$ijpTarget"
|
||||
}
|
||||
|
||||
publicApiValidation { excludedClassRegexes = setOf("org.jetbrains.jewel.markdown.extensions.images.*") }
|
||||
@@ -0,0 +1,2 @@
|
||||
androidx/compose/**
|
||||
coil3/ImageLoader
|
||||
@@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="kotlin-language" name="Kotlin">
|
||||
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
|
||||
<compilerSettings>
|
||||
<option name="additionalArguments" value="-Xjvm-default=all -opt-in=androidx.compose.ui.ExperimentalComposeUiApi -Xcontext-receivers -opt-in=androidx.compose.foundation.ExperimentalFoundationApi -opt-in=org.jetbrains.jewel.foundation.ExperimentalJewelApi -opt-in=org.jetbrains.jewel.foundation.InternalJewelApi -Xexplicit-api=strict" />
|
||||
</compilerSettings>
|
||||
<compilerArguments>
|
||||
<stringArguments>
|
||||
<stringArg name="jvmTarget" arg="17" />
|
||||
<stringArg name="apiVersion" arg="2.2" />
|
||||
<stringArg name="languageVersion" arg="2.2" />
|
||||
</stringArguments>
|
||||
<arrayArguments>
|
||||
<arrayArg name="pluginClasspaths">
|
||||
<args>$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-compose-compiler-plugin/2.2.0/kotlin-compose-compiler-plugin-2.2.0.jar</args>
|
||||
</arrayArg>
|
||||
</arrayArguments>
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="library" name="kotlin-stdlib" level="project" />
|
||||
<orderEntry type="library" name="kotlinx-coroutines-core" level="project" />
|
||||
<orderEntry type="library" name="jetbrains-annotations" level="project" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.foundation" />
|
||||
<orderEntry type="module" module-name="intellij.libraries.compose.foundation.desktop" />
|
||||
<orderEntry type="module-library">
|
||||
<library name="io.coil.kt.coil3.core.jvm" type="repository">
|
||||
<properties include-transitive-deps="false" maven-id="io.coil-kt.coil3:coil-core-jvm:3.1.0">
|
||||
<verification>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-core-jvm/3.1.0/coil-core-jvm-3.1.0.jar">
|
||||
<sha256sum>6d44a11188c53f4eea2e87ebadc6aad90069132c9b029fc1b35aeb0added5ef7</sha256sum>
|
||||
</artifact>
|
||||
</verification>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-core-jvm/3.1.0/coil-core-jvm-3.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-core-jvm/3.1.0/coil-core-jvm-3.1.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" exported="">
|
||||
<library name="io.coil.kt.coil3.compose.core.jvm" type="repository">
|
||||
<properties include-transitive-deps="false" maven-id="io.coil-kt.coil3:coil-compose-core-jvm:3.1.0">
|
||||
<verification>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-compose-core-jvm/3.1.0/coil-compose-core-jvm-3.1.0.jar">
|
||||
<sha256sum>8aa1d7ae1d11f969e8cdcc8fee42b7ee6a036e21f70567e3c3486edd9d7dc594</sha256sum>
|
||||
</artifact>
|
||||
</verification>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-compose-core-jvm/3.1.0/coil-compose-core-jvm-3.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-compose-core-jvm/3.1.0/coil-compose-core-jvm-3.1.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" exported="">
|
||||
<library name="io.coil.kt.coil3.compose.jvm" type="repository">
|
||||
<properties include-transitive-deps="false" maven-id="io.coil-kt.coil3:coil-compose-jvm:3.1.0">
|
||||
<verification>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-compose-jvm/3.1.0/coil-compose-jvm-3.1.0.jar">
|
||||
<sha256sum>d43e0ed4566d30f8ce8e023539240b494be6fa69a1b8c81b4c32f5f465a7cc06</sha256sum>
|
||||
</artifact>
|
||||
</verification>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-compose-jvm/3.1.0/coil-compose-jvm-3.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-compose-jvm/3.1.0/coil-compose-jvm-3.1.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="io.coil.kt.coil3.network.core.jvm" type="repository">
|
||||
<properties include-transitive-deps="false" maven-id="io.coil-kt.coil3:coil-network-core-jvm:3.1.0">
|
||||
<verification>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-network-core-jvm/3.1.0/coil-network-core-jvm-3.1.0.jar">
|
||||
<sha256sum>8332e45cf792cd24d9814744db84b0e6d33ec6eaf0724bd07ddc1fce7c55591f</sha256sum>
|
||||
</artifact>
|
||||
</verification>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-network-core-jvm/3.1.0/coil-network-core-jvm-3.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-network-core-jvm/3.1.0/coil-network-core-jvm-3.1.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="io.coil.kt.coil3.network.ktor3.jvm" type="repository">
|
||||
<properties include-transitive-deps="false" maven-id="io.coil-kt.coil3:coil-network-ktor3-jvm:3.1.0">
|
||||
<verification>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-network-ktor3-jvm/3.1.0/coil-network-ktor3-jvm-3.1.0.jar">
|
||||
<sha256sum>cc4f9f8d6d447e7559cb9717c3a45dfbd351ddd06a34724001322512160b0215</sha256sum>
|
||||
</artifact>
|
||||
</verification>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-network-ktor3-jvm/3.1.0/coil-network-ktor3-jvm-3.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-network-ktor3-jvm/3.1.0/coil-network-ktor3-jvm-3.1.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library" exported="">
|
||||
<library name="io.coil.kt.coil3.svg.jvm" type="repository">
|
||||
<properties include-transitive-deps="false" maven-id="io.coil-kt.coil3:coil-svg-jvm:3.1.0">
|
||||
<verification>
|
||||
<artifact url="file://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-svg-jvm/3.1.0/coil-svg-jvm-3.1.0.jar">
|
||||
<sha256sum>413a53b4b6e0a40b851d1a99a01a4cd91ac0dc68facefddd7adfdb2d5456588f</sha256sum>
|
||||
</artifact>
|
||||
</verification>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-svg-jvm/3.1.0/coil-svg-jvm-3.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/coil-kt/coil3/coil-svg-jvm/3.1.0/coil-svg-jvm-3.1.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module" module-name="intellij.libraries.compose.foundation.desktop.junit" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.jetbrains.jewel.markdown.extensions.images
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import coil3.ImageLoader
|
||||
import coil3.compose.LocalPlatformContext
|
||||
import coil3.memory.MemoryCache
|
||||
import org.jetbrains.jewel.markdown.extensions.ImageRendererExtension
|
||||
import org.jetbrains.jewel.markdown.extensions.MarkdownRendererExtension
|
||||
|
||||
private const val DEFAULT_MEMORY_CACHE_SIZE: Long = 20 * 1024 * 1024 // 20 MB
|
||||
|
||||
/**
|
||||
* A [MarkdownRendererExtension] for rendering images using the Coil3 library.
|
||||
*
|
||||
* This extension enables the display of images specified in Markdown, for example: ``.
|
||||
*
|
||||
* It requires an [ImageLoader] to handle fetching and displaying images. For optimal performance and resource
|
||||
* management (e.g., shared memory and disk caches), it is recommended to provide a single, app-wide [ImageLoader]
|
||||
* instance via the constructor.
|
||||
*/
|
||||
public class Coil3ImagesRendererExtension(private val imageLoader: ImageLoader) : MarkdownRendererExtension {
|
||||
override val imageRendererExtension: ImageRendererExtension
|
||||
get() = Coil3ImagesRendererExtensionImpl(imageLoader)
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* A default images loader with limited in-memory cache is to decouple clients from depending directly on coil
|
||||
* internals. This shouldn't be used if there is an app-wide image loader already availble; Which could be set
|
||||
* via a constructor.
|
||||
*/
|
||||
@Composable
|
||||
public fun withDefaultLoader(): Coil3ImagesRendererExtension =
|
||||
Coil3ImagesRendererExtension(
|
||||
ImageLoader.Builder(LocalPlatformContext.current)
|
||||
.memoryCache { MemoryCache.Builder().maxSizeBytes { DEFAULT_MEMORY_CACHE_SIZE }.build() }
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.jetbrains.jewel.markdown.extensions.images
|
||||
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.text.InlineTextContent
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.Placeholder
|
||||
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil3.ImageLoader
|
||||
import coil3.compose.AsyncImage
|
||||
import coil3.compose.LocalPlatformContext
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.size.Size
|
||||
import org.jetbrains.jewel.foundation.util.JewelLogger
|
||||
import org.jetbrains.jewel.markdown.InlineMarkdown
|
||||
import org.jetbrains.jewel.markdown.extensions.ImageRendererExtension
|
||||
|
||||
/**
|
||||
* Renders Markdown images using Coil3.
|
||||
*
|
||||
* This implementation uses [AsyncImage] to load and display images. It reserves space for the image with a
|
||||
* [Placeholder] and updates its size upon successful loading to prevent layout shifts.
|
||||
*
|
||||
* @param imageLoader A custom [ImageLoader] for Coil3 image requests.
|
||||
*/
|
||||
public class Coil3ImagesRendererExtensionImpl(private val imageLoader: ImageLoader) : ImageRendererExtension {
|
||||
@Composable
|
||||
public override fun renderImagesContent(image: InlineMarkdown.Image): InlineTextContent {
|
||||
val knownSize = remember(image.source) { mutableStateOf<ImageSize?>(null) }
|
||||
return InlineTextContent(
|
||||
with(LocalDensity.current) {
|
||||
// `toSp` ensures that the placeholder size matches the original image size in
|
||||
// pixels.
|
||||
// This approach doesn't allow images from appearing larger with different screen
|
||||
// scaling,
|
||||
// but simply maintains behavior consistent with standalone AsyncImage rendering.
|
||||
Placeholder(
|
||||
width = knownSize.value?.width?.dp?.toSp() ?: 0.sp,
|
||||
height = knownSize.value?.height?.dp?.toSp() ?: 1.sp,
|
||||
placeholderVerticalAlign = PlaceholderVerticalAlign.Bottom,
|
||||
)
|
||||
}
|
||||
) {
|
||||
AsyncImage(
|
||||
model =
|
||||
ImageRequest.Builder(LocalPlatformContext.current)
|
||||
.data(image.source)
|
||||
// make sure image doesn't get downscaled to the placeholder size
|
||||
.size(Size.ORIGINAL)
|
||||
.build(),
|
||||
imageLoader = imageLoader,
|
||||
contentDescription = image.title,
|
||||
onSuccess = { state ->
|
||||
// onSuccess should only be called once, but adding additional protection from
|
||||
// unnecessary rerender
|
||||
if (knownSize.value == null) {
|
||||
knownSize.value = state.result.image.let { ImageSize(it.width, it.height) }
|
||||
}
|
||||
},
|
||||
onError = { error ->
|
||||
JewelLogger.getInstance("Jewel").warn("AsyncImage loading: ${error.result.throwable}")
|
||||
},
|
||||
modifier = knownSize.value?.let { Modifier.height(it.height.dp).width(it.width.dp) } ?: Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private data class ImageSize(val width: Int, val height: Int)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<idea-plugin>
|
||||
<dependencies>
|
||||
<module name="intellij.platform.jewel.markdown.core" />
|
||||
<module name="intellij.platform.jewel.ui" />
|
||||
<module name="intellij.platform.jewel.foundation" />
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
@@ -8,5 +8,6 @@
|
||||
<module name="intellij.platform.jewel.markdown.extensions.gfmAlerts" />
|
||||
<module name="intellij.platform.jewel.markdown.extensions.gfmTables" />
|
||||
<module name="intellij.platform.jewel.markdown.extensions.gfmStrikethrough" />
|
||||
<module name="intellij.platform.jewel.markdown.extensions.images" />
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -42,6 +42,7 @@ jvm_library(
|
||||
"//platform/jewel/markdown/extensions/gfm-alerts",
|
||||
"//platform/jewel/markdown/extensions/gfm-tables",
|
||||
"//platform/jewel/markdown/extensions/gfm-strikethrough",
|
||||
"//platform/jewel/markdown/extensions/images",
|
||||
"//platform/jewel/int-ui/int-ui-standalone:jewel-intUi-standalone",
|
||||
"//libraries/compose-foundation-desktop",
|
||||
"//platform/jewel/samples/showcase",
|
||||
|
||||
@@ -12,10 +12,11 @@ dependencies {
|
||||
implementation(projects.intUi.intUiDecoratedWindow)
|
||||
implementation(projects.intUi.intUiStandalone)
|
||||
implementation(projects.markdown.core)
|
||||
implementation(projects.markdown.extensions.autolink)
|
||||
implementation(projects.markdown.extensions.gfmAlerts)
|
||||
implementation(projects.markdown.extensions.gfmStrikethrough)
|
||||
implementation(projects.markdown.extensions.gfmTables)
|
||||
implementation(projects.markdown.extensions.autolink)
|
||||
implementation(projects.markdown.extensions.images)
|
||||
implementation(projects.markdown.intUiStandaloneStyling)
|
||||
implementation(projects.samples.showcase)
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.extensions.gfmAlerts" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.extensions.gfmTables" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.extensions.gfmStrikethrough" />
|
||||
<orderEntry type="module" module-name="intellij.platform.jewel.markdown.extensions.images" />
|
||||
<orderEntry type="module-library" scope="RUNTIME">
|
||||
<library name="org.lwjgl.lwjgl.tinyfd" type="repository">
|
||||
<properties include-transitive-deps="false" maven-id="org.lwjgl:lwjgl-tinyfd:3.3.1">
|
||||
|
||||
@@ -21,6 +21,8 @@ desktop-optimized theme and set of components.
|
||||
>
|
||||
> Use at your own risk!
|
||||
|
||||

|
||||
|
||||
Jewel provides an implementation of the IntelliJ Platform themes that can be used in any Compose for Desktop
|
||||
application. Additionally, it has a Swing LaF Bridge that only works in the IntelliJ Platform (i.e., used to create IDE
|
||||
plugins), but automatically mirrors the current Swing LaF into Compose for a native-looking, consistent UI.
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.jewel.markdown.extensions.github.strikethrough.GitHubStrike
|
||||
import org.jetbrains.jewel.markdown.extensions.github.tables.GfmTableStyling
|
||||
import org.jetbrains.jewel.markdown.extensions.github.tables.GitHubTableProcessorExtension
|
||||
import org.jetbrains.jewel.markdown.extensions.github.tables.GitHubTableRendererExtension
|
||||
import org.jetbrains.jewel.markdown.extensions.images.Coil3ImagesRendererExtension
|
||||
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor
|
||||
import org.jetbrains.jewel.markdown.rendering.MarkdownBlockRenderer
|
||||
import org.jetbrains.jewel.markdown.rendering.MarkdownStyling
|
||||
@@ -65,6 +66,7 @@ public fun MarkdownPreview(modifier: Modifier = Modifier, rawMarkdown: CharSeque
|
||||
)
|
||||
)
|
||||
}
|
||||
val coil3ImagesRendererExtension = Coil3ImagesRendererExtension.withDefaultLoader()
|
||||
|
||||
LaunchedEffect(rawMarkdown) {
|
||||
// TODO you may want to debounce or drop on backpressure, in real usages. You should also
|
||||
@@ -81,6 +83,7 @@ public fun MarkdownPreview(modifier: Modifier = Modifier, rawMarkdown: CharSeque
|
||||
styling = markdownStyling,
|
||||
rendererExtensions =
|
||||
listOf(
|
||||
coil3ImagesRendererExtension,
|
||||
GitHubAlertRendererExtension(AlertStyling.dark(), markdownStyling),
|
||||
GitHubStrikethroughRendererExtension,
|
||||
GitHubTableRendererExtension(GfmTableStyling.dark(), markdownStyling),
|
||||
@@ -91,6 +94,7 @@ public fun MarkdownPreview(modifier: Modifier = Modifier, rawMarkdown: CharSeque
|
||||
styling = markdownStyling,
|
||||
rendererExtensions =
|
||||
listOf(
|
||||
coil3ImagesRendererExtension,
|
||||
GitHubAlertRendererExtension(AlertStyling.light(), markdownStyling),
|
||||
GitHubStrikethroughRendererExtension,
|
||||
GitHubTableRendererExtension(GfmTableStyling.light(), markdownStyling),
|
||||
|
||||
@@ -11,5 +11,6 @@
|
||||
<module name="intellij.platform.jewel.markdown.extensions.gfmStrikethrough" />
|
||||
<module name="intellij.platform.jewel.markdown.extensions.gfmTables" />
|
||||
<module name="intellij.platform.jewel.markdown.extensions.autolink" />
|
||||
<module name="intellij.platform.jewel.markdown.extensions.images" />
|
||||
</dependencies>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -43,6 +43,7 @@ include(
|
||||
":markdown:extensions:gfm-alerts",
|
||||
":markdown:extensions:gfm-strikethrough",
|
||||
":markdown:extensions:gfm-tables",
|
||||
":markdown:extensions:images",
|
||||
":markdown:int-ui-standalone-styling",
|
||||
":markdown:ide-laf-bridge-styling",
|
||||
":samples:ide-plugin",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<module name="intellij.platform.jewel.markdown.extensions.gfmAlerts"/>
|
||||
<module name="intellij.platform.jewel.markdown.extensions.gfmTables"/>
|
||||
<module name="intellij.platform.jewel.markdown.extensions.gfmStrikethrough"/>
|
||||
<module name="intellij.platform.jewel.markdown.extensions.images"/>
|
||||
<module name="intellij.platform.jewel.markdown.core"/>
|
||||
<module name="intellij.platform.diagnostic.freezeAnalyzer"/>
|
||||
<module name="intellij.platform.diagnostic.freezes"/>
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.jetbrains.jewel.markdown.extensions.github.strikethrough.GitHubStrike
|
||||
import org.jetbrains.jewel.markdown.extensions.github.tables.GfmTableStyling
|
||||
import org.jetbrains.jewel.markdown.extensions.github.tables.GitHubTableProcessorExtension
|
||||
import org.jetbrains.jewel.markdown.extensions.github.tables.GitHubTableRendererExtension
|
||||
import org.jetbrains.jewel.markdown.extensions.images.Coil3ImagesRendererExtension
|
||||
import org.jetbrains.jewel.markdown.processing.MarkdownProcessor
|
||||
import org.jetbrains.jewel.markdown.rendering.DefaultInlineMarkdownRenderer
|
||||
import org.jetbrains.jewel.markdown.scrolling.ScrollSyncMarkdownBlockRenderer
|
||||
@@ -57,7 +58,7 @@ import kotlin.time.Duration.Companion.milliseconds
|
||||
internal class MarkdownComposePanel(
|
||||
private val project: Project?,
|
||||
private val virtualFile: VirtualFile?,
|
||||
private val updateHandler: MarkdownUpdateHandler = MarkdownUpdateHandler.Debounced()
|
||||
private val updateHandler: MarkdownUpdateHandler = MarkdownUpdateHandler.Debounced(),
|
||||
) : MarkdownHtmlPanelEx, UserDataHolder by UserDataHolderBase() {
|
||||
|
||||
constructor() : this(null, null)
|
||||
@@ -95,7 +96,7 @@ internal class MarkdownComposePanel(
|
||||
val tableRenderer = remember(markdownStyling) {
|
||||
GitHubTableRendererExtension(GfmTableStyling.create(), markdownStyling)
|
||||
}
|
||||
val allRenderingExtensions = listOf(tableRenderer, GitHubStrikethroughRendererExtension)
|
||||
val allRenderingExtensions = listOf(tableRenderer, GitHubStrikethroughRendererExtension, Coil3ImagesRendererExtension.withDefaultLoader())
|
||||
val blockRenderer = remember(markdownStyling) {
|
||||
ScrollSyncMarkdownBlockRenderer(
|
||||
markdownStyling,
|
||||
@@ -132,10 +133,11 @@ internal class MarkdownComposePanel(
|
||||
@OptIn(FlowPreview::class)
|
||||
@Suppress("FunctionName")
|
||||
@Composable
|
||||
private fun MarkdownPreviewPanel(scrollState: ScrollState,
|
||||
scrollingSynchronizer: ScrollingSynchronizer?,
|
||||
blockRenderer: ScrollSyncMarkdownBlockRenderer,
|
||||
animationSpec: AnimationSpec<Float> = TweenSpec(easing = LinearEasing)
|
||||
private fun MarkdownPreviewPanel(
|
||||
scrollState: ScrollState,
|
||||
scrollingSynchronizer: ScrollingSynchronizer?,
|
||||
blockRenderer: ScrollSyncMarkdownBlockRenderer,
|
||||
animationSpec: AnimationSpec<Float> = TweenSpec(easing = LinearEasing),
|
||||
) {
|
||||
val request by updateHandler.requests.collectAsState(null)
|
||||
(request as? PreviewRequest.Update)?.let {
|
||||
@@ -170,7 +172,7 @@ internal class MarkdownComposePanel(
|
||||
MarkdownLinkOpener.getInstance().openLink(project, url)
|
||||
else
|
||||
MarkdownLinkOpener.getInstance().openLink(project, url, virtualFile)
|
||||
},
|
||||
},
|
||||
blockRenderer = blockRenderer,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user