11//! Facilities to produce git-formatted diffs.
22
33use std:: cmp:: Ordering ;
4- use std:: fmt:: Display ;
54use std:: ops:: Range ;
65
6+ use crate :: blob:: GitDiff ;
77use imara_diff:: intern:: { InternedInput , Interner , Token } ;
88use imara_diff:: Sink ;
99
@@ -25,6 +25,20 @@ const RELATIVE_OUTDENT_WITH_BLANK_PENALTY: i16 = 17;
2525const RELATIVE_DEDENT_PENALTY : i16 = 23 ;
2626const RELATIVE_DEDENT_WITH_BLANK_PENALTY : i16 = 17 ;
2727
28+ pub ( super ) mod types {
29+ use crate :: blob:: git_diff:: ChangeGroup ;
30+
31+ /// A [`Sink`](imara_diff::Sink) that creates a diff like git would.
32+ pub struct GitDiff < ' a , T >
33+ where
34+ T : std:: fmt:: Display ,
35+ {
36+ pub ( crate ) after : & ' a [ imara_diff:: intern:: Token ] ,
37+ pub ( crate ) interner : & ' a imara_diff:: intern:: Interner < T > ,
38+ pub ( crate ) changes : Vec < ChangeGroup > ,
39+ }
40+ }
41+
2842/// An enum indicating the kind of change that occurred.
2943#[ derive( PartialEq , Debug ) ]
3044pub enum ChangeKind {
@@ -63,22 +77,13 @@ pub struct ChangeGroup {
6377 /// Range indicating the lines of the previous block.
6478 /// To actually see how the previous block looked like, you need to combine this range with
6579 /// the [`InternedInput`].
66- before : Range < usize > ,
80+ pub before : Range < usize > ,
6781 /// Range indicating the lines of the new block
6882 /// To actually see how the current block looks like, you need to combine this range with
6983 /// the [`InternedInput`].
70- after : Range < usize > ,
71- change_kind : ChangeKind ,
72- }
73-
74- /// A [`Sink`] that creates a diff like git would.
75- pub struct GitDiff < ' a , T >
76- where
77- T : Display ,
78- {
79- after : & ' a [ Token ] ,
80- interner : & ' a Interner < T > ,
81- changes : Vec < ChangeGroup > ,
84+ pub after : Range < usize > ,
85+ /// Further specify what kind of change is denoted by the ranges above.
86+ pub change_kind : ChangeKind ,
8287}
8388
8489// Calculate the indentation of a single line
@@ -102,7 +107,12 @@ fn get_indent(s: String) -> Option<u8> {
102107 None
103108}
104109
105- fn measure_and_score_change < T : Display > ( lines : & [ Token ] , split : usize , interner : & Interner < T > , score : & mut Score ) {
110+ fn measure_and_score_change < T : std:: fmt:: Display > (
111+ lines : & [ Token ] ,
112+ split : usize ,
113+ interner : & Interner < T > ,
114+ score : & mut Score ,
115+ ) {
106116 // Gather information about the surroundings of the change
107117 let end_of_file = split >= lines. len ( ) ;
108118 let mut indent: Option < u8 > = if split >= lines. len ( ) {
@@ -181,7 +191,7 @@ fn measure_and_score_change<T: Display>(lines: &[Token], split: usize, interner:
181191
182192impl < ' a , T > GitDiff < ' a , T >
183193where
184- T : Display ,
194+ T : std :: fmt :: Display ,
185195{
186196 /// Create a new instance of [`GitDiff`] that can then be passed to [`imara_diff::diff`]
187197 /// and generate a more human-readable diff.
@@ -196,48 +206,37 @@ where
196206
197207impl < T > Sink for GitDiff < ' _ , T >
198208where
199- T : Display ,
209+ T : std :: fmt :: Display ,
200210{
201211 type Out = Vec < ChangeGroup > ;
202212
203213 fn process_change ( & mut self , before : Range < u32 > , after : Range < u32 > ) {
204- if before. is_empty ( ) && !after. is_empty ( ) {
205- self . changes . push ( ChangeGroup {
206- before : before. start as usize ..before. end as usize ,
207- after : after. start as usize ..after. end as usize ,
208- change_kind : ChangeKind :: Added ,
209- } ) ;
210- } else if after. is_empty ( ) && !before. is_empty ( ) {
211- if after. start == 0 {
212- self . changes . push ( ChangeGroup {
213- before : before. start as usize ..before. end as usize ,
214- after : after. start as usize ..after. end as usize ,
215- change_kind : ChangeKind :: RemovedAbove ,
216- } ) ;
217- } else {
218- self . changes . push ( ChangeGroup {
219- before : before. start as usize ..before. end as usize ,
220- after : after. start as usize ..after. end as usize ,
221- change_kind : ChangeKind :: RemovedBelow ,
222- } ) ;
214+ let change_kind = match ( before. is_empty ( ) , after. is_empty ( ) ) {
215+ ( true , false ) => ChangeKind :: Added ,
216+ ( false , true ) => {
217+ if after. start == 0 {
218+ ChangeKind :: RemovedAbove
219+ } else {
220+ ChangeKind :: RemovedBelow
221+ }
223222 }
224- } else {
225- self . changes . push ( ChangeGroup {
226- before : before . start as usize ..before . end as usize ,
227- after : after . start as usize ..after . end as usize ,
228- change_kind : ChangeKind :: Modified ,
229- } ) ;
230- }
223+ _ => ChangeKind :: Modified ,
224+ } ;
225+ self . changes . push ( ChangeGroup {
226+ before : before . start as usize ..before . end as usize ,
227+ after : after . start as usize ..after . end as usize ,
228+ change_kind ,
229+ } ) ;
231230 }
232231
233232 fn finish ( mut self ) -> Self :: Out {
234233 if self . changes . is_empty ( ) {
235234 return self . changes ;
236235 }
237- let mut shift: usize ;
238236
239- for change in self . changes . iter_mut ( ) {
240- // Skip one liner changes
237+ let mut shift: usize ;
238+ for change in & mut self . changes {
239+ // Skip one-liner changes
241240 if change. after . is_empty ( ) {
242241 continue ;
243242 }
@@ -316,85 +315,3 @@ where
316315 self . changes
317316 }
318317}
319-
320- #[ test]
321- fn git_diff_test ( ) {
322- let before = r#"struct SomeStruct {
323- field1: f64,
324- field2: f64,
325- }
326-
327- fn main() {
328- // Some comment
329- let c = SomeStruct { field1: 10.0, field2: 10.0 };
330-
331- println!(
332- "Print field1 from SomeStruct {}",
333- get_field1(&c)
334- );
335- }
336-
337- fn get_field1(c: &SomeStruct) -> f64 {
338- c.field1
339- }
340- "# ;
341-
342- let after = r#"/// This is a struct
343- struct SomeStruct {
344- field1: f64,
345- field2: f64,
346- }
347-
348- fn main() {
349- let c = SomeStruct { field1: 10.0, field2: 10.0 };
350-
351- println!(
352- "Print field1 and field2 from SomeStruct {} {}",
353- get_field1(&c), get_field2(&c)
354- );
355- println!("Print another line");
356- }
357-
358- fn get_field1(c: &SomeStruct) -> f64 {
359- c.field1
360- }
361-
362- fn get_field2(c: &SomeStruct) -> f64 {
363- c.field2
364- }
365- "# ;
366- use crate :: blob:: git_diff:: ChangeKind ;
367-
368- let input = InternedInput :: new ( before, after) ;
369- let diff = imara_diff:: diff ( imara_diff:: Algorithm :: Histogram , & input, GitDiff :: new ( & input) ) ;
370- assert_eq ! (
371- diff,
372- vec![
373- ChangeGroup {
374- before: 0 ..0 ,
375- after: 0 ..1 ,
376- change_kind: ChangeKind :: Added
377- } ,
378- ChangeGroup {
379- before: 6 ..7 ,
380- after: 7 ..7 ,
381- change_kind: ChangeKind :: RemovedBelow
382- } ,
383- ChangeGroup {
384- before: 10 ..12 ,
385- after: 10 ..12 ,
386- change_kind: ChangeKind :: Modified
387- } ,
388- ChangeGroup {
389- before: 13 ..13 ,
390- after: 13 ..14 ,
391- change_kind: ChangeKind :: Added
392- } ,
393- ChangeGroup {
394- before: 17 ..17 ,
395- after: 19 ..23 ,
396- change_kind: ChangeKind :: Added
397- }
398- ]
399- ) ;
400- }
0 commit comments