Skip to content

Commit

Permalink
patch: add support for configuring suppress_blank_empty
Browse files Browse the repository at this point in the history
Add support for configuring `--suppress-blank-empty` as is possible with
GNU diff and git-diff. This allows suppressing the trailing space that
would otherwise exist when formatting a patch with an empty context
line.
  • Loading branch information
bmwill committed Jan 29, 2025
1 parent acff31e commit 04cb09e
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 2 deletions.
75 changes: 75 additions & 0 deletions src/diff/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,81 @@ void Chunk_copy(Chunk *src, size_t src_start, Chunk *dst, size_t dst_start, size
assert_patch!(original, a, expected_diffy);
}

#[test]
fn suppress_blank_empty() {
let original = "\
1
2
3
4
";

let modified = "\
1
2
3
5
";

// Note that there is a space " " on the line after 3
let expected = "\
--- original
+++ modified
@@ -2,4 +2,4 @@
2
3
-4
+5
";

let f = PatchFormatter::new().suppress_blank_empty(false);
let patch = create_patch(original, modified);
let bpatch = create_patch_bytes(original.as_bytes(), modified.as_bytes());
let patch_str = format!("{}", f.fmt_patch(&patch));
let mut patch_bytes = Vec::new();
f.write_patch_into(&bpatch, &mut patch_bytes).unwrap();

assert_eq!(patch_str, expected);
assert_eq!(patch_bytes, patch_str.as_bytes());
assert_eq!(patch_bytes, expected.as_bytes());
assert_eq!(apply(original, &patch).unwrap(), modified);
assert_eq!(
crate::apply_bytes(original.as_bytes(), &bpatch).unwrap(),
modified.as_bytes()
);

// Note that there is no space " " on the line after 3
let expected_suppressed = "\
--- original
+++ modified
@@ -2,4 +2,4 @@
2
3
-4
+5
";

let f = PatchFormatter::new().suppress_blank_empty(true);
let patch = create_patch(original, modified);
let bpatch = create_patch_bytes(original.as_bytes(), modified.as_bytes());
let patch_str = format!("{}", f.fmt_patch(&patch));
let mut patch_bytes = Vec::new();
f.write_patch_into(&bpatch, &mut patch_bytes).unwrap();

assert_eq!(patch_str, expected_suppressed);
assert_eq!(patch_bytes, patch_str.as_bytes());
assert_eq!(patch_bytes, expected_suppressed.as_bytes());
assert_eq!(apply(original, &patch).unwrap(), modified);
assert_eq!(
crate::apply_bytes(original.as_bytes(), &bpatch).unwrap(),
modified.as_bytes()
);
}

// In the event that a patch has an invalid hunk range we want to ensure that when apply is
// attempting to search for a matching position to apply a hunk that the search algorithm runs in
// time bounded by the length of the original image being patched. Before clamping the search space
Expand Down
23 changes: 21 additions & 2 deletions src/patch/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::{
pub struct PatchFormatter {
with_color: bool,
with_missing_newline_message: bool,
suppress_blank_empty: bool,

context: Style,
delete: Style,
Expand All @@ -26,6 +27,10 @@ impl PatchFormatter {
with_color: false,
with_missing_newline_message: true,

// TODO the default in git-diff and GNU diff is to have this set to false, on the next
// semver breaking release we should contemplate switching this to be false by default
suppress_blank_empty: true,

context: Style::new(),
delete: Color::Red.normal(),
insert: Color::Green.normal(),
Expand Down Expand Up @@ -54,6 +59,20 @@ impl PatchFormatter {
self
}

/// Sets whether to suppress printing of a space before empty lines.
///
/// Defaults to `true`.
///
/// For more information you can refer to the [Omitting trailing blanks] manual page of GNU
/// diff or the [diff.suppressBlankEmpty] config for `git-diff`.
///
/// [Omitting trailing blanks]: https://www.gnu.org/software/diffutils/manual/html_node/Trailing-Blanks.html
/// [diff.suppressBlankEmpty]: https://git-scm.com/docs/git-diff#Documentation/git-diff.txt-codediffsuppressBlankEmptycode
pub fn suppress_blank_empty(mut self, enable: bool) -> Self {
self.suppress_blank_empty = enable;
self
}

/// Returns a `Display` impl which can be used to print a Patch
pub fn fmt_patch<'a>(&'a self, patch: &'a Patch<'a, str>) -> impl Display + 'a {
PatchDisplay { f: self, patch }
Expand Down Expand Up @@ -240,7 +259,7 @@ impl<T: AsRef<[u8]> + ?Sized> LineDisplay<'_, T> {
write!(w, "{}", style.prefix())?;
}

if sign == ' ' && line == b"\n" {
if self.f.suppress_blank_empty && sign == ' ' && line == b"\n" {
w.write_all(line)?;
} else {
write!(w, "{}", sign)?;
Expand Down Expand Up @@ -274,7 +293,7 @@ impl Display for LineDisplay<'_, str> {
write!(f, "{}", style.prefix())?;
}

if sign == ' ' && *line == "\n" {
if self.f.suppress_blank_empty && sign == ' ' && *line == "\n" {
write!(f, "{}", line)?;
} else {
write!(f, "{}{}", sign, line)?;
Expand Down

0 comments on commit 04cb09e

Please sign in to comment.