block_map.rs

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