document_operation.rs 6.6 KB

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