1675 lines · 60.2 KB · Rust
RawDownload
use super::{    wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},    TextHighlights,};use crate::{Anchor, Editor, ExcerptId, ExcerptRange, ToPoint as _};use collections::{Bound, HashMap, HashSet};use gpui::{fonts::HighlightStyle, AnyElement, ViewContext};use language::{BufferSnapshot, Chunk, Patch, Point};use parking_lot::Mutex;use std::{    cell::RefCell,    cmp::{self, Ordering},    fmt::Debug,    ops::{Deref, DerefMut, Range},    sync::{        atomic::{AtomicUsize, Ordering::SeqCst},        Arc,    },};use sum_tree::{Bias, SumTree};use text::Edit; const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize]; pub struct BlockMap {    next_block_id: AtomicUsize,    wrap_snapshot: RefCell<WrapSnapshot>,    blocks: Vec<Arc<Block>>,    transforms: RefCell<SumTree<Transform>>,    buffer_header_height: u8,    excerpt_header_height: u8,} pub struct BlockMapWriter<'a>(&'a mut BlockMap); pub struct BlockSnapshot {    wrap_snapshot: WrapSnapshot,    transforms: SumTree<Transform>,} #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]pub struct BlockId(usize); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]pub struct BlockPoint(pub Point); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]struct BlockRow(u32); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]struct WrapRow(u32); pub type RenderBlock = Arc<dyn Fn(&mut BlockContext) -> AnyElement<Editor>>; pub struct Block {    id: BlockId,    position: Anchor,    height: u8,    style: BlockStyle,    render: Mutex<RenderBlock>,    disposition: BlockDisposition,} #[derive(Clone)]pub struct BlockProperties<P>where    P: Clone,{    pub position: P,    pub height: u8,    pub style: BlockStyle,    pub render: Arc<dyn Fn(&mut BlockContext) -> AnyElement<Editor>>,    pub disposition: BlockDisposition,} #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]pub enum BlockStyle {    Fixed,    Flex,    Sticky,} pub struct BlockContext<'a, 'b, 'c> {    pub view_context: &'c mut ViewContext<'a, 'b, Editor>,    pub anchor_x: f32,    pub scroll_x: f32,    pub gutter_width: f32,    pub gutter_padding: f32,    pub em_width: f32,    pub line_height: f32,    pub block_id: usize,} #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]pub enum BlockDisposition {    Above,    Below,} #[derive(Clone, Debug)]struct Transform {    summary: TransformSummary,    block: Option<TransformBlock>,} #[allow(clippy::large_enum_variant)]#[derive(Clone)]pub enum TransformBlock {    Custom(Arc<Block>),    ExcerptHeader {        id: ExcerptId,        buffer: BufferSnapshot,        range: ExcerptRange<text::Anchor>,        height: u8,        starts_new_buffer: bool,    },} impl TransformBlock {    fn disposition(&self) -> BlockDisposition {        match self {            TransformBlock::Custom(block) => block.disposition,            TransformBlock::ExcerptHeader { .. } => BlockDisposition::Above,        }    }     pub fn height(&self) -> u8 {        match self {            TransformBlock::Custom(block) => block.height,            TransformBlock::ExcerptHeader { height, .. } => *height,        }    }} impl Debug for TransformBlock {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        match self {            Self::Custom(block) => f.debug_struct("Custom").field("block", block).finish(),            Self::ExcerptHeader { buffer, .. } => f                .debug_struct("ExcerptHeader")                .field("path", &buffer.file().map(|f| f.path()))                .finish(),        }    }} #[derive(Clone, Debug, Default)]struct TransformSummary {    input_rows: u32,    output_rows: u32,} pub struct BlockChunks<'a> {    transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,    input_chunks: wrap_map::WrapChunks<'a>,    input_chunk: Chunk<'a>,    output_row: u32,    max_output_row: u32,} #[derive(Clone)]pub struct BlockBufferRows<'a> {    transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,    input_buffer_rows: wrap_map::WrapBufferRows<'a>,    output_row: u32,    started: bool,} impl BlockMap {    pub fn new(        wrap_snapshot: WrapSnapshot,        buffer_header_height: u8,        excerpt_header_height: u8,    ) -> Self {        let row_count = wrap_snapshot.max_point().row() + 1;        let map = Self {            next_block_id: AtomicUsize::new(0),            blocks: Vec::new(),            transforms: RefCell::new(SumTree::from_item(Transform::isomorphic(row_count), &())),            wrap_snapshot: RefCell::new(wrap_snapshot.clone()),            buffer_header_height,            excerpt_header_height,        };        map.sync(            &wrap_snapshot,            Patch::new(vec![Edit {                old: 0..row_count,                new: 0..row_count,            }]),        );        map    }     pub fn read(&self, wrap_snapshot: WrapSnapshot, edits: Patch<u32>) -> BlockSnapshot {        self.sync(&wrap_snapshot, edits);        *self.wrap_snapshot.borrow_mut() = wrap_snapshot.clone();        BlockSnapshot {            wrap_snapshot,            transforms: self.transforms.borrow().clone(),        }    }     pub fn write(&mut self, wrap_snapshot: WrapSnapshot, edits: Patch<u32>) -> BlockMapWriter {        self.sync(&wrap_snapshot, edits);        *self.wrap_snapshot.borrow_mut() = wrap_snapshot;        BlockMapWriter(self)    }     fn sync(&self, wrap_snapshot: &WrapSnapshot, mut edits: Patch<u32>) {        let buffer = wrap_snapshot.buffer_snapshot();         // Handle changing the last excerpt if it is empty.        if buffer.trailing_excerpt_update_count()            != self                .wrap_snapshot                .borrow()                .buffer_snapshot()                .trailing_excerpt_update_count()        {            let max_point = wrap_snapshot.max_point();            let edit_start = wrap_snapshot.prev_row_boundary(max_point);            let edit_end = max_point.row() + 1;            edits = edits.compose([WrapEdit {                old: edit_start..edit_end,                new: edit_start..edit_end,            }]);        }         let edits = edits.into_inner();        if edits.is_empty() {            return;        }         let mut transforms = self.transforms.borrow_mut();        let mut new_transforms = SumTree::new();        let old_row_count = transforms.summary().input_rows;        let new_row_count = wrap_snapshot.max_point().row() + 1;        let mut cursor = transforms.cursor::<WrapRow>();        let mut last_block_ix = 0;        let mut blocks_in_edit = Vec::new();        let mut edits = edits.into_iter().peekable();         while let Some(edit) = edits.next() {            // Preserve any old transforms that precede this edit.            let old_start = WrapRow(edit.old.start);            let new_start = WrapRow(edit.new.start);            new_transforms.append(cursor.slice(&old_start, Bias::Left, &()), &());            if let Some(transform) = cursor.item() {                if transform.is_isomorphic() && old_start == cursor.end(&()) {                    new_transforms.push(transform.clone(), &());                    cursor.next(&());                    while let Some(transform) = cursor.item() {                        if transform                            .block                            .as_ref()                            .map_or(false, |b| b.disposition().is_below())                        {                            new_transforms.push(transform.clone(), &());                            cursor.next(&());                        } else {                            break;                        }                    }                }            }             // Preserve any portion of an old transform that precedes this edit.            let extent_before_edit = old_start.0 - cursor.start().0;            push_isomorphic(&mut new_transforms, extent_before_edit);             // Skip over any old transforms that intersect this edit.            let mut old_end = WrapRow(edit.old.end);            let mut new_end = WrapRow(edit.new.end);            cursor.seek(&old_end, Bias::Left, &());            cursor.next(&());            if old_end == *cursor.start() {                while let Some(transform) = cursor.item() {                    if transform                        .block                        .as_ref()                        .map_or(false, |b| b.disposition().is_below())                    {                        cursor.next(&());                    } else {                        break;                    }                }            }             // Combine this edit with any subsequent edits that intersect the same transform.            while let Some(next_edit) = edits.peek() {                if next_edit.old.start <= cursor.start().0 {                    old_end = WrapRow(next_edit.old.end);                    new_end = WrapRow(next_edit.new.end);                    cursor.seek(&old_end, Bias::Left, &());                    cursor.next(&());                    if old_end == *cursor.start() {                        while let Some(transform) = cursor.item() {                            if transform                                .block                                .as_ref()                                .map_or(false, |b| b.disposition().is_below())                            {                                cursor.next(&());                            } else {                                break;                            }                        }                    }                    edits.next();                } else {                    break;                }            }             // Find the blocks within this edited region.            let new_buffer_start =                wrap_snapshot.to_point(WrapPoint::new(new_start.0, 0), Bias::Left);            let start_bound = Bound::Included(new_buffer_start);            let start_block_ix = match self.blocks[last_block_ix..].binary_search_by(|probe| {                probe                    .position                    .to_point(buffer)                    .cmp(&new_buffer_start)                    .then(Ordering::Greater)            }) {                Ok(ix) | Err(ix) => last_block_ix + ix,            };             let end_bound;            let end_block_ix = if new_end.0 > wrap_snapshot.max_point().row() {                end_bound = Bound::Unbounded;                self.blocks.len()            } else {                let new_buffer_end =                    wrap_snapshot.to_point(WrapPoint::new(new_end.0, 0), Bias::Left);                end_bound = Bound::Excluded(new_buffer_end);                match self.blocks[start_block_ix..].binary_search_by(|probe| {                    probe                        .position                        .to_point(buffer)                        .cmp(&new_buffer_end)                        .then(Ordering::Greater)                }) {                    Ok(ix) | Err(ix) => start_block_ix + ix,                }            };            last_block_ix = end_block_ix;             debug_assert!(blocks_in_edit.is_empty());            blocks_in_edit.extend(                self.blocks[start_block_ix..end_block_ix]                    .iter()                    .map(|block| {                        let mut position = block.position.to_point(buffer);                        match block.disposition {                            BlockDisposition::Above => position.column = 0,                            BlockDisposition::Below => {                                position.column = buffer.line_len(position.row)                            }                        }                        let position = wrap_snapshot.make_wrap_point(position, Bias::Left);                        (position.row(), TransformBlock::Custom(block.clone()))                    }),            );            blocks_in_edit.extend(                buffer                    .excerpt_boundaries_in_range((start_bound, end_bound))                    .map(|excerpt_boundary| {                        (                            wrap_snapshot                                .make_wrap_point(Point::new(excerpt_boundary.row, 0), Bias::Left)                                .row(),                            TransformBlock::ExcerptHeader {                                id: excerpt_boundary.id,                                buffer: excerpt_boundary.buffer,                                range: excerpt_boundary.range,                                height: if excerpt_boundary.starts_new_buffer {                                    self.buffer_header_height                                } else {                                    self.excerpt_header_height                                },                                starts_new_buffer: excerpt_boundary.starts_new_buffer,                            },                        )                    }),            );             // Place excerpt headers above custom blocks on the same row.            blocks_in_edit.sort_unstable_by(|(row_a, block_a), (row_b, block_b)| {                row_a.cmp(row_b).then_with(|| match (block_a, block_b) {                    (                        TransformBlock::ExcerptHeader { .. },                        TransformBlock::ExcerptHeader { .. },                    ) => Ordering::Equal,                    (TransformBlock::ExcerptHeader { .. }, _) => Ordering::Less,                    (_, TransformBlock::ExcerptHeader { .. }) => Ordering::Greater,                    (TransformBlock::Custom(block_a), TransformBlock::Custom(block_b)) => block_a                        .disposition                        .cmp(&block_b.disposition)                        .then_with(|| block_a.id.cmp(&block_b.id)),                })            });             // For each of these blocks, insert a new isomorphic transform preceding the block,            // and then insert the block itself.            for (block_row, block) in blocks_in_edit.drain(..) {                let insertion_row = match block.disposition() {                    BlockDisposition::Above => block_row,                    BlockDisposition::Below => block_row + 1,                };                let extent_before_block = insertion_row - new_transforms.summary().input_rows;                push_isomorphic(&mut new_transforms, extent_before_block);                new_transforms.push(Transform::block(block), &());            }             old_end = WrapRow(old_end.0.min(old_row_count));            new_end = WrapRow(new_end.0.min(new_row_count));             // Insert an isomorphic transform after the final block.            let extent_after_last_block = new_end.0 - new_transforms.summary().input_rows;            push_isomorphic(&mut new_transforms, extent_after_last_block);             // Preserve any portion of the old transform after this edit.            let extent_after_edit = cursor.start().0 - old_end.0;            push_isomorphic(&mut new_transforms, extent_after_edit);        }         new_transforms.append(cursor.suffix(&()), &());        debug_assert_eq!(            new_transforms.summary().input_rows,            wrap_snapshot.max_point().row() + 1        );         drop(cursor);        *transforms = new_transforms;    }     pub fn replace(&mut self, mut renderers: HashMap<BlockId, RenderBlock>) {        for block in &self.blocks {            if let Some(render) = renderers.remove(&block.id) {                *block.render.lock() = render;            }        }    }} fn push_isomorphic(tree: &mut SumTree<Transform>, rows: u32) {    if rows == 0 {        return;    }     let mut extent = Some(rows);    tree.update_last(        |last_transform| {            if last_transform.is_isomorphic() {                let extent = extent.take().unwrap();                last_transform.summary.input_rows += extent;                last_transform.summary.output_rows += extent;            }        },        &(),    );    if let Some(extent) = extent {        tree.push(Transform::isomorphic(extent), &());    }} impl BlockPoint {    pub fn new(row: u32, column: u32) -> Self {        Self(Point::new(row, column))    }} impl Deref for BlockPoint {    type Target = Point;     fn deref(&self) -> &Self::Target {        &self.0    }} impl std::ops::DerefMut for BlockPoint {    fn deref_mut(&mut self) -> &mut Self::Target {        &mut self.0    }} impl<'a> BlockMapWriter<'a> {    pub fn insert(        &mut self,        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,    ) -> Vec<BlockId> {        let mut ids = Vec::new();        let mut edits = Patch::default();        let wrap_snapshot = &*self.0.wrap_snapshot.borrow();        let buffer = wrap_snapshot.buffer_snapshot();         for block in blocks {            let id = BlockId(self.0.next_block_id.fetch_add(1, SeqCst));

Lines 1–500 of 1675.