Auto merge of #14380 - DropDemBits:coalesce-indels, r=Veykril

internal: Coalesce adjacent Indels

Originally part of working on a structured snippet API (since sometimes the `$` bit of snippets would be broken off and would lead to it not being recognized), though since this is a pretty separate change, I thought it would make sense to put it into it's own PR.

The implementation is relatively straight forward and not overly optimized, though it's pretty low hanging fruit to optimize it when need be.
This commit is contained in:
bors 2023-03-25 13:16:43 +00:00
commit 68aa133108

View file

@ -176,6 +176,7 @@ impl TextEditBuilder {
pub fn finish(self) -> TextEdit {
let mut indels = self.indels;
assert_disjoint_or_equal(&mut indels);
indels = coalesce_indels(indels);
TextEdit { indels }
}
pub fn invalidates_offset(&self, offset: TextSize) -> bool {
@ -205,6 +206,21 @@ where
indels.clone().zip(indels.skip(1)).all(|(l, r)| l.delete.end() <= r.delete.start() || l == r)
}
fn coalesce_indels(indels: Vec<Indel>) -> Vec<Indel> {
indels
.into_iter()
.coalesce(|mut a, b| {
if a.delete.end() == b.delete.start() {
a.insert.push_str(&b.insert);
a.delete = TextRange::new(a.delete.start(), b.delete.end());
Ok(a)
} else {
Err((a, b))
}
})
.collect_vec()
}
#[cfg(test)]
mod tests {
use super::{TextEdit, TextEditBuilder, TextRange};
@ -261,4 +277,40 @@ mod tests {
let edit2 = TextEdit::delete(range(9, 13));
assert!(edit1.union(edit2).is_err());
}
#[test]
fn test_coalesce_disjoint() {
let mut builder = TextEditBuilder::default();
builder.replace(range(1, 3), "aa".into());
builder.replace(range(5, 7), "bb".into());
let edit = builder.finish();
assert_eq!(edit.indels.len(), 2);
}
#[test]
fn test_coalesce_adjacent() {
let mut builder = TextEditBuilder::default();
builder.replace(range(1, 3), "aa".into());
builder.replace(range(3, 5), "bb".into());
let edit = builder.finish();
assert_eq!(edit.indels.len(), 1);
assert_eq!(edit.indels[0].insert, "aabb");
assert_eq!(edit.indels[0].delete, range(1, 5));
}
#[test]
fn test_coalesce_adjacent_series() {
let mut builder = TextEditBuilder::default();
builder.replace(range(1, 3), "au".into());
builder.replace(range(3, 5), "www".into());
builder.replace(range(5, 8), "".into());
builder.replace(range(8, 9), "ub".into());
let edit = builder.finish();
assert_eq!(edit.indels.len(), 1);
assert_eq!(edit.indels[0].insert, "auwwwub");
assert_eq!(edit.indels[0].delete, range(1, 9));
}
}