1use super::wrap_map::{self, Edit as WrapEdit, Snapshot as WrapSnapshot, WrapPoint};
2use buffer::{rope, Anchor, Bias, Edit, Point, Rope, ToOffset, ToPoint as _};
3use gpui::{fonts::HighlightStyle, AppContext, ModelHandle};
4use language::{Buffer, Chunk};
5use parking_lot::Mutex;
6use std::{
7 cmp::{self, Ordering},
8 collections::HashSet,
9 iter,
10 ops::Range,
11 slice,
12 sync::{
13 atomic::{AtomicUsize, Ordering::SeqCst},
14 Arc,
15 },
16};
17use sum_tree::SumTree;
18
19pub struct BlockMap {
20 buffer: ModelHandle<Buffer>,
21 next_block_id: AtomicUsize,
22 wrap_snapshot: Mutex<WrapSnapshot>,
23 blocks: Vec<Arc<Block>>,
24 transforms: Mutex<SumTree<Transform>>,
25}
26
27pub struct BlockMapWriter<'a>(&'a mut BlockMap);
28
29pub struct BlockSnapshot {
30 wrap_snapshot: WrapSnapshot,
31 transforms: SumTree<Transform>,
32}
33
34#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
35pub struct BlockId(usize);
36
37#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
38pub struct BlockPoint(pub super::Point);
39
40#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
41struct BlockRow(u32);
42
43#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
44struct WrapRow(u32);
45
46#[derive(Debug)]
47struct Block {
48 id: BlockId,
49 position: Anchor,
50 text: Rope,
51 runs: Vec<(usize, HighlightStyle)>,
52 disposition: BlockDisposition,
53}
54
55#[derive(Clone)]
56pub struct BlockProperties<P, T>
57where
58 P: Clone,
59 T: Clone,
60{
61 pub position: P,
62 pub text: T,
63 pub runs: Vec<(usize, HighlightStyle)>,
64 pub disposition: BlockDisposition,
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
68pub enum BlockDisposition {
69 Above,
70 Below,
71}
72
73#[derive(Clone, Debug)]
74struct Transform {
75 summary: TransformSummary,
76 block: Option<Arc<Block>>,
77}
78
79#[derive(Clone, Debug, Default)]
80struct TransformSummary {
81 input_rows: u32,
82 output_rows: u32,
83}
84
85pub struct Chunks<'a> {
86 transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,
87 input_chunks: wrap_map::Chunks<'a>,
88 input_chunk: Chunk<'a>,
89 block_chunks: Option<BlockChunks<'a>>,
90 output_row: u32,
91 max_output_row: u32,
92 max_input_row: u32,
93}
94
95struct BlockChunks<'a> {
96 chunks: rope::Chunks<'a>,
97 runs: iter::Peekable<slice::Iter<'a, (usize, HighlightStyle)>>,
98 chunk: Option<&'a str>,
99 run_start: usize,
100 offset: usize,
101}
102
103pub struct BufferRows<'a> {
104 transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,
105 input_buffer_rows: wrap_map::BufferRows<'a>,
106 output_row: u32,
107 started: bool,
108}
109
110impl BlockMap {
111 pub fn new(buffer: ModelHandle<Buffer>, wrap_snapshot: WrapSnapshot) -> Self {
112 Self {
113 buffer,
114 next_block_id: AtomicUsize::new(0),
115 blocks: Vec::new(),
116 transforms: Mutex::new(SumTree::from_item(
117 Transform::isomorphic(wrap_snapshot.text_summary().lines.row + 1),
118 &(),
119 )),
120 wrap_snapshot: Mutex::new(wrap_snapshot),
121 }
122 }
123
124 pub fn read(
125 &self,
126 wrap_snapshot: WrapSnapshot,
127 edits: Vec<WrapEdit>,
128 cx: &AppContext,
129 ) -> BlockSnapshot {
130 self.sync(&wrap_snapshot, edits, cx);
131 *self.wrap_snapshot.lock() = wrap_snapshot.clone();
132 BlockSnapshot {
133 wrap_snapshot,
134 transforms: self.transforms.lock().clone(),
135 }
136 }
137
138 pub fn write(
139 &mut self,
140 wrap_snapshot: WrapSnapshot,
141 edits: Vec<WrapEdit>,
142 cx: &AppContext,
143 ) -> BlockMapWriter {
144 self.sync(&wrap_snapshot, edits, cx);
145 *self.wrap_snapshot.lock() = wrap_snapshot;
146 BlockMapWriter(self)
147 }
148
149 pub fn sync(&self, wrap_snapshot: &WrapSnapshot, edits: Vec<WrapEdit>, cx: &AppContext) {
150 if edits.is_empty() {
151 return;
152 }
153
154 let buffer = self.buffer.read(cx);
155 let mut transforms = self.transforms.lock();
156 let mut new_transforms = SumTree::new();
157 let old_row_count = transforms.summary().input_rows;
158 let new_row_count = wrap_snapshot.max_point().row() + 1;
159 let mut cursor = transforms.cursor::<WrapRow>();
160 let mut last_block_ix = 0;
161 let mut blocks_in_edit = Vec::new();
162 let mut edits = edits.into_iter().peekable();
163
164 while let Some(edit) = edits.next() {
165 // Preserve any old transforms that precede this edit.
166 let old_start = WrapRow(edit.old.start);
167 let new_start = WrapRow(edit.new.start);
168 new_transforms.push_tree(cursor.slice(&old_start, Bias::Left, &()), &());
169 if let Some(transform) = cursor.item() {
170 if transform.is_isomorphic() && old_start == cursor.end(&()) {
171 new_transforms.push(transform.clone(), &());
172 cursor.next(&());
173 while let Some(transform) = cursor.item() {
174 if transform
175 .block
176 .as_ref()
177 .map_or(false, |b| b.disposition.is_below())
178 {
179 new_transforms.push(transform.clone(), &());
180 cursor.next(&());
181 } else {
182 break;
183 }
184 }
185 }
186 }
187
188 // Preserve any portion of an old transform that precedes this edit.
189 let extent_before_edit = old_start.0 - cursor.start().0;
190 push_isomorphic(&mut new_transforms, extent_before_edit);
191
192 // Skip over any old transforms that intersect this edit.
193 let mut old_end = WrapRow(edit.old.end);
194 let mut new_end = WrapRow(edit.new.end);
195 cursor.seek(&old_end, Bias::Left, &());
196 cursor.next(&());
197 if old_end == *cursor.start() {
198 while let Some(transform) = cursor.item() {
199 if transform
200 .block
201 .as_ref()
202 .map_or(false, |b| b.disposition.is_below())
203 {
204 cursor.next(&());
205 } else {
206 break;
207 }
208 }
209 }
210
211 // Combine this edit with any subsequent edits that intersect the same transform.
212 while let Some(next_edit) = edits.peek() {
213 if next_edit.old.start <= cursor.start().0 {
214 old_end = WrapRow(next_edit.old.end);
215 new_end = WrapRow(next_edit.new.end);
216 cursor.seek(&old_end, Bias::Left, &());
217 cursor.next(&());
218 if old_end == *cursor.start() {
219 while let Some(transform) = cursor.item() {
220 if transform
221 .block
222 .as_ref()
223 .map_or(false, |b| b.disposition.is_below())
224 {
225 cursor.next(&());
226 } else {
227 break;
228 }
229 }
230 }
231 edits.next();
232 } else {
233 break;
234 }
235 }
236
237 // Find the blocks within this edited region.
238 let new_start = wrap_snapshot.to_point(WrapPoint::new(new_start.0, 0), Bias::Left);
239 let start_anchor = buffer.anchor_before(new_start);
240 let start_block_ix = match self.blocks[last_block_ix..].binary_search_by(|probe| {
241 probe
242 .position
243 .cmp(&start_anchor, buffer)
244 .unwrap()
245 .then(Ordering::Greater)
246 }) {
247 Ok(ix) | Err(ix) => last_block_ix + ix,
248 };
249 let end_block_ix = if new_end.0 > wrap_snapshot.max_point().row() {
250 self.blocks.len()
251 } else {
252 let new_end = wrap_snapshot.to_point(WrapPoint::new(new_end.0, 0), Bias::Left);
253 let end_anchor = buffer.anchor_before(new_end);
254 match self.blocks[start_block_ix..].binary_search_by(|probe| {
255 probe
256 .position
257 .cmp(&end_anchor, buffer)
258 .unwrap()
259 .then(Ordering::Greater)
260 }) {
261 Ok(ix) | Err(ix) => start_block_ix + ix,
262 }
263 };
264 last_block_ix = end_block_ix;
265 blocks_in_edit.clear();
266 blocks_in_edit.extend(
267 self.blocks[start_block_ix..end_block_ix]
268 .iter()
269 .map(|block| {
270 let mut position = block.position.to_point(buffer);
271 match block.disposition {
272 BlockDisposition::Above => position.column = 0,
273 BlockDisposition::Below => {
274 position.column = buffer.line_len(position.row)
275 }
276 }
277 let position = wrap_snapshot.from_point(position, Bias::Left);
278 (position.row(), block)
279 }),
280 );
281 blocks_in_edit.sort_unstable_by_key(|(row, block)| (*row, block.disposition, block.id));
282
283 // For each of these blocks, insert a new isomorphic transform preceding the block,
284 // and then insert the block itself.
285 for (block_row, block) in blocks_in_edit.iter().copied() {
286 let insertion_row = match block.disposition {
287 BlockDisposition::Above => block_row,
288 BlockDisposition::Below => block_row + 1,
289 };
290 let extent_before_block = insertion_row - new_transforms.summary().input_rows;
291 push_isomorphic(&mut new_transforms, extent_before_block);
292 new_transforms.push(Transform::block(block.clone()), &());
293 }
294
295 old_end = WrapRow(old_end.0.min(old_row_count));
296 new_end = WrapRow(new_end.0.min(new_row_count));
297
298 // Insert an isomorphic transform after the final block.
299 let extent_after_last_block = new_end.0 - new_transforms.summary().input_rows;
300 push_isomorphic(&mut new_transforms, extent_after_last_block);
301
302 // Preserve any portion of the old transform after this edit.
303 let extent_after_edit = cursor.start().0 - old_end.0;
304 push_isomorphic(&mut new_transforms, extent_after_edit);
305 }
306
307 new_transforms.push_tree(cursor.suffix(&()), &());
308 debug_assert_eq!(
309 new_transforms.summary().input_rows,
310 wrap_snapshot.max_point().row() + 1
311 );
312
313 drop(cursor);
314 *transforms = new_transforms;
315 }
316}
317
318fn push_isomorphic(tree: &mut SumTree<Transform>, rows: u32) {
319 if rows == 0 {
320 return;
321 }
322
323 let mut extent = Some(rows);
324 tree.update_last(
325 |last_transform| {
326 if last_transform.is_isomorphic() {
327 let extent = extent.take().unwrap();
328 last_transform.summary.input_rows += extent;
329 last_transform.summary.output_rows += extent;
330 }
331 },
332 &(),
333 );
334 if let Some(extent) = extent {
335 tree.push(Transform::isomorphic(extent), &());
336 }
337}
338
339impl BlockPoint {
340 fn new(row: u32, column: u32) -> Self {
341 Self(Point::new(row, column))
342 }
343}
344
345impl std::ops::Deref for BlockPoint {
346 type Target = Point;
347
348 fn deref(&self) -> &Self::Target {
349 &self.0
350 }
351}
352
353impl std::ops::DerefMut for BlockPoint {
354 fn deref_mut(&mut self) -> &mut Self::Target {
355 &mut self.0
356 }
357}
358
359impl<'a> BlockMapWriter<'a> {
360 pub fn insert<P, T>(
361 &mut self,
362 blocks: impl IntoIterator<Item = BlockProperties<P, T>>,
363 cx: &AppContext,
364 ) -> Vec<BlockId>
365 where
366 P: ToOffset + Clone,
367 T: Into<Rope> + Clone,
368 {
369 let buffer = self.0.buffer.read(cx);
370 let mut ids = Vec::new();
371 let mut edits = Vec::<Edit<u32>>::new();
372 let wrap_snapshot = &*self.0.wrap_snapshot.lock();
373
374 for block in blocks {
375 let id = BlockId(self.0.next_block_id.fetch_add(1, SeqCst));
376 ids.push(id);
377
378 let position = buffer.anchor_before(block.position);
379 let point = position.to_point(buffer);
380 let start_row = wrap_snapshot
381 .from_point(Point::new(point.row, 0), Bias::Left)
382 .row();
383 let end_row = if point.row == buffer.max_point().row {
384 wrap_snapshot.max_point().row() + 1
385 } else {
386 wrap_snapshot
387 .from_point(Point::new(point.row + 1, 0), Bias::Left)
388 .row()
389 };
390
391 let block_ix = match self
392 .0
393 .blocks
394 .binary_search_by(|probe| probe.position.cmp(&position, buffer).unwrap())
395 {
396 Ok(ix) | Err(ix) => ix,
397 };
398 self.0.blocks.insert(
399 block_ix,
400 Arc::new(Block {
401 id,
402 position,
403 text: block.text.into(),
404 runs: block.runs,
405 disposition: block.disposition,
406 }),
407 );
408
409 if let Err(edit_ix) = edits.binary_search_by_key(&start_row, |edit| edit.old.start) {
410 edits.insert(
411 edit_ix,
412 Edit {
413 old: start_row..end_row,
414 new: start_row..end_row,
415 },
416 );
417 }
418 }
419
420 self.0.sync(wrap_snapshot, edits, cx);
421 ids
422 }
423
424 pub fn remove(&mut self, block_ids: HashSet<BlockId>, cx: &AppContext) {
425 let buffer = self.0.buffer.read(cx);
426 let wrap_snapshot = &*self.0.wrap_snapshot.lock();
427 let mut edits = Vec::new();
428 let mut last_block_buffer_row = None;
429 self.0.blocks.retain(|block| {
430 if block_ids.contains(&block.id) {
431 let buffer_row = block.position.to_point(buffer).row;
432 if last_block_buffer_row != Some(buffer_row) {
433 last_block_buffer_row = Some(buffer_row);
434 let start_row = wrap_snapshot
435 .from_point(Point::new(buffer_row, 0), Bias::Left)
436 .row();
437 let end_row = wrap_snapshot
438 .from_point(
439 Point::new(buffer_row, buffer.line_len(buffer_row)),
440 Bias::Left,
441 )
442 .row()
443 + 1;
444 edits.push(Edit {
445 old: start_row..end_row,
446 new: start_row..end_row,
447 })
448 }
449 false
450 } else {
451 true
452 }
453 });
454 self.0.sync(wrap_snapshot, edits, cx);
455 }
456}
457
458impl BlockSnapshot {
459 #[cfg(test)]
460 fn text(&mut self) -> String {
461 self.chunks(0..self.transforms.summary().output_rows, false)
462 .map(|chunk| chunk.text)
463 .collect()
464 }
465
466 pub fn chunks(&self, rows: Range<u32>, highlights: bool) -> Chunks {
467 let max_input_row = self.transforms.summary().input_rows;
468 let max_output_row = cmp::min(rows.end, self.transforms.summary().output_rows);
469 let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
470 let output_row = rows.start;
471 cursor.seek(&BlockRow(output_row), Bias::Right, &());
472 let (input_start, output_start) = cursor.start();
473 let overshoot = rows.start - output_start.0;
474 let output_end_row = max_output_row.saturating_sub(1);
475 let input_start_row = input_start.0 + overshoot;
476 let input_end_row = self
477 .to_wrap_point(BlockPoint::new(
478 output_end_row,
479 self.wrap_snapshot.line_len(output_end_row),
480 ))
481 .row()
482 + 1;
483 let input_chunks = self
484 .wrap_snapshot
485 .chunks(input_start_row..input_end_row, highlights);
486 Chunks {
487 input_chunks,
488 input_chunk: Default::default(),
489 block_chunks: None,
490 transforms: cursor,
491 output_row,
492 max_output_row,
493 max_input_row,
494 }
495 }
496
497 pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
498 let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
499 cursor.seek(&BlockRow(start_row), Bias::Right, &());
500 let (input_start, output_start) = cursor.start();
501 let overshoot = if cursor.item().map_or(false, |t| t.is_isomorphic()) {
502 start_row - output_start.0
503 } else {
504 0
505 };
506 let input_start_row = input_start.0 + overshoot;
507 BufferRows {
508 transforms: cursor,
509 input_buffer_rows: self.wrap_snapshot.buffer_rows(input_start_row),
510 output_row: start_row,
511 started: false,
512 }
513 }
514
515 pub fn max_point(&self) -> BlockPoint {
516 todo!()
517 }
518
519 pub fn clip_point(&self, point: BlockPoint, bias: Bias) -> BlockPoint {
520 todo!()
521 // let mut cursor = self.transforms.cursor::<(BlockPoint, WrapPoint)>();
522 // cursor.seek(&point, Bias::Right, &());
523 // if let Some(transform) = cursor.prev_item() {
524 // if transform.is_isomorphic() && point == cursor.start().0 {
525 // return point;
526 // }
527 // }
528 // if let Some(transform) = cursor.item() {
529 // if transform.is_isomorphic() {
530 // let (output_start, input_start) = cursor.start();
531 // let output_overshoot = point.0 - output_start.0;
532 // let input_point = self
533 // .wrap_snapshot
534 // .clip_point(WrapPoint(input_start.0 + output_overshoot), bias);
535 // let input_overshoot = input_point.0 - input_start.0;
536 // BlockPoint(output_start.0 + input_overshoot)
537 // } else {
538 // if bias == Bias::Left && cursor.start().1 .0 > Point::zero()
539 // || cursor.end(&()).1 == self.wrap_snapshot.max_point()
540 // {
541 // loop {
542 // cursor.prev(&());
543 // let transform = cursor.item().unwrap();
544 // if transform.is_isomorphic() {
545 // return BlockPoint(cursor.end(&()).0 .0);
546 // }
547 // }
548 // } else {
549 // loop {
550 // cursor.next(&());
551 // let transform = cursor.item().unwrap();
552 // if transform.is_isomorphic() {
553 // return BlockPoint(cursor.start().0 .0);
554 // }
555 // }
556 // }
557 // }
558 // } else {
559 // self.max_point()
560 // }
561 }
562
563 pub fn to_block_point(&self, wrap_point: WrapPoint, bias: Bias) -> BlockPoint {
564 todo!()
565 // let mut cursor = self.transforms.cursor::<(WrapPoint, BlockPoint)>();
566 // cursor.seek(&wrap_point, bias, &());
567 // while let Some(item) = cursor.item() {
568 // if item.is_isomorphic() {
569 // break;
570 // }
571 // cursor.next(&());
572 // }
573 // let (input_start, output_start) = cursor.start();
574 // let input_overshoot = wrap_point.0 - input_start.0;
575 // BlockPoint(output_start.0 + input_overshoot)
576 }
577
578 pub fn to_wrap_point(&self, block_point: BlockPoint) -> WrapPoint {
579 let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
580 cursor.seek(&BlockRow(block_point.row), Bias::Right, &());
581 if let Some(transform) = cursor.item() {
582 match transform.block.as_ref().map(|b| b.disposition) {
583 Some(BlockDisposition::Above) => WrapPoint::new(cursor.start().1 .0, 0),
584 Some(BlockDisposition::Below) => {
585 let wrap_row = cursor.start().1 .0 - 1;
586 WrapPoint::new(wrap_row, self.wrap_snapshot.line_len(wrap_row))
587 }
588 None => {
589 let overshoot = block_point.row - cursor.start().0 .0;
590 let wrap_row = cursor.start().1 .0 + overshoot;
591 WrapPoint::new(wrap_row, block_point.column)
592 }
593 }
594 } else {
595 self.wrap_snapshot.max_point()
596 }
597 }
598}
599
600impl Transform {
601 fn isomorphic(rows: u32) -> Self {
602 Self {
603 summary: TransformSummary {
604 input_rows: rows,
605 output_rows: rows,
606 },
607 block: None,
608 }
609 }
610
611 fn block(block: Arc<Block>) -> Self {
612 Self {
613 summary: TransformSummary {
614 input_rows: 0,
615 output_rows: block.text.summary().lines.row + 1,
616 },
617 block: Some(block),
618 }
619 }
620
621 fn is_isomorphic(&self) -> bool {
622 self.block.is_none()
623 }
624}
625
626impl<'a> Iterator for Chunks<'a> {
627 type Item = Chunk<'a>;
628
629 fn next(&mut self) -> Option<Self::Item> {
630 if self.output_row >= self.max_output_row {
631 return None;
632 }
633
634 if let Some(block_chunks) = self.block_chunks.as_mut() {
635 if let Some(block_chunk) = block_chunks.next() {
636 self.output_row += block_chunk.text.matches('\n').count() as u32;
637 return Some(block_chunk);
638 } else {
639 self.block_chunks.take();
640 self.output_row += 1;
641 if self.output_row < self.max_output_row {
642 return Some(Chunk {
643 text: "\n",
644 ..Default::default()
645 });
646 } else {
647 return None;
648 }
649 }
650 }
651
652 let transform = self.transforms.item()?;
653 if let Some(block) = transform.block.as_ref() {
654 let block_start = self.transforms.start().0 .0;
655 let block_end = self.transforms.end(&()).0 .0;
656 let start_in_block = self.output_row - block_start;
657 let end_in_block = cmp::min(self.max_output_row, block_end) - block_start;
658 self.transforms.next(&());
659 self.block_chunks = Some(BlockChunks::new(block, start_in_block..end_in_block));
660 return self.next();
661 }
662
663 if self.input_chunk.text.is_empty() {
664 if let Some(input_chunk) = self.input_chunks.next() {
665 self.input_chunk = input_chunk;
666 } else {
667 self.output_row += 1;
668 if self.output_row < self.max_output_row {
669 self.transforms.next(&());
670 return Some(Chunk {
671 text: "\n",
672 ..Default::default()
673 });
674 } else {
675 return None;
676 }
677 }
678 }
679
680 let transform_end = self.transforms.end(&()).0 .0;
681 let (prefix_rows, prefix_bytes) =
682 offset_for_row(self.input_chunk.text, transform_end - self.output_row);
683 self.output_row += prefix_rows;
684 let (prefix, suffix) = self.input_chunk.text.split_at(prefix_bytes);
685 self.input_chunk.text = suffix;
686 if self.output_row == transform_end {
687 self.transforms.next(&());
688 }
689
690 Some(Chunk {
691 text: prefix,
692 ..self.input_chunk
693 })
694 }
695}
696
697impl<'a> BlockChunks<'a> {
698 fn new(block: &'a Block, rows: Range<u32>) -> Self {
699 let offset_range = block.text.point_to_offset(Point::new(rows.start, 0))
700 ..block.text.point_to_offset(Point::new(rows.end, 0));
701
702 let mut runs = block.runs.iter().peekable();
703 let mut run_start = 0;
704 while let Some((run_len, _)) = runs.peek() {
705 let run_end = run_start + run_len;
706 if run_end <= offset_range.start {
707 run_start = run_end;
708 runs.next();
709 } else {
710 break;
711 }
712 }
713
714 Self {
715 chunk: None,
716 run_start,
717 chunks: block.text.chunks_in_range(offset_range.clone()),
718 runs,
719 offset: offset_range.start,
720 }
721 }
722}
723
724impl<'a> Iterator for BlockChunks<'a> {
725 type Item = Chunk<'a>;
726
727 fn next(&mut self) -> Option<Self::Item> {
728 if self.chunk.is_none() {
729 self.chunk = self.chunks.next();
730 }
731
732 let chunk = self.chunk?;
733 let mut chunk_len = chunk.len();
734 // let mut highlight_style = None;
735 if let Some((run_len, _)) = self.runs.peek() {
736 // highlight_style = Some(style.clone());
737 let run_end_in_chunk = self.run_start + run_len - self.offset;
738 if run_end_in_chunk <= chunk_len {
739 chunk_len = run_end_in_chunk;
740 self.run_start += run_len;
741 self.runs.next();
742 }
743 }
744
745 self.offset += chunk_len;
746 let (chunk, suffix) = chunk.split_at(chunk_len);
747 self.chunk = if suffix.is_empty() {
748 None
749 } else {
750 Some(suffix)
751 };
752
753 Some(Chunk {
754 text: chunk,
755 highlight_id: Default::default(),
756 diagnostic: None,
757 })
758 }
759}
760
761impl<'a> Iterator for BufferRows<'a> {
762 type Item = Option<u32>;
763
764 fn next(&mut self) -> Option<Self::Item> {
765 if self.started {
766 self.output_row += 1;
767 } else {
768 self.started = true;
769 }
770
771 if self.output_row >= self.transforms.end(&()).0 .0 {
772 self.transforms.next(&());
773 }
774
775 let transform = self.transforms.item()?;
776 if transform.is_isomorphic() {
777 Some(self.input_buffer_rows.next().unwrap())
778 } else {
779 Some(None)
780 }
781 }
782}
783
784impl sum_tree::Item for Transform {
785 type Summary = TransformSummary;
786
787 fn summary(&self) -> Self::Summary {
788 self.summary.clone()
789 }
790}
791
792impl sum_tree::Summary for TransformSummary {
793 type Context = ();
794
795 fn add_summary(&mut self, summary: &Self, _: &()) {
796 self.input_rows += summary.input_rows;
797 self.output_rows += summary.output_rows;
798 }
799}
800
801impl<'a> sum_tree::Dimension<'a, TransformSummary> for WrapRow {
802 fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
803 self.0 += summary.input_rows;
804 }
805}
806
807impl<'a> sum_tree::Dimension<'a, TransformSummary> for BlockRow {
808 fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
809 self.0 += summary.output_rows;
810 }
811}
812
813impl BlockDisposition {
814 fn is_above(&self) -> bool {
815 matches!(self, BlockDisposition::Above)
816 }
817
818 fn is_below(&self) -> bool {
819 matches!(self, BlockDisposition::Below)
820 }
821}
822
823// Count the number of bytes prior to a target point. If the string doesn't contain the target
824// point, return its total extent. Otherwise return the target point itself.
825fn offset_for_row(s: &str, target: u32) -> (u32, usize) {
826 let mut row = 0;
827 let mut offset = 0;
828 for (ix, line) in s.split('\n').enumerate() {
829 if ix > 0 {
830 row += 1;
831 offset += 1;
832 }
833 if row >= target {
834 break;
835 }
836 offset += line.len() as usize;
837 }
838 (row, offset)
839}
840
841#[cfg(test)]
842mod tests {
843 use super::*;
844 use crate::display_map::{fold_map::FoldMap, tab_map::TabMap, wrap_map::WrapMap};
845 use buffer::RandomCharIter;
846 use language::Buffer;
847 use rand::prelude::*;
848 use std::env;
849
850 #[gpui::test]
851 fn test_offset_for_row() {
852 assert_eq!(offset_for_row("", 0), (0, 0));
853 assert_eq!(offset_for_row("", 1), (0, 0));
854 assert_eq!(offset_for_row("abcd", 0), (0, 0));
855 assert_eq!(offset_for_row("abcd", 1), (0, 4));
856 assert_eq!(offset_for_row("\n", 0), (0, 0));
857 assert_eq!(offset_for_row("\n", 1), (1, 1));
858 assert_eq!(offset_for_row("abc\ndef\nghi", 0), (0, 0));
859 assert_eq!(offset_for_row("abc\ndef\nghi", 1), (1, 4));
860 assert_eq!(offset_for_row("abc\ndef\nghi", 2), (2, 8));
861 assert_eq!(offset_for_row("abc\ndef\nghi", 3), (2, 11));
862 }
863
864 #[gpui::test]
865 fn test_basic_blocks(cx: &mut gpui::MutableAppContext) {
866 let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap();
867 let font_id = cx
868 .font_cache()
869 .select_font(family_id, &Default::default())
870 .unwrap();
871
872 let text = "aaa\nbbb\nccc\nddd";
873
874 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
875 let (fold_map, folds_snapshot) = FoldMap::new(buffer.clone(), cx);
876 let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
877 let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx);
878 let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone());
879
880 let mut writer = block_map.write(wraps_snapshot.clone(), vec![], cx);
881 writer.insert(
882 vec![
883 BlockProperties {
884 position: Point::new(1, 0),
885 text: "BLOCK 1",
886 disposition: BlockDisposition::Above,
887 runs: vec![],
888 },
889 BlockProperties {
890 position: Point::new(1, 2),
891 text: "BLOCK 2",
892 disposition: BlockDisposition::Above,
893 runs: vec![],
894 },
895 BlockProperties {
896 position: Point::new(3, 2),
897 text: "BLOCK 3",
898 disposition: BlockDisposition::Below,
899 runs: vec![],
900 },
901 ],
902 cx,
903 );
904
905 let mut snapshot = block_map.read(wraps_snapshot, vec![], cx);
906 assert_eq!(
907 snapshot.text(),
908 "aaa\nBLOCK 1\nBLOCK 2\nbbb\nccc\nddd\nBLOCK 3"
909 );
910 // assert_eq!(
911 // snapshot.to_block_point(WrapPoint::new(1, 0), Bias::Right),
912 // BlockPoint::new(3, 0)
913 // );
914 // assert_eq!(
915 // snapshot.clip_point(BlockPoint::new(1, 0), Bias::Left),
916 // BlockPoint::new(1, 0)
917 // );
918 // assert_eq!(
919 // snapshot.clip_point(BlockPoint::new(1, 0), Bias::Right),
920 // BlockPoint::new(1, 0)
921 // );
922 // assert_eq!(
923 // snapshot.clip_point(BlockPoint::new(1, 1), Bias::Left),
924 // BlockPoint::new(1, 0)
925 // );
926 // assert_eq!(
927 // snapshot.clip_point(BlockPoint::new(1, 1), Bias::Right),
928 // BlockPoint::new(3, 0)
929 // );
930 // assert_eq!(
931 // snapshot.clip_point(BlockPoint::new(3, 0), Bias::Left),
932 // BlockPoint::new(3, 0)
933 // );
934 // assert_eq!(
935 // snapshot.clip_point(BlockPoint::new(3, 0), Bias::Right),
936 // BlockPoint::new(3, 0)
937 // );
938 // assert_eq!(
939 // snapshot.clip_point(BlockPoint::new(5, 3), Bias::Left),
940 // BlockPoint::new(5, 3)
941 // );
942 // assert_eq!(
943 // snapshot.clip_point(BlockPoint::new(5, 3), Bias::Right),
944 // BlockPoint::new(5, 3)
945 // );
946 // assert_eq!(
947 // snapshot.clip_point(BlockPoint::new(6, 0), Bias::Left),
948 // BlockPoint::new(5, 3)
949 // );
950 // assert_eq!(
951 // snapshot.clip_point(BlockPoint::new(6, 0), Bias::Right),
952 // BlockPoint::new(5, 3)
953 // );
954
955 assert_eq!(
956 snapshot.buffer_rows(0).collect::<Vec<_>>(),
957 &[Some(0), None, None, Some(1), Some(2), Some(3), None]
958 );
959
960 // Insert a line break, separating two block decorations into separate
961 // lines.
962 buffer.update(cx, |buffer, cx| {
963 buffer.edit([Point::new(1, 1)..Point::new(1, 1)], "!!!\n", cx)
964 });
965
966 let (folds_snapshot, fold_edits) = fold_map.read(cx);
967 let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
968 let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
969 wrap_map.sync(tabs_snapshot, tab_edits, cx)
970 });
971 let mut snapshot = block_map.read(wraps_snapshot, wrap_edits, cx);
972 assert_eq!(
973 snapshot.text(),
974 "aaa\nBLOCK 1\nb!!!\nBLOCK 2\nbb\nccc\nddd\nBLOCK 3"
975 );
976 }
977
978 #[gpui::test]
979 fn test_blocks_on_wrapped_lines(cx: &mut gpui::MutableAppContext) {
980 let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap();
981 let font_id = cx
982 .font_cache()
983 .select_font(family_id, &Default::default())
984 .unwrap();
985
986 let text = "one two three\nfour five six\nseven eight";
987
988 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
989 let (_, folds_snapshot) = FoldMap::new(buffer.clone(), cx);
990 let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
991 let (_, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, Some(60.), cx);
992 let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone());
993
994 let mut writer = block_map.write(wraps_snapshot.clone(), vec![], cx);
995 writer.insert(
996 vec![
997 BlockProperties {
998 position: Point::new(1, 12),
999 text: "<BLOCK 1",
1000 disposition: BlockDisposition::Above,
1001 runs: vec![],
1002 },
1003 BlockProperties {
1004 position: Point::new(1, 1),
1005 text: ">BLOCK 2",
1006 disposition: BlockDisposition::Below,
1007 runs: vec![],
1008 },
1009 ],
1010 cx,
1011 );
1012
1013 // Blocks with an 'above' disposition go above their corresponding buffer line.
1014 // Blocks with a 'below' disposition go below their corresponding buffer line.
1015 let mut snapshot = block_map.read(wraps_snapshot, vec![], cx);
1016 assert_eq!(
1017 snapshot.text(),
1018 "one two \nthree\n<BLOCK 1\nfour five \nsix\n>BLOCK 2\nseven \neight"
1019 );
1020 }
1021
1022 #[gpui::test(iterations = 100)]
1023 fn test_random_blocks(cx: &mut gpui::MutableAppContext, mut rng: StdRng) {
1024 let operations = env::var("OPERATIONS")
1025 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1026 .unwrap_or(1);
1027
1028 let wrap_width = None;
1029 let tab_size = 1;
1030 let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap();
1031 let font_id = cx
1032 .font_cache()
1033 .select_font(family_id, &Default::default())
1034 .unwrap();
1035 let font_size = 14.0;
1036
1037 log::info!("Wrap width: {:?}", wrap_width);
1038
1039 let buffer = cx.add_model(|cx| {
1040 let len = rng.gen_range(0..10);
1041 let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
1042 log::info!("initial buffer text: {:?}", text);
1043 Buffer::new(0, text, cx)
1044 });
1045 let (fold_map, folds_snapshot) = FoldMap::new(buffer.clone(), cx);
1046 let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size);
1047 let (wrap_map, wraps_snapshot) =
1048 WrapMap::new(tabs_snapshot, font_id, font_size, wrap_width, cx);
1049 let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot);
1050 let mut expected_blocks = Vec::new();
1051
1052 for _ in 0..operations {
1053 match rng.gen_range(0..=100) {
1054 // 0..=19 => {
1055 // let wrap_width = if rng.gen_bool(0.2) {
1056 // None
1057 // } else {
1058 // Some(rng.gen_range(0.0..=100.0))
1059 // };
1060 // log::info!("Setting wrap width to {:?}", wrap_width);
1061 // wrap_map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
1062 // }
1063 20..=39 => {
1064 let block_count = rng.gen_range(1..=1);
1065 let block_properties = (0..block_count)
1066 .map(|_| {
1067 let buffer = buffer.read(cx);
1068 let position = buffer.anchor_before(rng.gen_range(0..=buffer.len()));
1069
1070 let len = rng.gen_range(0..10);
1071 let mut text = Rope::from(
1072 RandomCharIter::new(&mut rng)
1073 .take(len)
1074 .collect::<String>()
1075 .to_uppercase()
1076 .as_str(),
1077 );
1078 let disposition = if rng.gen() {
1079 text.push_front("<");
1080 BlockDisposition::Above
1081 } else {
1082 text.push_front(">");
1083 BlockDisposition::Below
1084 };
1085 log::info!(
1086 "inserting block {:?} {:?} with text {:?}",
1087 disposition,
1088 position.to_point(buffer),
1089 text.to_string()
1090 );
1091 BlockProperties {
1092 position,
1093 text,
1094 runs: Vec::<(usize, HighlightStyle)>::new(),
1095 disposition,
1096 }
1097 })
1098 .collect::<Vec<_>>();
1099
1100 let (folds_snapshot, fold_edits) = fold_map.read(cx);
1101 let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
1102 let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
1103 wrap_map.sync(tabs_snapshot, tab_edits, cx)
1104 });
1105 let mut block_map = block_map.write(wraps_snapshot, wrap_edits, cx);
1106 let block_ids = block_map.insert(block_properties.clone(), cx);
1107 for (block_id, props) in block_ids.into_iter().zip(block_properties) {
1108 expected_blocks.push((block_id, props));
1109 }
1110 }
1111 40..=59 if !expected_blocks.is_empty() => {
1112 let block_count = rng.gen_range(1..=4.min(expected_blocks.len()));
1113 let block_ids_to_remove = (0..block_count)
1114 .map(|_| {
1115 expected_blocks
1116 .remove(rng.gen_range(0..expected_blocks.len()))
1117 .0
1118 })
1119 .collect();
1120
1121 let (folds_snapshot, fold_edits) = fold_map.read(cx);
1122 let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
1123 let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
1124 wrap_map.sync(tabs_snapshot, tab_edits, cx)
1125 });
1126 let mut block_map = block_map.write(wraps_snapshot, wrap_edits, cx);
1127 block_map.remove(block_ids_to_remove, cx);
1128 }
1129 _ => {
1130 buffer.update(cx, |buffer, _| {
1131 buffer.randomly_edit(&mut rng, 1);
1132 log::info!("buffer text: {:?}", buffer.text());
1133 });
1134 }
1135 }
1136
1137 let (folds_snapshot, fold_edits) = fold_map.read(cx);
1138 let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
1139 let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
1140 wrap_map.sync(tabs_snapshot, tab_edits, cx)
1141 });
1142 let mut blocks_snapshot = block_map.read(wraps_snapshot.clone(), wrap_edits, cx);
1143 assert_eq!(
1144 blocks_snapshot.transforms.summary().input_rows,
1145 wraps_snapshot.max_point().row() + 1
1146 );
1147 log::info!("blocks text: {:?}", blocks_snapshot.text());
1148
1149 let buffer = buffer.read(cx);
1150 let mut sorted_blocks = expected_blocks
1151 .iter()
1152 .cloned()
1153 .map(|(id, block)| {
1154 let mut position = block.position.to_point(buffer);
1155 match block.disposition {
1156 BlockDisposition::Above => {
1157 position.column = 0;
1158 }
1159 BlockDisposition::Below => {
1160 position.column = buffer.line_len(position.row);
1161 }
1162 };
1163 let row = wraps_snapshot.from_point(position, Bias::Left).row();
1164 (
1165 id,
1166 BlockProperties {
1167 position: row,
1168 text: block.text,
1169 runs: block.runs,
1170 disposition: block.disposition,
1171 },
1172 )
1173 })
1174 .collect::<Vec<_>>();
1175 sorted_blocks
1176 .sort_unstable_by_key(|(id, block)| (block.position, block.disposition, *id));
1177 let mut sorted_blocks = sorted_blocks.into_iter().peekable();
1178
1179 let mut expected_buffer_rows = Vec::new();
1180 let mut expected_text = String::new();
1181 let input_text = wraps_snapshot.text();
1182 for (row, input_line) in input_text.split('\n').enumerate() {
1183 let row = row as u32;
1184 if row > 0 {
1185 expected_text.push('\n');
1186 }
1187
1188 let buffer_row = wraps_snapshot
1189 .to_point(WrapPoint::new(row, 0), Bias::Left)
1190 .row;
1191
1192 while let Some((_, block)) = sorted_blocks.peek() {
1193 if block.position == row && block.disposition == BlockDisposition::Above {
1194 let text = block.text.to_string();
1195 expected_text.push_str(&text);
1196 expected_text.push('\n');
1197 for _ in text.split('\n') {
1198 expected_buffer_rows.push(None);
1199 }
1200 sorted_blocks.next();
1201 } else {
1202 break;
1203 }
1204 }
1205
1206 let soft_wrapped = wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() > 0;
1207 expected_buffer_rows.push(if soft_wrapped { None } else { Some(buffer_row) });
1208 expected_text.push_str(input_line);
1209
1210 while let Some((_, block)) = sorted_blocks.peek() {
1211 if block.position == row && block.disposition == BlockDisposition::Below {
1212 let text = block.text.to_string();
1213 expected_text.push('\n');
1214 expected_text.push_str(&text);
1215 for _ in text.split('\n') {
1216 expected_buffer_rows.push(None);
1217 }
1218 sorted_blocks.next();
1219 } else {
1220 break;
1221 }
1222 }
1223 }
1224
1225 assert_eq!(blocks_snapshot.text(), expected_text);
1226 // for row in 0..=blocks_snapshot.wrap_snapshot.max_point().row() {
1227 // let wrap_point = WrapPoint::new(row, 0);
1228 // let block_point = blocks_snapshot.to_block_point(wrap_point, Bias::Right);
1229 // assert_eq!(blocks_snapshot.to_wrap_point(block_point), wrap_point);
1230 // }
1231 assert_eq!(
1232 blocks_snapshot.buffer_rows(0).collect::<Vec<_>>(),
1233 expected_buffer_rows
1234 );
1235 }
1236 }
1237}