patch_rs/context/
mod.rs

1//!
2//! The Patch context structures.
3//!
4
5mod flip;
6mod reduce;
7mod merge;
8
9use std::fmt;
10
11//use log::*;
12
13use crate::line::Line;
14
15#[derive(Default, Clone)]
16pub struct Context {
17    pub header: ContextHeader,
18    pub data: Vec<Line>,
19}
20
21impl Context {
22//    pub fn insert(&mut self, mut line: Line, after: usize) -> isize {
23//        let mut i = match line {
24//            Line::Delete(_) => self.array_index_for_insert(after),
25//            _ => self.array_index_for_delete(after),
26//        };
27//        trace!("Inserting {} after {} at index {}", line, after, i);
28//
29//        if let (Line::Delete(delete), Some(Line::Insert(insert))) = (&line, self.data.get(i)) {
30//            if delete == insert {
31//                trace!("Dedup {}", i);
32//                self.remove(i);
33//                return self.insert(line, after);
34//            }
35//        }
36//
37//        if let (Line::Delete(delete), Some(Line::Context(context))) = (&line, self.data.get(i)) {
38//            if context == delete {
39//                trace!("Dedup {}", i);
40//                self.remove(i);
41//                return self.insert(line, after);
42//            }
43//        }
44//
45//        if let (Line::Delete(delete), Some(Line::Context(context))) = (&line, self.data.get(i)) {
46//            if context == delete {
47//                trace!("Dedup {}", i);
48//                self.remove(i);
49//                return self.insert(line, after);
50//            }
51//        }
52//
53//        if let (Line::Context(context), Some(Line::Delete(delete))) = (&line, self.data.get(i)) {
54//            if context == delete {
55//                trace!("Dedup {}", i);
56//                return 0;
57//            }
58//        }
59//
60//        if let (Line::Context(context), Some(Line::Insert(insert))) = (&line, self.data.get(i)) {
61//            if context == insert {
62//                trace!("Dedup {}", i);
63//                return 0;
64//            }
65//        }
66//
67//        if let (Line::Context(context1), Some(Line::Context(context2))) = (&line, self.data.get(i)) {
68//            if context1 == context2 {
69//                trace!("Dedup {}", i);
70//                return 0;
71//            }
72//        }
73//
74//        if let Line::Delete(_) = line {
75//            while let Some(Line::Insert(_)) = self.data.get(i) {
76//                i -= 1;
77//            }
78//        }
79//
80//        if after == 0 {
81//            self.header.file1_l -= 1;
82//            self.header.file2_l -= 1;
83//        }
84//        match line {
85//            Line::Context(_) => {
86//                self.header.file1_s += 1;
87//                self.header.file2_s += 1;
88//            }
89//            Line::Insert(_) => {
90//                self.header.file2_s += 1;
91//            }
92//            Line::Delete(_) => {
93//                self.header.file1_s += 1;
94//            }
95//        }
96//        self.data.insert(i, line);
97//        0
98//    }
99
100//    pub fn array_index_for_delete(&self, line_number: usize) -> usize {
101//        let (mut i, mut l) = (0, self.header.file1_l);
102//        while let Some(line) = self.data.get(i) {
103//            match line {
104//                Line::Context(_) | Line::Delete(_) => {
105//                    l += 1;
106//                },
107//                Line::Insert(_) => {}
108//            }
109//            i += 1;
110//            if l > line_number {
111//                return i-1;
112//            }
113//        }
114//        self.size()
115//    }
116//
117//    pub fn array_index_for_insert(&self, line_number: usize) -> usize {
118//        let (mut i, mut l) = (0, self.header.file1_l);
119//        while let Some(line) = self.data.get(i) {
120//            match line {
121//                Line::Context(_) | Line::Insert(_) => {
122//                    l += 1;
123//                },
124//                Line::Delete(_) => {}
125//            }
126//            i += 1;
127//            if l > line_number {
128//                return i-1;
129//            }
130//        }
131//        self.size()
132//    }
133
134    pub fn pop_front(&mut self) -> Option<Line> {
135        self.remove(0)
136    }
137
138    pub fn pop_back(&mut self) -> Option<Line> {
139        self.remove(self.size()-1)
140    }
141
142    pub fn remove(&mut self, index: usize) -> Option<Line> {
143        if index > self.size() {
144            return None;
145        }
146
147        let line = self.data.remove(index);
148        if index == 0 {
149            self.header.file1_l += 1;
150            self.header.file2_l += 1;
151        }
152
153        match line {
154            Line::Context(_) => {
155                self.header.file1_s -= 1;
156                self.header.file2_s -= 1;
157            }
158            Line::Insert(_) => {
159                self.header.file2_s -= 1;
160            }
161            Line::Delete(_) => {
162                self.header.file1_s -= 1;
163            }
164        }
165
166        Some(line)
167    }
168
169    pub fn shift(&mut self, offset: isize) {
170        if offset > 0 {
171            self.header.file1_l += offset as usize;
172        }
173        if offset < 0 {
174            self.header.file1_l -= -offset as usize;
175        }
176    }
177
178    pub fn size(&self) -> usize {
179        self.data.len()
180    }
181
182    pub fn offset(&self) -> isize {
183        (self.header.file2_s as isize) - (self.header.file1_s as isize)
184    }
185
186    pub fn opening_context_size(&self) -> usize {
187        self.data.iter().take_while(|element| if let Line::Context(_) = element {
188            true
189        } else {
190            false
191        }).count()
192    }
193
194    pub fn closing_context_size(&self) -> usize {
195        self.data.iter().rev().take_while(|element| if let Line::Context(_) = element {
196            true
197        } else {
198            false
199        }).count()
200    }
201
202    pub fn has_changes(&self) -> bool {
203        for line in self.data.iter() {
204            match line {
205                Line::Context(_) => continue,
206                _ => return true,
207            }
208        }
209        false
210    }
211
212    pub fn update(&mut self) {
213        let mut s1 = 0;
214        let mut s2 = 0;
215        for line in self.data.iter() {
216            match line {
217                Line::Context(_) => {
218                    s1 += 1;
219                    s2 += 1;
220                },
221                Line::Insert(_) => s2 += 1,
222                Line::Delete(_) => s1 += 1,
223            }
224        }
225        self.header.file1_s = s1;
226        self.header.file2_s = s2;
227    }
228}
229
230impl fmt::Display for Context {
231    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232        writeln!(f, "{}", self.header)?;
233        for line in self.data.iter() {
234            writeln!(f, "{}", line)?;
235        }
236        Ok(())
237    }
238}
239
240#[derive(Default, Clone, Copy)]
241pub struct ContextHeader {
242    pub file1_l: usize,
243    pub file1_s: usize,
244    pub file2_l: usize,
245    pub file2_s: usize,
246}
247
248impl fmt::Display for ContextHeader {
249    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250        write!(f, "@@ -{},{} +{},{} @@", self.file1_l, self.file1_s, self.file2_l, self.file2_s)
251    }
252}