use crate::block::{BlockError, BlockRange};
use crate::diff::{apply, ApplyError, Change};
use crate::node::{Mark, Node};
use crate::range::Position;
use serde_json::{Map, Value};
pub struct Transform<'a> {
root: &'a mut Node,
changes: Vec<Change>,
}
impl Node {
pub fn transform(&mut self) -> Transform<'_> {
Transform {
root: self,
changes: Vec::new(),
}
}
}
impl<'a> Transform<'a> {
fn push(&mut self, change: Change) -> Result<&mut Self, ApplyError> {
apply(self.root, std::slice::from_ref(&change))?;
self.changes.push(change);
Ok(self)
}
pub fn set_attr(
&mut self,
path: Vec<usize>,
key: impl Into<String>,
value: impl Into<Value>,
) -> Result<&mut Self, ApplyError> {
self.push(Change::SetAttr {
path,
key: key.into(),
value: value.into(),
})
}
pub fn remove_attr(
&mut self,
path: Vec<usize>,
key: impl Into<String>,
) -> Result<&mut Self, ApplyError> {
self.push(Change::RemoveAttr {
path,
key: key.into(),
})
}
pub fn set_text(
&mut self,
path: Vec<usize>,
text: Option<String>,
) -> Result<&mut Self, ApplyError> {
self.push(Change::SetText { path, text })
}
pub fn set_marks(
&mut self,
path: Vec<usize>,
marks: Option<Vec<Mark>>,
) -> Result<&mut Self, ApplyError> {
self.push(Change::SetMarks { path, marks })
}
pub fn set_extra(
&mut self,
path: Vec<usize>,
key: impl Into<String>,
value: impl Into<Value>,
) -> Result<&mut Self, ApplyError> {
self.push(Change::SetExtra {
path,
key: key.into(),
value: value.into(),
})
}
pub fn remove_extra(
&mut self,
path: Vec<usize>,
key: impl Into<String>,
) -> Result<&mut Self, ApplyError> {
self.push(Change::RemoveExtra {
path,
key: key.into(),
})
}
pub fn insert(
&mut self,
path: Vec<usize>,
index: usize,
node: Node,
) -> Result<&mut Self, ApplyError> {
self.push(Change::Insert { path, index, node })
}
pub fn remove(&mut self, path: Vec<usize>, index: usize) -> Result<&mut Self, ApplyError> {
self.push(Change::Remove { path, index })
}
pub fn replace(&mut self, path: Vec<usize>, node: Node) -> Result<&mut Self, ApplyError> {
self.push(Change::Replace { path, node })
}
pub fn move_child(
&mut self,
path: Vec<usize>,
from: usize,
to: usize,
) -> Result<&mut Self, ApplyError> {
self.push(Change::Move { path, from, to })
}
pub fn changes(&self) -> &[Change] {
&self.changes
}
pub fn finish(self) -> Vec<Change> {
self.changes
}
}
impl Transform<'_> {
fn record_structural<F>(&mut self, f: F) -> Result<&mut Self, BlockError>
where
F: FnOnce(&mut Node) -> Result<(), BlockError>,
{
let before = self.root.clone();
f(self.root)?;
let patch = before.diff(self.root);
self.changes.extend(patch);
Ok(self)
}
pub fn set_block_type(
&mut self,
path: Vec<usize>,
new_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<&mut Self, BlockError> {
self.record_structural(|root| root.set_block_type(&path, new_type, attrs))
}
pub fn split_block(
&mut self,
path: Vec<usize>,
at: usize,
depth: usize,
) -> Result<&mut Self, BlockError> {
self.record_structural(|root| root.split_block(&path, at, depth))
}
pub fn split_block_at(
&mut self,
path: Vec<usize>,
pos: Position,
depth: usize,
) -> Result<&mut Self, BlockError> {
self.record_structural(|root| root.split_block_at(&path, pos, depth))
}
pub fn join_blocks(
&mut self,
parent: Vec<usize>,
index: usize,
) -> Result<&mut Self, BlockError> {
self.record_structural(|root| root.join_blocks(&parent, index))
}
pub fn wrap(
&mut self,
path: Vec<usize>,
wrapper_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<&mut Self, BlockError> {
self.record_structural(|root| root.wrap(&path, wrapper_type, attrs))
}
pub fn wrap_range(
&mut self,
range: BlockRange,
wrapper_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<&mut Self, BlockError> {
self.record_structural(|root| root.wrap_range(&range, wrapper_type, attrs))
}
pub fn lift(&mut self, path: Vec<usize>) -> Result<&mut Self, BlockError> {
self.record_structural(|root| root.lift(&path))
}
}