3180 lines · 114.7 KB · Rust
RawDownload
mod anchor; pub use anchor::{Anchor, AnchorRangeExt};use anyhow::Result;use clock::ReplicaId;use collections::{HashMap, HashSet};use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};use language::{    Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Outline,    OutlineItem, Selection, ToOffset as _, ToPoint as _, TransactionId,};use std::{    cell::{Ref, RefCell},    cmp, fmt, io,    iter::{self, FromIterator},    ops::{Range, Sub},    str,    sync::Arc,    time::{Duration, Instant},};use sum_tree::{Bias, Cursor, SumTree};use text::{    locator::Locator,    rope::TextDimension,    subscription::{Subscription, Topic},    AnchorRangeExt as _, Edit, Point, PointUtf16, TextSummary,};use theme::SyntaxTheme;use util::post_inc; const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize]; pub type ExcerptId = Locator; pub struct MultiBuffer {    snapshot: RefCell<MultiBufferSnapshot>,    buffers: RefCell<HashMap<usize, BufferState>>,    subscriptions: Topic,    singleton: bool,    replica_id: ReplicaId,    history: History,} struct History {    next_transaction_id: usize,    undo_stack: Vec<Transaction>,    redo_stack: Vec<Transaction>,    transaction_depth: usize,    group_interval: Duration,} struct Transaction {    id: usize,    buffer_transactions: HashSet<(usize, text::TransactionId)>,    first_edit_at: Instant,    last_edit_at: Instant,} pub trait ToOffset: 'static + fmt::Debug {    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;} pub trait ToPoint: 'static + fmt::Debug {    fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;} struct BufferState {    buffer: ModelHandle<Buffer>,    last_version: clock::Global,    last_parse_count: usize,    last_selections_update_count: usize,    last_diagnostics_update_count: usize,    excerpts: Vec<ExcerptId>,    _subscriptions: [gpui::Subscription; 2],} #[derive(Clone, Default)]pub struct MultiBufferSnapshot {    excerpts: SumTree<Excerpt>,    parse_count: usize,    diagnostics_update_count: usize,    is_dirty: bool,    has_conflict: bool,} pub struct ExcerptProperties<'a, T> {    pub buffer: &'a ModelHandle<Buffer>,    pub range: Range<T>,} #[derive(Clone)]struct Excerpt {    id: ExcerptId,    buffer_id: usize,    buffer: BufferSnapshot,    range: Range<text::Anchor>,    max_buffer_row: u32,    text_summary: TextSummary,    has_trailing_newline: bool,} #[derive(Clone, Debug, Default)]struct ExcerptSummary {    excerpt_id: ExcerptId,    max_buffer_row: u32,    text: TextSummary,} pub struct MultiBufferRows<'a> {    buffer_row_range: Range<u32>,    excerpts: Cursor<'a, Excerpt, Point>,} pub struct MultiBufferChunks<'a> {    range: Range<usize>,    excerpts: Cursor<'a, Excerpt, usize>,    excerpt_chunks: Option<ExcerptChunks<'a>>,    theme: Option<&'a SyntaxTheme>,} pub struct MultiBufferBytes<'a> {    range: Range<usize>,    excerpts: Cursor<'a, Excerpt, usize>,    excerpt_bytes: Option<ExcerptBytes<'a>>,    chunk: &'a [u8],} struct ExcerptChunks<'a> {    content_chunks: BufferChunks<'a>,    footer_height: usize,} struct ExcerptBytes<'a> {    content_bytes: language::rope::Bytes<'a>,    footer_height: usize,} impl MultiBuffer {    pub fn new(replica_id: ReplicaId) -> Self {        Self {            snapshot: Default::default(),            buffers: Default::default(),            subscriptions: Default::default(),            singleton: false,            replica_id,            history: History {                next_transaction_id: Default::default(),                undo_stack: Default::default(),                redo_stack: Default::default(),                transaction_depth: 0,                group_interval: Duration::from_millis(300),            },        }    }     pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {        let mut this = Self::new(buffer.read(cx).replica_id());        this.singleton = true;        this.push_excerpt(            ExcerptProperties {                buffer: &buffer,                range: text::Anchor::min()..text::Anchor::max(),            },            cx,        );        this    }     #[cfg(any(test, feature = "test-support"))]    pub fn build_simple(text: &str, cx: &mut gpui::MutableAppContext) -> ModelHandle<Self> {        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));        cx.add_model(|cx| Self::singleton(buffer, cx))    }     #[cfg(any(test, feature = "test-support"))]    pub fn build_random(        mut rng: &mut impl rand::Rng,        cx: &mut gpui::MutableAppContext,    ) -> ModelHandle<Self> {        use rand::prelude::*;        use std::env;        use text::RandomCharIter;         let max_excerpts = env::var("MAX_EXCERPTS")            .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))            .unwrap_or(5);        let excerpts = rng.gen_range(1..=max_excerpts);         cx.add_model(|cx| {            let mut multibuffer = MultiBuffer::new(0);            let mut buffers = Vec::new();            for _ in 0..excerpts {                let buffer_handle = if rng.gen() || buffers.is_empty() {                    let text = RandomCharIter::new(&mut rng).take(10).collect::<String>();                    buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));                    let buffer = buffers.last().unwrap();                    log::info!(                        "Creating new buffer {} with text: {:?}",                        buffer.id(),                        buffer.read(cx).text()                    );                    buffers.last().unwrap()                } else {                    buffers.choose(rng).unwrap()                };                 let buffer = buffer_handle.read(cx);                let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);                let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);                let header_height = rng.gen_range(0..=5);                log::info!(                    "Inserting excerpt from buffer {} with header height {} and range {:?}: {:?}",                    buffer_handle.id(),                    header_height,                    start_ix..end_ix,                    &buffer.text()[start_ix..end_ix]                );                 multibuffer.push_excerpt(                    ExcerptProperties {                        buffer: buffer_handle,                        range: start_ix..end_ix,                    },                    cx,                );            }            multibuffer        })    }     pub fn replica_id(&self) -> ReplicaId {        self.replica_id    }     pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {        self.sync(cx);        self.snapshot.borrow().clone()    }     pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {        self.sync(cx);        self.snapshot.borrow()    }     pub fn as_singleton(&self) -> Option<ModelHandle<Buffer>> {        if self.singleton {            return Some(                self.buffers                    .borrow()                    .values()                    .next()                    .unwrap()                    .buffer                    .clone(),            );        } else {            None        }    }     pub fn subscribe(&mut self) -> Subscription {        self.subscriptions.subscribe()    }     pub fn edit<I, S, T>(&mut self, ranges: I, new_text: T, cx: &mut ModelContext<Self>)    where        I: IntoIterator<Item = Range<S>>,        S: ToOffset,        T: Into<String>,    {        self.edit_internal(ranges, new_text, false, cx)    }     pub fn edit_with_autoindent<I, S, T>(        &mut self,        ranges: I,        new_text: T,        cx: &mut ModelContext<Self>,    ) where        I: IntoIterator<Item = Range<S>>,        S: ToOffset,        T: Into<String>,    {        self.edit_internal(ranges, new_text, true, cx)    }     pub fn edit_internal<I, S, T>(        &mut self,        ranges_iter: I,        new_text: T,        autoindent: bool,        cx: &mut ModelContext<Self>,    ) where        I: IntoIterator<Item = Range<S>>,        S: ToOffset,        T: Into<String>,    {        if let Some(buffer) = self.as_singleton() {            let snapshot = self.read(cx);            let ranges = ranges_iter                .into_iter()                .map(|range| range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot));            return buffer.update(cx, |buffer, cx| {                if autoindent {                    buffer.edit_with_autoindent(ranges, new_text, cx)                } else {                    buffer.edit(ranges, new_text, cx)                }            });        }         let snapshot = self.read(cx);        let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, bool)>> = Default::default();        let mut cursor = snapshot.excerpts.cursor::<usize>();        for range in ranges_iter {            let start = range.start.to_offset(&snapshot);            let end = range.end.to_offset(&snapshot);            cursor.seek(&start, Bias::Right, &());            if cursor.item().is_none() && start == *cursor.start() {                cursor.prev(&());            }            let start_excerpt = cursor.item().expect("start offset out of bounds");            let start_overshoot = start - cursor.start();            let buffer_start =                start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;             cursor.seek(&end, Bias::Right, &());            if cursor.item().is_none() && end == *cursor.start() {                cursor.prev(&());            }            let end_excerpt = cursor.item().expect("end offset out of bounds");            let end_overshoot = end - cursor.start();            let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;             if start_excerpt.id == end_excerpt.id {                buffer_edits                    .entry(start_excerpt.buffer_id)                    .or_insert(Vec::new())                    .push((buffer_start..buffer_end, true));            } else {                let start_excerpt_range =                    buffer_start..start_excerpt.range.end.to_offset(&start_excerpt.buffer);                let end_excerpt_range =                    end_excerpt.range.start.to_offset(&end_excerpt.buffer)..buffer_end;                buffer_edits                    .entry(start_excerpt.buffer_id)                    .or_insert(Vec::new())                    .push((start_excerpt_range, true));                buffer_edits                    .entry(end_excerpt.buffer_id)                    .or_insert(Vec::new())                    .push((end_excerpt_range, false));                 cursor.seek(&start, Bias::Right, &());                cursor.next(&());                while let Some(excerpt) = cursor.item() {                    if excerpt.id == end_excerpt.id {                        break;                    }                    buffer_edits                        .entry(excerpt.buffer_id)                        .or_insert(Vec::new())                        .push((excerpt.range.to_offset(&excerpt.buffer), false));                    cursor.next(&());                }            }        }         let new_text = new_text.into();        for (buffer_id, mut edits) in buffer_edits {            edits.sort_unstable_by_key(|(range, _)| range.start);            self.buffers.borrow()[&buffer_id]                .buffer                .update(cx, |buffer, cx| {                    let mut edits = edits.into_iter().peekable();                    let mut insertions = Vec::new();                    let mut deletions = Vec::new();                    while let Some((mut range, mut is_insertion)) = edits.next() {                        while let Some((next_range, next_is_insertion)) = edits.peek() {                            if range.end >= next_range.start {                                range.end = cmp::max(next_range.end, range.end);                                is_insertion |= *next_is_insertion;                                edits.next();                            } else {                                break;                            }                        }                         if is_insertion {                            insertions.push(                                buffer.anchor_before(range.start)..buffer.anchor_before(range.end),                            );                        } else if !range.is_empty() {                            deletions.push(                                buffer.anchor_before(range.start)..buffer.anchor_before(range.end),                            );                        }                    }                     if autoindent {                        buffer.edit_with_autoindent(deletions, "", cx);                        buffer.edit_with_autoindent(insertions, new_text.clone(), cx);                    } else {                        buffer.edit(deletions, "", cx);                        buffer.edit(insertions, new_text.clone(), cx);                    }                })        }    }     pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {        self.start_transaction_at(Instant::now(), cx)    }     pub(crate) fn start_transaction_at(        &mut self,        now: Instant,        cx: &mut ModelContext<Self>,    ) -> Option<TransactionId> {        if let Some(buffer) = self.as_singleton() {            return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));        }         for BufferState { buffer, .. } in self.buffers.borrow().values() {            buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));        }        self.history.start_transaction(now)    }     pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {        self.end_transaction_at(Instant::now(), cx)    }     pub(crate) fn end_transaction_at(        &mut self,        now: Instant,        cx: &mut ModelContext<Self>,    ) -> Option<TransactionId> {        if let Some(buffer) = self.as_singleton() {            return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));        }         let mut buffer_transactions = HashSet::default();        for BufferState { buffer, .. } in self.buffers.borrow().values() {            if let Some(transaction_id) =                buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))            {                buffer_transactions.insert((buffer.id(), transaction_id));            }        }         if self.history.end_transaction(now, buffer_transactions) {            let transaction_id = self.history.group().unwrap();            Some(transaction_id)        } else {            None        }    }     pub fn set_active_selections(        &mut self,        selections: &[Selection<Anchor>],        cx: &mut ModelContext<Self>,    ) {        let mut selections_by_buffer: HashMap<usize, Vec<Selection<text::Anchor>>> =            Default::default();        let snapshot = self.read(cx);        let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();        for selection in selections {            cursor.seek(&Some(&selection.start.excerpt_id), Bias::Left, &());            while let Some(excerpt) = cursor.item() {                if excerpt.id > selection.end.excerpt_id {                    break;                }                 let mut start = excerpt.range.start.clone();                let mut end = excerpt.range.end.clone();                if excerpt.id == selection.start.excerpt_id {                    start = selection.start.text_anchor.clone();                }                if excerpt.id == selection.end.excerpt_id {                    end = selection.end.text_anchor.clone();                }                selections_by_buffer                    .entry(excerpt.buffer_id)                    .or_default()                    .push(Selection {                        id: selection.id,                        start,                        end,                        reversed: selection.reversed,                        goal: selection.goal,                    });                 cursor.next(&());            }        }         for (buffer_id, buffer_state) in self.buffers.borrow().iter() {            if !selections_by_buffer.contains_key(buffer_id) {

Lines 1–500 of 3180.