git.rs

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