Engine-only Usage¶
Use HighlightEngine directly when you need to:
- Highlight code in a ViewModel or repository layer (outside of Compose)
- Produce
AnnotatedStringfor reuse across multiple widgets - Access raw highlighted HTML for custom rendering
- Query engine metadata (supported languages, Highlight.js version)
ViewModel example¶
import dev.hossain.highlight.engine.HighlightEngine
import dev.hossain.highlight.engine.HighlightTheme
class CodeViewModel(application: Application) : AndroidViewModel(application) {
private val engine = HighlightEngine(application.applicationContext)
private val _highlighted = MutableStateFlow<AnnotatedString?>(null)
val highlighted: StateFlow<AnnotatedString?> = _highlighted.asStateFlow()
init {
viewModelScope.launch { engine.initialize() }
}
fun highlight(code: String, language: String, theme: HighlightTheme) {
viewModelScope.launch {
engine.highlight(code, language, theme).onSuccess { result ->
_highlighted.value = result.annotated
}
}
}
override fun onCleared() {
engine.close()
}
}
Using the result in Compose¶
import dev.hossain.highlight.ui.SyntaxHighlightedCodeDefaults
@Composable
fun CodeScreen(viewModel: CodeViewModel = viewModel()) {
val highlighted by viewModel.highlighted.collectAsState()
SelectionContainer {
Text(
text = highlighted ?: AnnotatedString("loading..."),
style = SyntaxHighlightedCodeDefaults.codeTextStyle,
)
}
}
Raw HTML output¶
Get the raw Highlight.js HTML tokens for custom rendering pipelines:
engine.highlightToHtml("val x = 42", "kotlin").onSuccess { result ->
// result.html: "<span class=\"hljs-keyword\">val</span> x = <span class=\"hljs-number\">42</span>"
Log.d("HTML", result.html)
}
Querying engine metadata¶
engine.supportedLanguages().onSuccess { languages ->
Log.d("Engine", "Supports ${languages.size} languages")
}
engine.highlightJsVersion().onSuccess { version ->
Log.d("Engine", "highlight.js $version")
}
Error handling¶
All suspend methods return Result<T>. Failures are wrapped in HighlightException:
import dev.hossain.highlight.engine.HighlightException
engine.highlight(code, language, theme)
.onSuccess { result -> /* use result.annotated */ }
.onFailure { error ->
if (error is HighlightException) {
when (error) {
is HighlightException.WebViewInitFailed -> /* WebView not available (Go edition, MDM-disabled, mid-update) */
is HighlightException.JsExecutionFailed -> /* JS evaluation error */
is HighlightException.ThemeNotFound -> /* theme CSS found but contains no parseable color rules */
is HighlightException.HtmlParseFailed -> /* jsoup parse error, or theme asset IOException (check cause) */
is HighlightException.Timeout -> /* timed out waiting for WebView */
}
}
}
Missing asset files
If a theme asset file is missing or unreadable, the IOException is wrapped in
HtmlParseFailed (since theme resolution happens during the HTML processing stage).
Check error.cause to distinguish asset I/O errors from jsoup parse failures.
Important rules¶
- Always pass
applicationContext- never an Activity context. The engine retains the context beyond Activity lifecycle. - Always call
destroy()to release the WebView when done. UserememberHighlightEngine()in Compose for automatic lifecycle management. HighlightEngineis safe to call from any coroutine - all WebView operations are automatically dispatched to the Main thread internally.