diffy_fork_filenames/lib.rs
1//! Tools for finding and manipulating differences between files
2//!
3//! ## Overview
4//!
5//! This library is intended to be a collection of tools used to find and
6//! manipulate differences between files inspired by [LibXDiff] and [GNU
7//! Diffutils]. Version control systems like [Git] and [Mercurial] generally
8//! communicate differences between two versions of a file using a `diff` or
9//! `patch`.
10//!
11//! The current diff implementation is based on the [Myers' diff algorithm].
12//!
13//! ## UTF-8 and Non-UTF-8
14//!
15//! This library has support for working with both utf8 and non-utf8 texts.
16//! Most of the API's have two different variants, one for working with utf8
17//! `str` texts (e.g. [`create_patch`]) and one for working with bytes `[u8]`
18//! which may or may not be utf8 (e.g. [`create_patch_bytes`]).
19//!
20//! ## Creating a Patch
21//!
22//! A [`Patch`] between two texts can be created by doing the following:
23//!
24//! ```
25//! use diffy::create_patch;
26//!
27//! let original = "The Way of Kings\nWords of Radiance\n";
28//! let modified = "The Way of Kings\nWords of Radiance\nOathbringer\n";
29//!
30//! let patch = create_patch(original, modified);
31//! #
32//! # let expected = "\
33//! # --- original
34//! # +++ modified
35//! # @@ -1,2 +1,3 @@
36//! # The Way of Kings
37//! # Words of Radiance
38//! # +Oathbringer
39//! # ";
40//! #
41//! # assert_eq!(patch.to_string(), expected);
42//! ```
43//!
44//! A [`Patch`] can the be output in the [Unified Format] either by using its
45//! [`Display`] impl or by using a [`PatchFormatter`] to output the diff with
46//! color.
47//!
48//! ```
49//! # use diffy::create_patch;
50//! #
51//! # let original = "The Way of Kings\nWords of Radiance\n";
52//! # let modified = "The Way of Kings\nWords of Radiance\nOathbringer\n";
53//! #
54//! # let patch = create_patch(original, modified);
55//! #
56//! # let expected = "\
57//! # --- original
58//! # +++ modified
59//! # @@ -1,2 +1,3 @@
60//! # The Way of Kings
61//! # Words of Radiance
62//! # +Oathbringer
63//! # ";
64//! #
65//! # assert_eq!(patch.to_string(), expected);
66//! #
67//! // Without color
68//! print!("{}", patch);
69//!
70//! // With color
71//! # use diffy::PatchFormatter;
72//! let f = PatchFormatter::new().with_color();
73//! print!("{}", f.fmt_patch(&patch));
74//! ```
75//!
76//! ```console
77//! --- original
78//! +++ modified
79//! @@ -1,2 +1,3 @@
80//! The Way of Kings
81//! Words of Radiance
82//! +Oathbringer
83//! ```
84//!
85//! ## Applying a Patch
86//!
87//! Once you have a [`Patch`] you can apply it to a base image in order to
88//! recover the new text. Each hunk will be applied to the base image in
89//! sequence. Similarly to GNU `patch`, this implementation can detect when
90//! line numbers specified in the patch are incorrect and will attempt to find
91//! the correct place to apply each hunk by iterating forward and backward
92//! from the given position until all context lines from a hunk match the base
93//! image.
94//!
95//! ```
96//! use diffy::{apply, Patch};
97//!
98//! let s = "\
99//! --- a/skybreaker-ideals
100//! +++ b/skybreaker-ideals
101//! @@ -10,6 +10,8 @@
102//! First:
103//! Life before death,
104//! strength before weakness,
105//! journey before destination.
106//! Second:
107//! - I will put the law before all else.
108//! + I swear to seek justice,
109//! + to let it guide me,
110//! + until I find a more perfect Ideal.
111//! ";
112//!
113//! let patch = Patch::from_str(s).unwrap();
114//!
115//! let base_image = "\
116//! First:
117//! Life before death,
118//! strength before weakness,
119//! journey before destination.
120//! Second:
121//! I will put the law before all else.
122//! ";
123//!
124//! let expected = "\
125//! First:
126//! Life before death,
127//! strength before weakness,
128//! journey before destination.
129//! Second:
130//! I swear to seek justice,
131//! to let it guide me,
132//! until I find a more perfect Ideal.
133//! ";
134//!
135//! assert_eq!(apply(base_image, &patch).unwrap(), expected);
136//! ```
137//!
138//! ## Performing a Three-way Merge
139//!
140//! Two files `A` and `B` can be merged together given a common ancestor or
141//! original file `O` to produce a file `C` similarly to how [diff3]
142//! performs a three-way merge.
143//!
144//! ```console
145//! --- A ---
146//! / \
147//! / \
148//! O C
149//! \ /
150//! \ /
151//! --- B ---
152//! ```
153//!
154//! If files `A` and `B` modified different regions of the original file `O`
155//! (or the same region in the same way) then the files can be merged without
156//! conflict.
157//!
158//! ```
159//! use diffy::merge;
160//!
161//! let original = "the final empire\nThe Well of Ascension\nThe hero of ages\n";
162//! let a = "The Final Empire\nThe Well of Ascension\nThe Hero of Ages\n";
163//! let b = "The Final Empire\nThe Well of Ascension\nThe hero of ages\n";
164//! let expected = "\
165//! The Final Empire
166//! The Well of Ascension
167//! The Hero of Ages
168//! ";
169//!
170//! assert_eq!(merge(original, a, b).unwrap(), expected);
171//! ```
172//!
173//! If both files `A` and `B` modified the same region of the original file
174//! `O` (and those modifications are different), it would result in a conflict
175//! as it is not clear which modifications should be used in the merged
176//! result.
177//!
178//! ```
179//! use diffy::merge;
180//!
181//! let original = "The Final Empire\nThe Well of Ascension\nThe hero of ages\n";
182//! let a = "The Final Empire\nThe Well of Ascension\nThe Hero of Ages\nSecret History\n";
183//! let b = "The Final Empire\nThe Well of Ascension\nThe hero of ages\nThe Alloy of Law\n";
184//! let expected = "\
185//! The Final Empire
186//! The Well of Ascension
187//! <<<<<<< ours
188//! The Hero of Ages
189//! Secret History
190//! ||||||| original
191//! The hero of ages
192//! =======
193//! The hero of ages
194//! The Alloy of Law
195//! >>>>>>> theirs
196//! ";
197//!
198//! assert_eq!(merge(original, a, b).unwrap_err(), expected);
199//! ```
200//!
201//! [LibXDiff]: http://www.xmailserver.org/xdiff-lib.html
202//! [Myers' diff algorithm]: http://www.xmailserver.org/diff2.pdf
203//! [GNU Diffutils]: https://www.gnu.org/software/diffutils/
204//! [Git]: https://git-scm.com/
205//! [Mercurial]: https://www.mercurial-scm.org/
206//! [Unified Format]: https://en.wikipedia.org/wiki/Diff#Unified_format
207//! [diff3]: https://en.wikipedia.org/wiki/Diff3
208//!
209//! [`Display`]: https://doc.rust-lang.org/stable/std/fmt/trait.Display.html
210//! [`Patch`]: struct.Patch.html
211//! [`PatchFormatter`]: struct.PatchFormatter.html
212//! [`create_patch`]: fn.create_patch.html
213//! [`create_patch_bytes`]: fn.create_patch_bytes.html
214
215mod apply;
216mod diff;
217mod merge;
218mod patch;
219mod range;
220mod utils;
221
222pub use apply::{apply, apply_bytes, ApplyError};
223pub use diff::{create_patch, create_file_patch, create_patch_bytes, DiffOptions};
224pub use merge::{merge, merge_bytes, ConflictStyle, MergeOptions};
225pub use patch::{Hunk, HunkRange, Line, ParsePatchError, Patch, PatchFormatter};