Skip to content

Commit 26322ac

Browse files
eholkbmwill
andauthored
feat: control filenames in DiffOptions (#36)
Add the ability to change the filenames in patches produced by `DiffOptions`. --------- Co-authored-by: Brandon Williams <brandon@mystenlabs.com>
1 parent b36b981 commit 26322ac

2 files changed

Lines changed: 86 additions & 3 deletions

File tree

src/diff/mod.rs

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
range::{DiffRange, SliceLike},
44
utils::Classifier,
55
};
6-
use std::{cmp, ops};
6+
use std::{borrow::Cow, cmp, ops};
77

88
mod cleanup;
99
mod myers;
@@ -46,6 +46,8 @@ where
4646
pub struct DiffOptions {
4747
compact: bool,
4848
context_len: usize,
49+
original_filename: Option<Cow<'static, str>>,
50+
modified_filename: Option<Cow<'static, str>>,
4951
}
5052

5153
impl DiffOptions {
@@ -57,6 +59,8 @@ impl DiffOptions {
5759
Self {
5860
compact: true,
5961
context_len: 3,
62+
original_filename: Some("original".into()),
63+
modified_filename: Some("modified".into()),
6064
}
6165
}
6266

@@ -76,6 +80,28 @@ impl DiffOptions {
7680
self
7781
}
7882

83+
/// Set the filename to be used in the patch for the original text
84+
///
85+
/// If not set, the default value is "original".
86+
pub fn set_original_filename<T>(&mut self, filename: T) -> &mut Self
87+
where
88+
T: Into<Cow<'static, str>>,
89+
{
90+
self.original_filename = Some(filename.into());
91+
self
92+
}
93+
94+
/// Set the filename to be used in the patch for the modified text
95+
///
96+
/// If not set, the default value is "modified".
97+
pub fn set_modified_filename<T>(&mut self, filename: T) -> &mut Self
98+
where
99+
T: Into<Cow<'static, str>>,
100+
{
101+
self.modified_filename = Some(filename.into());
102+
self
103+
}
104+
79105
// TODO determine if this should be exposed in the public API
80106
#[allow(dead_code)]
81107
fn diff<'a>(&self, original: &'a str, modified: &'a str) -> Vec<Diff<'a, str>> {
@@ -102,7 +128,11 @@ impl DiffOptions {
102128
let solution = self.diff_slice(&old_ids, &new_ids);
103129

104130
let hunks = to_hunks(&old_lines, &new_lines, &solution, self.context_len);
105-
Patch::new(Some("original"), Some("modified"), hunks)
131+
Patch::new(
132+
self.original_filename.clone(),
133+
self.modified_filename.clone(),
134+
hunks,
135+
)
106136
}
107137

108138
/// Create a patch between two potentially non-utf8 texts
@@ -118,7 +148,20 @@ impl DiffOptions {
118148
let solution = self.diff_slice(&old_ids, &new_ids);
119149

120150
let hunks = to_hunks(&old_lines, &new_lines, &solution, self.context_len);
121-
Patch::new(Some(&b"original"[..]), Some(&b"modified"[..]), hunks)
151+
152+
// helper function to convert a utf8 cow to a bytes cow
153+
fn cow_str_to_bytes(cow: Cow<'static, str>) -> Cow<'static, [u8]> {
154+
match cow {
155+
Cow::Borrowed(b) => Cow::Borrowed(b.as_bytes()),
156+
Cow::Owned(o) => Cow::Owned(o.into_bytes()),
157+
}
158+
}
159+
160+
Patch::new(
161+
self.original_filename.clone().map(cow_str_to_bytes),
162+
self.modified_filename.clone().map(cow_str_to_bytes),
163+
hunks,
164+
)
122165
}
123166

124167
pub(crate) fn diff_slice<'a, T: PartialEq>(
@@ -358,3 +401,42 @@ fn build_edit_script<T>(solution: &[DiffRange<[T]>]) -> Vec<EditRange> {
358401

359402
edit_script
360403
}
404+
405+
#[cfg(test)]
406+
mod test {
407+
use super::DiffOptions;
408+
409+
#[test]
410+
fn set_original_and_modified_filenames() {
411+
let original = "\
412+
I am afraid, however, that all I have known - that my story - will be forgotten.
413+
I am afraid for the world that is to come.
414+
Afraid that my plans will fail.
415+
Afraid of a doom worse than the Deepness.
416+
";
417+
let modified = "\
418+
I am afraid, however, that all I have known - that my story - will be forgotten.
419+
I am afraid for the world that is to come.
420+
Afraid that Alendi will fail.
421+
Afraid of a doom brought by the Deepness.
422+
";
423+
let expected = "\
424+
--- the old version
425+
+++ the better version
426+
@@ -1,4 +1,4 @@
427+
I am afraid, however, that all I have known - that my story - will be forgotten.
428+
I am afraid for the world that is to come.
429+
-Afraid that my plans will fail.
430+
-Afraid of a doom worse than the Deepness.
431+
+Afraid that Alendi will fail.
432+
+Afraid of a doom brought by the Deepness.
433+
";
434+
435+
let patch = DiffOptions::new()
436+
.set_original_filename("the old version")
437+
.set_modified_filename("the better version")
438+
.create_patch(original, modified);
439+
440+
assert_eq!(patch.to_string(), expected);
441+
}
442+
}

src/patch/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ where
144144
struct Filename<'a, T: ToOwned + ?Sized>(Cow<'a, T>);
145145

146146
const ESCAPED_CHARS: &[char] = &['\n', '\t', '\0', '\r', '\"', '\\'];
147+
#[allow(clippy::byte_char_slices)]
147148
const ESCAPED_CHARS_BYTES: &[u8] = &[b'\n', b'\t', b'\0', b'\r', b'\"', b'\\'];
148149

149150
impl Filename<'_, str> {

0 commit comments

Comments
 (0)