gpui_component/diff/
decoration.rs1use std::collections::HashMap;
2
3use gpui::{ElementId, Hsla, SharedString};
4
5use super::{DiffLinePosition, DiffLineRange, DiffSide};
6
7#[derive(Clone)]
14pub struct DiffDecoration {
15 range: DiffLineRange,
16 background: Option<Hsla>,
17}
18
19impl DiffDecoration {
20 pub fn new(range: DiffLineRange) -> Self {
25 Self {
26 range,
27 background: None,
28 }
29 }
30 pub fn with_background(mut self, background: impl Into<Hsla>) -> Self {
32 self.background = Some(background.into());
33 self
34 }
35 pub fn range(&self) -> &DiffLineRange {
36 &self.range
37 }
38 pub fn background(&self) -> Option<Hsla> {
40 self.background
41 }
42
43 fn contains(&self, side: DiffSide, line: usize) -> bool {
44 let range = &self.range;
45 if range.is_single_side() {
46 side == range.side() && (range.start()..=range.end()).contains(&line)
47 } else if side == range.side() {
48 line >= range.start()
49 } else {
50 line <= range.end()
51 }
52 }
53}
54
55#[derive(Clone)]
61pub struct DiffGutterMarker {
62 id: ElementId,
63 position: DiffLinePosition,
64 label: SharedString,
65}
66
67impl DiffGutterMarker {
68 pub fn new(id: impl Into<ElementId>, position: DiffLinePosition) -> Self {
70 Self {
71 id: id.into(),
72 position,
73 label: SharedString::default(),
74 }
75 }
76 pub fn with_label(mut self, label: impl Into<SharedString>) -> Self {
78 self.label = label.into();
79 self
80 }
81 pub fn id(&self) -> &ElementId {
82 &self.id
83 }
84 pub fn position(&self) -> &DiffLinePosition {
85 &self.position
86 }
87 pub fn label(&self) -> &SharedString {
88 &self.label
89 }
90}
91
92#[derive(Default)]
94pub(super) struct Decorations {
95 files: HashMap<SharedString, Vec<DiffDecoration>>,
96}
97
98impl Decorations {
99 pub(super) fn new(decorations: impl IntoIterator<Item = DiffDecoration>) -> Self {
100 let mut index = Self::default();
101 for decoration in decorations {
102 index
103 .files
104 .entry(decoration.range.path().clone())
105 .or_default()
106 .push(decoration);
107 }
108 index
109 }
110
111 pub(super) fn at(&self, position: &DiffLinePosition) -> Option<&DiffDecoration> {
113 self.files
114 .get(position.path())?
115 .iter()
116 .rev()
117 .find(|decoration| decoration.contains(position.side(), position.line()))
118 }
119}
120
121#[derive(Default)]
123pub(super) struct GutterMarkers {
124 lines: HashMap<DiffLinePosition, DiffGutterMarker>,
125}
126
127impl GutterMarkers {
128 pub(super) fn new(markers: impl IntoIterator<Item = DiffGutterMarker>) -> Self {
129 let mut index = Self::default();
130 for marker in markers {
131 index.lines.entry(marker.position.clone()).or_insert(marker);
132 }
133 index
134 }
135
136 pub(super) fn is_empty(&self) -> bool {
137 self.lines.is_empty()
138 }
139
140 pub(super) fn at(&self, position: &DiffLinePosition) -> Option<&DiffGutterMarker> {
141 self.lines.get(position)
142 }
143}