2394 lines · 86.8 KB · Rust
RawDownload
use super::{    wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},    Highlights,};use crate::{EditorStyle, GutterDimensions};use collections::{Bound, HashMap, HashSet};use gpui::{AnyElement, EntityId, Pixels, WindowContext};use language::{BufferSnapshot, Chunk, Patch, Point};use multi_buffer::{Anchor, ExcerptId, ExcerptRange, MultiBufferRow, ToPoint as _};use parking_lot::Mutex;use std::{    cell::RefCell,    cmp::{self, Ordering},    fmt::Debug,    ops::{Deref, DerefMut, Range, RangeBounds},    sync::{        atomic::{AtomicUsize, Ordering::SeqCst},        Arc,    },};use sum_tree::{Bias, SumTree, TreeMap};use text::Edit;use ui::ElementId; const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];const BULLETS: &str = "********************************************************************************************************************************"; /// Tracks custom blocks such as diagnostics that should be displayed within buffer.////// See the [`display_map` module documentation](crate::display_map) for more information.pub struct BlockMap {    next_block_id: AtomicUsize,    wrap_snapshot: RefCell<WrapSnapshot>,    custom_blocks: Vec<Arc<CustomBlock>>,    custom_blocks_by_id: TreeMap<CustomBlockId, Arc<CustomBlock>>,    transforms: RefCell<SumTree<Transform>>,    show_excerpt_controls: bool,    buffer_header_height: u32,    excerpt_header_height: u32,    excerpt_footer_height: u32,} pub struct BlockMapReader<'a> {    blocks: &'a Vec<Arc<CustomBlock>>,    pub snapshot: BlockSnapshot,} pub struct BlockMapWriter<'a>(&'a mut BlockMap); #[derive(Clone)]pub struct BlockSnapshot {    wrap_snapshot: WrapSnapshot,    transforms: SumTree<Transform>,    custom_blocks_by_id: TreeMap<CustomBlockId, Arc<CustomBlock>>,    pub(super) buffer_header_height: u32,    pub(super) excerpt_header_height: u32,    pub(super) excerpt_footer_height: u32,} #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]pub struct CustomBlockId(usize); impl From<CustomBlockId> for ElementId {    fn from(val: CustomBlockId) -> Self {        ElementId::Integer(val.0)    }} #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]pub struct BlockPoint(pub Point); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]pub struct BlockRow(pub(super) u32); #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]struct WrapRow(u32); pub type RenderBlock = Box<dyn Send + FnMut(&mut BlockContext) -> AnyElement>; pub struct CustomBlock {    id: CustomBlockId,    position: Anchor,    height: u32,    style: BlockStyle,    render: Arc<Mutex<RenderBlock>>,    disposition: BlockDisposition,    priority: usize,} pub struct BlockProperties<P> {    pub position: P,    pub height: u32,    pub style: BlockStyle,    pub render: RenderBlock,    pub disposition: BlockDisposition,    pub priority: usize,} impl<P: Debug> Debug for BlockProperties<P> {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        f.debug_struct("BlockProperties")            .field("position", &self.position)            .field("height", &self.height)            .field("style", &self.style)            .field("disposition", &self.disposition)            .finish()    }} #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]pub enum BlockStyle {    Fixed,    Flex,    Sticky,} pub struct BlockContext<'a, 'b> {    pub context: &'b mut WindowContext<'a>,    pub anchor_x: Pixels,    pub max_width: Pixels,    pub gutter_dimensions: &'b GutterDimensions,    pub em_width: Pixels,    pub line_height: Pixels,    pub block_id: BlockId,    pub editor_style: &'b EditorStyle,} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]pub enum BlockId {    Custom(CustomBlockId),    ExcerptHeader(ExcerptId),    ExcerptFooter(ExcerptId),} impl From<BlockId> for EntityId {    fn from(value: BlockId) -> Self {        match value {            BlockId::Custom(CustomBlockId(id)) => EntityId::from(id as u64),            BlockId::ExcerptHeader(id) => id.into(),            BlockId::ExcerptFooter(id) => id.into(),        }    }} impl From<BlockId> for ElementId {    fn from(value: BlockId) -> Self {        match value {            BlockId::Custom(CustomBlockId(id)) => ("Block", id).into(),            BlockId::ExcerptHeader(id) => ("ExcerptHeader", EntityId::from(id)).into(),            BlockId::ExcerptFooter(id) => ("ExcerptFooter", EntityId::from(id)).into(),        }    }} impl std::fmt::Display for BlockId {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        match self {            Self::Custom(id) => write!(f, "Block({id:?})"),            Self::ExcerptHeader(id) => write!(f, "ExcerptHeader({id:?})"),            Self::ExcerptFooter(id) => write!(f, "ExcerptFooter({id:?})"),        }    }} /// Whether the block should be considered above or below the anchor line#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]pub enum BlockDisposition {    Above,    Below,} #[derive(Clone, Debug)]struct Transform {    summary: TransformSummary,    block: Option<Block>,} pub(crate) enum BlockType {    Custom(CustomBlockId),    Header,    Footer,} pub(crate) trait BlockLike {    fn block_type(&self) -> BlockType;    fn disposition(&self) -> BlockDisposition;    fn priority(&self) -> usize;} #[allow(clippy::large_enum_variant)]#[derive(Clone)]pub enum Block {    Custom(Arc<CustomBlock>),    ExcerptHeader {        id: ExcerptId,        buffer: BufferSnapshot,        range: ExcerptRange<text::Anchor>,        height: u32,        starts_new_buffer: bool,        show_excerpt_controls: bool,    },    ExcerptFooter {        id: ExcerptId,        disposition: BlockDisposition,        height: u32,    },} impl BlockLike for Block {    fn block_type(&self) -> BlockType {        match self {            Block::Custom(block) => BlockType::Custom(block.id),            Block::ExcerptHeader { .. } => BlockType::Header,            Block::ExcerptFooter { .. } => BlockType::Footer,        }    }     fn disposition(&self) -> BlockDisposition {        self.disposition()    }     fn priority(&self) -> usize {        match self {            Block::Custom(block) => block.priority,            Block::ExcerptHeader { .. } => usize::MAX,            Block::ExcerptFooter { .. } => 0,        }    }} impl Block {    pub fn id(&self) -> BlockId {        match self {            Block::Custom(block) => BlockId::Custom(block.id),            Block::ExcerptHeader { id, .. } => BlockId::ExcerptHeader(*id),            Block::ExcerptFooter { id, .. } => BlockId::ExcerptFooter(*id),        }    }     fn disposition(&self) -> BlockDisposition {        match self {            Block::Custom(block) => block.disposition,            Block::ExcerptHeader { .. } => BlockDisposition::Above,            Block::ExcerptFooter { disposition, .. } => *disposition,        }    }     pub fn height(&self) -> u32 {        match self {            Block::Custom(block) => block.height,            Block::ExcerptHeader { height, .. } => *height,            Block::ExcerptFooter { height, .. } => *height,        }    }     pub fn style(&self) -> BlockStyle {        match self {            Block::Custom(block) => block.style,            Block::ExcerptHeader { .. } => BlockStyle::Sticky,            Block::ExcerptFooter { .. } => BlockStyle::Sticky,        }    }} impl Debug for Block {    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,                starts_new_buffer,                id,                ..            } => f                .debug_struct("ExcerptHeader")                .field("id", &id)                .field("path", &buffer.file().map(|f| f.path()))                .field("starts_new_buffer", &starts_new_buffer)                .finish(),            Block::ExcerptFooter {                id, disposition, ..            } => f                .debug_struct("ExcerptFooter")                .field("id", &id)                .field("disposition", &disposition)                .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,    masked: bool,} #[derive(Clone)]pub struct BlockBufferRows<'a> {    transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,    input_buffer_rows: wrap_map::WrapBufferRows<'a>,    output_row: BlockRow,    started: bool,} impl BlockMap {    pub fn new(        wrap_snapshot: WrapSnapshot,        show_excerpt_controls: bool,        buffer_header_height: u32,        excerpt_header_height: u32,        excerpt_footer_height: u32,    ) -> Self {        let row_count = wrap_snapshot.max_point().row() + 1;        let map = Self {            next_block_id: AtomicUsize::new(0),            custom_blocks: Vec::new(),            custom_blocks_by_id: TreeMap::default(),            transforms: RefCell::new(SumTree::from_item(Transform::isomorphic(row_count), &())),            wrap_snapshot: RefCell::new(wrap_snapshot.clone()),            show_excerpt_controls,            buffer_header_height,            excerpt_header_height,            excerpt_footer_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>) -> BlockMapReader {        self.sync(&wrap_snapshot, edits);        *self.wrap_snapshot.borrow_mut() = wrap_snapshot.clone();        BlockMapReader {            blocks: &self.custom_blocks,            snapshot: BlockSnapshot {                wrap_snapshot,                transforms: self.transforms.borrow().clone(),                custom_blocks_by_id: self.custom_blocks_by_id.clone(),                buffer_header_height: self.buffer_header_height,                excerpt_header_height: self.excerpt_header_height,                excerpt_footer_height: self.excerpt_footer_height,            },        }    }     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::default();        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.custom_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.custom_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.custom_blocks[start_block_ix..].binary_search_by(|probe| {                    probe                        .position                        .to_point(buffer)                        .cmp(&new_buffer_end)

Lines 1–500 of 2394.