gpui_base/input/editor/display_map/
display_map.rs1use std::ops::Range;
8
9use gpui::{App, Font, Pixels};
10use ropey::Rope;
11
12use super::fold_map::FoldMap;
13use super::folding::FoldRange;
14pub use super::text_wrapper::WrappingIndent;
15use super::text_wrapper::{LineItem, WrapDisplayPoint};
16use super::wrap_map::WrapMap;
17use super::{BufferPoint, DisplayPoint};
18use crate::input::Point as TreeSitterPoint;
19use crate::input::display_map::WrapPoint;
20use crate::input::rope_ext::RopeExt as _;
21
22pub struct DisplayMap {
30 wrap_map: WrapMap,
31 fold_map: FoldMap,
32}
33
34impl DisplayMap {
35 pub fn new(font: Font, font_size: Pixels, wrap_width: Option<Pixels>) -> Self {
36 Self {
37 wrap_map: WrapMap::new(font, font_size, wrap_width),
38 fold_map: FoldMap::new(),
39 }
40 }
41
42 pub fn buffer_pos_to_display_pos(&self, pos: BufferPoint) -> DisplayPoint {
46 let wrap_pos = self.wrap_map.buffer_pos_to_wrap_pos(pos);
48
49 if let Some(display_row) = self.fold_map.wrap_row_to_display_row(wrap_pos.row) {
51 DisplayPoint::new(display_row, wrap_pos.col)
52 } else {
53 let display_row = self.fold_map.nearest_visible_display_row(wrap_pos.row);
55 DisplayPoint::new(display_row, 0) }
57 }
58
59 pub fn display_pos_to_buffer_pos(&self, pos: DisplayPoint) -> BufferPoint {
61 let wrap_row = self.fold_map.display_row_to_wrap_row(pos.row).unwrap_or(0);
63
64 let wrap_pos = WrapPoint::new(wrap_row, pos.col);
66 self.wrap_map.wrap_pos_to_buffer_pos(wrap_pos)
67 }
68
69 #[inline]
71 pub fn display_row_count(&self) -> usize {
72 self.fold_map.display_row_count()
73 }
74
75 pub fn display_row_to_buffer_line(&self, display_row: usize) -> usize {
77 let wrap_row = self
79 .fold_map
80 .display_row_to_wrap_row(display_row)
81 .unwrap_or(0);
82
83 self.wrap_map.wrap_row_to_buffer_line(wrap_row)
85 }
86
87 pub fn buffer_line_to_display_row_range(&self, line: usize) -> Option<Range<usize>> {
90 let wrap_row_range = self.wrap_map.buffer_line_to_wrap_row_range(line);
92
93 let mut first_display_row = None;
95 let mut last_display_row = None;
96
97 for wrap_row in wrap_row_range {
98 if let Some(display_row) = self.fold_map.wrap_row_to_display_row(wrap_row) {
99 if first_display_row.is_none() {
100 first_display_row = Some(display_row);
101 }
102 last_display_row = Some(display_row);
103 }
104 }
105
106 if let (Some(start), Some(end)) = (first_display_row, last_display_row) {
107 Some(start..end + 1)
108 } else {
109 None }
111 }
112
113 #[inline]
115 pub fn is_buffer_line_hidden(&self, line: usize) -> bool {
116 self.buffer_line_to_display_row_range(line).is_none()
117 }
118
119 pub fn buffer_line_to_display_row(&self, line: usize) -> usize {
122 match self.buffer_line_to_display_row_range(line) {
123 Some(range) => range.start,
124 None => {
125 let wrap_row = self.wrap_map.buffer_line_to_first_wrap_row(line);
126 self.fold_map.nearest_visible_display_row(wrap_row)
127 }
128 }
129 }
130
131 pub fn set_fold_candidates(&mut self, candidates: Vec<FoldRange>) {
133 self.fold_map.set_candidates(candidates);
134 self.rebuild_fold_projection();
135 }
136
137 pub fn set_folded(&mut self, start_line: usize, folded: bool) {
139 self.fold_map.set_folded(start_line, folded);
140 self.rebuild_fold_projection();
141 }
142
143 pub fn toggle_fold(&mut self, start_line: usize) {
145 self.fold_map.toggle_fold(start_line);
146 self.rebuild_fold_projection();
147 }
148
149 #[inline]
151 pub fn is_folded_at(&self, start_line: usize) -> bool {
152 self.fold_map.is_folded_at(start_line)
153 }
154
155 #[inline]
157 pub fn is_fold_candidate(&self, start_line: usize) -> bool {
158 self.fold_map.is_fold_candidate(start_line)
159 }
160
161 #[inline]
163 pub fn folded_ranges(&self) -> &[FoldRange] {
164 self.fold_map.folded_ranges()
165 }
166
167 pub fn clear_folds(&mut self) {
169 self.fold_map.clear_folds();
170 self.rebuild_fold_projection();
171 }
172
173 pub fn adjust_folds_for_edit(&mut self, old_text: &Rope, range: &Range<usize>, new_text: &str) {
180 if self.fold_map.folded_ranges().is_empty() && self.fold_map.fold_candidates().is_empty() {
181 return;
182 }
183
184 let edit_start_line = old_text.offset_to_point(range.start).row;
185 let edit_end_line = old_text.offset_to_point(range.end.min(old_text.len())).row;
186
187 let old_lines_in_range = edit_end_line.saturating_sub(edit_start_line);
188 let new_lines_in_range = new_text.chars().filter(|c| *c == '\n').count();
189 let line_delta = new_lines_in_range as isize - old_lines_in_range as isize;
190
191 self.fold_map
192 .adjust_folds_for_edit(edit_start_line, edit_end_line, line_delta);
193 }
194
195 pub fn update_fold_candidates_for_edit(
200 &mut self,
201 extract_fold_ranges: impl FnOnce(Range<usize>, &Rope) -> Vec<FoldRange>,
202 edit_byte_range: Range<usize>,
203 new_text: &Rope,
204 ) {
205 let new_start_line = new_text.offset_to_point(edit_byte_range.start).row;
206 let new_end_line = new_text
207 .offset_to_point(edit_byte_range.end.min(new_text.len()))
208 .row;
209
210 let new_candidates = extract_fold_ranges(edit_byte_range, new_text);
211 self.fold_map
212 .merge_candidates_for_edit(new_start_line, new_end_line, new_candidates);
213 }
214
215 pub fn on_text_changed(
217 &mut self,
218 changed_text: &Rope,
219 range: &Range<usize>,
220 new_text: &Rope,
221 cx: &mut App,
222 ) {
223 self.wrap_map
224 .on_text_changed(changed_text, range, new_text, cx);
225 self.rebuild_fold_projection();
226 }
227
228 pub(crate) fn set_inline_metrics(
230 &mut self,
231 metrics: std::rc::Rc<[(std::ops::Range<usize>, Pixels)]>,
232 cx: &mut App,
233 ) {
234 self.wrap_map.set_inline_metrics(metrics, cx);
235 self.rebuild_fold_projection();
236 }
237
238 pub fn on_layout_changed(&mut self, wrap_width: Option<Pixels>, cx: &mut App) {
239 self.wrap_map.on_layout_changed(wrap_width, cx);
240 self.rebuild_fold_projection();
241 }
242
243 pub fn set_wrapping_indent(&mut self, wrapping_indent: WrappingIndent, cx: &mut App) {
245 self.wrap_map.set_wrapping_indent(wrapping_indent, cx);
246 self.rebuild_fold_projection();
247 }
248
249 pub fn set_font(&mut self, font: Font, font_size: Pixels, cx: &mut App) {
251 self.wrap_map.set_font(font, font_size, cx);
252 self.rebuild_fold_projection();
253 }
254
255 pub fn ensure_text_prepared(&mut self, text: &Rope, cx: &mut App) {
257 let did_initialize = self.wrap_map.ensure_text_prepared(text, cx);
258 if did_initialize {
259 self.rebuild_fold_projection();
260 }
261 }
262
263 pub fn set_text(&mut self, text: &Rope, cx: &mut App) {
265 self.wrap_map.set_text(text, cx);
266 self.rebuild_fold_projection();
267 }
268
269 fn rebuild_fold_projection(&mut self) {
274 if !self.fold_map.folded_ranges().is_empty() {
275 self.fold_map.rebuild(&self.wrap_map);
276 } else {
277 self.fold_map
280 .mark_dirty_with_wrap_count(self.wrap_map.wrap_row_count());
281 }
282 }
283
284 #[inline]
288 pub(crate) fn offset_to_wrap_display_point(&self, offset: usize) -> WrapDisplayPoint {
289 self.wrap_map.wrapper().offset_to_display_point(offset)
290 }
291
292 #[inline]
295 pub(crate) fn offset_to_wrap_display_point_with_affinity(
296 &self,
297 offset: usize,
298 line_end_affinity: bool,
299 ) -> WrapDisplayPoint {
300 self.wrap_map
301 .wrapper()
302 .offset_to_display_point_with_affinity(offset, line_end_affinity)
303 }
304
305 #[inline]
307 pub(crate) fn wrap_display_point_to_offset(&self, point: WrapDisplayPoint) -> usize {
308 self.wrap_map.wrapper().display_point_to_offset(point)
309 }
310
311 #[inline]
313 pub(crate) fn wrap_display_point_to_point(&self, point: WrapDisplayPoint) -> TreeSitterPoint {
314 self.wrap_map.wrapper().display_point_to_point(point)
315 }
316
317 #[inline]
320 pub fn wrap_row_to_display_row(&self, wrap_row: usize) -> Option<usize> {
321 self.fold_map.wrap_row_to_display_row(wrap_row)
322 }
323
324 #[inline]
326 pub fn nearest_visible_display_row(&self, wrap_row: usize) -> usize {
327 self.fold_map.nearest_visible_display_row(wrap_row)
328 }
329
330 #[inline]
332 pub fn display_row_to_wrap_row(&self, display_row: usize) -> Option<usize> {
333 self.fold_map.display_row_to_wrap_row(display_row)
334 }
335
336 pub(crate) fn display_row_column_to_offset(&self, display_row: usize, column: usize) -> usize {
337 let wrap_row = self
338 .fold_map
339 .display_row_to_wrap_row(display_row)
340 .unwrap_or(0);
341 self.wrap_map
342 .wrapper()
343 .display_point_to_offset(WrapDisplayPoint::new(wrap_row, 0, column))
344 }
345
346 #[inline]
348 pub(crate) fn longest_row(&self) -> usize {
349 self.wrap_map.wrapper().longest_row()
350 }
351
352 #[inline]
356 pub(crate) fn line(&self, row: usize) -> Option<&LineItem> {
357 self.wrap_map.line(row)
358 }
359
360 #[inline]
362 pub fn text(&self) -> &Rope {
363 self.wrap_map.text()
364 }
365
366 #[inline]
368 pub fn visible_wrap_row_count_for_buffer_line(&self, line: usize) -> usize {
369 self.wrap_map
370 .visible_wrap_row_count_for_line(line, &self.fold_map)
371 }
372
373 #[inline]
375 pub fn wrap_row_count(&self) -> usize {
376 self.wrap_map.wrap_row_count()
377 }
378
379 #[inline]
381 pub fn buffer_line_count(&self) -> usize {
382 self.wrap_map.buffer_line_count()
383 }
384}