block_map.rs

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