/-- Get line index (0-based) containing the byte offset.
Newline byte itself belongs to the previous line (same as getLineRange semantics). -/
def getLineIndexAtOffset (t : ViE.PieceTree) (offset : Nat) (pt : ViE.PieceTable) : Nat := Id.run do
let target := min offset (length t)
let mut node := t
let mut currLines := 0
let mut rem := target
while true do
match node with
| ViE.PieceTree.empty =>
return currLines
| ViE.PieceTree.leaf pieces _ _ =>
let mut i := 0
while i < pieces.size && rem > 0 do
let p := pieces[i]!
let pLen := p.length.toNat
if rem >= pLen then
currLines := currLines + p.lineBreaks.toNat
rem := rem - pLen
else
let buf := PieceTableHelper.getBuffer pt p.source
let (lines, _) := ViE.Unicode.countNewlinesAndChars buf p.start.toNat rem
currLines := currLines + lines
rem := 0
i := i + 1
return currLines
| ViE.PieceTree.internal children _ _ imeta =>
if children.isEmpty then
return currLines
let childIdx := findChildForOffset imeta rem.toUInt64
currLines := currLines + imeta.cumulativeLines[childIdx]!.toNat
let childStart := imeta.cumulativeBytes[childIdx]!.toNat
rem := rem - childStart
node := children[childIdx]!
return currLines