rememberSyntaxHighlightedEditorValue

fun rememberSyntaxHighlightedEditorValue(value: TextFieldValue, language: String, theme: HighlightTheme = LocalHighlightTheme.current, debounceMs: Long = SyntaxHighlightedTextEditorDefaults.DEBOUNCE_MS, onHighlightComplete: (AnnotatedString) -> Unit? = null, onError: (HighlightException) -> Unit? = null): TextFieldValue

Runs the debounce + syntax-highlight pipeline for a live code editor and returns the display TextFieldValue ready to pass directly to BasicTextField (or any other text field that accepts TextFieldValue).

This is the lower-level counterpart to SyntaxHighlightedTextEditor: it owns the engine call, the debounce window, and the span-clipping logic, but does not render anything. Callers drive their own layout, which makes it easy to:

  • wrap an OutlinedTextField or a third-party editor with syntax highlighting

  • test the highlight pipeline in isolation without a Surface/BasicTextField in the tree

The returned TextFieldValue is recomputed each time a new highlight result arrives. Between updates the previous spans are transferred using a prefix/suffix analysis: spans on unchanged text before the edit are kept as-is, spans on unchanged text after the edit (lines below) are shifted by the length delta, and spans in the edited region are dropped. This means syntax colors on all lines above and below a mid-text edit remain correct during the debounce window, and only the characters being typed are temporarily unstyled.

Usage - standalone (with BasicTextField)

var editorValue by remember { mutableStateOf(TextFieldValue("fun hello() = println(\"Hello!\")")) }

HighlightThemeProvider(
lightHighlightTheme = HighlightTheme.tomorrow(),
darkHighlightTheme = HighlightTheme.tomorrowNight(),
) {
val displayValue = rememberSyntaxHighlightedEditorValue(
value = editorValue,
language = "kotlin",
)
BasicTextField(
value = displayValue,
onValueChange = { editorValue = it },
)
}

Usage - with SyntaxHighlightedTextEditor (preferred for most cases)

For the common case of a themed, bordered editor use SyntaxHighlightedTextEditor directly. It calls this function internally and adds the Surface + padding + test-tag wrapper.

Return

The TextFieldValue with syntax-highlight spans applied, preserving the original cursor position and selection. Falls back to plain text while a highlight result is in flight, on error, or when the language/theme has just changed. Because this function is a non-restartable composable (returns a non-Unit type), all internal State reads (including the highlight snapshot) automatically subscribe the caller's recompose scope - callers should use it like any other composable helper (val x = rememberXxx()).

Parameters

value

The current TextFieldValue, including text, cursor position, and selection.

language

Highlight.js language identifier (e.g. "kotlin", "python", "sql").

theme

The highlight theme to apply. Defaults to LocalHighlightTheme.

debounceMs

Milliseconds to wait after the last keystroke before triggering a new highlight call. Defaults to 150 ms. If debounceMs changes, the new value is used on the next keystroke. The currently running debounce window is unaffected (the original delay completes with its captured-at-suspension value).

onHighlightComplete

Optional callback invoked each time a highlight cycle completes successfully. Receives the resulting AnnotatedString with syntax spans applied. Useful for testing (wait until the first result arrives) and for observing the highlight output without owning the editor's text state.

onError

Optional callback invoked with the HighlightException when a highlight cycle fails. The editor falls back to plain text on failure regardless of whether this callback is set - it is purely observational. Use it to log failures, show a snackbar, or record analytics. Possible failure types: HighlightException.Timeout, HighlightException.JsExecutionFailed, HighlightException.WebViewInitFailed, HighlightException.HtmlParseFailed.