diff --git a/shared-lib/lib-ot/src/core/document/document.rs b/shared-lib/lib-ot/src/core/document/document.rs index 4200d4e398..9d1d071f95 100644 --- a/shared-lib/lib-ot/src/core/document/document.rs +++ b/shared-lib/lib-ot/src/core/document/document.rs @@ -1,25 +1,25 @@ use crate::core::document::position::Position; -use crate::core::{DeleteOperation, DocumentOperation, InsertOperation, NodeAttributes, NodeData, TextEditOperation, Transaction, UpdateOperation}; +use crate::core::{ + DeleteOperation, DocumentOperation, InsertOperation, NodeAttributes, NodeData, TextEditOperation, Transaction, + UpdateOperation, +}; use indextree::{Arena, NodeId}; pub struct DocumentTree { - arena: Arena, - root: NodeId, + 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: Arena::new(), - root, - } + DocumentTree { arena, root } } pub fn node_at_path(&self, position: &Position) -> Option { if position.is_empty() { - return None; + return Some(self.root); } let mut iterate_node = self.root; @@ -93,7 +93,7 @@ impl DocumentTree { } fn apply_op(&mut self, op: &DocumentOperation) { - match op { + match op { DocumentOperation::Insert(op) => self.apply_insert(op), DocumentOperation::Update(op) => self.apply_update(op), DocumentOperation::Delete(op) => self.apply_delete(op), @@ -106,12 +106,18 @@ impl DocumentTree { 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 { - self.insert_child_at_index(parent_node, last_index, &op.nodes); + 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 && insert_children.len() == 0 { + if index == 0 && parent.children(&self.arena).next().is_none() { for id in insert_children { parent.append(*id, &mut self.arena); } diff --git a/shared-lib/lib-ot/src/core/document/document_operation.rs b/shared-lib/lib-ot/src/core/document/document_operation.rs index d5c60cc45d..7b7b0c4a62 100644 --- a/shared-lib/lib-ot/src/core/document/document_operation.rs +++ b/shared-lib/lib-ot/src/core/document/document_operation.rs @@ -1,6 +1,5 @@ use crate::core::document::position::Position; -use crate::core::{NodeAttributes, TextDelta}; -use indextree::NodeId; +use crate::core::{NodeAttributes, NodeData, TextDelta}; pub enum DocumentOperation { Insert(InsertOperation), @@ -36,7 +35,7 @@ impl DocumentOperation { pub struct InsertOperation { pub path: Position, - pub nodes: Vec, + pub nodes: Vec, } pub struct UpdateOperation { @@ -47,7 +46,7 @@ pub struct UpdateOperation { pub struct DeleteOperation { pub path: Position, - pub nodes: Vec, + pub nodes: Vec, } pub struct TextEditOperation { diff --git a/shared-lib/lib-ot/src/core/document/mod.rs b/shared-lib/lib-ot/src/core/document/mod.rs index 968c78bc2b..b019cb0f71 100644 --- a/shared-lib/lib-ot/src/core/document/mod.rs +++ b/shared-lib/lib-ot/src/core/document/mod.rs @@ -9,4 +9,5 @@ pub use attributes::*; pub use document::*; pub use document_operation::*; pub use node::*; +pub use position::*; pub use transaction::*; diff --git a/shared-lib/lib-ot/src/core/document/node.rs b/shared-lib/lib-ot/src/core/document/node.rs index 2fa9706ce3..a3ec5e729a 100644 --- a/shared-lib/lib-ot/src/core/document/node.rs +++ b/shared-lib/lib-ot/src/core/document/node.rs @@ -1,6 +1,7 @@ +use crate::core::{NodeAttributes, TextDelta}; use std::cell::RefCell; -use crate::core::{TextDelta, NodeAttributes}; +#[derive(Clone)] pub struct NodeData { pub node_type: String, pub attributes: RefCell, diff --git a/shared-lib/lib-ot/src/core/document/transaction.rs b/shared-lib/lib-ot/src/core/document/transaction.rs index c75cb16bea..875b1bebdf 100644 --- a/shared-lib/lib-ot/src/core/document/transaction.rs +++ b/shared-lib/lib-ot/src/core/document/transaction.rs @@ -1,17 +1,14 @@ -use crate::core::{DocumentOperation, DocumentTree}; +use crate::core::document::position::Position; +use crate::core::{DeleteOperation, DocumentOperation, DocumentTree, InsertOperation, NodeData}; pub struct Transaction { pub operations: Vec, } impl Transaction { - fn new(operations: Vec) -> Transaction { - Transaction { - operations, - } + Transaction { operations } } - } pub struct TransactionBuilder<'a> { @@ -23,17 +20,42 @@ impl<'a> TransactionBuilder<'a> { pub fn new(document: &'a DocumentTree) -> TransactionBuilder { TransactionBuilder { document, - operations: Vec::new() + operations: Vec::new(), } } + pub fn insert_nodes(&mut self, path: &Position, nodes: &[NodeData]) { + self.push(DocumentOperation::Insert(InsertOperation { + path: path.clone(), + nodes: nodes.to_vec(), + })); + } + + pub fn delete_node(&mut self, path: &Position) { + self.delete_nodes(path, 1); + } + + pub fn delete_nodes(&mut self, path: &Position, length: usize) { + let mut node = self.document.node_at_path(path).unwrap(); + let mut deleted_nodes: Vec = Vec::new(); + + for _ in 0..length { + let data = self.document.arena.get(node).unwrap(); + deleted_nodes.push(data.get().clone()); + node = node.following_siblings(&self.document.arena).next().unwrap(); + } + + self.operations.push(DocumentOperation::Delete(DeleteOperation { + path: path.clone(), + nodes: deleted_nodes, + })) + } + pub fn push(&mut self, op: DocumentOperation) { self.operations.push(op); } pub fn finalize(self) -> Transaction { - Transaction { - operations: self.operations, - } + Transaction::new(self.operations) } } diff --git a/shared-lib/lib-ot/tests/main.rs b/shared-lib/lib-ot/tests/main.rs index ecfdfb4da2..8ed7c8a74e 100644 --- a/shared-lib/lib-ot/tests/main.rs +++ b/shared-lib/lib-ot/tests/main.rs @@ -1,4 +1,4 @@ -use lib_ot::core::{DocumentTree, TransactionBuilder}; +use lib_ot::core::{DocumentTree, NodeData, Position, TransactionBuilder}; #[test] fn main() { @@ -9,7 +9,8 @@ fn main() { #[test] fn test_documents() { let mut document = DocumentTree::new(); - let tb = TransactionBuilder::new(&document); + let mut tb = TransactionBuilder::new(&document); + tb.insert_nodes(&Position(vec![0]), &vec![NodeData::new("type")]); let transaction = tb.finalize(); document.apply(transaction); }