document_operation.rs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. use crate::core::document::position::Position;
  2. use crate::core::{NodeAttributes, NodeSubTree, TextDelta};
  3. #[derive(Clone, serde::Serialize, serde::Deserialize)]
  4. #[serde(tag = "op")]
  5. pub enum DocumentOperation {
  6. #[serde(rename = "insert")]
  7. Insert {
  8. path: Position,
  9. nodes: Vec<Box<NodeSubTree>>,
  10. },
  11. #[serde(rename = "update")]
  12. Update {
  13. path: Position,
  14. attributes: NodeAttributes,
  15. #[serde(rename = "oldAttributes")]
  16. old_attributes: NodeAttributes,
  17. },
  18. #[serde(rename = "delete")]
  19. Delete {
  20. path: Position,
  21. nodes: Vec<Box<NodeSubTree>>,
  22. },
  23. #[serde(rename = "text-edit")]
  24. TextEdit {
  25. path: Position,
  26. delta: TextDelta,
  27. inverted: TextDelta,
  28. },
  29. }
  30. impl DocumentOperation {
  31. pub fn path(&self) -> &Position {
  32. match self {
  33. DocumentOperation::Insert { path, .. } => path,
  34. DocumentOperation::Update { path, .. } => path,
  35. DocumentOperation::Delete { path, .. } => path,
  36. DocumentOperation::TextEdit { path, .. } => path,
  37. }
  38. }
  39. pub fn invert(&self) -> DocumentOperation {
  40. match self {
  41. DocumentOperation::Insert { path, nodes } => DocumentOperation::Delete {
  42. path: path.clone(),
  43. nodes: nodes.clone(),
  44. },
  45. DocumentOperation::Update {
  46. path,
  47. attributes,
  48. old_attributes,
  49. } => DocumentOperation::Update {
  50. path: path.clone(),
  51. attributes: old_attributes.clone(),
  52. old_attributes: attributes.clone(),
  53. },
  54. DocumentOperation::Delete { path, nodes } => DocumentOperation::Insert {
  55. path: path.clone(),
  56. nodes: nodes.clone(),
  57. },
  58. DocumentOperation::TextEdit { path, delta, inverted } => DocumentOperation::TextEdit {
  59. path: path.clone(),
  60. delta: inverted.clone(),
  61. inverted: delta.clone(),
  62. },
  63. }
  64. }
  65. pub fn clone_with_new_path(&self, path: Position) -> DocumentOperation {
  66. match self {
  67. DocumentOperation::Insert { nodes, .. } => DocumentOperation::Insert {
  68. path,
  69. nodes: nodes.clone(),
  70. },
  71. DocumentOperation::Update {
  72. attributes,
  73. old_attributes,
  74. ..
  75. } => DocumentOperation::Update {
  76. path,
  77. attributes: attributes.clone(),
  78. old_attributes: old_attributes.clone(),
  79. },
  80. DocumentOperation::Delete { nodes, .. } => DocumentOperation::Delete {
  81. path,
  82. nodes: nodes.clone(),
  83. },
  84. DocumentOperation::TextEdit { delta, inverted, .. } => DocumentOperation::TextEdit {
  85. path,
  86. delta: delta.clone(),
  87. inverted: inverted.clone(),
  88. },
  89. }
  90. }
  91. pub fn transform(a: &DocumentOperation, b: &DocumentOperation) -> DocumentOperation {
  92. match a {
  93. DocumentOperation::Insert { path: a_path, nodes } => {
  94. let new_path = Position::transform(a_path, b.path(), nodes.len() as i64);
  95. b.clone_with_new_path(new_path)
  96. }
  97. DocumentOperation::Delete { path: a_path, nodes } => {
  98. let new_path = Position::transform(a_path, b.path(), nodes.len() as i64);
  99. b.clone_with_new_path(new_path)
  100. }
  101. _ => b.clone(),
  102. }
  103. }
  104. }
  105. #[cfg(test)]
  106. mod tests {
  107. use crate::core::{Delta, DocumentOperation, NodeAttributes, NodeSubTree, Position};
  108. #[test]
  109. fn test_transform_path_1() {
  110. assert_eq!(
  111. { Position::transform(&Position(vec![0, 1]), &Position(vec![0, 1]), 1) }.0,
  112. vec![0, 2]
  113. );
  114. }
  115. #[test]
  116. fn test_transform_path_2() {
  117. assert_eq!(
  118. { Position::transform(&Position(vec![0, 1]), &Position(vec![0, 2]), 1) }.0,
  119. vec![0, 3]
  120. );
  121. }
  122. #[test]
  123. fn test_transform_path_3() {
  124. assert_eq!(
  125. { Position::transform(&Position(vec![0, 1]), &Position(vec![0, 2, 7, 8, 9]), 1) }.0,
  126. vec![0, 3, 7, 8, 9]
  127. );
  128. }
  129. #[test]
  130. fn test_transform_path_not_changed() {
  131. assert_eq!(
  132. { Position::transform(&Position(vec![0, 1, 2]), &Position(vec![0, 0, 7, 8, 9]), 1) }.0,
  133. vec![0, 0, 7, 8, 9]
  134. );
  135. assert_eq!(
  136. { Position::transform(&Position(vec![0, 1, 2]), &Position(vec![0, 1]), 1) }.0,
  137. vec![0, 1]
  138. );
  139. assert_eq!(
  140. { Position::transform(&Position(vec![1, 1]), &Position(vec![1, 0]), 1) }.0,
  141. vec![1, 0]
  142. );
  143. }
  144. #[test]
  145. fn test_transform_delta() {
  146. assert_eq!(
  147. { Position::transform(&Position(vec![0, 1]), &Position(vec![0, 1]), 5) }.0,
  148. vec![0, 6]
  149. );
  150. }
  151. #[test]
  152. fn test_serialize_insert_operation() {
  153. let insert = DocumentOperation::Insert {
  154. path: Position(vec![0, 1]),
  155. nodes: vec![Box::new(NodeSubTree::new("text"))],
  156. };
  157. let result = serde_json::to_string(&insert).unwrap();
  158. assert_eq!(
  159. result,
  160. r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text","attributes":{}}]}"#
  161. );
  162. }
  163. #[test]
  164. fn test_serialize_insert_sub_trees() {
  165. let insert = DocumentOperation::Insert {
  166. path: Position(vec![0, 1]),
  167. nodes: vec![Box::new(NodeSubTree {
  168. node_type: "text".into(),
  169. attributes: NodeAttributes::new(),
  170. delta: None,
  171. children: vec![Box::new(NodeSubTree::new("text"))],
  172. })],
  173. };
  174. let result = serde_json::to_string(&insert).unwrap();
  175. assert_eq!(
  176. result,
  177. r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text","attributes":{},"children":[{"type":"text","attributes":{}}]}]}"#
  178. );
  179. }
  180. #[test]
  181. fn test_serialize_update_operation() {
  182. let insert = DocumentOperation::Update {
  183. path: Position(vec![0, 1]),
  184. attributes: NodeAttributes::new(),
  185. old_attributes: NodeAttributes::new(),
  186. };
  187. let result = serde_json::to_string(&insert).unwrap();
  188. assert_eq!(
  189. result,
  190. r#"{"op":"update","path":[0,1],"attributes":{},"oldAttributes":{}}"#
  191. );
  192. }
  193. #[test]
  194. fn test_serialize_text_edit_operation() {
  195. let insert = DocumentOperation::TextEdit {
  196. path: Position(vec![0, 1]),
  197. delta: Delta::new(),
  198. inverted: Delta::new(),
  199. };
  200. let result = serde_json::to_string(&insert).unwrap();
  201. assert_eq!(result, r#"{"op":"text-edit","path":[0,1],"delta":[],"inverted":[]}"#);
  202. }
  203. }