gix_diff/blob/unified_diff/
mod.rs

1//! Facilities to produce the unified diff format.
2//!
3//! Originally based on <https://github.com/pascalkuthe/imara-diff/pull/14>.
4
5/// Defines the size of the context printed before and after each change.
6///
7/// Similar to the `-U` option in git diff or gnu-diff. If the context overlaps
8/// with previous or next change, the context gets reduced accordingly.
9#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
10pub struct ContextSize {
11    /// Defines the size of the context printed before and after each change.
12    symmetrical: u32,
13}
14
15impl Default for ContextSize {
16    fn default() -> Self {
17        ContextSize::symmetrical(3)
18    }
19}
20
21/// Instantiation
22impl ContextSize {
23    /// Create a symmetrical context with `n` lines before and after a changed hunk.
24    pub fn symmetrical(n: u32) -> Self {
25        ContextSize { symmetrical: n }
26    }
27}
28
29/// Represents the type of a line in a unified diff.
30#[doc(alias = "git2")]
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
32pub enum DiffLineKind {
33    /// A line that exists in both the old and the new version, added based on [`ContextSize`].
34    Context,
35    /// A line that was added in the new version.
36    Add,
37    /// A line that was removed from the old version.
38    Remove,
39}
40
41/// Holds information about a unified diff hunk, specifically with respect to line numbers.
42#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
43pub struct HunkHeader {
44    /// The 1-based start position in the 'before' lines.
45    pub before_hunk_start: u32,
46    /// The size of the 'before' hunk in lines.
47    pub before_hunk_len: u32,
48    /// The 1-based start position in the 'after' lines.
49    pub after_hunk_start: u32,
50    /// The size of the 'after' hunk in lines.
51    pub after_hunk_len: u32,
52}
53
54/// An adapter with [`ConsumeHunk`] implementation to call a delegate which receives each stringified hunk.
55pub struct ConsumeBinaryHunk<'a, D> {
56    /// The newline to use to separate lines if these don't yet contain a newline.
57    /// It should also be used to separate the stringified header from the hunk itself.
58    pub newline: &'a str,
59    /// The delegate to receive stringified hunks.
60    pub delegate: D,
61
62    header_buf: String,
63    hunk_buf: Vec<u8>,
64}
65
66/// A trait for use in conjunction with [`ConsumeBinaryHunk`].
67pub trait ConsumeBinaryHunkDelegate {
68    /// Consume a single `hunk` in unified diff format, along with its `header_str` that already has a trailing newline added based
69    /// on the parent [`ConsumeBinaryHunk`] configuration, also in unified diff format.
70    /// The `header` is the data used to produce `header_str`.
71    fn consume_binary_hunk(&mut self, header: HunkHeader, header_str: &str, hunk: &[u8]) -> std::io::Result<()>;
72}
73
74/// A utility trait for use in [`UnifiedDiff`](super::UnifiedDiff).
75pub trait ConsumeHunk {
76    /// The item this instance produces after consuming all hunks.
77    type Out;
78
79    /// Consume a single hunk which is represented by its `lines`, each of which with a `DiffLineKind` value
80    /// to know if it's added, removed or context.
81    /// The `header` specifies hunk offsets, which positions the `lines` in the old and new file respectively.
82    ///
83    /// Note that the [`UnifiedDiff`](super::UnifiedDiff) sink will wrap its output in an [`std::io::Result`].
84    /// After this method returned its first error, it will not be called anymore.
85    fn consume_hunk(&mut self, header: HunkHeader, lines: &[(DiffLineKind, &[u8])]) -> std::io::Result<()>;
86
87    /// Called after the last hunk is consumed to produce an output.
88    fn finish(self) -> Self::Out;
89}
90
91pub(super) mod impls;