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, Chunk};
   5use parking_lot::Mutex;
   6use std::{
   7    cmp::{self, Ordering},
   8    collections::HashSet,
   9    iter,
  10    ops::Range,
  11    slice,
  12    sync::{
  13        atomic::{AtomicUsize, Ordering::SeqCst},
  14        Arc,
  15    },
  16};
  17use sum_tree::SumTree;
  18
  19pub struct BlockMap {
  20    buffer: ModelHandle<Buffer>,
  21    next_block_id: AtomicUsize,
  22    wrap_snapshot: Mutex<WrapSnapshot>,
  23    blocks: Vec<Arc<Block>>,
  24    transforms: Mutex<SumTree<Transform>>,
  25}
  26
  27pub struct BlockMapWriter<'a>(&'a mut BlockMap);
  28
  29pub struct BlockSnapshot {
  30    wrap_snapshot: WrapSnapshot,
  31    transforms: SumTree<Transform>,
  32}
  33
  34#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
  35pub struct BlockId(usize);
  36
  37#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
  38pub struct BlockPoint(pub super::Point);
  39
  40#[derive(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    pub position: P,
  56    pub text: T,
  57    pub runs: Vec<(usize, HighlightStyle)>,
  58    pub disposition: BlockDisposition,
  59}
  60
  61#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
  62pub enum 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 Chunks<'a> {
  80    transforms: sum_tree::Cursor<'a, Transform, (BlockPoint, WrapPoint)>,
  81    input_chunks: wrap_map::Chunks<'a>,
  82    input_chunk: Chunk<'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.chunks(0..self.max_point().0.row + 1, false)
 437            .map(|chunk| chunk.text)
 438            .collect()
 439    }
 440
 441    pub fn chunks(&self, rows: Range<u32>, highlights: bool) -> Chunks {
 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            .chunks(input_start_row..input_end_row, highlights);
 453        Chunks {
 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, bias: Bias) -> BlockPoint {
 536        let mut cursor = self.transforms.cursor::<(WrapPoint, BlockPoint)>();
 537        cursor.seek(&wrap_point, bias, &());
 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 Chunks<'a> {
 585    type Item = Chunk<'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(Chunk {
 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 = Chunk<'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(Chunk {
 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        //     "============== 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
 735            if let Some(transform) = self.transforms.item() {
 736                self.in_block = !transform.is_isomorphic();
 737            }
 738
 739            // log::info!(
 740            //     "  Advanced to the next transform (block text: {:?}). Output row: {}, Transform starts at: {:?}",
 741            //     self.transforms.item().and_then(|t| t.block.as_ref()).map(|b| b.text.to_string()),
 742            //     self.output_row,
 743            //     self.transforms.start().1
 744            // );
 745
 746            let mut new_input_position = self.transforms.start().1 .0;
 747            if self.transforms.item().map_or(false, |t| t.is_isomorphic()) {
 748                new_input_position += Point::new(self.output_row, 0) - self.transforms.start().0 .0;
 749                new_input_position = cmp::min(new_input_position, self.transforms.end(&()).1 .0);
 750            }
 751
 752            if new_input_position.row > self.input_row {
 753                self.input_row = new_input_position.row;
 754                self.input_buffer_row = self.input_buffer_rows.next();
 755                // log::info!(
 756                //     "    Advanced the input buffer row. Input row: {}, Input buffer row {:?}",
 757                //     self.input_row,
 758                //     self.input_buffer_row
 759                // )
 760            }
 761        } else if self.transforms.item().map_or(true, |t| t.is_isomorphic()) {
 762            self.input_row += 1;
 763            self.input_buffer_row = self.input_buffer_rows.next();
 764            // log::info!(
 765            //     "  Advancing in isomorphic transform (off the end: {}). Input row: {}, Input buffer row {:?}",
 766            //     self.transforms.item().is_none(),
 767            //     self.input_row,
 768            //     self.input_buffer_row
 769            // )
 770        }
 771
 772        Some((buffer_row, false))
 773    }
 774}
 775
 776impl sum_tree::Item for Transform {
 777    type Summary = TransformSummary;
 778
 779    fn summary(&self) -> Self::Summary {
 780        self.summary.clone()
 781    }
 782}
 783
 784impl sum_tree::Summary for TransformSummary {
 785    type Context = ();
 786
 787    fn add_summary(&mut self, summary: &Self, _: &()) {
 788        self.input += summary.input;
 789        self.output += summary.output;
 790    }
 791}
 792
 793impl<'a> sum_tree::Dimension<'a, TransformSummary> for WrapPoint {
 794    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
 795        self.0 += summary.input;
 796    }
 797}
 798
 799impl<'a> sum_tree::Dimension<'a, TransformSummary> for BlockPoint {
 800    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
 801        self.0 += summary.output;
 802    }
 803}
 804
 805impl BlockDisposition {
 806    fn is_above(&self) -> bool {
 807        matches!(self, BlockDisposition::Above)
 808    }
 809
 810    fn is_below(&self) -> bool {
 811        matches!(self, BlockDisposition::Below)
 812    }
 813}
 814
 815// Count the number of bytes prior to a target point. If the string doesn't contain the target
 816// point, return its total extent. Otherwise return the target point itself.
 817fn offset_for_point(s: &str, target: Point) -> (Point, usize) {
 818    let mut point = Point::zero();
 819    let mut offset = 0;
 820    for (row, line) in s.split('\n').enumerate().take(target.row as usize + 1) {
 821        let row = row as u32;
 822        if row > 0 {
 823            offset += 1;
 824        }
 825        point.row = row;
 826        point.column = if row == target.row {
 827            cmp::min(line.len() as u32, target.column)
 828        } else {
 829            line.len() as u32
 830        };
 831        offset += point.column as usize;
 832    }
 833    (point, offset)
 834}
 835
 836#[cfg(test)]
 837mod tests {
 838    use super::*;
 839    use crate::display_map::{fold_map::FoldMap, tab_map::TabMap, wrap_map::WrapMap};
 840    use buffer::RandomCharIter;
 841    use language::Buffer;
 842    use rand::prelude::*;
 843    use std::env;
 844
 845    #[gpui::test]
 846    fn test_basic_blocks(cx: &mut gpui::MutableAppContext) {
 847        let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap();
 848        let font_id = cx
 849            .font_cache()
 850            .select_font(family_id, &Default::default())
 851            .unwrap();
 852
 853        let text = "aaa\nbbb\nccc\nddd";
 854
 855        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 856        let (fold_map, folds_snapshot) = FoldMap::new(buffer.clone(), cx);
 857        let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
 858        let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx);
 859        let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone());
 860
 861        let mut writer = block_map.write(wraps_snapshot.clone(), vec![], cx);
 862        writer.insert(
 863            vec![
 864                BlockProperties {
 865                    position: Point::new(1, 0),
 866                    text: "BLOCK 1",
 867                    disposition: BlockDisposition::Above,
 868                    runs: vec![],
 869                },
 870                BlockProperties {
 871                    position: Point::new(1, 2),
 872                    text: "BLOCK 2",
 873                    disposition: BlockDisposition::Above,
 874                    runs: vec![],
 875                },
 876                BlockProperties {
 877                    position: Point::new(3, 2),
 878                    text: "BLOCK 3",
 879                    disposition: BlockDisposition::Below,
 880                    runs: vec![],
 881                },
 882            ],
 883            cx,
 884        );
 885
 886        let mut snapshot = block_map.read(wraps_snapshot, vec![], cx);
 887        assert_eq!(
 888            snapshot.text(),
 889            "aaa\nBLOCK 1\nBLOCK 2\nbbb\nccc\nddd\nBLOCK 3"
 890        );
 891        assert_eq!(
 892            snapshot.to_block_point(WrapPoint::new(1, 0), Bias::Right),
 893            BlockPoint::new(3, 0)
 894        );
 895        assert_eq!(
 896            snapshot.clip_point(BlockPoint::new(1, 0), Bias::Left),
 897            BlockPoint::new(1, 0)
 898        );
 899        assert_eq!(
 900            snapshot.clip_point(BlockPoint::new(1, 0), Bias::Right),
 901            BlockPoint::new(1, 0)
 902        );
 903        assert_eq!(
 904            snapshot.clip_point(BlockPoint::new(1, 1), Bias::Left),
 905            BlockPoint::new(1, 0)
 906        );
 907        assert_eq!(
 908            snapshot.clip_point(BlockPoint::new(1, 1), Bias::Right),
 909            BlockPoint::new(3, 0)
 910        );
 911        assert_eq!(
 912            snapshot.clip_point(BlockPoint::new(3, 0), Bias::Left),
 913            BlockPoint::new(3, 0)
 914        );
 915        assert_eq!(
 916            snapshot.clip_point(BlockPoint::new(3, 0), Bias::Right),
 917            BlockPoint::new(3, 0)
 918        );
 919        assert_eq!(
 920            snapshot.clip_point(BlockPoint::new(5, 3), Bias::Left),
 921            BlockPoint::new(5, 3)
 922        );
 923        assert_eq!(
 924            snapshot.clip_point(BlockPoint::new(5, 3), Bias::Right),
 925            BlockPoint::new(5, 3)
 926        );
 927        assert_eq!(
 928            snapshot.clip_point(BlockPoint::new(6, 0), Bias::Left),
 929            BlockPoint::new(5, 3)
 930        );
 931        assert_eq!(
 932            snapshot.clip_point(BlockPoint::new(6, 0), Bias::Right),
 933            BlockPoint::new(5, 3)
 934        );
 935
 936        assert_eq!(
 937            snapshot.buffer_rows(0).collect::<Vec<_>>(),
 938            &[
 939                (0, true),
 940                (1, false),
 941                (1, false),
 942                (1, true),
 943                (2, true),
 944                (3, true),
 945                (3, false),
 946            ]
 947        );
 948
 949        // Insert a line break, separating two block decorations into separate
 950        // lines.
 951        buffer.update(cx, |buffer, cx| {
 952            buffer.edit([Point::new(1, 1)..Point::new(1, 1)], "!!!\n", cx)
 953        });
 954
 955        let (folds_snapshot, fold_edits) = fold_map.read(cx);
 956        let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
 957        let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
 958            wrap_map.sync(tabs_snapshot, tab_edits, cx)
 959        });
 960        let mut snapshot = block_map.read(wraps_snapshot, wrap_edits, cx);
 961        assert_eq!(
 962            snapshot.text(),
 963            "aaa\nBLOCK 1\nb!!!\nBLOCK 2\nbb\nccc\nddd\nBLOCK 3"
 964        );
 965    }
 966
 967    #[gpui::test]
 968    fn test_blocks_on_wrapped_lines(cx: &mut gpui::MutableAppContext) {
 969        let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap();
 970        let font_id = cx
 971            .font_cache()
 972            .select_font(family_id, &Default::default())
 973            .unwrap();
 974
 975        let text = "one two three\nfour five six\nseven eight";
 976
 977        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 978        let (_, folds_snapshot) = FoldMap::new(buffer.clone(), cx);
 979        let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
 980        let (_, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, Some(60.), cx);
 981        let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone());
 982
 983        let mut writer = block_map.write(wraps_snapshot.clone(), vec![], cx);
 984        writer.insert(
 985            vec![
 986                BlockProperties {
 987                    position: Point::new(1, 12),
 988                    text: "BLOCK 1",
 989                    disposition: BlockDisposition::Above,
 990                    runs: vec![],
 991                },
 992                BlockProperties {
 993                    position: Point::new(1, 1),
 994                    text: "BLOCK 2",
 995                    disposition: BlockDisposition::Below,
 996                    runs: vec![],
 997                },
 998            ],
 999            cx,
1000        );
1001
1002        // Blocks with an 'above' disposition go above their corresponding buffer line.
1003        // Blocks with a 'below' disposition go below their corresponding buffer line.
1004        let mut snapshot = block_map.read(wraps_snapshot, vec![], cx);
1005        assert_eq!(
1006            snapshot.text(),
1007            "one two \nthree\nBLOCK 1\nfour five \nsix\nBLOCK 2\nseven \neight"
1008        );
1009    }
1010
1011    #[gpui::test(iterations = 100)]
1012    fn test_random_blocks(cx: &mut gpui::MutableAppContext, mut rng: StdRng) {
1013        let operations = env::var("OPERATIONS")
1014            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1015            .unwrap_or(10);
1016
1017        let wrap_width = if rng.gen_bool(0.2) {
1018            None
1019        } else {
1020            Some(rng.gen_range(0.0..=100.0))
1021        };
1022        let tab_size = 1;
1023        let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap();
1024        let font_id = cx
1025            .font_cache()
1026            .select_font(family_id, &Default::default())
1027            .unwrap();
1028        let font_size = 14.0;
1029
1030        log::info!("Wrap width: {:?}", wrap_width);
1031
1032        let buffer = cx.add_model(|cx| {
1033            let len = rng.gen_range(0..10);
1034            let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
1035            log::info!("initial buffer text: {:?}", text);
1036            Buffer::new(0, text, cx)
1037        });
1038        let (fold_map, folds_snapshot) = FoldMap::new(buffer.clone(), cx);
1039        let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size);
1040        let (wrap_map, wraps_snapshot) =
1041            WrapMap::new(tabs_snapshot, font_id, font_size, wrap_width, cx);
1042        let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot);
1043        let mut expected_blocks = Vec::new();
1044
1045        for _ in 0..operations {
1046            match rng.gen_range(0..=100) {
1047                0..=19 => {
1048                    let wrap_width = if rng.gen_bool(0.2) {
1049                        None
1050                    } else {
1051                        Some(rng.gen_range(0.0..=100.0))
1052                    };
1053                    log::info!("Setting wrap width to {:?}", wrap_width);
1054                    wrap_map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
1055                }
1056                20..=39 => {
1057                    let block_count = rng.gen_range(1..=1);
1058                    let block_properties = (0..block_count)
1059                        .map(|_| {
1060                            let buffer = buffer.read(cx);
1061                            let position = buffer.anchor_before(rng.gen_range(0..=buffer.len()));
1062
1063                            let len = rng.gen_range(0..10);
1064                            let mut text = Rope::from(
1065                                RandomCharIter::new(&mut rng)
1066                                    .take(len)
1067                                    .collect::<String>()
1068                                    .to_uppercase()
1069                                    .as_str(),
1070                            );
1071                            let disposition = if rng.gen() {
1072                                text.push_front("<");
1073                                BlockDisposition::Above
1074                            } else {
1075                                text.push_front(">");
1076                                BlockDisposition::Below
1077                            };
1078                            log::info!(
1079                                "inserting block {:?} {:?} with text {:?}",
1080                                disposition,
1081                                position.to_point(buffer),
1082                                text.to_string()
1083                            );
1084                            BlockProperties {
1085                                position,
1086                                text,
1087                                runs: Vec::<(usize, HighlightStyle)>::new(),
1088                                disposition,
1089                            }
1090                        })
1091                        .collect::<Vec<_>>();
1092
1093                    let (folds_snapshot, fold_edits) = fold_map.read(cx);
1094                    let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
1095                    let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
1096                        wrap_map.sync(tabs_snapshot, tab_edits, cx)
1097                    });
1098                    let mut block_map = block_map.write(wraps_snapshot, wrap_edits, cx);
1099                    let block_ids = block_map.insert(block_properties.clone(), cx);
1100                    for (block_id, props) in block_ids.into_iter().zip(block_properties) {
1101                        expected_blocks.push((block_id, props));
1102                    }
1103                }
1104                40..=59 if !expected_blocks.is_empty() => {
1105                    let block_count = rng.gen_range(1..=4.min(expected_blocks.len()));
1106                    let block_ids_to_remove = (0..block_count)
1107                        .map(|_| {
1108                            expected_blocks
1109                                .remove(rng.gen_range(0..expected_blocks.len()))
1110                                .0
1111                        })
1112                        .collect();
1113
1114                    let (folds_snapshot, fold_edits) = fold_map.read(cx);
1115                    let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
1116                    let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
1117                        wrap_map.sync(tabs_snapshot, tab_edits, cx)
1118                    });
1119                    let mut block_map = block_map.write(wraps_snapshot, wrap_edits, cx);
1120                    block_map.remove(block_ids_to_remove, cx);
1121                }
1122                _ => {
1123                    buffer.update(cx, |buffer, _| {
1124                        buffer.randomly_edit(&mut rng, 1);
1125                        log::info!("buffer text: {:?}", buffer.text());
1126                    });
1127                }
1128            }
1129
1130            let (folds_snapshot, fold_edits) = fold_map.read(cx);
1131            let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
1132            let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
1133                wrap_map.sync(tabs_snapshot, tab_edits, cx)
1134            });
1135            let mut blocks_snapshot = block_map.read(wraps_snapshot.clone(), wrap_edits, cx);
1136            assert_eq!(
1137                blocks_snapshot.transforms.summary().input,
1138                wraps_snapshot.max_point().0
1139            );
1140            log::info!("blocks text: {:?}", blocks_snapshot.text());
1141
1142            let buffer = buffer.read(cx);
1143            let mut sorted_blocks = expected_blocks
1144                .iter()
1145                .cloned()
1146                .map(|(id, block)| {
1147                    let mut position = block.position.to_point(buffer);
1148                    match block.disposition {
1149                        BlockDisposition::Above => {
1150                            position.column = 0;
1151                        }
1152                        BlockDisposition::Below => {
1153                            position.column = buffer.line_len(position.row);
1154                        }
1155                    };
1156                    let row = wraps_snapshot.from_point(position, Bias::Left).row();
1157                    (
1158                        id,
1159                        BlockProperties {
1160                            position: row,
1161                            text: block.text,
1162                            runs: block.runs,
1163                            disposition: block.disposition,
1164                        },
1165                    )
1166                })
1167                .collect::<Vec<_>>();
1168            sorted_blocks
1169                .sort_unstable_by_key(|(id, block)| (block.position, block.disposition, *id));
1170            let mut sorted_blocks = sorted_blocks.into_iter().peekable();
1171
1172            let mut expected_buffer_rows = Vec::new();
1173            let mut expected_text = String::new();
1174            let input_text = wraps_snapshot.text();
1175            for (row, input_line) in input_text.split('\n').enumerate() {
1176                let row = row as u32;
1177                if row > 0 {
1178                    expected_text.push('\n');
1179                }
1180
1181                let buffer_row = wraps_snapshot
1182                    .to_point(WrapPoint::new(row, 0), Bias::Left)
1183                    .row;
1184
1185                while let Some((_, block)) = sorted_blocks.peek() {
1186                    if block.position == row && block.disposition == BlockDisposition::Above {
1187                        let text = block.text.to_string();
1188                        expected_text.push_str(&text);
1189                        expected_text.push('\n');
1190                        for _ in text.split('\n') {
1191                            expected_buffer_rows.push((buffer_row, false));
1192                        }
1193                        sorted_blocks.next();
1194                    } else {
1195                        break;
1196                    }
1197                }
1198
1199                let soft_wrapped = wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() > 0;
1200                expected_buffer_rows.push((buffer_row, false));
1201                expected_text.push_str(input_line);
1202
1203                while let Some((_, block)) = sorted_blocks.peek() {
1204                    if block.position == row && block.disposition == BlockDisposition::Below {
1205                        let text = block.text.to_string();
1206                        expected_text.push('\n');
1207                        expected_text.push_str(&text);
1208                        for _ in text.split('\n') {
1209                            expected_buffer_rows.push((buffer_row, false));
1210                        }
1211                        sorted_blocks.next();
1212                    } else {
1213                        break;
1214                    }
1215                }
1216            }
1217
1218            assert_eq!(blocks_snapshot.text(), expected_text);
1219            for row in 0..=blocks_snapshot.wrap_snapshot.max_point().row() {
1220                let wrap_point = WrapPoint::new(row, 0);
1221                let block_point = blocks_snapshot.to_block_point(wrap_point, Bias::Right);
1222                assert_eq!(blocks_snapshot.to_wrap_point(block_point), wrap_point);
1223            }
1224
1225            assert_eq!(
1226                blocks_snapshot.buffer_rows(0).collect::<Vec<_>>(),
1227                expected_buffer_rows
1228            );
1229        }
1230    }
1231}