
High-performance code highlighting with AST-based incremental parsing, streaming cursor for real-time output, 28+ languages, rich themes, customizable lexers, interactive token clicks, line numbers, copy and collapsible blocks.
A high-performance cross-platform code highlighting library developed based on Kotlin Multiplatform (KMP) and Compose Multiplatform. It supports consistent rendering effects on Android, iOS, macOS (Kotlin/Native), Desktop (JVM), and Web (Wasm/JS) platforms.
The library modules expose an experimental macosArm64 Kotlin/Native target. Native consumers must opt in with org.jetbrains.compose.experimental.macos.enabled=true; the demo application remains JVM-based. The macOS CI job runs native tests and checks the Maven variant metadata. This does not add Windows or Linux Native UI targets; those platforms continue to use JVM artifacts.
<?php tags, keywords, strings, comments, $variable tokens, and ->/:: operatorssetState
case class, trait, and object
local variables, and require/print
library, data.frame, and common data analysis built-ins| Theme | Type | Description |
|---|---|---|
| OneDarkPro | Dark | Based on Atom's popular One Dark Pro theme |
| GithubLight | Light | Based on GitHub's code highlighting colors |
| DraculaPro | Dark | Based on the Dracula Pro color scheme |
| SolarizedLight | Light | Based on Ethan Schoonover's Solarized Light |
Starting with 1.3.0, mainline is built with Kotlin 2.4.21 and Compose Multiplatform 1.12.2. Android consumers need compileSdk 37 or later.
Projects that cannot upgrade their toolchain can continue using 1.2.1, built with Kotlin 2.3.20, Compose Multiplatform 1.10.3, and Android compileSdk 36. Pin both codehighlight-parser and codehighlight-render to 1.2.1; legacy sources are available on the release-1.2.1 branch.
Add to your gradle/libs.versions.toml:
[versions]
codehigh = "<version>"
[libraries]
codehigh-render = { module = "io.github.huarangmeng:codehighlight-render", version.ref = "codehigh" }
codehigh-parser = { module = "io.github.huarangmeng:codehighlight-parser", version.ref = "codehigh" }Replace <version> with a published release, using the same version for both modules.
Then add it in your module's build.gradle.kts:
dependencies {
implementation(libs.codehigh.render)
implementation(libs.codehigh.parser)
}If you do not use Version Catalog, you can add the dependency directly:
dependencies {
implementation("io.github.huarangmeng:codehighlight-render:<version>")
implementation("io.github.huarangmeng:codehighlight-parser:<version>")
}Use codehighlight-parser directly when you only need tokenization, language registration, or incremental parsing without Compose rendering.
The examples below describe the current source API; publish the upgraded renderer before using them with a release dependency.
In a Compose Multiplatform project, you can use the CodeBlock component directly:
import com.hrm.codehigh.renderer.CodeBlock
@Composable
fun MyScreen() {
CodeBlock(
code = """
fun main() {
println("Hello, CodeHigh!")
}
""".trimIndent(),
language = "kotlin",
showLineNumbers = true,
showCopyButton = true
)
}CodeBlock(code = code) and InlineCode(text = text) work without configuration. Both accept the same three optional groups: colors: CodeColors for syntax and surfaces, typography: CodeTypography for text, and layout: CodeLayout for padding, shapes, and line-number geometry. Display switches stay direct parameters, as does the single host event, onTokenClick.
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.hrm.codehigh.renderer.*
val colors = CodeDefaults.oneDarkProColors()
val typography = CodeTypography(
text = TextStyle(fontSize = 20.sp, lineHeight = 32.sp),
inlineCode = TextStyle(fontSize = 14.sp, lineHeight = 20.sp),
title = TextStyle(fontSize = 16.sp),
)
val layout = CodeLayout(
contentPadding = PaddingValues(16.dp),
inlineContentPadding = PaddingValues(horizontal = 8.dp, vertical = 3.dp),
)
CodeBlock(code = code, language = "kotlin", colors = colors, typography = typography, layout = layout)
InlineCode(text = "README.md", colors = colors, typography = typography, layout = layout)Rendering defaults are preserved: One Dark Pro, 13sp/20sp body and inline text, 12dp horizontal / 8dp vertical block padding, and 6dp horizontal / 2dp vertical inline padding with a 4dp corner radius and 1dp border. Every preset retains its inline surfaces, borders, diff colors, and highlighted-line colors. Streaming, copy, folding, line numbers, and token clicks keep their behavior; maxVisibleLines = 0 still supports initially hiding all lines.
Measurement accepts the same typography and layout as painting; colors are unnecessary. measureCodeBlockSize returns pixel height, lineHeight, and toolbarHeight for a full uncollapsed block. Pass the same source, language, title, and copy-button flag; a trailing newline still represents an additional empty code line. measureInlineCodeSize preserves its existing size reservation including padding and border.
val blockSize = measureCodeBlockSize(
code = code,
language = "kotlin",
typography = typography,
layout = layout,
density = LocalDensity.current,
textMeasurer = rememberTextMeasurer(),
)
val inlineSize = measureInlineCodeSize(
text = "README.md",
typography = typography,
layout = layout,
density = LocalDensity.current,
textMeasurer = rememberTextMeasurer(),
)For streaming scenarios (e.g., AI chatbots), enable the isStreaming flag to show a blinking cursor animation at the end:
import com.hrm.codehigh.renderer.CodeBlock
@Composable
fun StreamingCode() {
var code by remember { mutableStateOf("") }
CodeBlock(
code = code,
language = "python",
isStreaming = true // Shows blinking cursor at the end
)
}For long code blocks, use maxVisibleLines to make them collapsible:
CodeBlock(
code = longCode,
language = "java",
maxVisibleLines = 20 // Collapse after 20 lines
)All four original palettes retain every token color:
| Preset / 预设 | Factory / 工厂 |
|---|---|
| GitHub Light |
CodeDefaults.githubLightColors() / lightColors()
|
| One Dark Pro |
CodeDefaults.oneDarkProColors() / darkColors()
|
| Dracula Pro | CodeDefaults.draculaProColors() |
| Solarized Light | CodeDefaults.solarizedLightColors() |
CodeColors() is a fixed GitHub Light palette; components still default to One Dark Pro. Customize a preset with .copy(...). ProvideCodeDefaults supplies app defaults and instance arguments take precedence. CodeDefaults.colors(keyword = ...) overrides only that named color and inherits the rest from the current scope.
import androidx.compose.ui.graphics.Color
import com.hrm.codehigh.renderer.*
@Composable
fun App() {
val colors = CodeDefaults.githubLightColors().copy(
keyword = Color(0xFF569CD6),
string = Color(0xFFCE9178),
)
ProvideCodeDefaults(colors = colors) {
CodeBlock(code = "val answer = 42", language = "kotlin")
InlineCode(text = "answer")
CodeBlock(
code = "println(answer)", language = "kotlin",
colors = CodeDefaults.colors(keyword = Color.Magenta),
onTokenClick = { token -> /* host action */ },
)
}
}You can register custom lexers for additional languages:
import com.hrm.codehigh.lexer.LanguageRegistry
import com.hrm.codehigh.lexer.Lexer
// Register your custom lexer
LanguageRegistry.register("my-language", MyCustomLexer)
LanguageRegistry.registerAlias("ml", "my-language") // Add alias
// Use it in CodeBlock
CodeBlock(
code = myCode,
language = "my-language" // Or "ml" via alias
):codehighlight-parser: Parser SDK module, containing tokens, lexers, language registration, and incremental parsing.:codehighlight-render: Compose render SDK module, containing renderer components, themes, and parser integration.:codehighlight-preview: Preview components and sample datasets.:composeApp: Cross-platform Demo application.:androidApp: Android Demo application.:iosApp: iOS application entry module../gradlew :androidApp:assembleDebug
./gradlew :composeApp:run
./gradlew :composeApp:wasmJsBrowserDevelopmentRun
iosApp/iosApp.xcworkspace in Xcode to run../gradlew testFor a detailed list of supported features, please refer to: HIGHLIGHTER_COVERAGE_ANALYSIS.md
codehigh.This project is licensed under the MIT License - see the LICENSE file for details.
MIT License
Copyright (c) 2026 huarangmeng
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
A high-performance cross-platform code highlighting library developed based on Kotlin Multiplatform (KMP) and Compose Multiplatform. It supports consistent rendering effects on Android, iOS, macOS (Kotlin/Native), Desktop (JVM), and Web (Wasm/JS) platforms.
The library modules expose an experimental macosArm64 Kotlin/Native target. Native consumers must opt in with org.jetbrains.compose.experimental.macos.enabled=true; the demo application remains JVM-based. The macOS CI job runs native tests and checks the Maven variant metadata. This does not add Windows or Linux Native UI targets; those platforms continue to use JVM artifacts.
<?php tags, keywords, strings, comments, $variable tokens, and ->/:: operatorssetState
case class, trait, and object
local variables, and require/print
library, data.frame, and common data analysis built-ins| Theme | Type | Description |
|---|---|---|
| OneDarkPro | Dark | Based on Atom's popular One Dark Pro theme |
| GithubLight | Light | Based on GitHub's code highlighting colors |
| DraculaPro | Dark | Based on the Dracula Pro color scheme |
| SolarizedLight | Light | Based on Ethan Schoonover's Solarized Light |
Starting with 1.3.0, mainline is built with Kotlin 2.4.21 and Compose Multiplatform 1.12.2. Android consumers need compileSdk 37 or later.
Projects that cannot upgrade their toolchain can continue using 1.2.1, built with Kotlin 2.3.20, Compose Multiplatform 1.10.3, and Android compileSdk 36. Pin both codehighlight-parser and codehighlight-render to 1.2.1; legacy sources are available on the release-1.2.1 branch.
Add to your gradle/libs.versions.toml:
[versions]
codehigh = "<version>"
[libraries]
codehigh-render = { module = "io.github.huarangmeng:codehighlight-render", version.ref = "codehigh" }
codehigh-parser = { module = "io.github.huarangmeng:codehighlight-parser", version.ref = "codehigh" }Replace <version> with a published release, using the same version for both modules.
Then add it in your module's build.gradle.kts:
dependencies {
implementation(libs.codehigh.render)
implementation(libs.codehigh.parser)
}If you do not use Version Catalog, you can add the dependency directly:
dependencies {
implementation("io.github.huarangmeng:codehighlight-render:<version>")
implementation("io.github.huarangmeng:codehighlight-parser:<version>")
}Use codehighlight-parser directly when you only need tokenization, language registration, or incremental parsing without Compose rendering.
The examples below describe the current source API; publish the upgraded renderer before using them with a release dependency.
In a Compose Multiplatform project, you can use the CodeBlock component directly:
import com.hrm.codehigh.renderer.CodeBlock
@Composable
fun MyScreen() {
CodeBlock(
code = """
fun main() {
println("Hello, CodeHigh!")
}
""".trimIndent(),
language = "kotlin",
showLineNumbers = true,
showCopyButton = true
)
}CodeBlock(code = code) and InlineCode(text = text) work without configuration. Both accept the same three optional groups: colors: CodeColors for syntax and surfaces, typography: CodeTypography for text, and layout: CodeLayout for padding, shapes, and line-number geometry. Display switches stay direct parameters, as does the single host event, onTokenClick.
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.hrm.codehigh.renderer.*
val colors = CodeDefaults.oneDarkProColors()
val typography = CodeTypography(
text = TextStyle(fontSize = 20.sp, lineHeight = 32.sp),
inlineCode = TextStyle(fontSize = 14.sp, lineHeight = 20.sp),
title = TextStyle(fontSize = 16.sp),
)
val layout = CodeLayout(
contentPadding = PaddingValues(16.dp),
inlineContentPadding = PaddingValues(horizontal = 8.dp, vertical = 3.dp),
)
CodeBlock(code = code, language = "kotlin", colors = colors, typography = typography, layout = layout)
InlineCode(text = "README.md", colors = colors, typography = typography, layout = layout)Rendering defaults are preserved: One Dark Pro, 13sp/20sp body and inline text, 12dp horizontal / 8dp vertical block padding, and 6dp horizontal / 2dp vertical inline padding with a 4dp corner radius and 1dp border. Every preset retains its inline surfaces, borders, diff colors, and highlighted-line colors. Streaming, copy, folding, line numbers, and token clicks keep their behavior; maxVisibleLines = 0 still supports initially hiding all lines.
Measurement accepts the same typography and layout as painting; colors are unnecessary. measureCodeBlockSize returns pixel height, lineHeight, and toolbarHeight for a full uncollapsed block. Pass the same source, language, title, and copy-button flag; a trailing newline still represents an additional empty code line. measureInlineCodeSize preserves its existing size reservation including padding and border.
val blockSize = measureCodeBlockSize(
code = code,
language = "kotlin",
typography = typography,
layout = layout,
density = LocalDensity.current,
textMeasurer = rememberTextMeasurer(),
)
val inlineSize = measureInlineCodeSize(
text = "README.md",
typography = typography,
layout = layout,
density = LocalDensity.current,
textMeasurer = rememberTextMeasurer(),
)For streaming scenarios (e.g., AI chatbots), enable the isStreaming flag to show a blinking cursor animation at the end:
import com.hrm.codehigh.renderer.CodeBlock
@Composable
fun StreamingCode() {
var code by remember { mutableStateOf("") }
CodeBlock(
code = code,
language = "python",
isStreaming = true // Shows blinking cursor at the end
)
}For long code blocks, use maxVisibleLines to make them collapsible:
CodeBlock(
code = longCode,
language = "java",
maxVisibleLines = 20 // Collapse after 20 lines
)All four original palettes retain every token color:
| Preset / 预设 | Factory / 工厂 |
|---|---|
| GitHub Light |
CodeDefaults.githubLightColors() / lightColors()
|
| One Dark Pro |
CodeDefaults.oneDarkProColors() / darkColors()
|
| Dracula Pro | CodeDefaults.draculaProColors() |
| Solarized Light | CodeDefaults.solarizedLightColors() |
CodeColors() is a fixed GitHub Light palette; components still default to One Dark Pro. Customize a preset with .copy(...). ProvideCodeDefaults supplies app defaults and instance arguments take precedence. CodeDefaults.colors(keyword = ...) overrides only that named color and inherits the rest from the current scope.
import androidx.compose.ui.graphics.Color
import com.hrm.codehigh.renderer.*
@Composable
fun App() {
val colors = CodeDefaults.githubLightColors().copy(
keyword = Color(0xFF569CD6),
string = Color(0xFFCE9178),
)
ProvideCodeDefaults(colors = colors) {
CodeBlock(code = "val answer = 42", language = "kotlin")
InlineCode(text = "answer")
CodeBlock(
code = "println(answer)", language = "kotlin",
colors = CodeDefaults.colors(keyword = Color.Magenta),
onTokenClick = { token -> /* host action */ },
)
}
}You can register custom lexers for additional languages:
import com.hrm.codehigh.lexer.LanguageRegistry
import com.hrm.codehigh.lexer.Lexer
// Register your custom lexer
LanguageRegistry.register("my-language", MyCustomLexer)
LanguageRegistry.registerAlias("ml", "my-language") // Add alias
// Use it in CodeBlock
CodeBlock(
code = myCode,
language = "my-language" // Or "ml" via alias
):codehighlight-parser: Parser SDK module, containing tokens, lexers, language registration, and incremental parsing.:codehighlight-render: Compose render SDK module, containing renderer components, themes, and parser integration.:codehighlight-preview: Preview components and sample datasets.:composeApp: Cross-platform Demo application.:androidApp: Android Demo application.:iosApp: iOS application entry module../gradlew :androidApp:assembleDebug
./gradlew :composeApp:run
./gradlew :composeApp:wasmJsBrowserDevelopmentRun
iosApp/iosApp.xcworkspace in Xcode to run../gradlew testFor a detailed list of supported features, please refer to: HIGHLIGHTER_COVERAGE_ANALYSIS.md
codehigh.This project is licensed under the MIT License - see the LICENSE file for details.
MIT License
Copyright (c) 2026 huarangmeng
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.