rust/crates/libeditor/src/edit.rs

94 lines
2.3 KiB
Rust
Raw Normal View History

2018-08-12 17:50:16 +02:00
use {TextRange, TextUnit};
#[derive(Debug)]
pub struct Edit {
pub atoms: Vec<AtomEdit>,
}
#[derive(Debug)]
pub struct AtomEdit {
pub delete: TextRange,
pub insert: String,
}
#[derive(Debug)]
pub struct EditBuilder {
atoms: Vec<AtomEdit>
}
impl EditBuilder {
pub fn new() -> EditBuilder {
EditBuilder { atoms: Vec::new() }
}
pub fn replace(&mut self, range: TextRange, replacement: String) {
let range = self.translate(range);
self.atoms.push(AtomEdit { delete: range, insert: replacement })
}
pub fn delete(&mut self, range: TextRange) {
self.replace(range, String::new());
}
pub fn insert(&mut self, offset: TextUnit, text: String) {
self.replace(TextRange::offset_len(offset, 0.into()), text)
}
pub fn finish(self) -> Edit {
Edit { atoms: self.atoms }
}
fn translate(&self, range: TextRange) -> TextRange {
let mut range = range;
for atom in self.atoms.iter() {
range = atom.apply_to_range(range)
.expect("conflicting edits");
}
range
}
}
impl Edit {
pub fn apply(&self, text: &str) -> String {
let mut text = text.to_owned();
for atom in self.atoms.iter() {
text = atom.apply(&text);
}
text
}
}
impl AtomEdit {
fn apply(&self, text: &str) -> String {
let prefix = &text[
TextRange::from_to(0.into(), self.delete.start())
];
let suffix = &text[
TextRange::from_to(self.delete.end(), TextUnit::of_str(text))
];
let mut res = String::with_capacity(prefix.len() + self.insert.len() + suffix.len());
res.push_str(prefix);
res.push_str(&self.insert);
res.push_str(suffix);
res
}
fn apply_to_position(&self, pos: TextUnit) -> Option<TextUnit> {
if pos <= self.delete.start() {
return Some(pos);
}
if pos < self.delete.end() {
return None;
}
Some(pos - self.delete.len() + TextUnit::of_str(&self.insert))
}
fn apply_to_range(&self, range: TextRange) -> Option<TextRange> {
Some(TextRange::from_to(
self.apply_to_position(range.start())?,
self.apply_to_position(range.end())?,
))
}
}