Expose iter_changes outside the text module
This commit is contained in:
parent
d4495038a3
commit
cab87515bd
2 changed files with 111 additions and 79 deletions
|
|
@ -102,7 +102,7 @@ pub use self::udiff::{unified_diff, UnifiedDiff, UnifiedDiffHunk, UnifiedHunkHea
|
||||||
|
|
||||||
use self::utils::{upper_seq_ratio, QuickSeqRatio};
|
use self::utils::{upper_seq_ratio, QuickSeqRatio};
|
||||||
use crate::algorithms::{capture_diff_slices, get_diff_ratio, group_diff_ops};
|
use crate::algorithms::{capture_diff_slices, get_diff_ratio, group_diff_ops};
|
||||||
use crate::types::{Algorithm, Change, ChangeTag, DiffOp, DiffTag};
|
use crate::types::{Algorithm, Change, DiffOp};
|
||||||
|
|
||||||
/// A builder type config for more complex uses of [`TextDiff`].
|
/// A builder type config for more complex uses of [`TextDiff`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -374,80 +374,7 @@ impl<'old, 'new, 'bufs, T: DiffableStr + ?Sized + 'old + 'new> TextDiff<'old, 'n
|
||||||
/// up the value from the appropriate slice and also handle correct index
|
/// up the value from the appropriate slice and also handle correct index
|
||||||
/// handling.
|
/// handling.
|
||||||
pub fn iter_changes(&self, op: &DiffOp) -> impl Iterator<Item = Change<'_, T>> {
|
pub fn iter_changes(&self, op: &DiffOp) -> impl Iterator<Item = Change<'_, T>> {
|
||||||
let (tag, old_range, new_range) = op.as_tag_tuple();
|
op.iter_changes(self.old_slices(), self.new_slices())
|
||||||
let mut old_index = old_range.start;
|
|
||||||
let mut new_index = new_range.start;
|
|
||||||
let mut old_slices = &self.old_slices()[op.old_range()];
|
|
||||||
let mut new_slices = &self.new_slices()[op.new_range()];
|
|
||||||
|
|
||||||
std::iter::from_fn(move || match tag {
|
|
||||||
DiffTag::Equal => {
|
|
||||||
if let Some((&first, rest)) = old_slices.split_first() {
|
|
||||||
old_slices = rest;
|
|
||||||
old_index += 1;
|
|
||||||
new_index += 1;
|
|
||||||
Some(Change {
|
|
||||||
tag: ChangeTag::Equal,
|
|
||||||
old_index: Some(old_index - 1),
|
|
||||||
new_index: Some(new_index - 1),
|
|
||||||
value: first,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DiffTag::Delete => {
|
|
||||||
if let Some((&first, rest)) = old_slices.split_first() {
|
|
||||||
old_slices = rest;
|
|
||||||
old_index += 1;
|
|
||||||
Some(Change {
|
|
||||||
tag: ChangeTag::Delete,
|
|
||||||
old_index: Some(old_index - 1),
|
|
||||||
new_index: None,
|
|
||||||
value: first,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DiffTag::Insert => {
|
|
||||||
if let Some((&first, rest)) = new_slices.split_first() {
|
|
||||||
new_slices = rest;
|
|
||||||
new_index += 1;
|
|
||||||
Some(Change {
|
|
||||||
tag: ChangeTag::Insert,
|
|
||||||
old_index: None,
|
|
||||||
new_index: Some(new_index - 1),
|
|
||||||
value: first,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DiffTag::Replace => {
|
|
||||||
if let Some((&first, rest)) = old_slices.split_first() {
|
|
||||||
old_slices = rest;
|
|
||||||
old_index += 1;
|
|
||||||
Some(Change {
|
|
||||||
tag: ChangeTag::Delete,
|
|
||||||
old_index: Some(old_index - 1),
|
|
||||||
new_index: None,
|
|
||||||
value: first,
|
|
||||||
})
|
|
||||||
} else if let Some((&first, rest)) = new_slices.split_first() {
|
|
||||||
new_slices = rest;
|
|
||||||
new_index += 1;
|
|
||||||
Some(Change {
|
|
||||||
tag: ChangeTag::Insert,
|
|
||||||
old_index: None,
|
|
||||||
new_index: Some(new_index - 1),
|
|
||||||
value: first,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the captured diff ops.
|
/// Returns the captured diff ops.
|
||||||
|
|
|
||||||
113
src/types.rs
113
src/types.rs
|
|
@ -1,5 +1,5 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Range;
|
use std::ops::{Index, Range};
|
||||||
|
|
||||||
use crate::algorithms::DiffHook;
|
use crate::algorithms::DiffHook;
|
||||||
|
|
||||||
|
|
@ -44,11 +44,16 @@ impl fmt::Display for ChangeTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the expanded textual change.
|
/// Represents the expanded [`DiffOp`] change.
|
||||||
|
///
|
||||||
|
/// This type is returned from [`DiffOp::iter_changes`] and
|
||||||
|
/// [`TextDiff::iter_changes`](crate::text::TextDiff::iter_changes).
|
||||||
///
|
///
|
||||||
/// This type is returned from the [`crate::text::TextDiff::iter_changes`] method.
|
|
||||||
/// It exists so that it's more convenient to work with textual differences as
|
/// It exists so that it's more convenient to work with textual differences as
|
||||||
/// the underlying [`DiffOp`] does not know anything about strings.
|
/// the underlying [`DiffOp`] encodes a group of changes.
|
||||||
|
///
|
||||||
|
/// This type has additional methods that are only available for types
|
||||||
|
/// implementing [`DiffableStr`](crate::text::DiffableStr).
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd)]
|
||||||
pub struct Change<'s, T: ?Sized> {
|
pub struct Change<'s, T: ?Sized> {
|
||||||
pub(crate) tag: ChangeTag,
|
pub(crate) tag: ChangeTag,
|
||||||
|
|
@ -57,6 +62,7 @@ pub struct Change<'s, T: ?Sized> {
|
||||||
pub(crate) value: &'s T,
|
pub(crate) value: &'s T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// These methods are available for all change types.
|
||||||
impl<'s, T: ?Sized> Change<'s, T> {
|
impl<'s, T: ?Sized> Change<'s, T> {
|
||||||
/// Returns the change tag.
|
/// Returns the change tag.
|
||||||
pub fn tag(&self) -> ChangeTag {
|
pub fn tag(&self) -> ChangeTag {
|
||||||
|
|
@ -235,6 +241,102 @@ impl DiffOp {
|
||||||
} => d.replace(old_index, old_len, new_index, new_len),
|
} => d.replace(old_index, old_len, new_index, new_len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterates over all changes encoded in the diff op against old and new
|
||||||
|
/// sequences.
|
||||||
|
///
|
||||||
|
/// `old` and `new` are two indexable objects like the types you pass to
|
||||||
|
/// the diffing algorithm functions.
|
||||||
|
pub fn iter_changes<'x, Old, New, T>(
|
||||||
|
&self,
|
||||||
|
old: &'x Old,
|
||||||
|
new: &'x New,
|
||||||
|
) -> impl Iterator<Item = Change<'x, T>>
|
||||||
|
where
|
||||||
|
Old: Index<usize, Output = &'x T> + ?Sized,
|
||||||
|
New: Index<usize, Output = &'x T> + ?Sized,
|
||||||
|
T: 'x + ?Sized,
|
||||||
|
{
|
||||||
|
let (tag, old_range, new_range) = self.as_tag_tuple();
|
||||||
|
let mut old_index = old_range.start;
|
||||||
|
let mut new_index = new_range.start;
|
||||||
|
let mut old_i = old_range.start;
|
||||||
|
let mut new_i = new_range.start;
|
||||||
|
|
||||||
|
std::iter::from_fn(move || match tag {
|
||||||
|
DiffTag::Equal => {
|
||||||
|
if old_i < old_range.end {
|
||||||
|
let value = old[old_i];
|
||||||
|
old_i += 1;
|
||||||
|
old_index += 1;
|
||||||
|
new_index += 1;
|
||||||
|
Some(Change {
|
||||||
|
tag: ChangeTag::Equal,
|
||||||
|
old_index: Some(old_index - 1),
|
||||||
|
new_index: Some(new_index - 1),
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DiffTag::Delete => {
|
||||||
|
if old_i < old_range.end {
|
||||||
|
let value = old[old_i];
|
||||||
|
old_i += 1;
|
||||||
|
old_index += 1;
|
||||||
|
Some(Change {
|
||||||
|
tag: ChangeTag::Delete,
|
||||||
|
old_index: Some(old_index - 1),
|
||||||
|
new_index: None,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DiffTag::Insert => {
|
||||||
|
if new_i < new_range.end {
|
||||||
|
let value = new[new_i];
|
||||||
|
new_i += 1;
|
||||||
|
new_index += 1;
|
||||||
|
Some(Change {
|
||||||
|
tag: ChangeTag::Insert,
|
||||||
|
old_index: None,
|
||||||
|
new_index: Some(new_index - 1),
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DiffTag::Replace => {
|
||||||
|
if old_i < old_range.end {
|
||||||
|
let value = old[old_i];
|
||||||
|
old_i += 1;
|
||||||
|
old_index += 1;
|
||||||
|
Some(Change {
|
||||||
|
tag: ChangeTag::Delete,
|
||||||
|
old_index: Some(old_index - 1),
|
||||||
|
new_index: None,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
} else if new_i < new_range.end {
|
||||||
|
let value = new[new_i];
|
||||||
|
new_i += 1;
|
||||||
|
new_index += 1;
|
||||||
|
Some(Change {
|
||||||
|
tag: ChangeTag::Insert,
|
||||||
|
old_index: None,
|
||||||
|
new_index: Some(new_index - 1),
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "text")]
|
#[cfg(feature = "text")]
|
||||||
|
|
@ -243,6 +345,9 @@ mod text_additions {
|
||||||
use crate::text::DiffableStr;
|
use crate::text::DiffableStr;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
/// The text interface can produce changes over [`DiffableStr`] implemeting
|
||||||
|
/// values. As those are generic interfaces for different types of strings
|
||||||
|
/// utility methods to make working with standard rust strings more enjoyable.
|
||||||
impl<'s, T: DiffableStr + ?Sized> Change<'s, T> {
|
impl<'s, T: DiffableStr + ?Sized> Change<'s, T> {
|
||||||
/// Returns the value as string if it is utf-8.
|
/// Returns the value as string if it is utf-8.
|
||||||
pub fn as_str(&self) -> Option<&'s str> {
|
pub fn as_str(&self) -> Option<&'s str> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue