block_map.rs

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