Skip to content

Bidirectional Text

Kodemirror supports bidirectional (BiDi) text for languages written right-to-left, such as Arabic and Hebrew.

Direction

The Direction enum represents text direction:

enum class Direction { LTR, RTL }

Per-line text direction

Enable per-line direction detection so each line can independently be LTR or RTL. Here is the live demo's setup:

            val session = rememberEditorSession(
                doc = SampleDocs.bidi,
                extensions = showcaseSetup + javascript().extension +
                    perLineTextDirection.of(true) +
                    editorContentStyle.of(TextStyle(fontFamily = monoFont)) +
                    rtlExt
            )

When enabled, the editor detects the dominant direction of each line and lays it out accordingly.

Detecting direction

The autoDirection function detects the dominant direction of a text range:

import com.monkopedia.kodemirror.view.autoDirection

val dir = autoDirection(text, from = 0, to = text.length)
// Returns Direction.LTR or Direction.RTL

Computing bidi spans

For fine-grained layout, computeOrder splits a line into directional spans following the Unicode Bidirectional Algorithm:

import com.monkopedia.kodemirror.view.computeOrder

val spans: List<BidiSpan> = computeOrder(
    line = "Hello مرحبا World",
    direction = Direction.LTR
)

Each BidiSpan represents a contiguous run of text with the same direction:

data class BidiSpan(
    val from: Int,
    val to: Int,
    val level: Int
) {
    val dir: Direction get() = if ((level % 2) == 0) Direction.LTR else Direction.RTL
}

The bidi level follows the Unicode Bidi Algorithm: even levels are LTR, odd levels are RTL. Level 0 is the base LTR direction.

Isolates

Use Isolate to mark regions that should be treated as directional isolates (preventing their direction from affecting surrounding text):

import com.monkopedia.kodemirror.view.Isolate

val spans = computeOrder(
    line = lineText,
    direction = Direction.LTR,
    isolates = listOf(
        Isolate(from = 10, to = 20, direction = Direction.RTL)
    )
)

Key points

  • Base direction is typically LTR for code editors. Enable perLineTextDirection for documents mixing LTR and RTL content.
  • computeOrder implements a simplified version of UAX#9 (Unicode Bidirectional Algorithm) in pure Kotlin.
  • The editor's line layout uses bidi spans internally to correctly position characters and handle cursor movement across direction boundaries.

Based on the CodeMirror Right-to-Left example.