///|
fn edit_is_boundary(text : String, position : Int) -> Bool {
if position == 0 || position == text.length() {
return true
}
let before = text.unsafe_get(position - 1)
let after = text.unsafe_get(position)
!(before >= 0xD800 && before <= 0xDBFF && after >= 0xDC00 && after <= 0xDFFF)
}
///|
fn edit_slice(text : String, start : Int, end : Int) -> String {
text[start:end].to_owned()
}
///|
/// Apply independent edits whose offsets refer to the original source. Edits
/// may be supplied in any order; overlapping edits, duplicate insertion points,
/// invalid ranges and boundaries inside a UTF-16 surrogate pair are rejected.
/// The caller's source and edit array are never mutated.
pub fn apply_edits(
text : String,
edits : Array[TextEdit],
) -> Result[String, EditError] {
if edits.length() > 10000 {
return Err(InvalidEdit("at most 10000 edits may be applied at once"))
}
let ordered = edits.copy()
ordered.sort_by(fn(a, b) {
if a.offset < b.offset {
-1
} else if a.offset > b.offset {
1
} else if a.length < b.length {
-1
} else if a.length > b.length {
1
} else {
0
}
})
let mut previous_offset = -1
let mut previous_end = 0
for edit in ordered {
if edit.offset < 0 ||
edit.offset > text.length() ||
edit.length < 0 ||
edit.length > text.length() - edit.offset {
return Err(InvalidEdit("edit range is outside the original source"))
}
if edit.offset == previous_offset || edit.offset < previous_end {
return Err(InvalidEdit("edits overlap or share an insertion position"))
}
if !edit_is_boundary(text, edit.offset) ||
!edit_is_boundary(text, edit.offset + edit.length) {
return Err(InvalidEdit("edit boundary splits a UTF-16 surrogate pair"))
}
previous_offset = edit.offset
previous_end = edit.offset + edit.length
}
let output = StringBuilder()
let mut position = 0
for edit in ordered {
output.write_string(edit_slice(text, position, edit.offset))
output.write_string(edit.content)
position = edit.offset + edit.length
}
output.write_string(edit_slice(text, position, text.length()))
Ok(output.to_string())
}