Skip to content

Commit 134cc80

Browse files
authored
Merge pull request #206 from mikepenz/feature/124
Introduce syntax highlighting support
2 parents 290bda0 + 6caf007 commit 134cc80

File tree

11 files changed

+363
-25
lines changed

11 files changed

+363
-25
lines changed

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ Markdown(
251251
```
252252

253253
> [!NOTE]
254-
> 0.21.0 adds JVM support for this dependency via `HTTPUrlConnection` -> however this is expected to be removed in the future.
254+
> 0.21.0 adds JVM support for this dependency via `HTTPUrlConnection` -> however this is expected to be removed in the
255+
> future.
255256
256257
> [!NOTE]
257258
> Please refer to the official coil2 documentation on how to adjust the `ImageLoader`
@@ -276,6 +277,43 @@ Markdown(
276277
> [!NOTE]
277278
> The `coil3` module does depend on SNAPSHOT builds of coil3
278279
280+
### Syntax Highlighting
281+
282+
The library (introduced with 0.27.0) offers optional support for syntax highlighting via
283+
the [Highlights](https://github.com/SnipMeDev/Highlights) project.
284+
This support is not included in the core, and can be enabled by adding the `multiplatform-markdown-renderer-code`
285+
dependency.
286+
287+
```groovy
288+
implementation("com.mikepenz:multiplatform-markdown-renderer-code:${version}")
289+
```
290+
291+
Once added, the `Markdown` has to be configured to use the alternative code highlighter.
292+
293+
```kotlin
294+
// Use default color scheme
295+
Markdown(
296+
MARKDOWN,
297+
components = markdownComponents(
298+
codeBlock = highlightedCodeBlock,
299+
codeFence = highlightedCodeFence,
300+
)
301+
)
302+
303+
// ADVANCED: Customize Highlights library by defining different theme
304+
val isDarkTheme = isSystemInDarkTheme()
305+
val highlightsBuilder = remember(isDarkTheme) {
306+
Highlights.Builder().theme(SyntaxThemes.atom(darkMode = isDarkTheme))
307+
}
308+
Markdown(
309+
MARKDOWN,
310+
components = markdownComponents(
311+
codeBlock = { MarkdownHighlightedCodeBlock(it.content, it.node, highlightsBuilder) },
312+
codeFence = { MarkdownHighlightedCodeFence(it.content, it.node, highlightsBuilder) },
313+
)
314+
)
315+
```
316+
279317
## Dependency
280318

281319
This project uses JetBrains [markdown](https://github.com/JetBrains/markdown/) Multiplatform

app-desktop/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies {
1919
implementation(projects.multiplatformMarkdownRenderer)
2020
implementation(projects.multiplatformMarkdownRendererM2)
2121
implementation(projects.multiplatformMarkdownRendererCoil3)
22+
implementation(projects.multiplatformMarkdownRendererCode)
2223

2324
implementation(compose.desktop.currentOs)
2425
implementation(compose.foundation)

app-desktop/src/main/kotlin/main.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import androidx.compose.foundation.isSystemInDarkTheme
12
import androidx.compose.foundation.layout.fillMaxSize
23
import androidx.compose.foundation.layout.padding
34
import androidx.compose.foundation.rememberScrollState
@@ -11,12 +12,17 @@ import androidx.compose.ui.unit.dp
1112
import androidx.compose.ui.window.Window
1213
import androidx.compose.ui.window.application
1314
import com.mikepenz.markdown.coil3.Coil3ImageTransformerImpl
15+
import com.mikepenz.markdown.compose.components.markdownComponents
16+
import com.mikepenz.markdown.compose.elements.MarkdownHighlightedCodeBlock
17+
import com.mikepenz.markdown.compose.elements.MarkdownHighlightedCodeFence
1418
import com.mikepenz.markdown.compose.extendedspans.ExtendedSpans
1519
import com.mikepenz.markdown.compose.extendedspans.RoundedCornerSpanPainter
1620
import com.mikepenz.markdown.compose.extendedspans.SquigglyUnderlineSpanPainter
1721
import com.mikepenz.markdown.compose.extendedspans.rememberSquigglyUnderlineAnimator
1822
import com.mikepenz.markdown.m2.Markdown
1923
import com.mikepenz.markdown.model.markdownExtendedSpans
24+
import dev.snipme.highlights.Highlights
25+
import dev.snipme.highlights.model.SyntaxThemes
2026

2127
fun main() = application {
2228
Window(onCloseRequest = ::exitApplication, title = "Markdown Sample") {
@@ -29,9 +35,17 @@ fun main() = application {
2935
}
3036
) {
3137
val scrollState = rememberScrollState()
38+
val isDarkTheme = isSystemInDarkTheme()
39+
val highlightsBuilder = remember(isDarkTheme) {
40+
Highlights.Builder().theme(SyntaxThemes.atom(darkMode = isDarkTheme))
41+
}
3242

3343
Markdown(
3444
MARKDOWN,
45+
components = markdownComponents(
46+
codeBlock = { MarkdownHighlightedCodeBlock(it.content, it.node, highlightsBuilder) },
47+
codeFence = { MarkdownHighlightedCodeFence(it.content, it.node, highlightsBuilder) },
48+
),
3549
imageTransformer = Coil3ImageTransformerImpl,
3650
extendedSpans = markdownExtendedSpans {
3751
val animator = rememberSquigglyUnderlineAnimator()
@@ -76,7 +90,7 @@ This is a paragraph with a [link](https://www.jetbrains.com/).
7690
This is a code block:
7791
```kotlin
7892
fun main() {
79-
println("Hello, world!")
93+
println("Hello, world!")
8094
}
8195
```
8296

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ detekt = "1.23.6"
1818
gradleMvnPublish = "0.29.0"
1919
screenshot = "0.0.1-alpha05"
2020
ktor = "3.0.0-beta-2"
21+
highlights = "0.9.1"
2122

2223
[libraries]
2324
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
@@ -39,6 +40,7 @@ markdown = { module = "org.jetbrains:markdown", version.ref = "markdown" }
3940
kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" }
4041
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
4142
ktor-client-java = { module = "io.ktor:ktor-client-java", version.ref = "ktor" }
43+
highlights = { module = "dev.snipme:highlights", version.ref = "highlights" }
4244

4345
[plugins]
4446
androidApplication = { id = "com.android.application", version.ref = "agp" }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import com.vanniktech.maven.publish.SonatypeHost
2+
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
3+
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
4+
5+
plugins {
6+
kotlin("multiplatform")
7+
alias(libs.plugins.androidLibrary)
8+
alias(libs.plugins.jetbrainsCompose)
9+
alias(libs.plugins.composeCompiler)
10+
alias(libs.plugins.dokka)
11+
alias(libs.plugins.mavenPublish)
12+
}
13+
14+
android {
15+
namespace = "com.mikepenz.markdown.code"
16+
compileSdk = libs.versions.compileSdk.get().toInt()
17+
18+
defaultConfig {
19+
minSdk = libs.versions.minSdk.get().toInt()
20+
targetSdk = libs.versions.targetSdk.get().toInt()
21+
}
22+
23+
buildTypes {
24+
getByName("release") {
25+
isMinifyEnabled = false
26+
proguardFiles(
27+
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
28+
)
29+
}
30+
}
31+
32+
compileOptions {
33+
sourceCompatibility = JavaVersion.VERSION_11
34+
targetCompatibility = JavaVersion.VERSION_11
35+
}
36+
37+
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
38+
kotlinOptions.jvmTarget = "11"
39+
40+
kotlinOptions {
41+
if (project.findProperty("composeCompilerReports") == "true") {
42+
freeCompilerArgs += listOf(
43+
"-P",
44+
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_compiler"
45+
)
46+
}
47+
if (project.findProperty("composeCompilerMetrics") == "true") {
48+
freeCompilerArgs += listOf(
49+
"-P",
50+
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_compiler"
51+
)
52+
}
53+
}
54+
}
55+
}
56+
57+
kotlin {
58+
applyDefaultHierarchyTemplate()
59+
60+
targets.all {
61+
compilations.all {
62+
compilerOptions.configure {
63+
languageVersion.set(KotlinVersion.KOTLIN_1_9)
64+
apiVersion.set(KotlinVersion.KOTLIN_1_9)
65+
}
66+
}
67+
}
68+
androidTarget {
69+
publishLibraryVariants("release")
70+
}
71+
jvm {
72+
compilations {
73+
all {
74+
kotlinOptions.jvmTarget = "11"
75+
}
76+
}
77+
78+
testRuns["test"].executionTask.configure {
79+
useJUnit {
80+
excludeCategories("org.intellij.markdown.ParserPerformanceTest")
81+
}
82+
}
83+
}
84+
@OptIn(ExperimentalWasmDsl::class)
85+
wasmJs {
86+
browser()
87+
}
88+
js(IR) {
89+
nodejs()
90+
}
91+
macosX64()
92+
macosArm64()
93+
iosX64()
94+
iosArm64()
95+
iosSimulatorArm64()
96+
97+
sourceSets {
98+
val commonMain by getting
99+
val commonTest by getting {
100+
dependencies {
101+
implementation(kotlin("test"))
102+
}
103+
}
104+
val fileBasedTest by creating {
105+
dependsOn(commonTest)
106+
}
107+
val jvmTest by getting {
108+
dependsOn(fileBasedTest)
109+
}
110+
val jsTest by getting {
111+
dependsOn(fileBasedTest)
112+
}
113+
val nativeMain by getting {
114+
dependsOn(commonMain)
115+
}
116+
val nativeTest by getting {
117+
dependsOn(fileBasedTest)
118+
}
119+
val nativeSourceSets = listOf(
120+
"macosX64",
121+
"macosArm64",
122+
"ios",
123+
"iosSimulatorArm64"
124+
).map { "${it}Main" }
125+
for (set in nativeSourceSets) {
126+
getByName(set).dependsOn(nativeMain)
127+
}
128+
val nativeTestSourceSets = listOf(
129+
"macosX64",
130+
"macosArm64"
131+
).map { "${it}Test" }
132+
for (set in nativeTestSourceSets) {
133+
getByName(set).dependsOn(nativeTest)
134+
getByName(set).dependsOn(fileBasedTest)
135+
}
136+
}
137+
}
138+
139+
dependencies {
140+
commonMainApi(projects.multiplatformMarkdownRenderer)
141+
commonMainCompileOnly(compose.runtime)
142+
commonMainCompileOnly(compose.ui)
143+
commonMainCompileOnly(compose.foundation)
144+
145+
commonMainApi(libs.highlights)
146+
}
147+
148+
tasks.dokkaHtml.configure {
149+
dokkaSourceSets {
150+
configureEach {
151+
noAndroidSdkLink.set(false)
152+
}
153+
}
154+
}
155+
156+
tasks.create<Jar>("javadocJar") {
157+
dependsOn("dokkaJavadoc")
158+
archiveClassifier.set("javadoc")
159+
from("${layout.buildDirectory}/javadoc")
160+
}
161+
162+
mavenPublishing {
163+
publishToMavenCentral(SonatypeHost.S01)
164+
signAllPublications()
165+
}
166+
167+
publishing {
168+
repositories {
169+
maven {
170+
name = "installLocally"
171+
setUrl("${rootProject.layout.buildDirectory}/localMaven")
172+
}
173+
}
174+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
POM_NAME=Multiplatform Markdown Renderer - Code
2+
POM_DESCRIPTION=Kotlin Multiplatform Markdown Renderer. (Android, Desktop, ...) powered by Compose Multiplatform
3+
POM_ARTIFACT_ID=multiplatform-markdown-renderer-code

0 commit comments

Comments
 (0)