///|
/// A UTF-16 range in a document. The index and length must be nonnegative
/// and lie within the document passed to diff_with_cursor_info.
pub(all) struct CursorRange {
index : Int32
length : Int32
}
///|
pub fn CursorRange::new(index : Int32, length : Int32) -> CursorRange {
{ index, length, }
}
///|
/// Before-and-after selection ranges accepted by Quill Delta's diff cursor
/// option. A selected old range followed by a zero-length new range denotes
/// replacement of the selection, with the new index at the resulting caret.
pub(all) struct CursorInfo {
old_range : CursorRange
new_range : CursorRange
}
///|
pub fn CursorInfo::new(
old_range : CursorRange,
new_range : CursorRange,
) -> CursorInfo {
{ old_range, new_range, }
}
///|
/// Use Quill's selected-range cursor convention, or explicit old/new edit
/// ranges when they align with otherwise unchanged content.
pub fn Delta::diff_with_cursor_info(
self : Delta,
target : Delta,
cursor : CursorInfo,
) -> Delta raise DeltaError {
if physical_equal(self.ops, target.ops) { return Delta::new() }
let old_range = cursor.old_range
let new_range = cursor.new_range
if old_range.length == 0 && new_range.length == 0 {
return self.diff_at_carets(target, old_range.index, Some(new_range.index))
}
if old_range.length > 0 && new_range.length == 0 &&
old_range.index >= 0 && old_range.length >= 0 &&
old_range.index.to_int64() + old_range.length.to_int64() <=
self.length().to_int64() {
let suffix_length = self.length() - old_range.index - old_range.length
let new_middle_length = target.length().to_int64() -
old_range.index.to_int64() - suffix_length.to_int64()
if new_middle_length >= 0L && new_middle_length <= 2147483647L {
return self.diff_splice(
target,
old_range,
CursorRange::new(old_range.index, new_middle_length.to_int()),
)
}
}
self.diff_splice(target, old_range, new_range)
}
///|
fn Delta::diff_splice(
self : Delta,
target : Delta,
old_range : CursorRange,
new_range : CursorRange,
) -> Delta raise DeltaError {
if !self.is_document() || !target.is_document() {
raise Invalid("diff requires two insert-only documents")
}
if old_range.index < 0 ||
old_range.length < 0 ||
new_range.index < 0 ||
new_range.length < 0 ||
old_range.index.to_int64() + old_range.length.to_int64() >
self.length().to_int64() ||
new_range.index.to_int64() + new_range.length.to_int64() >
target.length().to_int64() {
return self.diff(target)
}
let old_end = old_range.index + old_range.length
let new_end = new_range.index + new_range.length
let old_units = self.diff_units()
let new_units = target.diff_units()
let old_start_unit = unit_index_at(old_units, old_range.index, self.length())
let old_end_unit = unit_index_at(old_units, old_end, self.length())
let new_start_unit = unit_index_at(
new_units,
new_range.index,
target.length(),
)
let new_end_unit = unit_index_at(new_units, new_end, target.length())
if old_start_unit < 0 ||
old_end_unit < 0 ||
new_start_unit < 0 ||
new_end_unit < 0 ||
old_start_unit != new_start_unit ||
old_units.length() - old_end_unit != new_units.length() - new_end_unit {
return self.diff(target)
}
let old_keys = diff_keys(old_units)
let new_keys = diff_keys(new_units)
if !placeholder_range_equal(
old_keys, 0, old_start_unit, new_keys, 0, new_start_unit,
) { return self.diff(target) }
for index in 0..<(old_units.length() - old_end_unit) {
if old_keys[old_end_unit + index] != new_keys[new_end_unit + index] {
return self.diff(target)
}
}
let result = Delta::new()
for index in 0.. 0 {
ignore(result.delete(old_range.length))
}
if new_range.length > 0 {
for op in target.slice(new_range.index, new_end).ops {
ignore(result.push(op))
}
}
}
for index in 0..<(old_units.length() - old_end_unit) {
append_matched_unit(
result,
old_units[old_end_unit + index],
new_units[new_end_unit + index],
target,
)
}
result.chop()
}
///|
fn unit_index_at(
units : Array[DiffUnit],
offset : Int32,
total : Int32,
) -> Int32 {
if offset == total {
return units.length()
}
for index, unit in units {
if unit.offset == offset {
return index
}
}
-1
}