211 lines
6.7 KiB
Rust
Raw Normal View History

2021-08-05 20:05:40 +08:00
use crate::{
2021-08-06 08:40:45 +08:00
client::{History, RevId, UndoResult},
2021-08-05 20:05:40 +08:00
core::{
Attribute,
Attributes,
AttributesDataRule,
AttrsBuilder,
Delta,
Interval,
OpBuilder,
Operation,
},
2021-08-05 22:52:19 +08:00
errors::{ErrorBuilder, OTError, OTErrorCode::*},
2021-08-05 20:05:40 +08:00
};
pub struct Document {
data: Delta,
history: History,
2021-08-05 22:52:19 +08:00
rev_id_counter: u64,
2021-08-05 20:05:40 +08:00
}
impl Document {
pub fn new() -> Self {
2021-08-06 08:40:45 +08:00
let mut delta = Delta::new();
delta.insert("\n", Attributes::Empty);
2021-08-05 20:05:40 +08:00
Document {
2021-08-06 08:40:45 +08:00
data: delta,
2021-08-05 20:05:40 +08:00
history: History::new(),
2021-08-05 22:52:19 +08:00
rev_id_counter: 1,
2021-08-05 20:05:40 +08:00
}
}
2021-08-06 08:40:45 +08:00
pub fn edit(&mut self, index: usize, text: &str) -> Result<(), OTError> {
2021-08-05 20:05:40 +08:00
if self.data.target_len < index {
log::error!(
"{} out of bounds. should 0..{}",
index,
self.data.target_len
);
}
let probe = Interval::new(index, index + 1);
let mut attributes = self.data.get_attributes(probe);
if attributes == Attributes::Empty {
attributes = Attributes::Follow;
}
let insert = OpBuilder::insert(text).attributes(attributes).build();
let interval = Interval::new(index, index);
2021-08-06 08:40:45 +08:00
self.update_with_op(insert, interval)
2021-08-05 20:05:40 +08:00
}
2021-08-06 08:40:45 +08:00
pub fn format(
&mut self,
interval: Interval,
attribute: Attribute,
enable: bool,
) -> Result<(), OTError> {
2021-08-05 20:05:40 +08:00
let attributes = match enable {
true => AttrsBuilder::new().add_attribute(attribute).build(),
false => AttrsBuilder::new().remove_attribute(attribute).build(),
};
2021-08-06 08:40:45 +08:00
self.update_with_attribute(attributes, interval)
2021-08-05 20:05:40 +08:00
}
2021-08-05 22:52:19 +08:00
pub fn can_undo(&self) -> bool { self.history.can_undo() }
2021-08-05 20:05:40 +08:00
2021-08-05 22:52:19 +08:00
pub fn can_redo(&self) -> bool { self.history.can_redo() }
pub fn undo(&mut self) -> Result<UndoResult, OTError> {
match self.history.undo() {
None => Err(ErrorBuilder::new(UndoFail).build()),
Some(undo_delta) => {
let new_delta = self.data.compose(&undo_delta)?;
let result = UndoResult::success(new_delta.target_len as u64);
let redo_delta = undo_delta.invert_delta(&self.data);
self.data = new_delta;
self.history.add_redo(redo_delta);
Ok(result)
},
}
}
pub fn redo(&mut self) -> Result<UndoResult, OTError> {
match self.history.redo() {
None => Err(ErrorBuilder::new(RedoFail).build()),
Some(redo_delta) => {
let new_delta = self.data.compose(&redo_delta)?;
let result = UndoResult::success(new_delta.target_len as u64);
let redo_delta = redo_delta.invert_delta(&self.data);
self.data = new_delta;
self.history.add_undo(redo_delta);
Ok(result)
},
}
}
2021-08-05 20:05:40 +08:00
2021-08-06 08:40:45 +08:00
pub fn delete(&mut self, interval: Interval) -> Result<(), OTError> {
2021-08-05 20:05:40 +08:00
let delete = OpBuilder::delete(interval.size() as u64).build();
2021-08-06 08:40:45 +08:00
self.update_with_op(delete, interval)
2021-08-05 20:05:40 +08:00
}
pub fn to_json(&self) -> String { self.data.to_json() }
pub fn data(&self) -> &Delta { &self.data }
pub fn set_data(&mut self, data: Delta) { self.data = data; }
2021-08-06 08:40:45 +08:00
fn update_with_op(&mut self, op: Operation, interval: Interval) -> Result<(), OTError> {
2021-08-05 20:05:40 +08:00
let mut new_delta = Delta::default();
let (prefix, interval, suffix) = split_length_with_interval(self.data.target_len, interval);
// prefix
if prefix.is_empty() == false && prefix != interval {
let intervals = split_interval_with_delta(&self.data, &prefix);
intervals.into_iter().for_each(|i| {
let attributes = self.data.get_attributes(i);
log::debug!("prefix attribute: {:?}, interval: {:?}", attributes, i);
new_delta.retain(i.size() as u64, attributes);
});
}
log::debug!("add new op: {:?}", op);
new_delta.add(op);
// suffix
if suffix.is_empty() == false {
let intervals = split_interval_with_delta(&self.data, &suffix);
intervals.into_iter().for_each(|i| {
let attributes = self.data.get_attributes(i);
log::debug!("suffix attribute: {:?}, interval: {:?}", attributes, i);
new_delta.retain(i.size() as u64, attributes);
});
}
2021-08-06 08:40:45 +08:00
let new_data = self.data.compose(&new_delta)?;
let undo_delta = new_delta.invert_delta(&self.data);
2021-08-05 22:52:19 +08:00
self.rev_id_counter += 1;
2021-08-06 08:40:45 +08:00
self.history.record(undo_delta);
2021-08-05 20:05:40 +08:00
self.data = new_data;
2021-08-06 08:40:45 +08:00
Ok(())
2021-08-05 20:05:40 +08:00
}
2021-08-06 08:40:45 +08:00
pub fn update_with_attribute(
&mut self,
mut attributes: Attributes,
interval: Interval,
) -> Result<(), OTError> {
2021-08-05 20:05:40 +08:00
let old_attributes = self.data.get_attributes(interval);
log::debug!(
"merge attributes: {:?}, with old: {:?}",
attributes,
old_attributes
);
let new_attributes = match &mut attributes {
Attributes::Follow => old_attributes,
Attributes::Custom(attr_data) => {
attr_data.merge(old_attributes.data());
attr_data.clone().into_attributes()
},
Attributes::Empty => Attributes::Empty,
};
log::debug!("new attributes: {:?}", new_attributes);
let retain = OpBuilder::retain(interval.size() as u64)
.attributes(new_attributes)
.build();
log::debug!(
"Update delta with new attributes: {:?} at: {:?}",
retain,
interval
);
2021-08-06 08:40:45 +08:00
self.update_with_op(retain, interval)
2021-08-05 20:05:40 +08:00
}
2021-08-05 22:52:19 +08:00
fn next_rev_id(&self) -> RevId { RevId(self.rev_id_counter) }
2021-08-05 20:05:40 +08:00
}
fn split_length_with_interval(length: usize, interval: Interval) -> (Interval, Interval, Interval) {
let original_interval = Interval::new(0, length);
let prefix = original_interval.prefix(interval);
let suffix = original_interval.suffix(interval);
(prefix, interval, suffix)
}
fn split_interval_with_delta(delta: &Delta, interval: &Interval) -> Vec<Interval> {
let mut start = 0;
let mut new_intervals = vec![];
delta.ops.iter().for_each(|op| match op {
Operation::Delete(_) => {},
Operation::Retain(_) => {},
Operation::Insert(insert) => {
let len = insert.num_chars() as usize;
let end = start + len;
let insert_interval = Interval::new(start, end);
let new_interval = interval.intersect(insert_interval);
if !new_interval.is_empty() {
new_intervals.push(new_interval)
}
start += len;
},
});
new_intervals
}