Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,34 @@ pub fn apply(base_image: &str, patch: &Patch<'_, str>) -> Result<String, ApplyEr
}

/// Apply a non-utf8 `Patch` to a base image
///
/// # Examples
///
/// ```
/// use diffy::apply_bytes;
/// use diffy::Patch;
///
/// let patch = Patch::from_bytes(
/// b"\
/// --- a/ideals
/// +++ b/ideals
/// @@ -1 +1,2 @@
/// First Ideal
/// +Second Ideal
/// ",
/// )
/// .unwrap();
///
/// let applied = apply_bytes(b"First Ideal\n", &patch).unwrap();
///
/// assert_eq!(
/// applied,
/// b"\
/// First Ideal
/// Second Ideal
/// ",
/// );
/// ```
pub fn apply_bytes(base_image: &[u8], patch: &Patch<'_, [u8]>) -> Result<Vec<u8>, ApplyError> {
let mut image: Vec<_> = LineIter::new(base_image)
.map(ImageLine::Unpatched)
Expand Down
57 changes: 57 additions & 0 deletions src/binary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,36 @@ impl<'a> BinaryPatch<'a> {
/// - If the forward block is `Delta`: applies delta instructions to `original`.
///
/// Unlike `git apply`, this doesn't validate the original content hash.
///
/// # Examples
///
/// ```
/// use diffy::patch_set::ParseOptions;
/// use diffy::patch_set::PatchSet;
///
/// let input = b"\
/// diff --git a/blob b/blob
/// index e69de29..0000000 100644
/// GIT binary patch
/// literal 10
/// UcmV+l0QLU>0RjUA1qKHQ2>`DEE&u=k
///
/// literal 0
/// KcmV+b0RR6000031
///
/// ";
///
/// let patch = PatchSet::parse_bytes(input, ParseOptions::gitdiff())
/// .next()
/// .unwrap()
/// .unwrap();
/// let binary = patch.patch().as_binary().unwrap();
///
/// assert_eq!(
/// binary.apply(&[]).unwrap(),
/// b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t"
/// );
/// ```
#[cfg(feature = "binary")]
#[cfg_attr(docsrs, doc(cfg(feature = "binary")))]
pub fn apply(&self, original: &[u8]) -> Result<Vec<u8>, BinaryPatchParseError> {
Expand All @@ -96,6 +126,33 @@ impl<'a> BinaryPatch<'a> {
/// - If the reverse block is `Delta`: applies delta instructions to `modified`.
///
/// Unlike `git apply`, this doesn't validate the modified content hash.
///
/// # Examples
///
/// ```
/// use diffy::patch_set::ParseOptions;
/// use diffy::patch_set::PatchSet;
///
/// let input = b"\
/// diff --git a/blob b/blob
/// index e69de29..0000000 100644
/// GIT binary patch
/// literal 10
/// UcmV+l0QLU>0RjUA1qKHQ2>`DEE&u=k
///
/// literal 0
/// KcmV+b0RR6000031
///
/// ";
///
/// let patch = PatchSet::parse_bytes(input, ParseOptions::gitdiff())
/// .next()
/// .unwrap()
/// .unwrap();
/// let binary = patch.patch().as_binary().unwrap();
///
/// assert_eq!(binary.apply_reverse(&[]).unwrap(), b"");
/// ```
#[cfg(feature = "binary")]
#[cfg_attr(docsrs, doc(cfg(feature = "binary")))]
pub fn apply_reverse(&self, modified: &[u8]) -> Result<Vec<u8>, BinaryPatchParseError> {
Expand Down
58 changes: 58 additions & 0 deletions src/diff/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,44 @@ where
}

/// A collection of options for modifying the way a diff is performed
///
/// # Examples
///
/// ```
/// use diffy::DiffOptions;
///
/// let mut options = DiffOptions::new();
/// options
/// .set_context_len(1)
/// .set_original_filename("before.txt")
/// .set_modified_filename("after.txt");
///
/// let patch = options.create_patch(
/// "\
/// alpha
/// beta
/// gamma
/// ",
/// "\
/// alpha
/// BETA
/// gamma
/// ",
/// );
///
/// assert_eq!(
/// patch.to_string(),
/// "\
/// --- before.txt
/// +++ after.txt
/// @@ -1,3 +1,3 @@
/// alpha
/// -beta
/// +BETA
/// gamma
/// ",
/// );
/// ```
#[derive(Debug)]
pub struct DiffOptions {
compact: bool,
Expand Down Expand Up @@ -234,6 +272,26 @@ pub fn create_patch<'a>(original: &'a str, modified: &'a str) -> Patch<'a, str>
}

/// Create a patch between two potentially non-utf8 texts
///
/// # Examples
///
/// ```
/// use diffy::create_patch_bytes;
///
/// let patch = create_patch_bytes(b"alpha\nbeta\n", b"alpha\nBETA\n");
///
/// assert_eq!(
/// patch.to_bytes(),
/// b"\
/// --- original
/// +++ modified
/// @@ -1,2 +1,2 @@
/// alpha
/// -beta
/// +BETA
/// ",
/// );
/// ```
pub fn create_patch_bytes<'a>(original: &'a [u8], modified: &'a [u8]) -> Patch<'a, [u8]> {
DiffOptions::default().create_patch_bytes(original, modified)
}
Expand Down
57 changes: 57 additions & 0 deletions src/merge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,31 @@ pub enum ConflictStyle {
}

/// A collection of options for modifying the way a merge is performed
///
/// # Examples
///
/// ```
/// use diffy::ConflictStyle;
/// use diffy::MergeOptions;
///
/// let mut options = MergeOptions::new();
/// options
/// .set_conflict_style(ConflictStyle::Merge)
/// .set_conflict_marker_length(5);
///
/// let conflict = options.merge("value\n", "ours\n", "theirs\n").unwrap_err();
///
/// assert_eq!(
/// conflict,
/// "\
/// <<<<< ours
/// ours
/// =====
/// theirs
/// >>>>> theirs
/// ",
/// );
/// ```
#[derive(Debug)]
pub struct MergeOptions {
conflict_marker_length: usize,
Expand Down Expand Up @@ -272,6 +297,38 @@ pub fn merge<'a>(ancestor: &'a str, ours: &'a str, theirs: &'a str) -> Result<St
}

/// Perform a 3-way merge between potentially non-utf8 texts
///
/// # Examples
///
/// ```
/// use diffy::merge_bytes;
///
/// let merged = merge_bytes(
/// b"\
/// alpha
/// beta
/// ",
/// b"\
/// ALPHA
/// beta
/// ",
/// b"\
/// alpha
/// beta
/// gamma
/// ",
/// )
/// .unwrap();
///
/// assert_eq!(
/// merged,
/// b"\
/// ALPHA
/// beta
/// gamma
/// ",
/// );
/// ```
pub fn merge_bytes<'a>(
ancestor: &'a [u8],
ours: &'a [u8],
Expand Down
32 changes: 31 additions & 1 deletion src/patch/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,32 @@ use super::Line;
use super::Patch;
use super::NO_NEWLINE_AT_EOF;

/// Struct used to adjust the formatting of a `Patch`
/// Formats patches for display or writing into byte streams.
///
/// # Examples
///
/// ```
/// use diffy::create_patch;
/// use diffy::PatchFormatter;
///
/// let patch = create_patch("alpha\nbeta\n", "ALPHA\nbeta\n");
/// let formatter = PatchFormatter::new().missing_newline_message(false);
/// let mut output = Vec::new();
///
/// formatter.write_patch_into(&patch, &mut output).unwrap();
///
/// assert_eq!(
/// String::from_utf8(output).unwrap(),
/// "\
/// --- original
/// +++ modified
/// @@ -1,2 +1,2 @@
/// -alpha
/// +ALPHA
/// beta
/// ",
/// );
/// ```
#[derive(Debug)]
pub struct PatchFormatter {
#[cfg(feature = "color")]
Expand Down Expand Up @@ -76,6 +101,11 @@ impl PatchFormatter {
PatchDisplay { f: self, patch }
}

/// Writes a formatted patch into a writer.
///
/// This is the byte-oriented equivalent of [`fmt_patch`](Self::fmt_patch)
/// for callers that want to stream the formatted patch into an `io::Write`
/// sink instead of going through `Display`.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn write_patch_into<T: ToOwned + AsRef<[u8]> + ?Sized, W: io::Write>(
Expand Down
6 changes: 6 additions & 0 deletions src/patch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ impl<'a, T: ToOwned + ?Sized> Patch<'a, T> {
&self.hunks
}

/// Returns a patch that transforms the modified text back into the original text.
pub fn reverse(&self) -> Patch<'_, T> {
let hunks = self.hunks.iter().map(Hunk::reverse).collect();
Patch {
Expand Down Expand Up @@ -438,6 +439,11 @@ impl<T: ?Sized> Clone for Line<'_, T> {
}

impl<T: ?Sized> Line<'_, T> {
/// Reverses the direction of this diff line.
///
/// * Context lines are unchanged
/// * Insertions become deletions
/// * Deletions become insertions
pub fn reverse(&self) -> Self {
match self {
Line::Context(s) => Line::Context(s),
Expand Down
16 changes: 14 additions & 2 deletions src/patch_set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,17 +285,29 @@ pub enum FileOperation<'a, T: ToOwned + ?Sized> {
///
/// Usually, the caller needs to strip the prefix from the paths to determine.
Modify {
/// The original path before the modification.
original: Cow<'a, T>,
/// The resulting path after the modification.
modified: Cow<'a, T>,
},
/// Rename a file (move from `from` to `to`, delete `from`).
///
/// Only produced when git extended headers explicitly indicate a rename.
Rename { from: Cow<'a, T>, to: Cow<'a, T> },
Rename {
/// The source path before the rename.
from: Cow<'a, T>,
/// The destination path after the rename.
to: Cow<'a, T>,
},
/// Copy a file (copy from `from` to `to`, keep `from`).
///
/// Only produced when git extended headers explicitly indicate a copy.
Copy { from: Cow<'a, T>, to: Cow<'a, T> },
Copy {
/// The source path that is copied from.
from: Cow<'a, T>,
/// The destination path that is copied to.
to: Cow<'a, T>,
},
}

impl<T: ToOwned + ?Sized> Clone for FileOperation<'_, T> {
Expand Down