Rope class

A persistent (immutable-node) B-tree rope indexed in UTF-16 code units.

Design notes

  • All offsets and lengths are UTF-16 code units, so they line up with Flutter's TextSelection/TextPosition, String.length and LSP. Leaf boundaries never split a surrogate pair. Callers must not pass an offset that lands in the middle of a pair.
  • Nodes are immutable. An edit copies only the O(log n) nodes on the path and shares the rest, so copy is O(1) and the *Immutable helpers cost O(log n). Cheap snapshots make undo history simple.
  • Every node caches length, newline count and strong RTL/LTR counts, so line seeks and textDirection are O(log n) / O(1).
  • Deletes merge underfull siblings so the tree does not degrade.

Only \n counts as a line break. \r before \n is stripped from line text. Normalise lone \r on load if you need to support old Mac files.

Complexity (n = document length, k = result size): insert/delete/replace O(log n + leaf size) getLineStartOffset etc. O(log n + leaf size) slice / lineRange O(log n + k) getText / lineLengths O(n) (export, save, stats only)

Constructors

Rope([String initialText = ''])

Properties

bidiSegments → List<BiDiSegment>
Direction runs for the whole document. O(n). Prefer getBiDiSegmentsForLine / getBiDiSegmentsInRange when rendering.
no setter
cachedLines → List<String>
no setter
containsRtl → bool
no setter
core → Rope
no setter
hashCode → int
The hash code for this object.
no setterinherited
isLtr → bool
no setter
isMixed → bool
True when the document has both strong RTL and strong LTR text. O(1).
no setter
isRtl → bool
no setter
length → int
no setter
lineCount → int
no setter
lines → Iterable<String>
Lazily yields lines in batches. Still O(n) if fully consumed.
no setter
primaryDirection → TextDirection
no setter
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
selection → TextSelection
no setter
textDirection → TextDirection
no setter

Methods

cachedLinesRange(int startLine, int endLine) → List<String>
charAt(int position) → String
The character at position. Returns the whole pair for an astral character whose high surrogate sits at position.
codeUnitAt(int position) → int
UTF-16 code unit at position, or -1 when out of range.
concatImmutable(Rope other) → Rope
Appends other leaf by leaf. Never materialises either document.
copy() → Rope
O(1): nodes are immutable, so the snapshot shares the whole tree.
delete(int start, int end) → void
deleteImmutable(int start, int end) → Rope
findLineEnd(int offset) → int
findLineStart(int offset) → int
getBiDiSegmentsForLine(int lineIndex) → List<BiDiSegment>
getBiDiSegmentsInRange(int start, int end) → List<BiDiSegment>
Splits [start, end) into runs of one strong direction. Neutral characters attach to the run before them (leading neutrals join the first run). Costs O(log n + range length).
getLineAtOffset(int charOffset) → int
getLineStartOffset(int lineIndex) → int
getLineText(int lineIndex) → String
getRtlSegments() → List<(int, int)>
getText() → String
O(n). Use for save/export only, never per keystroke.
insert(int position, String text) → void
insertImmutable(int position, String text) → Rope
lineLengthAt(int lineIndex) → int
Length of the line in code units, excluding \n and a preceding \r.
lineLengths() → List<int>
O(n). Length of every line in code units.
lineRange(int startLine, int endLine) → List<String>
Lines [startLine, endLine) fetched with a single slice and split. Use this for viewport rendering, highlighting and gutters.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
replace(int start, int end, String text) → void
replaceRangeAndUpdateSelection({required int start, required int end, required String replacement, required bool preserveOldCursor, required int oldBase, required int oldExtent}) → SelectionState
Replaces [start, end) with replacement and remaps the selection.
setSelection(TextSelection value) → void
slice(int start, int end) → String
splitImmutable(int position) → (Rope, Rope)
Both halves share structure with this rope. position must not be in the middle of a surrogate pair.
substring(int start, [int? end]) → String
toString() → String
A string representation of this object.
inherited
toStringWithBiDiControls() → String

Operators

operator ==(Object other) → bool
The equality operator.
inherited