use crate::node::Node;
use crate::normalize::{normalize_children, NormalizeOptions};
use crate::range::{ensure_boundary, Position, RangeError};
use serde_json::{Map, Value};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BlockRange {
pub parent: Vec<usize>,
pub start: usize,
pub end: usize,
}
impl BlockRange {
pub fn new(parent: Vec<usize>, start: usize, end: usize) -> Self {
Self { parent, start, end }
}
pub fn single(path: &[usize]) -> Self {
match path.split_last() {
Some((&i, parent)) => Self::new(parent.to_vec(), i, i + 1),
None => Self::new(Vec::new(), 0, 0),
}
}
pub fn len(&self) -> usize {
self.end.saturating_sub(self.start)
}
pub fn is_empty(&self) -> bool {
self.end <= self.start
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BlockError {
PathNotFound {
path: Vec<usize>,
},
IndexOutOfRange {
parent: Vec<usize>,
index: usize,
},
NoParent,
NoPreviousSibling {
path: Vec<usize>,
},
InvalidRange {
parent: Vec<usize>,
start: usize,
end: usize,
},
Range(RangeError),
}
impl From<RangeError> for BlockError {
fn from(e: RangeError) -> Self {
BlockError::Range(e)
}
}
impl fmt::Display for BlockError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BlockError::PathNotFound { path } => write!(f, "block: no node at path {path:?}"),
BlockError::IndexOutOfRange { parent, index } => {
write!(f, "block: index {index} out of range under {parent:?}")
}
BlockError::NoParent => write!(f, "block: operation requires a parent node"),
BlockError::NoPreviousSibling { path } => {
write!(f, "block: no previous sibling to join at {path:?}")
}
BlockError::InvalidRange { parent, start, end } => {
write!(f, "block: invalid range [{start},{end}) under {parent:?}")
}
BlockError::Range(e) => write!(f, "block: {e}"),
}
}
}
impl std::error::Error for BlockError {}
fn with_content(meta: &Node, content: Vec<Node>) -> Node {
Node {
node_type: meta.node_type.clone(),
attrs: meta.attrs.clone(),
marks: meta.marks.clone(),
extra: meta.extra.clone(),
content: Some(content),
text: None,
}
}
impl Node {
pub fn set_block_type(
&mut self,
path: &[usize],
new_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<(), BlockError> {
let node = self.at_block(path)?;
node.node_type = Some(new_type.into());
node.attrs = attrs;
Ok(())
}
pub fn split_block(
&mut self,
path: &[usize],
at: usize,
depth: usize,
) -> Result<(), BlockError> {
if path.is_empty() {
return Err(BlockError::NoParent);
}
let block = self.node_at(path).ok_or_else(|| BlockError::PathNotFound {
path: path.to_vec(),
})?;
let len = block.children().len();
if at > len {
return Err(BlockError::IndexOutOfRange {
parent: path.to_vec(),
index: at,
});
}
let block_mut = self.node_at_mut(path).unwrap();
let right_children = block_mut.children_mut().split_off(at);
normalize_children(block_mut.children_mut(), &NormalizeOptions::default());
let mut new_node = with_content(block_mut, right_children);
normalize_children(
new_node.content.as_mut().unwrap(),
&NormalizeOptions::default(),
);
let mut cur = path.to_vec();
for _ in 0..depth {
if cur.len() < 2 {
break; }
let pidx = *cur.last().unwrap();
let ppath = &cur[..cur.len() - 1];
let parent = self.node_at_mut(ppath).unwrap();
let following = parent.children_mut().split_off(pidx + 1);
let mut content = Vec::with_capacity(following.len() + 1);
content.push(new_node);
content.extend(following);
new_node = with_content(parent, content);
cur.truncate(cur.len() - 1);
}
let insert_idx = *cur.last().unwrap() + 1;
let host = self.node_at_mut(&cur[..cur.len() - 1]).unwrap();
host.insert_child(insert_idx, new_node);
Ok(())
}
pub fn split_block_at(
&mut self,
path: &[usize],
pos: Position,
depth: usize,
) -> Result<(), BlockError> {
if path.is_empty() {
return Err(BlockError::NoParent);
}
let at = {
let block = self
.node_at_mut(path)
.ok_or_else(|| BlockError::PathNotFound {
path: path.to_vec(),
})?;
ensure_boundary(block.children_mut(), pos)?
};
self.split_block(path, at, depth)
}
pub fn join_blocks(&mut self, parent: &[usize], index: usize) -> Result<(), BlockError> {
if index == 0 {
let mut path = parent.to_vec();
path.push(0);
return Err(BlockError::NoPreviousSibling { path });
}
let parent_node = self
.node_at_mut(parent)
.ok_or_else(|| BlockError::PathNotFound {
path: parent.to_vec(),
})?;
let children = match parent_node.content.as_mut() {
Some(c) if index < c.len() => c,
_ => {
return Err(BlockError::IndexOutOfRange {
parent: parent.to_vec(),
index,
})
}
};
let right = children.remove(index);
if let Some(rc) = right.content {
if !rc.is_empty() {
let left = &mut children[index - 1];
left.children_mut().extend(rc);
normalize_children(left.children_mut(), &NormalizeOptions::default());
}
}
Ok(())
}
pub fn wrap(
&mut self,
path: &[usize],
wrapper_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<(), BlockError> {
self.wrap_range(&BlockRange::single(path), wrapper_type, attrs)
}
pub fn wrap_range(
&mut self,
range: &BlockRange,
wrapper_type: impl Into<String>,
attrs: Option<Map<String, Value>>,
) -> Result<(), BlockError> {
let parent = self
.node_at_mut(&range.parent)
.ok_or_else(|| BlockError::PathNotFound {
path: range.parent.clone(),
})?;
let children = parent.children_mut();
if range.start > range.end || range.end > children.len() {
return Err(BlockError::InvalidRange {
parent: range.parent.clone(),
start: range.start,
end: range.end,
});
}
let run: Vec<Node> = children
.splice(range.start..range.end, std::iter::empty())
.collect();
let wrapper = Node {
node_type: Some(wrapper_type.into()),
attrs,
content: Some(run),
..Node::default()
};
children.insert(range.start, wrapper);
Ok(())
}
pub fn lift(&mut self, path: &[usize]) -> Result<(), BlockError> {
let n = path.len();
if n < 2 {
return Err(BlockError::NoParent);
}
self.node_at(path).ok_or_else(|| BlockError::PathNotFound {
path: path.to_vec(),
})?;
let child_idx = path[n - 1];
let parent_idx = path[n - 2];
let parent = self.node_at_mut(&path[..n - 1]).unwrap();
let mut tail = parent.children_mut().split_off(child_idx);
let moved = tail.remove(0);
let right_children = tail;
let left_children = std::mem::take(parent.content.as_mut().unwrap());
let mut insert: Vec<Node> = Vec::with_capacity(3);
if !left_children.is_empty() {
insert.push(with_content(parent, left_children));
}
insert.push(moved);
if !right_children.is_empty() {
insert.push(with_content(parent, right_children));
}
let gp = self.node_at_mut(&path[..n - 2]).unwrap();
gp.children_mut().splice(parent_idx..parent_idx + 1, insert);
Ok(())
}
fn at_block(&mut self, path: &[usize]) -> Result<&mut Node, BlockError> {
self.node_at_mut(path)
.ok_or_else(|| BlockError::PathNotFound {
path: path.to_vec(),
})
}
}