///|
// A local edit leaves a hint at the inserted item's visible offset. Sequence
// mutation invalidates it; compaction moves it to the surviving merged item.
// Formatted text must scan its attributes from the beginning instead.
fn Text::position_start(self : Text, index : Int32) -> (Int32, Id?, Id?) {
let branch = self.doc.branch(self.name)
guard !branch.formatted && branch.position_hint is Some((hint, offset)) else {
return (0, None, branch.head)
}
let mut item = hint
let mut start = offset
while start > index && item.left is Some(id) {
item = self.doc.items[id]
if !item.deleted {
start -= item.content.offset_length(self.doc)
}
}
// Rich-text removal stops before tombstones at an exact boundary. Plain
// insertion will subsequently skip them. Preserve both positioning rules.
if start == index {
while item.left is Some(id) && self.doc.items[id].deleted {
item = self.doc.items[id]
}
}
(start, item.left, Some(item.id))
}