Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/imara-diff-0.1.8/src/unified_diff.rs
Line
Count
Source
1
use std::fmt::{Display, Write};
2
use std::ops::Range;
3
4
use crate::intern::{InternedInput, Interner, Token};
5
use crate::Sink;
6
7
/// A [`Sink`] that creates a textual diff
8
/// in the format typically output by git or gnu-diff if the `-u` option is used
9
pub struct UnifiedDiffBuilder<'a, W, T>
10
where
11
    W: Write,
12
    T: Display,
13
{
14
    before: &'a [Token],
15
    after: &'a [Token],
16
    interner: &'a Interner<T>,
17
18
    pos: u32,
19
    before_hunk_start: u32,
20
    after_hunk_start: u32,
21
    before_hunk_len: u32,
22
    after_hunk_len: u32,
23
24
    buffer: String,
25
    dst: W,
26
}
27
28
impl<'a, T> UnifiedDiffBuilder<'a, String, T>
29
where
30
    T: Display,
31
{
32
    /// Create a new `UnifiedDiffBuilder` for the given `input`,
33
    /// that will return a [`String`].
34
0
    pub fn new(input: &'a InternedInput<T>) -> Self {
35
0
        Self {
36
0
            before_hunk_start: 0,
37
0
            after_hunk_start: 0,
38
0
            before_hunk_len: 0,
39
0
            after_hunk_len: 0,
40
0
            buffer: String::with_capacity(8),
41
0
            dst: String::new(),
42
0
            interner: &input.interner,
43
0
            before: &input.before,
44
0
            after: &input.after,
45
0
            pos: 0,
46
0
        }
47
0
    }
48
}
49
50
impl<'a, W, T> UnifiedDiffBuilder<'a, W, T>
51
where
52
    W: Write,
53
    T: Display,
54
{
55
    /// Create a new `UnifiedDiffBuilder` for the given `input`,
56
    /// that will writes it output to the provided implementation of [`Write`].
57
0
    pub fn with_writer(input: &'a InternedInput<T>, writer: W) -> Self {
58
0
        Self {
59
0
            before_hunk_start: 0,
60
0
            after_hunk_start: 0,
61
0
            before_hunk_len: 0,
62
0
            after_hunk_len: 0,
63
0
            buffer: String::with_capacity(8),
64
0
            dst: writer,
65
0
            interner: &input.interner,
66
0
            before: &input.before,
67
0
            after: &input.after,
68
0
            pos: 0,
69
0
        }
70
0
    }
71
72
0
    fn print_tokens(&mut self, tokens: &[Token], prefix: char) {
73
0
        for &token in tokens {
74
0
            writeln!(&mut self.buffer, "{prefix}{}", self.interner[token]).unwrap();
75
0
        }
76
0
    }
77
78
0
    fn flush(&mut self) {
79
0
        if self.before_hunk_len == 0 && self.after_hunk_len == 0 {
80
0
            return;
81
0
        }
82
83
0
        let end = (self.pos + 3).min(self.before.len() as u32);
84
0
        self.update_pos(end, end);
85
86
0
        writeln!(
87
0
            &mut self.dst,
88
            "@@ -{},{} +{},{} @@",
89
0
            self.before_hunk_start + 1,
90
            self.before_hunk_len,
91
0
            self.after_hunk_start + 1,
92
            self.after_hunk_len,
93
        )
94
0
        .unwrap();
95
0
        write!(&mut self.dst, "{}", &self.buffer).unwrap();
96
0
        self.buffer.clear();
97
0
        self.before_hunk_len = 0;
98
0
        self.after_hunk_len = 0
99
0
    }
100
101
0
    fn update_pos(&mut self, print_to: u32, move_to: u32) {
102
0
        self.print_tokens(&self.before[self.pos as usize..print_to as usize], ' ');
103
0
        let len = print_to - self.pos;
104
0
        self.pos = move_to;
105
0
        self.before_hunk_len += len;
106
0
        self.after_hunk_len += len;
107
0
    }
108
}
109
110
impl<W, T> Sink for UnifiedDiffBuilder<'_, W, T>
111
where
112
    W: Write,
113
    T: Display,
114
{
115
    type Out = W;
116
117
0
    fn process_change(&mut self, before: Range<u32>, after: Range<u32>) {
118
0
        if before.start - self.pos > 6 {
119
0
            self.flush();
120
0
            self.pos = before.start - 3;
121
0
            self.before_hunk_start = self.pos;
122
0
            self.after_hunk_start = after.start - 3;
123
0
        }
124
0
        self.update_pos(before.start, before.end);
125
0
        self.before_hunk_len += before.end - before.start;
126
0
        self.after_hunk_len += after.end - after.start;
127
0
        self.print_tokens(
128
0
            &self.before[before.start as usize..before.end as usize],
129
            '-',
130
        );
131
0
        self.print_tokens(&self.after[after.start as usize..after.end as usize], '+');
132
0
    }
133
134
0
    fn finish(mut self) -> Self::Out {
135
0
        self.flush();
136
0
        self.dst
137
0
    }
138
}