Repository navigation
Home
BetterText is a Jetpack Compose library for rendering the replies of LLM chat apps: Markdown with math, inline components and highlighted code, streamed in token by token.
It lays out text itself with Android's StaticLayout and ports KaTeX for math, so inline formulas wrap and sit on the text baseline, lines grow to fit tall content instead of overlapping, and a whole conversation can be selected and copied.
| Module | Artifact | What it does | Guide |
|---|---|---|---|
text |
com.github.re-ovo.bettertext:text |
BetterText, a BasicText replacement with inline content, and BetterSelectionContainer
|
BetterText |
latex |
com.github.re-ovo.bettertext:latex |
A Kotlin port of KaTeX 0.19.1 (with mhchem), as composables and as inline items for BetterText
|
LaTeX |
markdown |
com.github.re-ovo.bettertext:markdown |
Streaming Markdown (GFM, math, embedded HTML) rendered with BetterText
|
Markdown |
highlight |
com.github.re-ovo.bettertext:highlight |
A pure Kotlin port of highlight.js 11.11.1, 30 languages, producing an AnnotatedString
|
Highlight |
latex and markdown both depend on text. markdown depends on neither latex nor highlight nor Material 3: the app registers formulas, code blocks and other components itself, so apps without math don't ship KaTeX.
All modules require minSdk 24.
The modules are published on JitPack. Add the repository in settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven("https://jitpack.io")
}
}Then add the BOM with a release tag (such as v0.1.3) or a commit hash, and the modules you need:
dependencies {
implementation(platform("com.github.re-ovo.bettertext:bom:<version>"))
implementation("com.github.re-ovo.bettertext:text")
implementation("com.github.re-ovo.bettertext:latex")
implementation("com.github.re-ovo.bettertext:markdown")
implementation("com.github.re-ovo.bettertext:highlight")
}A chat reply with math and highlighted code, selectable as a whole:
// Stable components: a top-level value, or remembered.
val chatComponents = MarkdownComponents(
inlineMath = { formula -> LatexInline.cached(formula, context) },
mathBlock = { formula ->
val style = LocalMarkdownTextStyle.current
LatexBlock(formula, fontSize = style.fontSize, color = style.color)
},
codeBlock = { block ->
val style = LocalMarkdownTextStyle.current
BetterText(
text = rememberHighlightedCode(block.code, block.language.orEmpty()),
modifier = Modifier.horizontalScroll(rememberScrollState()),
style = style.copy(fontFamily = FontFamily.Monospace, fontFeatureSettings = CODE_FONT_FEATURES),
)
},
)
@Composable
fun Reply(text: String, generating: Boolean) {
BetterSelectionContainer {
Markdown(
content = text,
style = MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.onSurface),
components = chatComponents,
streaming = generating,
)
}
}The default highlight palette is Atom One Dark; see Highlight to pick colors for a light background.
- BetterText: styled text, links, inline items (drawn and composable), selection across texts and lazy lists.
-
LaTeX: standalone formulas, display blocks, inline formulas in
BetterText, settings, macros and chemistry. - Markdown: rendering, theming, registering components, streaming, and parsing ahead of time.
- Highlight: highlighting code, color palettes, supported languages.
Two open Compose issues prevent building on BasicText and SelectionContainer:
-
427657659: with
lineHeightset, every line gets the same height, so a tall inline formula or a span with a larger font overlaps the lines next to it. Material 3 typography always setslineHeight. -
233102278:
SelectionRegistraris internal, so a custom text layout can't take part inSelectionContainer.
BetterText works around both with its own layout and selection, and will switch to the built-in APIs once they are fixed.
The :app module is a gallery with one tab per module: LaTeX samples, a line-wrapping demo and a live editor; rich text; Markdown, including a long conversation to select across; and code highlighting. Install it with:
./gradlew :app:installDebuggallery/markdown/MaterialMarkdown.kt is a complete example of registering Markdown components with Material 3.