default_limits : Limits
Bidi
Bidi :: # (opaque)
Retained paragraph analysis for Unicode 17 UAX #9. The retained tape keeps
original scalar identities and coordinates; it deliberately never retains
the input Str. Line reordering is a separate operation because L1 is
defined at actual line boundaries.
paragraph_ranges : Str -> List(TextRange)
Split complete text according to P1. A paragraph separator belongs to the preceding returned range. CR LF is one separator (and therefore one preceding-paragraph suffix); a lone CR, lone LF, and U+001C..U+001E each terminate their preceding paragraph. No artificial empty paragraph is produced after a final separator.
analyze_paragraph : Str, BaseDirection, Limits -> Try(Analysis, Error)
analyze_range : Str, TextRange, BaseDirection, Limits -> Try(Analysis, Error)
Analyze one P1 paragraph selected from a complete source. Validation scans
through the selected P1 boundary, then replays only the selected seamless
slice for retained analysis; this explicit replay keeps global coordinates
without retaining the source. Line ranges and visual mappings remain
absolute to source.
paragraph_level : Analysis -> U8
requested_base_direction : Analysis -> BaseDirection
paragraph_range : Analysis -> TextRange
matched_brackets : Analysis -> List([Some(U64), None])
Matched paired-bracket partner indices after BD16/N0, or None for an
unmatched/non-bracket scalar. Indices always refer to original logical
scalars, never an X9-filtered working buffer.
logical_runs : Analysis -> Iter(LevelRun)
Lazily walk maximal same-level spans in the X9-filtered logical sequence. Removed controls bridge equal-level runs but are not themselves yielded.
collect_logical_runs : Analysis -> List(LevelRun)
Explicit materializing convenience for clients that need every retained
run at once. logical_runs is the primary, early-stoppable traversal.
reorder_line : Analysis, ScalarRange -> Try(LineOrder, Error)
L1/L2 for a scalar-aligned, paragraph-local logical line. The display
permutation omits only X9 controls. LRI/RLI/FSI/PDI remain in it, marked
non_rendering in the analysis for renderers that do not draw controls.
line_levels : LineOrder -> List(ResolvedLevel)
visual_to_logical : LineOrder -> List(U64)
logical_to_visual : LineOrder -> List([Some(U64), None])
visual_runs : LineOrder -> List(VisualRun)
line_mirroring : LineOrder -> List(MirrorInfo)
BaseDirection : [Auto, LeftToRight, RightToLeft]
Direction : [LeftToRight, RightToLeft]
LimitStage : [Ingestion]
ResolvedLevel : [Level(U8), RemovedByX9]
Error : [ScalarLimitExceeded({ limit : U64, required : U64, stage : LimitStage, range : TextRange }), ByteLimitExceeded({ limit : U64, required : U64, stage : LimitStage, range : ByteRange }), MultipleParagraphs, InvalidParagraphRange(TextRange), LineOutOfBounds({ requested : ScalarRange, paragraph : ScalarRange })]
Limit errors identify the operation before the retained tape is committed. Their paragraph range is in the caller's original source coordinates.
ScalarInfo : { range : TextRange, scalar : Scalar, original_class : Value, working_class : Value, level : [Some(U8), None], matched_bracket : [Some(U64), None], non_rendering : Bool, needs_mirrored_glyph : Bool, mirroring_glyph : [Some(Scalar), None] }
Analysis
:= { requested_base : BaseDirection, paragraph_range : TextRange, paragraph_level : U8, entries : List(ScalarInfo), byte_len : U64, scalar_len : U64 }
MirrorInfo : { needs_glyph : Bool, glyph : [Some(Scalar), None] }
LineOrder
:= { line_range : ScalarRange, levels : List([Some(U8), None]), visual_to_logical : List(U64), logical_to_visual : List([Some(U64), None]), visual_runs : List(VisualRun), mirroring : List(MirrorInfo) }
RunSequences
:= { links : List([Some(U64), None]), starts : List(U64), sos : List(Value), eos : List(Value) }
Private intermediate links for the X10/N0 implementation. No public operation exposes this value.