1use std::ops::Range;
8
9use gpui::{
10 BorderStyle, Bounds, Hsla, Pixels, Point, TextRun, Window, WrappedLineLayout, point, px, quad,
11 size,
12};
13
14use super::caret;
15
16#[derive(Clone, Debug, PartialEq)]
18pub struct Overdraw {
19 pub range: Range<usize>,
20 pub plate: Hsla,
22 pub ink: Hsla,
24}
25
26#[derive(Clone, Debug)]
31pub struct Layers<S> {
32 washes: Vec<(Range<usize>, Hsla, S)>,
33 selection: Option<(Range<usize>, Hsla, S)>,
34}
35
36impl<S> Default for Layers<S> {
37 fn default() -> Self {
38 Self {
39 washes: Vec::new(),
40 selection: None,
41 }
42 }
43}
44
45impl<S> Layers<S> {
46 pub fn new() -> Self {
47 Self::default()
48 }
49
50 pub fn wash(mut self, range: Range<usize>, color: Hsla, shape: S) -> Self {
52 self.washes.push((range, color, shape));
53 self
54 }
55
56 pub fn select(mut self, range: Range<usize>, color: Hsla, shape: S) -> Self {
58 self.selection = Some((range, color, shape));
59 self
60 }
61
62 pub fn painted(&self) -> impl Iterator<Item = (&Range<usize>, Hsla, &S)> {
65 self.selection
66 .iter()
67 .chain(&self.washes)
68 .map(|(range, color, shape)| (range, *color, shape))
69 }
70
71 pub fn surface(&self, page: Hsla, piece: &Range<usize>) -> Hsla {
74 theme::stack(
75 page,
76 self.washes
77 .iter()
78 .filter(|(range, ..)| covers(range, piece))
79 .map(|(_, color, _)| *color),
80 )
81 }
82
83 pub fn plate(&self, page: Hsla, piece: &Range<usize>) -> Option<Hsla> {
86 let mut over = self
87 .painted()
88 .filter(|(range, ..)| covers(range, piece))
89 .map(|(_, color, _)| color)
90 .peekable();
91 over.peek()?;
92 Some(theme::stack(page, over))
93 }
94
95 pub fn clipped(&self, span: &Range<usize>) -> Self
97 where
98 S: Clone,
99 {
100 let clip = |(range, color, shape): &(Range<usize>, Hsla, S)| {
101 let (from, to) = (range.start.max(span.start), range.end.min(span.end));
102 (from < to).then(|| (from - span.start..to - span.start, *color, shape.clone()))
103 };
104 Self {
105 washes: self.washes.iter().filter_map(clip).collect(),
106 selection: self.selection.as_ref().and_then(clip),
107 }
108 }
109
110 fn edges(&self) -> impl Iterator<Item = usize> + '_ {
111 self.washes
112 .iter()
113 .map(|(range, ..)| range)
114 .chain(self.selection.as_ref().map(|(range, ..)| range))
115 .flat_map(|range| [range.start, range.end])
116 }
117}
118
119pub fn overdraws<S>(runs: &[TextRun], page: Hsla, layers: &Layers<S>) -> Vec<Overdraw> {
124 let mut out: Vec<Overdraw> = Vec::new();
125 let mut at = 0;
126 for run in runs {
127 let end = at + run.len;
128 let mut cuts: Vec<usize> = layers
129 .edges()
130 .filter(|cut| (at + 1..end).contains(cut))
131 .chain([at, end])
132 .collect();
133 cuts.sort_unstable();
134 cuts.dedup();
135 for piece in cuts.windows(2) {
136 let (from, to) = (piece[0], piece[1]);
137 let Some(plate) = layers.plate(page, &(from..to)) else {
138 continue;
139 };
140 let surface = layers.surface(page, &(from..to));
141 let ink = theme::ink_over(run.color, page, surface, plate);
142 if ink == run.color {
143 continue;
144 }
145 match out.last_mut() {
146 Some(last) if last.range.end == from && last.plate == plate && last.ink == ink => {
147 last.range.end = to;
148 }
149 _ => out.push(Overdraw {
150 range: from..to,
151 plate,
152 ink,
153 }),
154 }
155 }
156 at = end;
157 }
158 out
159}
160
161fn covers(range: &Range<usize>, piece: &Range<usize>) -> bool {
162 range.start <= piece.start && piece.end <= range.end
163}
164
165pub fn paint<'a>(
170 lines: impl IntoIterator<Item = &'a WrappedLineLayout>,
171 origin: Point<Pixels>,
172 line_height: Pixels,
173 radius: Pixels,
174 pieces: &[Overdraw],
175 window: &mut Window,
176) {
177 if pieces.is_empty() {
178 return;
179 }
180 let (mut start, mut top) = (0, origin);
181 for line in lines {
182 let end = start + line.len();
183 for piece in pieces {
184 let (from, to) = (piece.range.start.max(start), piece.range.end.min(end));
185 if from < to {
186 paint_line(
187 line,
188 top,
189 line_height,
190 radius,
191 from - start..to - start,
192 piece,
193 window,
194 );
195 }
196 }
197 start = end + 1;
198 top.y += line.size(line_height).height;
199 }
200}
201
202fn paint_line(
204 line: &WrappedLineLayout,
205 origin: Point<Pixels>,
206 line_height: Pixels,
207 radius: Pixels,
208 range: Range<usize>,
209 piece: &Overdraw,
210 window: &mut Window,
211) {
212 let layout = &line.unwrapped_layout;
213 let starts: Vec<usize> = std::iter::once(0)
214 .chain(
215 line.wrap_boundaries()
216 .iter()
217 .map(|wrap| layout.runs[wrap.run_ix].glyphs[wrap.glyph_ix].index),
218 )
219 .collect();
220 let ends = starts.iter().skip(1).copied().chain([line.len()]);
221 for (row, (start, end)) in starts.iter().copied().zip(ends).enumerate() {
222 let (from, to) = (range.start.max(start), range.end.min(end));
223 if from >= to {
224 continue;
225 }
226 let (left, right) = (layout.x_for_index(from), layout.x_for_index(to));
227 let at = origin + point(left - layout.x_for_index(start), line_height * row as f32);
228 window.paint_quad(quad(
229 Bounds::new(at, size(right - left, line_height)),
230 radius,
231 piece.plate,
232 px(0.),
233 gpui::transparent_black(),
234 BorderStyle::default(),
235 ));
236 caret::paint_covered(layout, &(from..to), at, line_height, piece.ink, window);
237 }
238}