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 } => display_row_range.start..=display_row_range.end - 1,
40 };
41
42 range.contains(&display_row)
43 }
44}
45
46pub fn diff_hunk_to_display(hunk: DiffHunk<u32>, snapshot: &DisplaySnapshot) -> DisplayDiffHunk {
47 let hunk_start_point = Point::new(hunk.buffer_range.start, 0);
48 let hunk_start_point_sub = Point::new(hunk.buffer_range.start.saturating_sub(1), 0);
49 let hunk_end_point_sub = Point::new(
50 hunk.buffer_range
51 .end
52 .saturating_sub(1)
53 .max(hunk.buffer_range.start),
54 0,
55 );
56
57 let is_removal = hunk.status() == DiffHunkStatus::Removed;
58
59 let folds_start = Point::new(hunk.buffer_range.start.saturating_sub(2), 0);
60 let folds_end = Point::new(hunk.buffer_range.end + 2, 0);
61 let folds_range = folds_start..folds_end;
62
63 let containing_fold = snapshot.folds_in_range(folds_range).find(|fold_range| {
64 let fold_point_range = fold_range.to_point(&snapshot.buffer_snapshot);
65 let fold_point_range = fold_point_range.start..=fold_point_range.end;
66
67 let folded_start = fold_point_range.contains(&hunk_start_point);
68 let folded_end = fold_point_range.contains(&hunk_end_point_sub);
69 let folded_start_sub = fold_point_range.contains(&hunk_start_point_sub);
70
71 (folded_start && folded_end) || (is_removal && folded_start_sub)
72 });
73
74 if let Some(fold) = containing_fold {
75 let row = fold.start.to_display_point(snapshot).row();
76 DisplayDiffHunk::Folded { display_row: row }
77 } else {
78 let start = hunk_start_point.to_display_point(snapshot).row();
79
80 let hunk_end_row_inclusive = hunk.buffer_range.end.max(hunk.buffer_range.start);
81 let hunk_end_point = Point::new(hunk_end_row_inclusive, 0);
82 let end = hunk_end_point.to_display_point(snapshot).row();
83
84 DisplayDiffHunk::Unfolded {
85 display_row_range: start..end,
86 status: hunk.status(),
87 }
88 }
89}