An Android app that showcases three different syntax highlighting approaches for displaying code beautifully in Jetpack Compose:
- ☁️ Server-driven — a hosted Shiki Token Service tokenizes code on the server and returns per-token colors; the app just renders them.
- 📴 On-device (TextMate) — kotlin-textmate applies TextMate grammars and themes locally with no network required.
- 🌐 On-device (Highlight.js) — compose-highlight runs Highlight.js inside a hidden WebView and converts the tokenized HTML output to a native
AnnotatedString— 190+ languages, no grammar files to maintain.
All approaches produce a Compose AnnotatedString and share the same code samples and UI structure, making it easy to compare their output, performance, and trade-offs side by side.
- 🆚 Side-by-side comparison — compare all three approaches (output, performance, device footprint) together
- 🌗 Dark & light theme support on all screens
- 🔤 Multiple languages — Kotlin, Python, JSON, JavaScript
- 🎭 Multiple themes — GitHub, One Dark Pro, Dracula (Shiki); VS Dark+/Light+, One Dark Pro/Quiet Light, Monokai/Solarized Light (TextMate)
- 📊 Performance metrics — network request time, total time, on-device tokenization time, line/char counts
- 📋 Copy to clipboard on all screens
- 🔄 Refresh (Shiki) — re-trigger the network request in one tap
- 📋 Plain-text fallback — raw code shown when the Shiki server is unavailable
| Shiki Token Service | Native Kotlin TextMate | Compose Highlight | Compare All |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Code is sent to a hosted Shiki Token Service which returns per-token dark/light hex colors. The app builds a Compose AnnotatedString directly from the token list — no grammar files needed on device. Metrics include network round-trip time and total rendering time.
kotlin-textmate tokenizes code using .tmLanguage.json grammar files and VS Code-style theme files bundled in assets/. Fully offline — all tokenization runs on Dispatchers.Default with no network calls. Metrics show CPU tokenization time.
compose-highlight runs Highlight.js inside a hidden WebView. Supports 190+ languages with no grammar files to maintain. A single JS round-trip produces both dark and light AnnotatedString outputs simultaneously. Metrics show the WebView JS round-trip time.
→ Detailed implementation notes
- TextMate can load any TextMate/VS Code grammar format; 250+ are available in the VS Code ecosystem.
¹ Median time to highlight small code sample (Pixel 9 Pro XL + Galaxy S24 Ultra average). Shiki performance depends on network latency; shown values are for on-device processing only (TextMate & Compose Highlight).
→ Full details & benchmarks:
| Layer | Library |
|---|---|
| UI | Jetpack Compose + Material 3 |
| Architecture | Circuit UDF (presenter + UI composable) |
| Dependency Injection | Metro |
| Server highlighting | Shiki Token Service SDK (Ktor-based) |
| On-device highlighting (TextMate) | kotlin-textmate (Maven Central) |
| On-device highlighting (Highlight.js) | compose-highlight (WebView + Highlight.js) |
| Networking | Ktor (via Shiki SDK) |
| Min SDK | 28 (Android 9) |
- Clone the repo and open in Android Studio
- Build and run — all four screens work out of the box:
- Shiki uses the hosted service at
https://syntax-highlight.gohk.xyz - TextMate runs fully on-device using bundled grammar/theme assets
- Compose Highlight runs fully on-device using Highlight.js inside a hidden WebView
- Shiki uses the hosted service at
- To point Shiki at your own service instance, update
SHIKI_BASE_URLinShikiRepositoryImpl.kt
# Build debug APK
./gradlew assembleDebug
# Format Kotlin code
./gradlew formatKotlin


