mirror of
https://github.com/hexedtech/codemp.git
synced 2024-12-23 13:24:54 +01:00
62 lines
1.5 KiB
Rust
62 lines
1.5 KiB
Rust
use operational_transform::OperationSeq;
|
|
use similar::{TextDiff, ChangeTag};
|
|
|
|
pub trait OperationFactory {
|
|
fn content(&self) -> String;
|
|
|
|
fn replace(&self, txt: &str) -> OperationSeq { self.delta(0, txt, 0) }
|
|
|
|
fn delta(&self, skip: usize, txt: &str, tail: usize) -> OperationSeq {
|
|
let mut out = OperationSeq::default();
|
|
let content = self.content();
|
|
let tail_index = content.len() - tail;
|
|
let content_slice = &content[skip..tail_index];
|
|
|
|
if content_slice == txt {
|
|
return out; // TODO this won't work, should we return a noop instead?
|
|
}
|
|
|
|
out.retain(skip as u64);
|
|
|
|
let diff = TextDiff::from_chars(content_slice, txt);
|
|
|
|
for change in diff.iter_all_changes() {
|
|
match change.tag() {
|
|
ChangeTag::Equal => out.retain(1),
|
|
ChangeTag::Delete => out.delete(1),
|
|
ChangeTag::Insert => out.insert(change.value()),
|
|
}
|
|
}
|
|
|
|
out.retain(tail as u64);
|
|
|
|
out
|
|
}
|
|
|
|
fn insert(&self, txt: &str, pos: u64) -> OperationSeq {
|
|
let mut out = OperationSeq::default();
|
|
let total = self.content().len() as u64;
|
|
out.retain(pos);
|
|
out.insert(txt);
|
|
out.retain(total - pos);
|
|
out
|
|
}
|
|
|
|
fn delete(&self, pos: u64, count: u64) -> OperationSeq {
|
|
let mut out = OperationSeq::default();
|
|
let len = self.content().len() as u64;
|
|
out.retain(pos - count);
|
|
out.delete(count);
|
|
out.retain(len - pos);
|
|
out
|
|
}
|
|
|
|
fn cancel(&self, pos: u64, count: u64) -> OperationSeq {
|
|
let mut out = OperationSeq::default();
|
|
let len = self.content().len() as u64;
|
|
out.retain(pos);
|
|
out.delete(count);
|
|
out.retain(len - (pos+count));
|
|
out
|
|
}
|
|
}
|