git.rs

 1use std::ops::Range;
 2
 3use git::diff::{DiffHunk, DiffHunkStatus};
 4use language::Point;
 5
 6use crate::{
 7    display_map::{DisplaySnapshot, ToDisplayPoint},
 8    AnchorRangeExt,
 9};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum DisplayDiffHunk {
13    Folded {
14        display_row: u32,
15    },
16
17    Unfolded {
18        display_row_range: Range<u32>,
19        status: DiffHunkStatus,
20    },
21}
22
23impl DisplayDiffHunk {
24    pub fn start_display_row(&self) -> u32 {
25        match self {
26            &DisplayDiffHunk::Folded { display_row } => display_row,
27            DisplayDiffHunk::Unfolded {
28                display_row_range, ..
29            } => display_row_range.start,
30        }
31    }
32
33    pub fn contains_display_row(&self, display_row: u32) -> bool {
34        let range = match self {
35            &DisplayDiffHunk::Folded { display_row } => display_row..=display_row,
36
37            DisplayDiffHunk::Unfolded {
38                display_row_range, ..
39            } => {
40                if display_row_range.len() == 0 {
41                    display_row_range.start..=display_row_range.end
42                } else {
43                    display_row_range.start..=display_row_range.end - 1
44                }
45            }
46        };
47
48        range.contains(&display_row)
49    }
50}
51
52pub fn diff_hunk_to_display(hunk: DiffHunk<u32>, snapshot: &DisplaySnapshot) -> DisplayDiffHunk {
53    let hunk_start_point = Point::new(hunk.buffer_range.start, 0);
54    let hunk_end_point = Point::new(hunk.buffer_range.end, 0);
55    let hunk_start_point_sub = Point::new(hunk.buffer_range.start.saturating_sub(1), 0);
56    let hunk_end_point_sub = Point::new(
57        hunk.buffer_range
58            .end
59            .saturating_sub(1)
60            .max(hunk.buffer_range.start),
61        0,
62    );
63
64    let is_removal = hunk.status() == DiffHunkStatus::Removed;
65
66    let folds_start = Point::new(hunk.buffer_range.start.saturating_sub(1), 0);
67    let folds_end = Point::new(hunk.buffer_range.end + 1, 0);
68    let folds_range = folds_start..folds_end;
69
70    let containing_fold = snapshot.folds_in_range(folds_range).find(|fold_range| {
71        let fold_point_range = fold_range.to_point(&snapshot.buffer_snapshot);
72        let fold_point_range = fold_point_range.start..=fold_point_range.end;
73
74        let folded_start = fold_point_range.contains(&hunk_start_point);
75        let folded_end = fold_point_range.contains(&hunk_end_point_sub);
76        let folded_start_sub = fold_point_range.contains(&hunk_start_point_sub);
77
78        (folded_start && folded_end) || (is_removal && folded_start_sub)
79    });
80
81    if let Some(fold) = containing_fold {
82        let row = fold.start.to_display_point(snapshot).row();
83        DisplayDiffHunk::Folded { display_row: row }
84    } else {
85        let start = hunk_start_point.to_display_point(snapshot).row();
86        let end = hunk_end_point.to_display_point(snapshot).row();
87        DisplayDiffHunk::Unfolded {
88            display_row_range: start..end,
89            status: hunk.status(),
90        }
91    }
92}