diff --git a/src/operation_transformation.rs b/src/operation_transformation.rs index c971229..5e00ae6 100644 --- a/src/operation_transformation.rs +++ b/src/operation_transformation.rs @@ -110,8 +110,8 @@ mod test { }, // inside of "s|ample" because "text" got replaced by "sample" CursorPosition { id: 3, - char_index: 42 - }, // before "cursor movements" + char_index: 30 + }, // after "complex sample" ] ) ); diff --git a/src/operation_transformation/edited_text.rs b/src/operation_transformation/edited_text.rs index 10a0133..d081c27 100644 --- a/src/operation_transformation/edited_text.rs +++ b/src/operation_transformation/edited_text.rs @@ -161,41 +161,47 @@ where let original_length = operation.len() as i64; let result = match side { Side::Left => { - let result = operation.merge_operations_with_context( - order, - &mut last_other_op, - maybe_other_operation, - ); + let result = operation.merge_operations_with_context(order, &mut last_other_op); - if let Some( - ref op @ (OrderedOperation { - operation: Operation::Insert { .. }, - .. - } - | OrderedOperation { - operation: Operation::Equal { .. }, - .. - }), - ) = result + if let ref op @ (OrderedOperation { + operation: Operation::Insert { .. }, + .. + } + | OrderedOperation { + operation: Operation::Equal { .. }, + .. + }) = result { - let mut shift = merged_length as i64 - seen_left_length as i64; - if !matches!( - op, - OrderedOperation { - operation: Operation::Equal { .. }, - .. - } - ) { - shift += op.operation.len() as i64 - original_length; - } + println!( + "merrged_length: {}, seen_left_length: {}, op len {}, original_length \ + {}", + merged_length, + seen_left_length, + op.operation.len(), + original_length + ); + let mut shift = merged_length as i64 + // - last_other_op + // .map(|op| op.operation.len() as i64) + // .unwrap_or(0) as i64 + - seen_left_length as i64; + // if !matches!( + // op, + // OrderedOperation { + // operation: Operation::Equal { .. }, + // .. + // } + // ) { + shift += op.operation.len() as i64 - original_length; + // } while let Some(cursor) = left_cursors.next_if(|cursor| { cursor.char_index <= seen_left_length + original_length as usize }) { - merged_cursors.push(cursor.with_index( - (merged_length as i64).max(cursor.char_index as i64 + shift) - as usize, - )); + println!("cursor {}", cursor.char_index); + merged_cursors.push( + cursor.with_index((cursor.char_index as i64 + shift) as usize), + ); } } @@ -204,46 +210,53 @@ where } maybe_left_op = left_iter.next(); - last_left_op = result.clone(); + last_left_op = Some(result.clone()); result } Side::Right => { - let result = operation.merge_operations_with_context( - order, - &mut last_other_op, - maybe_other_operation, - ); + let result = operation.merge_operations_with_context(order, &mut last_other_op); - if let Some( - ref op @ (OrderedOperation { - operation: Operation::Insert { .. }, - .. - } - | OrderedOperation { - operation: Operation::Equal { .. }, - .. - }), - ) = result + if let ref op @ (OrderedOperation { + operation: Operation::Insert { .. }, + .. + } + | OrderedOperation { + operation: Operation::Equal { .. }, + .. + }) = result { - let mut shift = merged_length as i64 - seen_right_length as i64; - if !matches!( - op, - OrderedOperation { - operation: Operation::Equal { .. }, - .. - } - ) { - shift += op.operation.len() as i64 - original_length; - } + println!( + "merrged_length: {}, seen_left_length: {}, op len {}, original_length \ + {}", + merged_length, + seen_left_length, + op.operation.len(), + original_length + ); + let mut shift = merged_length as i64 + // - last_other_op + // .map(|op| op.operation.len() as i64) + // .unwrap_or(0) as i64 + - seen_right_length as i64; + // if !matches!( + // op, + // OrderedOperation { + // operation: Operation::Equal { .. }, + // .. + // } + // ) { + shift += op.operation.len() as i64 - original_length; + // } while let Some(cursor) = right_cursors.next_if(|cursor| { cursor.char_index <= seen_right_length + original_length as usize }) { - merged_cursors.push(cursor.with_index( - (merged_length as i64).max(cursor.char_index as i64 + shift) - as usize, - )); + println!("cursor {}", cursor.char_index); + + merged_cursors.push( + cursor.with_index((cursor.char_index as i64 + shift) as usize), + ); } } @@ -252,7 +265,7 @@ where } maybe_right_op = right_iter.next(); - last_right_op = result.clone(); + last_right_op = Some(result.clone()); result } @@ -260,17 +273,15 @@ where println!(" = {result:?}"); - if let Some(operation) = result { - if operation.operation.len() == 0 { - continue; - } - - if is_advancing_operation { - merged_length += operation.operation.len(); - } - - merged_operations.push(operation); + if result.operation.len() == 0 { + continue; } + + if is_advancing_operation { + merged_length += result.operation.len(); + } + + merged_operations.push(result); } for cursor in left_cursors.chain(right_cursors) { diff --git a/src/operation_transformation/operation.rs b/src/operation_transformation/operation.rs index fbaf786..c0b2f5c 100644 --- a/src/operation_transformation/operation.rs +++ b/src/operation_transformation/operation.rs @@ -46,66 +46,45 @@ where /// Creates an equal operation with the given index. /// This operation is used to indicate that the text at the given index /// is unchanged. - pub fn create_equal(length: usize) -> Option { - Some(Operation::Equal { + pub fn create_equal(length: usize) -> Self { + Operation::Equal { length, #[cfg(debug_assertions)] text: None, - }) + } } - pub fn create_equal_with_text(text: String) -> Option { - if text.is_empty() { - return None; - } - - Some(Operation::Equal { + pub fn create_equal_with_text(text: String) -> Self { + Operation::Equal { length: text.chars().count(), #[cfg(debug_assertions)] text: Some(text), - }) + } } /// Creates an insert operation with the given index and text. - /// If the text is empty (meaning that the operation would be a no-op), - /// returns None. - pub fn create_insert(text: Vec>) -> Option { - if text.is_empty() { - return None; - } - - Some(Operation::Insert { text }) - } + pub fn create_insert(text: Vec>) -> Self { Operation::Insert { text } } /// Creates a delete operation with the given index and number of - /// to-be-deleted characters. If the operation would delete 0 (meaning - /// that the operation would be a no-op), returns None. - pub fn create_delete(deleted_character_count: usize) -> Option { - if deleted_character_count == 0 { - return None; - } - - Some(Operation::Delete { + /// to-be-deleted characters. + pub fn create_delete(deleted_character_count: usize) -> Self { + Operation::Delete { deleted_character_count, #[cfg(debug_assertions)] deleted_text: None, - }) + } } - pub fn create_delete_with_text(text: String) -> Option { - if text.is_empty() { - return None; - } - - Some(Operation::Delete { + pub fn create_delete_with_text(text: String) -> Self { + Operation::Delete { deleted_character_count: text.chars().count(), #[cfg(debug_assertions)] deleted_text: Some(text), - }) + } } /// Applies the operation to the given `StringBuilder`, returning the @@ -181,12 +160,8 @@ where self, order: usize, previous_operation: &mut Option>, - other_operation: Option>, - ) -> Option> { - println!( - "mergin: {self} (order {order}) - previous: {previous_operation:?} - other: \ - {other_operation:?}" - ); + ) -> OrderedOperation { + println!("mergin: {self} (order {order}) - previous: {previous_operation:?}"); let operation = self; match (operation, previous_operation) { @@ -209,7 +184,10 @@ where let trimmed_operation = Operation::create_insert(text[offset_in_tokens..].to_vec()); - trimmed_operation.map(|operation| OrderedOperation { order, operation }) + OrderedOperation { + order, + operation: trimmed_operation, + } } ( @@ -248,10 +226,10 @@ where #[cfg(not(debug_assertions))] let updated_delete = Operation::create_delete(new_length); - updated_delete.map(|operation| OrderedOperation { + OrderedOperation { order: order + overlap, - operation, - }) + operation: updated_delete, + } } ( @@ -268,19 +246,6 @@ where }, ), ) => { - if let Some(other_operation) = other_operation { - if matches!(other_operation.operation, Operation::Equal { .. }) - && operation.len() == other_operation.operation.len() - && order == other_operation.order - { - println!(" !!!equal to next"); - return Some(OrderedOperation { - order, - operation: Operation::create_equal(0).unwrap(), - }); - } - } - let last_delete_end_index = last_delete.order + last_delete.operation.len(); let overlap = @@ -299,30 +264,32 @@ where #[cfg(not(debug_assertions))] let updated_equal = Operation::create_equal((length as i64 - overlap) as usize); - updated_equal.map(|operation| OrderedOperation { + OrderedOperation { order: order + overlap as usize, - operation, - }) - } - - (operation @ Operation::Equal { .. }, _) => { - if let Some(other_operation) = other_operation { - if matches!(other_operation.operation, Operation::Equal { .. }) - && operation.len() == other_operation.operation.len() - && order == other_operation.order - { - println!(" !!!equal to next"); - Operation::create_equal(0) - } else { - Some(operation) - } - } else { - Some(operation) + operation: updated_equal, } - .map(|operation| OrderedOperation { order, operation }) } - (operation, _) => Some(OrderedOperation { order, operation }), + ( + operation @ Operation::Equal { .. }, + Some( + last_equal @ OrderedOperation { + operation: Operation::Equal { .. }, + .. + }, + ), + ) => OrderedOperation { + order, + operation: if operation.len() == last_equal.operation.len() + && order == last_equal.order + { + Operation::create_equal(0) + } else { + operation + }, + }, + + (operation, _) => OrderedOperation { order, operation }, } } } @@ -404,9 +371,8 @@ mod tests { #[test] fn test_apply_delete_with_create() { let builder = StringBuilder::new("hello world"); - let delete_operation = - Operation::<()>::create_delete_with_text("hello ".to_owned()).unwrap(); - let retain_operation = Operation::<()>::create_equal(5).unwrap(); + let delete_operation = Operation::<()>::create_delete_with_text("hello ".to_owned()); + let retain_operation = Operation::<()>::create_equal(5); let mut builder = delete_operation.apply(builder); builder = retain_operation.apply(builder); @@ -418,8 +384,8 @@ mod tests { fn test_apply_insert() { let builder = StringBuilder::new("hello"); - let retain_operation = Operation::<()>::create_equal(5).unwrap(); - let insert_operation = Operation::create_insert(vec![" my friend".into()]).unwrap(); + let retain_operation = Operation::<()>::create_equal(5); + let insert_operation = Operation::create_insert(vec![" my friend".into()]); let mut builder = retain_operation.apply(builder); builder = insert_operation.apply(builder); diff --git a/src/operation_transformation/utils/cook_operations.rs b/src/operation_transformation/utils/cook_operations.rs index d03ea51..0e21de7 100644 --- a/src/operation_transformation/utils/cook_operations.rs +++ b/src/operation_transformation/utils/cook_operations.rs @@ -11,31 +11,37 @@ where { let mut order = 0; // this is the start index of the operation on the original text - raw_operations.into_iter().filter_map(move |raw_operation| { + raw_operations.into_iter().map(move |raw_operation| { let length = raw_operation.original_text_length(); match raw_operation { RawOperation::Equal(..) => { - let op = if cfg!(debug_assertions) { - Operation::create_equal_with_text(raw_operation.get_original_text()) - } else { - Operation::create_equal(length) - } - .map(|operation| OrderedOperation { order, operation }); + let op = OrderedOperation { + order, + operation: if cfg!(debug_assertions) { + Operation::create_equal_with_text(raw_operation.get_original_text()) + } else { + Operation::create_equal(length) + }, + }; order += length; op } - RawOperation::Insert(tokens) => Operation::create_insert(tokens) - .map(|operation| OrderedOperation { order, operation }), + RawOperation::Insert(tokens) => OrderedOperation { + order, + operation: Operation::create_insert(tokens), + }, RawOperation::Delete(..) => { - let op = if cfg!(debug_assertions) { - Operation::create_delete_with_text(raw_operation.get_original_text()) - } else { - Operation::create_delete(length) - } - .map(|operation| OrderedOperation { order, operation }); + let op = OrderedOperation { + order, + operation: if cfg!(debug_assertions) { + Operation::create_delete_with_text(raw_operation.get_original_text()) + } else { + Operation::create_delete(length) + }, + }; order += length; diff --git a/src/utils/string_builder.rs b/src/utils/string_builder.rs index 63aebdc..5659d3e 100644 --- a/src/utils/string_builder.rs +++ b/src/utils/string_builder.rs @@ -1,4 +1,3 @@ -use core::ops::Range; use std::iter::Iterator; /// A helper for building a string in-order based on an original string and a diff --git a/tests/examples/deletes.yml b/tests/examples/deletes.yml index d8c2819..3476e95 100644 --- a/tests/examples/deletes.yml +++ b/tests/examples/deletes.yml @@ -28,7 +28,7 @@ expected: long small parent: long run of text where one barely has no changes but has cursors left: long| run of tex|t where one barely has no |changes but has |cursors right: long run one barely has no changes cursors -expected: long| run| one barely has no |changes |cursors +expected: long| ru|n one barely has no |changes |cursors --- parent: long text where the cursor has to be clamped after delete diff --git a/tests/examples/replacing.yml b/tests/examples/replacing.yml index cea57b8..15126d8 100644 --- a/tests/examples/replacing.yml +++ b/tests/examples/replacing.yml @@ -2,7 +2,7 @@ parent: original_1 original_2 original_3 left: original_1 edit_1| original_3 right: original_1 original_2| edit_2 -expected: original_1 edit_1|| edit_2 +expected: original_1| edit_1| edit_2 --- # Both replace the same token with the same value diff --git a/tests/examples/various.yml b/tests/examples/various.yml index 7a87e4e..4576edc 100644 --- a/tests/examples/various.yml +++ b/tests/examples/various.yml @@ -43,7 +43,7 @@ expected: Send the |detailed |quarterly |detailed report to the |entire |team parent: Ready, Set go left: Ready! Set go| right: Ready, Set, go!| -expected: Ready! Set, go!|| +expected: Ready!| Set, go!| --- parent: "Total: $100" @@ -67,7 +67,7 @@ expected: market| placemarket|space parent: A B C D left: A X B D| right: A B Y| -expected: A X B Y|| +expected: A X B| Y| --- parent: Please submit your assignment by Friday