1use super::{
2 fold_map,
3 tab_map::{self, Edit as TabEdit, Snapshot as TabSnapshot, TabPoint, TextSummary},
4};
5use gpui::{fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, Task};
6use language::{HighlightedChunk, Point};
7use lazy_static::lazy_static;
8use smol::future::yield_now;
9use std::{collections::VecDeque, mem, ops::Range, time::Duration};
10use sum_tree::{Bias, Cursor, SumTree};
11
12pub type Edit = buffer::Edit<u32>;
13
14pub struct WrapMap {
15 snapshot: Snapshot,
16 pending_edits: VecDeque<(TabSnapshot, Vec<TabEdit>)>,
17 interpolated_edits: Patch,
18 edits_since_sync: Patch,
19 wrap_width: Option<f32>,
20 background_task: Option<Task<()>>,
21 font: (FontId, f32),
22}
23
24#[derive(Default)]
25struct Patch(Vec<Edit>);
26
27impl Entity for WrapMap {
28 type Event = ();
29}
30
31#[derive(Clone)]
32pub struct Snapshot {
33 tab_snapshot: TabSnapshot,
34 transforms: SumTree<Transform>,
35 interpolated: bool,
36}
37
38#[derive(Clone, Debug, Default, Eq, PartialEq)]
39struct Transform {
40 summary: TransformSummary,
41 display_text: Option<&'static str>,
42}
43
44#[derive(Clone, Debug, Default, Eq, PartialEq)]
45struct TransformSummary {
46 input: TextSummary,
47 output: TextSummary,
48}
49
50#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
51pub struct WrapPoint(super::Point);
52
53pub struct Chunks<'a> {
54 input_chunks: tab_map::Chunks<'a>,
55 input_chunk: &'a str,
56 output_position: WrapPoint,
57 transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>,
58}
59
60pub struct HighlightedChunks<'a> {
61 input_chunks: tab_map::HighlightedChunks<'a>,
62 input_chunk: HighlightedChunk<'a>,
63 output_position: WrapPoint,
64 max_output_row: u32,
65 transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>,
66}
67
68pub struct BufferRows<'a> {
69 input_buffer_rows: fold_map::BufferRows<'a>,
70 input_buffer_row: u32,
71 output_row: u32,
72 soft_wrapped: bool,
73 max_output_row: u32,
74 transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>,
75}
76
77impl WrapMap {
78 pub fn new(
79 tab_snapshot: TabSnapshot,
80 font_id: FontId,
81 font_size: f32,
82 wrap_width: Option<f32>,
83 cx: &mut ModelContext<Self>,
84 ) -> Self {
85 let mut this = Self {
86 font: (font_id, font_size),
87 wrap_width: None,
88 pending_edits: Default::default(),
89 interpolated_edits: Default::default(),
90 edits_since_sync: Default::default(),
91 snapshot: Snapshot::new(tab_snapshot),
92 background_task: None,
93 };
94 this.set_wrap_width(wrap_width, cx);
95
96 this
97 }
98
99 #[cfg(test)]
100 pub fn is_rewrapping(&self) -> bool {
101 self.background_task.is_some()
102 }
103
104 pub fn sync(
105 &mut self,
106 tab_snapshot: TabSnapshot,
107 edits: Vec<TabEdit>,
108 cx: &mut ModelContext<Self>,
109 ) -> (Snapshot, Vec<Edit>) {
110 self.pending_edits.push_back((tab_snapshot, edits));
111 self.flush_edits(cx);
112 (
113 self.snapshot.clone(),
114 mem::take(&mut self.edits_since_sync).0,
115 )
116 }
117
118 pub fn set_font(&mut self, font_id: FontId, font_size: f32, cx: &mut ModelContext<Self>) {
119 if (font_id, font_size) != self.font {
120 self.font = (font_id, font_size);
121 self.rewrap(cx)
122 }
123 }
124
125 pub fn set_wrap_width(&mut self, wrap_width: Option<f32>, cx: &mut ModelContext<Self>) -> bool {
126 if wrap_width == self.wrap_width {
127 return false;
128 }
129
130 self.wrap_width = wrap_width;
131 self.rewrap(cx);
132 true
133 }
134
135 fn rewrap(&mut self, cx: &mut ModelContext<Self>) {
136 self.background_task.take();
137
138 if let Some(wrap_width) = self.wrap_width {
139 let mut new_snapshot = self.snapshot.clone();
140 let font_cache = cx.font_cache().clone();
141 let (font_id, font_size) = self.font;
142 let task = cx.background().spawn(async move {
143 let mut line_wrapper = font_cache.line_wrapper(font_id, font_size);
144 let tab_snapshot = new_snapshot.tab_snapshot.clone();
145 let range = TabPoint::zero()..tab_snapshot.max_point();
146 new_snapshot
147 .update(
148 tab_snapshot,
149 &[TabEdit {
150 old_lines: range.clone(),
151 new_lines: range.clone(),
152 }],
153 wrap_width,
154 &mut line_wrapper,
155 )
156 .await;
157 new_snapshot
158 });
159
160 match cx
161 .background()
162 .block_with_timeout(Duration::from_millis(5), task)
163 {
164 Ok(snapshot) => {
165 self.snapshot = snapshot;
166 cx.notify();
167 }
168 Err(wrap_task) => {
169 self.background_task = Some(cx.spawn(|this, mut cx| async move {
170 let snapshot = wrap_task.await;
171 this.update(&mut cx, |this, cx| {
172 this.snapshot = snapshot;
173 this.background_task = None;
174 this.flush_edits(cx);
175 cx.notify();
176 });
177 }));
178 }
179 }
180 } else {
181 self.snapshot.transforms = SumTree::new();
182 let summary = self.snapshot.tab_snapshot.text_summary();
183 if !summary.lines.is_zero() {
184 self.snapshot
185 .transforms
186 .push(Transform::isomorphic(summary), &());
187 }
188 }
189 }
190
191 fn flush_edits(&mut self, cx: &mut ModelContext<Self>) {
192 if !self.snapshot.interpolated {
193 let mut to_remove_len = 0;
194 for (tab_snapshot, _) in &self.pending_edits {
195 if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() {
196 to_remove_len += 1;
197 } else {
198 break;
199 }
200 }
201 self.pending_edits.drain(..to_remove_len);
202 }
203
204 if self.pending_edits.is_empty() {
205 return;
206 }
207
208 if let Some(wrap_width) = self.wrap_width {
209 if self.background_task.is_none() {
210 let pending_edits = self.pending_edits.clone();
211 let mut snapshot = self.snapshot.clone();
212 let font_cache = cx.font_cache().clone();
213 let (font_id, font_size) = self.font;
214 let update_task = cx.background().spawn(async move {
215 let mut line_wrapper = font_cache.line_wrapper(font_id, font_size);
216
217 let mut output_edits = Patch::default();
218 for (tab_snapshot, edits) in pending_edits {
219 let wrap_edits = snapshot
220 .update(tab_snapshot, &edits, wrap_width, &mut line_wrapper)
221 .await;
222 output_edits.compose(&wrap_edits);
223 }
224 (snapshot, output_edits)
225 });
226
227 match cx
228 .background()
229 .block_with_timeout(Duration::from_millis(1), update_task)
230 {
231 Ok((snapshot, output_edits)) => {
232 self.snapshot = snapshot;
233 self.edits_since_sync.compose(&output_edits);
234 }
235 Err(update_task) => {
236 self.background_task = Some(cx.spawn(|this, mut cx| async move {
237 let (snapshot, output_edits) = update_task.await;
238 this.update(&mut cx, |this, cx| {
239 this.snapshot = snapshot;
240 this.edits_since_sync
241 .compose(mem::take(&mut this.interpolated_edits).invert())
242 .compose(&output_edits);
243 this.background_task = None;
244 this.flush_edits(cx);
245 cx.notify();
246 });
247 }));
248 }
249 }
250 }
251 }
252
253 let was_interpolated = self.snapshot.interpolated;
254 let mut to_remove_len = 0;
255 for (tab_snapshot, edits) in &self.pending_edits {
256 if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() {
257 to_remove_len += 1;
258 } else {
259 let interpolated_edits = self.snapshot.interpolate(tab_snapshot.clone(), &edits);
260 self.edits_since_sync.compose(&interpolated_edits);
261 self.interpolated_edits.compose(&interpolated_edits);
262 }
263 }
264
265 if !was_interpolated {
266 self.pending_edits.drain(..to_remove_len);
267 }
268 }
269}
270
271impl Patch {
272 fn compose(&mut self, other: &Self) -> &mut Self {
273
274 // let mut other_ranges = edit.ranges.iter().peekable();
275 // let mut new_ranges = Vec::new();
276 // let insertion_len = edit.new_text.as_ref().map_or(0, |t| t.len());
277 // let mut delta = 0;
278
279 // for mut self_range in self.ranges.iter().cloned() {
280 // self_range.start += delta;
281 // self_range.end += delta;
282
283 // while let Some(other_range) = other_ranges.peek() {
284 // let mut other_range = (*other_range).clone();
285 // other_range.start += delta;
286 // other_range.end += delta;
287
288 // if other_range.start <= self_range.end {
289 // other_ranges.next().unwrap();
290 // delta += insertion_len;
291
292 // if other_range.end < self_range.start {
293 // new_ranges.push(other_range.start..other_range.end + insertion_len);
294 // self_range.start += insertion_len;
295 // self_range.end += insertion_len;
296 // } else {
297 // self_range.start = cmp::min(self_range.start, other_range.start);
298 // self_range.end = cmp::max(self_range.end, other_range.end) + insertion_len;
299 // }
300 // } else {
301 // break;
302 // }
303 // }
304
305 // new_ranges.push(self_range);
306 // }
307
308 // for other_range in other_ranges {
309 // new_ranges.push(other_range.start + delta..other_range.end + delta + insertion_len);
310 // delta += insertion_len;
311 // }
312
313 // self.ranges = new_ranges;
314 }
315
316 fn invert(&mut self) -> &mut Self {
317 for edit in &mut self.0 {
318 mem::swap(&mut edit.old, &mut edit.new);
319 }
320 self
321 }
322}
323
324impl Snapshot {
325 fn new(tab_snapshot: TabSnapshot) -> Self {
326 let mut transforms = SumTree::new();
327 let extent = tab_snapshot.text_summary();
328 if !extent.lines.is_zero() {
329 transforms.push(Transform::isomorphic(extent), &());
330 }
331 Self {
332 transforms,
333 tab_snapshot,
334 interpolated: true,
335 }
336 }
337
338 fn interpolate(&mut self, new_tab_snapshot: TabSnapshot, edits: &[TabEdit]) -> Patch {
339 let mut new_transforms;
340 if edits.is_empty() {
341 new_transforms = self.transforms.clone();
342 } else {
343 let mut old_cursor = self.transforms.cursor::<TabPoint>();
344 let mut edits = edits.into_iter().peekable();
345 new_transforms =
346 old_cursor.slice(&edits.peek().unwrap().old_lines.start, Bias::Right, &());
347
348 while let Some(edit) = edits.next() {
349 if edit.new_lines.start > TabPoint::from(new_transforms.summary().input.lines) {
350 let summary = new_tab_snapshot.text_summary_for_range(
351 TabPoint::from(new_transforms.summary().input.lines)..edit.new_lines.start,
352 );
353 new_transforms.push_or_extend(Transform::isomorphic(summary));
354 }
355
356 if !edit.new_lines.is_empty() {
357 new_transforms.push_or_extend(Transform::isomorphic(
358 new_tab_snapshot.text_summary_for_range(edit.new_lines.clone()),
359 ));
360 }
361
362 old_cursor.seek_forward(&edit.old_lines.end, Bias::Right, &());
363 if let Some(next_edit) = edits.peek() {
364 if next_edit.old_lines.start > old_cursor.end(&()) {
365 if old_cursor.end(&()) > edit.old_lines.end {
366 let summary = self
367 .tab_snapshot
368 .text_summary_for_range(edit.old_lines.end..old_cursor.end(&()));
369 new_transforms.push_or_extend(Transform::isomorphic(summary));
370 }
371 old_cursor.next(&());
372 new_transforms.push_tree(
373 old_cursor.slice(&next_edit.old_lines.start, Bias::Right, &()),
374 &(),
375 );
376 }
377 } else {
378 if old_cursor.end(&()) > edit.old_lines.end {
379 let summary = self
380 .tab_snapshot
381 .text_summary_for_range(edit.old_lines.end..old_cursor.end(&()));
382 new_transforms.push_or_extend(Transform::isomorphic(summary));
383 }
384 old_cursor.next(&());
385 new_transforms.push_tree(old_cursor.suffix(&()), &());
386 }
387 }
388 }
389
390 self.transforms = new_transforms;
391 self.tab_snapshot = new_tab_snapshot;
392 self.interpolated = true;
393 self.check_invariants();
394 todo!()
395 }
396
397 async fn update(
398 &mut self,
399 new_tab_snapshot: TabSnapshot,
400 edits: &[TabEdit],
401 wrap_width: f32,
402 line_wrapper: &mut LineWrapper,
403 ) -> Patch {
404 #[derive(Debug)]
405 struct RowEdit {
406 old_rows: Range<u32>,
407 new_rows: Range<u32>,
408 }
409
410 let mut edits = edits.into_iter().peekable();
411 let mut row_edits = Vec::new();
412 while let Some(edit) = edits.next() {
413 let mut row_edit = RowEdit {
414 old_rows: edit.old_lines.start.row()..edit.old_lines.end.row() + 1,
415 new_rows: edit.new_lines.start.row()..edit.new_lines.end.row() + 1,
416 };
417
418 while let Some(next_edit) = edits.peek() {
419 if next_edit.old_lines.start.row() <= row_edit.old_rows.end {
420 row_edit.old_rows.end = next_edit.old_lines.end.row() + 1;
421 row_edit.new_rows.end = next_edit.new_lines.end.row() + 1;
422 edits.next();
423 } else {
424 break;
425 }
426 }
427
428 row_edits.push(row_edit);
429 }
430
431 let mut new_transforms;
432 if row_edits.is_empty() {
433 new_transforms = self.transforms.clone();
434 } else {
435 let mut row_edits = row_edits.into_iter().peekable();
436 let mut old_cursor = self.transforms.cursor::<TabPoint>();
437
438 new_transforms = old_cursor.slice(
439 &TabPoint::new(row_edits.peek().unwrap().old_rows.start, 0),
440 Bias::Right,
441 &(),
442 );
443
444 while let Some(edit) = row_edits.next() {
445 if edit.new_rows.start > new_transforms.summary().input.lines.row {
446 let summary = new_tab_snapshot.text_summary_for_range(
447 TabPoint::new(new_transforms.summary().input.lines.row, 0)
448 ..TabPoint::new(edit.new_rows.start, 0),
449 );
450 new_transforms.push_or_extend(Transform::isomorphic(summary));
451 }
452
453 let mut line = String::new();
454 let mut remaining = None;
455 let mut chunks = new_tab_snapshot.chunks_at(TabPoint::new(edit.new_rows.start, 0));
456 let mut edit_transforms = Vec::<Transform>::new();
457 for _ in edit.new_rows.start..edit.new_rows.end {
458 while let Some(chunk) = remaining.take().or_else(|| chunks.next()) {
459 if let Some(ix) = chunk.find('\n') {
460 line.push_str(&chunk[..ix + 1]);
461 remaining = Some(&chunk[ix + 1..]);
462 break;
463 } else {
464 line.push_str(chunk)
465 }
466 }
467
468 if line.is_empty() {
469 break;
470 }
471
472 let mut prev_boundary_ix = 0;
473 for boundary in line_wrapper.wrap_line(&line, wrap_width) {
474 let wrapped = &line[prev_boundary_ix..boundary.ix];
475 push_isomorphic(&mut edit_transforms, TextSummary::from(wrapped));
476 edit_transforms.push(Transform::wrap(boundary.next_indent));
477 prev_boundary_ix = boundary.ix;
478 }
479
480 if prev_boundary_ix < line.len() {
481 push_isomorphic(
482 &mut edit_transforms,
483 TextSummary::from(&line[prev_boundary_ix..]),
484 );
485 }
486
487 line.clear();
488 yield_now().await;
489 }
490
491 let mut edit_transforms = edit_transforms.into_iter();
492 if let Some(transform) = edit_transforms.next() {
493 new_transforms.push_or_extend(transform);
494 }
495 new_transforms.extend(edit_transforms, &());
496
497 old_cursor.seek_forward(&TabPoint::new(edit.old_rows.end, 0), Bias::Right, &());
498 if let Some(next_edit) = row_edits.peek() {
499 if next_edit.old_rows.start > old_cursor.end(&()).row() {
500 if old_cursor.end(&()) > TabPoint::new(edit.old_rows.end, 0) {
501 let summary = self.tab_snapshot.text_summary_for_range(
502 TabPoint::new(edit.old_rows.end, 0)..old_cursor.end(&()),
503 );
504 new_transforms.push_or_extend(Transform::isomorphic(summary));
505 }
506 old_cursor.next(&());
507 new_transforms.push_tree(
508 old_cursor.slice(
509 &TabPoint::new(next_edit.old_rows.start, 0),
510 Bias::Right,
511 &(),
512 ),
513 &(),
514 );
515 }
516 } else {
517 if old_cursor.end(&()) > TabPoint::new(edit.old_rows.end, 0) {
518 let summary = self.tab_snapshot.text_summary_for_range(
519 TabPoint::new(edit.old_rows.end, 0)..old_cursor.end(&()),
520 );
521 new_transforms.push_or_extend(Transform::isomorphic(summary));
522 }
523 old_cursor.next(&());
524 new_transforms.push_tree(old_cursor.suffix(&()), &());
525 }
526 }
527 }
528
529 self.transforms = new_transforms;
530 self.tab_snapshot = new_tab_snapshot;
531 self.interpolated = false;
532 self.check_invariants();
533 todo!()
534 }
535
536 pub fn chunks_at(&self, wrap_row: u32) -> Chunks {
537 let point = WrapPoint::new(wrap_row, 0);
538 let mut transforms = self.transforms.cursor::<(WrapPoint, TabPoint)>();
539 transforms.seek(&point, Bias::Right, &());
540 let mut input_position = TabPoint(transforms.start().1 .0);
541 if transforms.item().map_or(false, |t| t.is_isomorphic()) {
542 input_position.0 += point.0 - transforms.start().0 .0;
543 }
544 let input_chunks = self.tab_snapshot.chunks_at(input_position);
545 Chunks {
546 input_chunks,
547 transforms,
548 output_position: point,
549 input_chunk: "",
550 }
551 }
552
553 pub fn highlighted_chunks_for_rows(&mut self, rows: Range<u32>) -> HighlightedChunks {
554 let output_start = WrapPoint::new(rows.start, 0);
555 let output_end = WrapPoint::new(rows.end, 0);
556 let mut transforms = self.transforms.cursor::<(WrapPoint, TabPoint)>();
557 transforms.seek(&output_start, Bias::Right, &());
558 let mut input_start = TabPoint(transforms.start().1 .0);
559 if transforms.item().map_or(false, |t| t.is_isomorphic()) {
560 input_start.0 += output_start.0 - transforms.start().0 .0;
561 }
562 let input_end = self
563 .to_tab_point(output_end)
564 .min(self.tab_snapshot.max_point());
565 HighlightedChunks {
566 input_chunks: self.tab_snapshot.highlighted_chunks(input_start..input_end),
567 input_chunk: Default::default(),
568 output_position: output_start,
569 max_output_row: rows.end,
570 transforms,
571 }
572 }
573
574 pub fn max_point(&self) -> WrapPoint {
575 self.to_wrap_point(self.tab_snapshot.max_point())
576 }
577
578 pub fn line_len(&self, row: u32) -> u32 {
579 let mut len = 0;
580 for chunk in self.chunks_at(row) {
581 if let Some(newline_ix) = chunk.find('\n') {
582 len += newline_ix;
583 break;
584 } else {
585 len += chunk.len();
586 }
587 }
588 len as u32
589 }
590
591 pub fn soft_wrap_indent(&self, row: u32) -> Option<u32> {
592 let mut cursor = self.transforms.cursor::<WrapPoint>();
593 cursor.seek(&WrapPoint::new(row + 1, 0), Bias::Right, &());
594 cursor.item().and_then(|transform| {
595 if transform.is_isomorphic() {
596 None
597 } else {
598 Some(transform.summary.output.lines.column)
599 }
600 })
601 }
602
603 pub fn longest_row(&self) -> u32 {
604 self.transforms.summary().output.longest_row
605 }
606
607 pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
608 let mut transforms = self.transforms.cursor::<(WrapPoint, TabPoint)>();
609 transforms.seek(&WrapPoint::new(start_row, 0), Bias::Left, &());
610 let mut input_row = transforms.start().1.row();
611 if transforms.item().map_or(false, |t| t.is_isomorphic()) {
612 input_row += start_row - transforms.start().0.row();
613 }
614 let soft_wrapped = transforms.item().map_or(false, |t| !t.is_isomorphic());
615 let mut input_buffer_rows = self.tab_snapshot.buffer_rows(input_row);
616 let input_buffer_row = input_buffer_rows.next().unwrap();
617 BufferRows {
618 transforms,
619 input_buffer_row,
620 input_buffer_rows,
621 output_row: start_row,
622 soft_wrapped,
623 max_output_row: self.max_point().row(),
624 }
625 }
626
627 pub fn to_tab_point(&self, point: WrapPoint) -> TabPoint {
628 let mut cursor = self.transforms.cursor::<(WrapPoint, TabPoint)>();
629 cursor.seek(&point, Bias::Right, &());
630 let mut tab_point = cursor.start().1 .0;
631 if cursor.item().map_or(false, |t| t.is_isomorphic()) {
632 tab_point += point.0 - cursor.start().0 .0;
633 }
634 TabPoint(tab_point)
635 }
636
637 pub fn to_wrap_point(&self, point: TabPoint) -> WrapPoint {
638 let mut cursor = self.transforms.cursor::<(TabPoint, WrapPoint)>();
639 cursor.seek(&point, Bias::Right, &());
640 WrapPoint(cursor.start().1 .0 + (point.0 - cursor.start().0 .0))
641 }
642
643 pub fn clip_point(&self, mut point: WrapPoint, bias: Bias) -> WrapPoint {
644 if bias == Bias::Left {
645 let mut cursor = self.transforms.cursor::<WrapPoint>();
646 cursor.seek(&point, Bias::Right, &());
647 if cursor.item().map_or(false, |t| !t.is_isomorphic()) {
648 point = *cursor.start();
649 *point.column_mut() -= 1;
650 }
651 }
652
653 self.to_wrap_point(self.tab_snapshot.clip_point(self.to_tab_point(point), bias))
654 }
655
656 fn check_invariants(&self) {
657 #[cfg(test)]
658 {
659 assert_eq!(
660 TabPoint::from(self.transforms.summary().input.lines),
661 self.tab_snapshot.max_point()
662 );
663
664 {
665 let mut transforms = self.transforms.cursor::<()>().peekable();
666 while let Some(transform) = transforms.next() {
667 if let Some(next_transform) = transforms.peek() {
668 assert!(transform.is_isomorphic() != next_transform.is_isomorphic());
669 }
670 }
671 }
672
673 let mut expected_buffer_rows = Vec::new();
674 let mut buffer_row = 0;
675 let mut prev_tab_row = 0;
676 for display_row in 0..=self.max_point().row() {
677 let tab_point = self.to_tab_point(WrapPoint::new(display_row, 0));
678 let soft_wrapped;
679 if tab_point.row() == prev_tab_row {
680 soft_wrapped = display_row != 0;
681 } else {
682 let fold_point = self.tab_snapshot.to_fold_point(tab_point, Bias::Left).0;
683 let buffer_point = fold_point.to_buffer_point(&self.tab_snapshot.fold_snapshot);
684 buffer_row = buffer_point.row;
685 prev_tab_row = tab_point.row();
686 soft_wrapped = false;
687 }
688 expected_buffer_rows.push((buffer_row, soft_wrapped));
689 }
690
691 for start_display_row in 0..expected_buffer_rows.len() {
692 assert_eq!(
693 self.buffer_rows(start_display_row as u32)
694 .collect::<Vec<_>>(),
695 &expected_buffer_rows[start_display_row..],
696 "invalid buffer_rows({}..)",
697 start_display_row
698 );
699 }
700 }
701 }
702}
703
704impl<'a> Iterator for Chunks<'a> {
705 type Item = &'a str;
706
707 fn next(&mut self) -> Option<Self::Item> {
708 let transform = self.transforms.item()?;
709 if let Some(display_text) = transform.display_text {
710 if self.output_position > self.transforms.start().0 {
711 self.output_position.0.column += transform.summary.output.lines.column;
712 self.transforms.next(&());
713 return Some(&display_text[1..]);
714 } else {
715 self.output_position.0 += transform.summary.output.lines;
716 self.transforms.next(&());
717 return Some(display_text);
718 }
719 }
720
721 if self.input_chunk.is_empty() {
722 self.input_chunk = self.input_chunks.next().unwrap();
723 }
724
725 let mut input_len = 0;
726 let transform_end = self.transforms.end(&()).0;
727 for c in self.input_chunk.chars() {
728 let char_len = c.len_utf8();
729 input_len += char_len;
730 if c == '\n' {
731 *self.output_position.row_mut() += 1;
732 *self.output_position.column_mut() = 0;
733 } else {
734 *self.output_position.column_mut() += char_len as u32;
735 }
736
737 if self.output_position >= transform_end {
738 self.transforms.next(&());
739 break;
740 }
741 }
742
743 let (prefix, suffix) = self.input_chunk.split_at(input_len);
744 self.input_chunk = suffix;
745 Some(prefix)
746 }
747}
748
749impl<'a> Iterator for HighlightedChunks<'a> {
750 type Item = HighlightedChunk<'a>;
751
752 fn next(&mut self) -> Option<Self::Item> {
753 if self.output_position.row() >= self.max_output_row {
754 return None;
755 }
756
757 let transform = self.transforms.item()?;
758 if let Some(display_text) = transform.display_text {
759 let mut start_ix = 0;
760 let mut end_ix = display_text.len();
761 let mut summary = transform.summary.output.lines;
762
763 if self.output_position > self.transforms.start().0 {
764 // Exclude newline starting prior to the desired row.
765 start_ix = 1;
766 summary.row = 0;
767 } else if self.output_position.row() + 1 >= self.max_output_row {
768 // Exclude soft indentation ending after the desired row.
769 end_ix = 1;
770 summary.column = 0;
771 }
772
773 self.output_position.0 += summary;
774 self.transforms.next(&());
775 return Some(HighlightedChunk {
776 text: &display_text[start_ix..end_ix],
777 ..self.input_chunk
778 });
779 }
780
781 if self.input_chunk.text.is_empty() {
782 self.input_chunk = self.input_chunks.next().unwrap();
783 }
784
785 let mut input_len = 0;
786 let transform_end = self.transforms.end(&()).0;
787 for c in self.input_chunk.text.chars() {
788 let char_len = c.len_utf8();
789 input_len += char_len;
790 if c == '\n' {
791 *self.output_position.row_mut() += 1;
792 *self.output_position.column_mut() = 0;
793 } else {
794 *self.output_position.column_mut() += char_len as u32;
795 }
796
797 if self.output_position >= transform_end {
798 self.transforms.next(&());
799 break;
800 }
801 }
802
803 let (prefix, suffix) = self.input_chunk.text.split_at(input_len);
804 self.input_chunk.text = suffix;
805 Some(HighlightedChunk {
806 text: prefix,
807 ..self.input_chunk
808 })
809 }
810}
811
812impl<'a> Iterator for BufferRows<'a> {
813 type Item = (u32, bool);
814
815 fn next(&mut self) -> Option<Self::Item> {
816 if self.output_row > self.max_output_row {
817 return None;
818 }
819
820 let buffer_row = self.input_buffer_row;
821 let soft_wrapped = self.soft_wrapped;
822
823 self.output_row += 1;
824 self.transforms
825 .seek_forward(&WrapPoint::new(self.output_row, 0), Bias::Left, &());
826 if self.transforms.item().map_or(false, |t| t.is_isomorphic()) {
827 self.input_buffer_row = self.input_buffer_rows.next().unwrap();
828 self.soft_wrapped = false;
829 } else {
830 self.soft_wrapped = true;
831 }
832
833 Some((buffer_row, soft_wrapped))
834 }
835}
836
837impl Transform {
838 fn isomorphic(summary: TextSummary) -> Self {
839 #[cfg(test)]
840 assert!(!summary.lines.is_zero());
841
842 Self {
843 summary: TransformSummary {
844 input: summary.clone(),
845 output: summary,
846 },
847 display_text: None,
848 }
849 }
850
851 fn wrap(indent: u32) -> Self {
852 lazy_static! {
853 static ref WRAP_TEXT: String = {
854 let mut wrap_text = String::new();
855 wrap_text.push('\n');
856 wrap_text.extend((0..LineWrapper::MAX_INDENT as usize).map(|_| ' '));
857 wrap_text
858 };
859 }
860
861 Self {
862 summary: TransformSummary {
863 input: TextSummary::default(),
864 output: TextSummary {
865 lines: Point::new(1, indent),
866 first_line_chars: 0,
867 last_line_chars: indent,
868 longest_row: 1,
869 longest_row_chars: indent,
870 },
871 },
872 display_text: Some(&WRAP_TEXT[..1 + indent as usize]),
873 }
874 }
875
876 fn is_isomorphic(&self) -> bool {
877 self.display_text.is_none()
878 }
879}
880
881impl sum_tree::Item for Transform {
882 type Summary = TransformSummary;
883
884 fn summary(&self) -> Self::Summary {
885 self.summary.clone()
886 }
887}
888
889fn push_isomorphic(transforms: &mut Vec<Transform>, summary: TextSummary) {
890 if let Some(last_transform) = transforms.last_mut() {
891 if last_transform.is_isomorphic() {
892 last_transform.summary.input += &summary;
893 last_transform.summary.output += &summary;
894 return;
895 }
896 }
897 transforms.push(Transform::isomorphic(summary));
898}
899
900trait SumTreeExt {
901 fn push_or_extend(&mut self, transform: Transform);
902}
903
904impl SumTreeExt for SumTree<Transform> {
905 fn push_or_extend(&mut self, transform: Transform) {
906 let mut transform = Some(transform);
907 self.update_last(
908 |last_transform| {
909 if last_transform.is_isomorphic() && transform.as_ref().unwrap().is_isomorphic() {
910 let transform = transform.take().unwrap();
911 last_transform.summary.input += &transform.summary.input;
912 last_transform.summary.output += &transform.summary.output;
913 }
914 },
915 &(),
916 );
917
918 if let Some(transform) = transform {
919 self.push(transform, &());
920 }
921 }
922}
923
924impl WrapPoint {
925 pub fn new(row: u32, column: u32) -> Self {
926 Self(super::Point::new(row, column))
927 }
928
929 #[cfg(test)]
930 pub fn is_zero(&self) -> bool {
931 self.0.is_zero()
932 }
933
934 pub fn row(self) -> u32 {
935 self.0.row
936 }
937
938 pub fn column(self) -> u32 {
939 self.0.column
940 }
941
942 pub fn row_mut(&mut self) -> &mut u32 {
943 &mut self.0.row
944 }
945
946 pub fn column_mut(&mut self) -> &mut u32 {
947 &mut self.0.column
948 }
949}
950
951impl sum_tree::Summary for TransformSummary {
952 type Context = ();
953
954 fn add_summary(&mut self, other: &Self, _: &()) {
955 self.input += &other.input;
956 self.output += &other.output;
957 }
958}
959
960impl<'a> sum_tree::Dimension<'a, TransformSummary> for TabPoint {
961 fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
962 self.0 += summary.input.lines;
963 }
964}
965
966impl<'a> sum_tree::Dimension<'a, TransformSummary> for WrapPoint {
967 fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
968 self.0 += summary.output.lines;
969 }
970}
971
972fn compose(prev: &mut Vec<Edit>, next: &[Edit]) {}
973
974#[cfg(test)]
975mod tests {
976 use super::*;
977 use crate::{
978 display_map::{fold_map::FoldMap, tab_map::TabMap},
979 test::Observer,
980 };
981 use language::{Buffer, RandomCharIter};
982 use rand::prelude::*;
983 use std::env;
984
985 #[gpui::test(iterations = 100)]
986 async fn test_random_wraps(mut cx: gpui::TestAppContext, mut rng: StdRng) {
987 cx.foreground().set_block_on_ticks(0..=50);
988 cx.foreground().forbid_parking();
989 let operations = env::var("OPERATIONS")
990 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
991 .unwrap_or(10);
992
993 let font_cache = cx.font_cache().clone();
994 let font_system = cx.platform().fonts();
995 let mut wrap_width = if rng.gen_bool(0.1) {
996 None
997 } else {
998 Some(rng.gen_range(0.0..=1000.0))
999 };
1000 let tab_size = rng.gen_range(1..=4);
1001 let family_id = font_cache.load_family(&["Helvetica"]).unwrap();
1002 let font_id = font_cache
1003 .select_font(family_id, &Default::default())
1004 .unwrap();
1005 let font_size = 14.0;
1006
1007 log::info!("Tab size: {}", tab_size);
1008 log::info!("Wrap width: {:?}", wrap_width);
1009
1010 let buffer = cx.add_model(|cx| {
1011 let len = rng.gen_range(0..10);
1012 let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
1013 Buffer::new(0, text, cx)
1014 });
1015 let (mut fold_map, folds_snapshot) = cx.read(|cx| FoldMap::new(buffer.clone(), cx));
1016 let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size);
1017 log::info!(
1018 "Unwrapped text (no folds): {:?}",
1019 buffer.read_with(&cx, |buf, _| buf.text())
1020 );
1021 log::info!(
1022 "Unwrapped text (unexpanded tabs): {:?}",
1023 folds_snapshot.text()
1024 );
1025 log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text());
1026
1027 let mut line_wrapper = LineWrapper::new(font_id, font_size, font_system);
1028 let unwrapped_text = tabs_snapshot.text();
1029 let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
1030
1031 let wrap_map = cx.add_model(|cx| {
1032 WrapMap::new(tabs_snapshot.clone(), font_id, font_size, wrap_width, cx)
1033 });
1034 let (_observer, notifications) = Observer::new(&wrap_map, &mut cx);
1035
1036 if wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) {
1037 notifications.recv().await.unwrap();
1038 }
1039
1040 let (snapshot, _) =
1041 wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx));
1042 let actual_text = snapshot.text();
1043 assert_eq!(
1044 actual_text, expected_text,
1045 "unwrapped text is: {:?}",
1046 unwrapped_text
1047 );
1048 log::info!("Wrapped text: {:?}", actual_text);
1049
1050 for _i in 0..operations {
1051 match rng.gen_range(0..=100) {
1052 0..=19 => {
1053 wrap_width = if rng.gen_bool(0.2) {
1054 None
1055 } else {
1056 Some(rng.gen_range(0.0..=1000.0))
1057 };
1058 log::info!("Setting wrap width to {:?}", wrap_width);
1059 wrap_map.update(&mut cx, |map, cx| map.set_wrap_width(wrap_width, cx));
1060 }
1061 20..=39 => {
1062 for (folds_snapshot, edits) in
1063 cx.read(|cx| fold_map.randomly_mutate(&mut rng, cx))
1064 {
1065 let (tabs_snapshot, edits) = tab_map.sync(folds_snapshot, edits);
1066 let (mut snapshot, _) =
1067 wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, edits, cx));
1068 snapshot.check_invariants();
1069 snapshot.verify_chunks(&mut rng);
1070 }
1071 }
1072 _ => {
1073 buffer.update(&mut cx, |buffer, _| buffer.randomly_mutate(&mut rng));
1074 }
1075 }
1076
1077 log::info!(
1078 "Unwrapped text (no folds): {:?}",
1079 buffer.read_with(&cx, |buf, _| buf.text())
1080 );
1081 let (folds_snapshot, edits) = cx.read(|cx| fold_map.read(cx));
1082 log::info!(
1083 "Unwrapped text (unexpanded tabs): {:?}",
1084 folds_snapshot.text()
1085 );
1086 let (tabs_snapshot, edits) = tab_map.sync(folds_snapshot, edits);
1087 log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text());
1088
1089 let unwrapped_text = tabs_snapshot.text();
1090 let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
1091 let (mut snapshot, _) = wrap_map.update(&mut cx, |map, cx| {
1092 map.sync(tabs_snapshot.clone(), edits, cx)
1093 });
1094 snapshot.check_invariants();
1095 snapshot.verify_chunks(&mut rng);
1096
1097 if wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) && rng.gen_bool(0.4) {
1098 log::info!("Waiting for wrapping to finish");
1099 while wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) {
1100 notifications.recv().await.unwrap();
1101 }
1102 }
1103
1104 if !wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) {
1105 let (mut wrapped_snapshot, _) =
1106 wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx));
1107 let actual_text = wrapped_snapshot.text();
1108 log::info!("Wrapping finished: {:?}", actual_text);
1109 wrapped_snapshot.check_invariants();
1110 wrapped_snapshot.verify_chunks(&mut rng);
1111 assert_eq!(
1112 actual_text, expected_text,
1113 "unwrapped text is: {:?}",
1114 unwrapped_text
1115 );
1116 }
1117 }
1118 }
1119
1120 fn wrap_text(
1121 unwrapped_text: &str,
1122 wrap_width: Option<f32>,
1123 line_wrapper: &mut LineWrapper,
1124 ) -> String {
1125 if let Some(wrap_width) = wrap_width {
1126 let mut wrapped_text = String::new();
1127 for (row, line) in unwrapped_text.split('\n').enumerate() {
1128 if row > 0 {
1129 wrapped_text.push('\n')
1130 }
1131
1132 let mut prev_ix = 0;
1133 for boundary in line_wrapper.wrap_line(line, wrap_width) {
1134 wrapped_text.push_str(&line[prev_ix..boundary.ix]);
1135 wrapped_text.push('\n');
1136 wrapped_text.push_str(&" ".repeat(boundary.next_indent as usize));
1137 prev_ix = boundary.ix;
1138 }
1139 wrapped_text.push_str(&line[prev_ix..]);
1140 }
1141 wrapped_text
1142 } else {
1143 unwrapped_text.to_string()
1144 }
1145 }
1146
1147 impl Snapshot {
1148 fn text(&self) -> String {
1149 self.chunks_at(0).collect()
1150 }
1151
1152 fn verify_chunks(&mut self, rng: &mut impl Rng) {
1153 for _ in 0..5 {
1154 let mut end_row = rng.gen_range(0..=self.max_point().row());
1155 let start_row = rng.gen_range(0..=end_row);
1156 end_row += 1;
1157
1158 let mut expected_text = self.chunks_at(start_row).collect::<String>();
1159 if expected_text.ends_with("\n") {
1160 expected_text.push('\n');
1161 }
1162 let mut expected_text = expected_text
1163 .lines()
1164 .take((end_row - start_row) as usize)
1165 .collect::<Vec<_>>()
1166 .join("\n");
1167 if end_row <= self.max_point().row() {
1168 expected_text.push('\n');
1169 }
1170
1171 let actual_text = self
1172 .highlighted_chunks_for_rows(start_row..end_row)
1173 .map(|c| c.text)
1174 .collect::<String>();
1175 assert_eq!(
1176 expected_text,
1177 actual_text,
1178 "chunks != highlighted_chunks for rows {:?}",
1179 start_row..end_row
1180 );
1181 }
1182 }
1183 }
1184}