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