Improve docs and compare with alternatives
This commit is contained in:
parent
5962feb90a
commit
3d382ad741
14 changed files with 106 additions and 69 deletions
|
|
@ -18,18 +18,16 @@ use crate::{
|
|||
utils::string_builder::StringBuilder,
|
||||
};
|
||||
|
||||
/// A text document and a sequence of operations that can be applied to the text
|
||||
/// document. `EditedText` supports merging two sequences of operations using
|
||||
/// the principles of Operational Transformation.
|
||||
/// A text document with a sequence of operations derived from diffing it
|
||||
/// against an updated version. Supports merging two `EditedText` instances
|
||||
/// (from the same original) via Operational Transformation.
|
||||
///
|
||||
/// It's mainly created through the `from_strings` method, then merged with
|
||||
/// another `EditedText` derived from the same original text and then applied to
|
||||
/// the original text to get the reconciled text of concurrent edits.
|
||||
/// Created via `from_strings`, `from_strings_with_tokenizer`, or `from_diff`,
|
||||
/// then merged with another `EditedText` and applied to get the reconciled
|
||||
/// text.
|
||||
///
|
||||
/// In addition to text and operations, it also keeps track of cursor positions
|
||||
/// in the original text. The cursor positions are updated when the operations
|
||||
/// are applied, so that the cursor positions can be used to restore the
|
||||
/// cursor positions in the updated text.
|
||||
/// Also tracks cursor positions from the updated text, repositioning them
|
||||
/// when operations are applied.
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct EditedText<'a, T>
|
||||
|
|
@ -43,12 +41,8 @@ where
|
|||
}
|
||||
|
||||
impl<'a> EditedText<'a, String> {
|
||||
/// Create an `EditedText` from the given original (old) and updated (new)
|
||||
/// strings. The returned `EditedText` represents the changes from the
|
||||
/// original to the updated text. When the return value is applied to
|
||||
/// the original text, it will result in the updated text. The default
|
||||
/// word tokenizer is used to tokenize the text which splits the text on
|
||||
/// whitespaces.
|
||||
/// Create an `EditedText` from the given original and updated strings.
|
||||
/// Uses the default word tokenizer (splits on word boundaries).
|
||||
#[must_use]
|
||||
pub fn from_strings(original: &'a str, updated: &TextWithCursors) -> Self {
|
||||
Self::from_strings_with_tokenizer(original, updated, &*BuiltinTokenizer::Word)
|
||||
|
|
@ -59,11 +53,8 @@ impl<'a, T> EditedText<'a, T>
|
|||
where
|
||||
T: PartialEq + Clone + Debug,
|
||||
{
|
||||
/// Create an `EditedText` from the given original (old) and updated (new)
|
||||
/// strings. The returned `EditedText` represents the changes from the
|
||||
/// original to the updated text. When the return value is applied to
|
||||
/// the original text, it will result in the updated text. The tokenizer
|
||||
/// function is used to tokenize the text.
|
||||
/// Create an `EditedText` from the given original and updated strings
|
||||
/// using the provided tokenizer.
|
||||
pub fn from_strings_with_tokenizer(
|
||||
original: &'a str,
|
||||
updated: &TextWithCursors,
|
||||
|
|
@ -110,7 +101,7 @@ where
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if there's an integer overflow (in i64) when calculating new
|
||||
/// Panics if there's an integer overflow (in isize) when calculating new
|
||||
/// cursor positions.
|
||||
#[must_use]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
|
|
@ -280,7 +271,7 @@ where
|
|||
/// Apply the operations to the text and return the resulting text in chunks
|
||||
/// together with the provenance describing where each chunk came from.
|
||||
///
|
||||
/// The result includes deleted spans as well.
|
||||
/// Returns all spans including deletions (not present in the merged text).
|
||||
///
|
||||
/// ```
|
||||
/// use reconcile_text::{History, SpanWithHistory, BuiltinTokenizer, reconcile};
|
||||
|
|
@ -422,7 +413,7 @@ where
|
|||
result
|
||||
}
|
||||
|
||||
/// Deserialize an `EditedText` from a change list and the original text.
|
||||
/// Reconstruct an `EditedText` from a diff and the original text.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
|
|
|
|||
|
|
@ -46,9 +46,8 @@ impl<T> Operation<T>
|
|||
where
|
||||
T: PartialEq + Clone + Debug,
|
||||
{
|
||||
/// Creates an equal operation with the given index.
|
||||
/// This operation is used to indicate that the text at the given index
|
||||
/// is unchanged.
|
||||
/// Creates an equal (retain) operation starting at the given character
|
||||
/// offset in the original text.
|
||||
pub fn create_equal(order: usize, length: usize) -> Self {
|
||||
Operation::Equal {
|
||||
order,
|
||||
|
|
@ -69,13 +68,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates an insert operation with the given index and text.
|
||||
/// Creates an insert operation at the given character offset with the
|
||||
/// given tokens.
|
||||
pub fn create_insert(order: usize, text: Vec<Token<T>>) -> Self {
|
||||
Operation::Insert { order, text }
|
||||
}
|
||||
|
||||
/// Creates a delete operation with the given index and number of
|
||||
/// to-be-deleted characters.
|
||||
/// Creates a delete operation at the given character offset for the
|
||||
/// specified number of characters.
|
||||
pub fn create_delete(order: usize, deleted_character_count: usize) -> Self {
|
||||
Operation::Delete {
|
||||
order,
|
||||
|
|
@ -179,8 +179,8 @@ where
|
|||
builder
|
||||
}
|
||||
|
||||
/// Returns the number of affected characters. It is always greater than 0
|
||||
/// because empty operations cannot be created.
|
||||
/// Returns the number of affected characters. May be 0 after
|
||||
/// `merge_operations`.
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Operation::Equal { length, .. } => *length,
|
||||
|
|
@ -192,10 +192,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Merges the operation with the given context, producing a new operation
|
||||
/// and updating the context. This implements a comples FSM that handles
|
||||
/// the merging of operations in a way that is consistent with the text.
|
||||
/// The contexts are updated in-place.
|
||||
/// Adjusts this operation based on `previous_operation` from the other side
|
||||
/// to avoid duplicating or conflicting changes. Updates
|
||||
/// `previous_operation` in-place.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn merge_operations(self, previous_operation: &mut Option<Self>) -> Operation<T> {
|
||||
let operation = self;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue