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