3707 lines · 139.9 KB · Rust
RawDownload
use super::{    wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},    Highlights,};use crate::{EditorStyle, GutterDimensions};use collections::{Bound, HashMap, HashSet};use gpui::{AnyElement, App, EntityId, Pixels, Window};use language::{Chunk, Patch, Point};use multi_buffer::{    Anchor, ExcerptId, ExcerptInfo, MultiBuffer, MultiBufferRow, MultiBufferSnapshot, RowInfo,    ToOffset, ToPoint as _,};use parking_lot::Mutex;use std::{    cell::RefCell,    cmp::{self, Ordering},    fmt::Debug,    ops::{Deref, DerefMut, Range, RangeBounds, RangeInclusive},    sync::{        atomic::{AtomicUsize, Ordering::SeqCst},        Arc,    },};use sum_tree::{Bias, SumTree, Summary, TreeMap};use text::{BufferId, 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(super) folded_buffers: HashSet<BufferId>,} 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 = Arc<dyn Send + Sync + Fn(&mut BlockContext) -> AnyElement>; #[derive(Clone, Debug, Eq, PartialEq)]pub enum BlockPlacement<T> {    Above(T),    Below(T),    Replace(RangeInclusive<T>),} impl<T> BlockPlacement<T> {    fn start(&self) -> &T {        match self {            BlockPlacement::Above(position) => position,            BlockPlacement::Below(position) => position,            BlockPlacement::Replace(range) => range.start(),        }    }     fn end(&self) -> &T {        match self {            BlockPlacement::Above(position) => position,            BlockPlacement::Below(position) => position,            BlockPlacement::Replace(range) => range.end(),        }    }     pub fn as_ref(&self) -> BlockPlacement<&T> {        match self {            BlockPlacement::Above(position) => BlockPlacement::Above(position),            BlockPlacement::Below(position) => BlockPlacement::Below(position),            BlockPlacement::Replace(range) => BlockPlacement::Replace(range.start()..=range.end()),        }    }     pub fn map<R>(self, mut f: impl FnMut(T) -> R) -> BlockPlacement<R> {        match self {            BlockPlacement::Above(position) => BlockPlacement::Above(f(position)),            BlockPlacement::Below(position) => BlockPlacement::Below(f(position)),            BlockPlacement::Replace(range) => {                let (start, end) = range.into_inner();                BlockPlacement::Replace(f(start)..=f(end))            }        }    }} impl BlockPlacement<Anchor> {    fn cmp(&self, other: &Self, buffer: &MultiBufferSnapshot) -> Ordering {        match (self, other) {            (BlockPlacement::Above(anchor_a), BlockPlacement::Above(anchor_b))            | (BlockPlacement::Below(anchor_a), BlockPlacement::Below(anchor_b)) => {                anchor_a.cmp(anchor_b, buffer)            }            (BlockPlacement::Above(anchor_a), BlockPlacement::Below(anchor_b)) => {                anchor_a.cmp(anchor_b, buffer).then(Ordering::Less)            }            (BlockPlacement::Below(anchor_a), BlockPlacement::Above(anchor_b)) => {                anchor_a.cmp(anchor_b, buffer).then(Ordering::Greater)            }            (BlockPlacement::Above(anchor), BlockPlacement::Replace(range)) => {                anchor.cmp(range.start(), buffer).then(Ordering::Less)            }            (BlockPlacement::Replace(range), BlockPlacement::Above(anchor)) => {                range.start().cmp(anchor, buffer).then(Ordering::Greater)            }            (BlockPlacement::Below(anchor), BlockPlacement::Replace(range)) => {                anchor.cmp(range.start(), buffer).then(Ordering::Greater)            }            (BlockPlacement::Replace(range), BlockPlacement::Below(anchor)) => {                range.start().cmp(anchor, buffer).then(Ordering::Less)            }            (BlockPlacement::Replace(range_a), BlockPlacement::Replace(range_b)) => range_a                .start()                .cmp(range_b.start(), buffer)                .then_with(|| range_b.end().cmp(range_a.end(), buffer)),        }    }     fn to_wrap_row(&self, wrap_snapshot: &WrapSnapshot) -> Option<BlockPlacement<WrapRow>> {        let buffer_snapshot = wrap_snapshot.buffer_snapshot();        match self {            BlockPlacement::Above(position) => {                let mut position = position.to_point(buffer_snapshot);                position.column = 0;                let wrap_row = WrapRow(wrap_snapshot.make_wrap_point(position, Bias::Left).row());                Some(BlockPlacement::Above(wrap_row))            }            BlockPlacement::Below(position) => {                let mut position = position.to_point(buffer_snapshot);                position.column = buffer_snapshot.line_len(MultiBufferRow(position.row));                let wrap_row = WrapRow(wrap_snapshot.make_wrap_point(position, Bias::Left).row());                Some(BlockPlacement::Below(wrap_row))            }            BlockPlacement::Replace(range) => {                let mut start = range.start().to_point(buffer_snapshot);                let mut end = range.end().to_point(buffer_snapshot);                if start == end {                    None                } else {                    start.column = 0;                    let start_wrap_row =                        WrapRow(wrap_snapshot.make_wrap_point(start, Bias::Left).row());                    end.column = buffer_snapshot.line_len(MultiBufferRow(end.row));                    let end_wrap_row =                        WrapRow(wrap_snapshot.make_wrap_point(end, Bias::Left).row());                    Some(BlockPlacement::Replace(start_wrap_row..=end_wrap_row))                }            }        }    }} pub struct CustomBlock {    id: CustomBlockId,    placement: BlockPlacement<Anchor>,    height: u32,    style: BlockStyle,    render: Arc<Mutex<RenderBlock>>,    priority: usize,} pub struct BlockProperties<P> {    pub placement: BlockPlacement<P>,    pub height: u32,    pub style: BlockStyle,    pub render: RenderBlock,    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("placement", &self.placement)            .field("height", &self.height)            .field("style", &self.style)            .finish()    }} #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]pub enum BlockStyle {    Fixed,    Flex,    Sticky,} #[derive(gpui::AppContext, gpui::VisualContext)]pub struct BlockContext<'a, 'b> {    #[window]    pub window: &'a mut Window,    #[app]    pub app: &'b mut App,    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 selected: bool,    pub editor_style: &'b EditorStyle,} #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]pub enum BlockId {    ExcerptBoundary(Option<ExcerptId>),    FoldedBuffer(ExcerptId),    Custom(CustomBlockId),} impl From<BlockId> for ElementId {    fn from(value: BlockId) -> Self {        match value {            BlockId::Custom(CustomBlockId(id)) => ("Block", id).into(),            BlockId::ExcerptBoundary(next_excerpt) => match next_excerpt {                Some(id) => ("ExcerptBoundary", EntityId::from(id)).into(),                None => "LastExcerptBoundary".into(),            },            BlockId::FoldedBuffer(id) => ("FoldedBuffer", 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::ExcerptBoundary(id) => write!(f, "ExcerptHeader({id:?})"),            Self::FoldedBuffer(id) => write!(f, "FoldedBuffer({id:?})"),        }    }} #[derive(Clone, Debug)]struct Transform {    summary: TransformSummary,    block: Option<Block>,} #[allow(clippy::large_enum_variant)]#[derive(Clone)]pub enum Block {    Custom(Arc<CustomBlock>),    FoldedBuffer {        first_excerpt: ExcerptInfo,        prev_excerpt: Option<ExcerptInfo>,        height: u32,        show_excerpt_controls: bool,    },    ExcerptBoundary {        prev_excerpt: Option<ExcerptInfo>,        next_excerpt: Option<ExcerptInfo>,        height: u32,        starts_new_buffer: bool,        show_excerpt_controls: bool,    },} impl Block {    pub fn id(&self) -> BlockId {        match self {            Block::Custom(block) => BlockId::Custom(block.id),            Block::ExcerptBoundary { next_excerpt, .. } => {                BlockId::ExcerptBoundary(next_excerpt.as_ref().map(|info| info.id))            }            Block::FoldedBuffer { first_excerpt, .. } => BlockId::FoldedBuffer(first_excerpt.id),        }    }     pub fn height(&self) -> u32 {        match self {            Block::Custom(block) => block.height,            Block::ExcerptBoundary { height, .. } | Block::FoldedBuffer { height, .. } => *height,        }    }     pub fn style(&self) -> BlockStyle {        match self {            Block::Custom(block) => block.style,            Block::ExcerptBoundary { .. } | Block::FoldedBuffer { .. } => BlockStyle::Sticky,        }    }     fn place_above(&self) -> bool {        match self {            Block::Custom(block) => matches!(block.placement, BlockPlacement::Above(_)),            Block::FoldedBuffer { .. } => false,            Block::ExcerptBoundary { next_excerpt, .. } => next_excerpt.is_some(),        }    }     fn place_below(&self) -> bool {        match self {            Block::Custom(block) => matches!(block.placement, BlockPlacement::Below(_)),            Block::FoldedBuffer { .. } => false,            Block::ExcerptBoundary { next_excerpt, .. } => next_excerpt.is_none(),        }    }     fn is_replacement(&self) -> bool {        match self {            Block::Custom(block) => matches!(block.placement, BlockPlacement::Replace(_)),            Block::FoldedBuffer { .. } => true,            Block::ExcerptBoundary { .. } => false,        }    }     fn is_header(&self) -> bool {        match self {            Block::Custom(_) => false,            Block::FoldedBuffer { .. } => true,            Block::ExcerptBoundary { .. } => true,        }    }} 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::FoldedBuffer {                first_excerpt,                prev_excerpt,                height,                show_excerpt_controls,            } => f                .debug_struct("FoldedBuffer")                .field("first_excerpt", &first_excerpt)                .field("prev_excerpt", prev_excerpt)                .field("height", height)                .field("show_excerpt_controls", show_excerpt_controls)                .finish(),            Self::ExcerptBoundary {                starts_new_buffer,                next_excerpt,                prev_excerpt,                ..            } => f                .debug_struct("ExcerptBoundary")                .field("prev_excerpt", prev_excerpt)                .field("next_excerpt", next_excerpt)                .field("starts_new_buffer", starts_new_buffer)                .finish(),        }    }} #[derive(Clone, Debug, Default)]struct TransformSummary {    input_rows: u32,    output_rows: u32,    longest_row: u32,    longest_row_chars: 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 BlockRows<'a> {    transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,    input_rows: wrap_map::WrapRows<'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 mut transforms = SumTree::default();        push_isomorphic(&mut transforms, row_count, &wrap_snapshot);        let map = Self {            next_block_id: AtomicUsize::new(0),            custom_blocks: Vec::new(),            custom_blocks_by_id: TreeMap::default(),            folded_buffers: HashSet::default(),            transforms: RefCell::new(transforms),            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 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() {

Lines 1–500 of 3707.