use crate::core::document::position::Position; use crate::core::{ DeleteOperation, DocumentOperation, InsertOperation, NodeAttributes, NodeData, TextEditOperation, Transaction, UpdateOperation, }; use indextree::{Arena, NodeId}; pub struct DocumentTree { pub arena: Arena, pub root: NodeId, } impl DocumentTree { pub fn new() -> DocumentTree { let mut arena = Arena::new(); let root = arena.new_node(NodeData::new("root".into())); DocumentTree { arena, root } } pub fn node_at_path(&self, position: &Position) -> Option { if position.is_empty() { return Some(self.root); } let mut iterate_node = self.root; for id in &position.0 { let child = self.child_at_index_of_path(iterate_node, id.clone()); iterate_node = match child { Some(node) => node, None => return None, }; } Some(iterate_node) } pub fn path_of_node(&self, node_id: NodeId) -> Position { let mut path: Vec = Vec::new(); let mut ancestors = node_id.ancestors(&self.arena); let mut current_node = node_id; let mut parent = ancestors.next(); while parent.is_some() { let parent_node = parent.unwrap(); let counter = self.index_of_node(parent_node, current_node); path.push(counter); current_node = parent_node; parent = ancestors.next(); } Position(path) } fn index_of_node(&self, parent_node: NodeId, child_node: NodeId) -> usize { let mut counter: usize = 0; let mut children_iterator = parent_node.children(&self.arena); let mut node = children_iterator.next(); while node.is_some() { if node.unwrap() == child_node { return counter; } node = children_iterator.next(); counter += 1; } counter } fn child_at_index_of_path(&self, at_node: NodeId, index: usize) -> Option { let children = at_node.children(&self.arena); let mut counter = 0; for child in children { if counter == index { return Some(child); } counter += 1; } None } pub fn apply(&mut self, transaction: Transaction) { for op in &transaction.operations { self.apply_op(op); } } fn apply_op(&mut self, op: &DocumentOperation) { match op { DocumentOperation::Insert(op) => self.apply_insert(op), DocumentOperation::Update(op) => self.apply_update(op), DocumentOperation::Delete(op) => self.apply_delete(op), DocumentOperation::TextEdit(op) => self.apply_text_edit(op), } } fn apply_insert(&mut self, op: &InsertOperation) { let parent_path = &op.path.0[0..(op.path.0.len() - 1)]; let last_index = op.path.0[op.path.0.len() - 1]; let parent_node = self.node_at_path(&Position(parent_path.to_vec())); if let Some(parent_node) = parent_node { let mut inserted_nodes = Vec::new(); for node in &op.nodes { inserted_nodes.push(self.arena.new_node(node.clone())); } self.insert_child_at_index(parent_node, last_index, &inserted_nodes); } } fn insert_child_at_index(&mut self, parent: NodeId, index: usize, insert_children: &[NodeId]) { if index == 0 && parent.children(&self.arena).next().is_none() { for id in insert_children { parent.append(*id, &mut self.arena); } return; } let children_length = parent.children(&self.arena).fold(0, |counter, _| counter + 1); if index == children_length { for id in insert_children { parent.append(*id, &mut self.arena); } return; } let node_to_insert = self.child_at_index_of_path(parent, index).unwrap(); for id in insert_children { node_to_insert.insert_before(*id, &mut self.arena); } } fn apply_update(&self, op: &UpdateOperation) { let update_node = self.node_at_path(&op.path).unwrap(); let node_data = self.arena.get(update_node).unwrap(); let new_attributes = { let old_attributes = node_data.get().attributes.borrow(); NodeAttributes::compose(&old_attributes, &op.attributes) }; node_data.get().attributes.replace(new_attributes); } fn apply_delete(&mut self, op: &DeleteOperation) { let update_node = self.node_at_path(&op.path).unwrap(); update_node.remove_subtree(&mut self.arena); } fn apply_text_edit(&self, _op: &TextEditOperation) { unimplemented!() } }