From d1500a6ab1c5be206c52958115c557f8f25b079b Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 29 Jan 2025 16:13:36 -0600 Subject: [PATCH] patch: allow configuring the "No newline at end of file" message Allow configuring the "No newline at end of file" message from being printed when formatting a patch. --- src/diff/tests.rs | 30 ++++++++++++++++++++++++++++++ src/patch/format.rs | 23 +++++++++++++++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/diff/tests.rs b/src/diff/tests.rs index 9ac8fa7..e383a7d 100644 --- a/src/diff/tests.rs +++ b/src/diff/tests.rs @@ -4,6 +4,7 @@ use crate::{ diff::{Diff, DiffRange}, patch::Patch, range::Range, + PatchFormatter, }; // Helper macros are based off of the ones used in [dissimilar](https://docs.rs/dissimilar) @@ -518,6 +519,35 @@ fn no_newline_at_eof() { assert_patch!(old, new, expected); } +#[test] +fn without_no_newline_at_eof_message() { + let old = "old line"; + let new = "new line"; + let expected = "\ +--- original ++++ modified +@@ -1 +1 @@ +-old line ++new line +"; + + let f = PatchFormatter::new().missing_newline_message(false); + let patch = create_patch(old, new); + let bpatch = create_patch_bytes(old.as_bytes(), new.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(old, &patch).unwrap(), new); + assert_eq!( + crate::apply_bytes(old.as_bytes(), &bpatch).unwrap(), + new.as_bytes() + ); +} + #[test] fn myers_diffy_vs_git() { let original = "\ diff --git a/src/patch/format.rs b/src/patch/format.rs index 7a51450..815e18b 100644 --- a/src/patch/format.rs +++ b/src/patch/format.rs @@ -9,6 +9,7 @@ use std::{ #[derive(Debug)] pub struct PatchFormatter { with_color: bool, + with_missing_newline_message: bool, context: Style, delete: Style, @@ -23,6 +24,7 @@ impl PatchFormatter { pub fn new() -> Self { Self { with_color: false, + with_missing_newline_message: true, context: Style::new(), delete: Color::Red.normal(), @@ -39,6 +41,19 @@ impl PatchFormatter { self } + /// Sets whether to format a patch with a "No newline at end of file" message. + /// + /// Default is `true`. + /// + /// Note: If this is disabled by setting to `false`, formatted patches will no longer contain + /// sufficient information to determine if a file ended with a newline character (`\n`) or not + /// and the patch will be formatted as if both the original and modified files ended with a + /// newline character (`\n`). + pub fn missing_newline_message(mut self, enable: bool) -> Self { + self.with_missing_newline_message = 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 } @@ -238,7 +253,9 @@ impl + ?Sized> LineDisplay<'_, T> { if !line.ends_with(b"\n") { writeln!(w)?; - writeln!(w, "{}", NO_NEWLINE_AT_EOF)?; + if self.f.with_missing_newline_message { + writeln!(w, "{}", NO_NEWLINE_AT_EOF)?; + } } Ok(()) @@ -269,7 +286,9 @@ impl Display for LineDisplay<'_, str> { if !line.ends_with('\n') { writeln!(f)?; - writeln!(f, "{}", NO_NEWLINE_AT_EOF)?; + if self.f.with_missing_newline_message { + writeln!(f, "{}", NO_NEWLINE_AT_EOF)?; + } } Ok(())