Conrad Irwinpanics (#7793)65a19382 years agoHistory
5525 lines · 197.9 KB · Rust
RawDownload
mod anchor; pub use anchor::{Anchor, AnchorRangeExt};use anyhow::{anyhow, Result};use clock::ReplicaId;use collections::{BTreeMap, Bound, HashMap, HashSet};use futures::{channel::mpsc, SinkExt};use git::diff::DiffHunk;use gpui::{AppContext, EventEmitter, Model, ModelContext};pub use language::Completion;use language::{    char_kind,    language_settings::{language_settings, LanguageSettings},    AutoindentMode, Buffer, BufferChunks, BufferSnapshot, Capability, CharKind, Chunk, CursorShape,    DiagnosticEntry, File, IndentSize, Language, LanguageScope, OffsetRangeExt, OffsetUtf16,    Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _,    ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped,};use std::{    borrow::Cow,    cell::{Ref, RefCell},    cmp, fmt,    future::Future,    io,    iter::{self, FromIterator},    mem,    ops::{Range, RangeBounds, Sub},    str,    sync::Arc,    time::{Duration, Instant},};use sum_tree::{Bias, Cursor, SumTree};use text::{    locator::Locator,    subscription::{Subscription, Topic},    BufferId, Edit, TextSummary,};use theme::SyntaxTheme; use util::post_inc; #[cfg(any(test, feature = "test-support"))]use gpui::Context; const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize]; #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]pub struct ExcerptId(usize); pub struct MultiBuffer {    snapshot: RefCell<MultiBufferSnapshot>,    buffers: RefCell<HashMap<BufferId, BufferState>>,    subscriptions: Topic,    singleton: bool,    replica_id: ReplicaId,    history: History,    title: Option<String>,    capability: Capability,} #[derive(Clone, Debug, PartialEq, Eq)]pub enum Event {    ExcerptsAdded {        buffer: Model<Buffer>,        predecessor: ExcerptId,        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,    },    ExcerptsRemoved {        ids: Vec<ExcerptId>,    },    ExcerptsEdited {        ids: Vec<ExcerptId>,    },    Edited {        singleton_buffer_edited: bool,    },    TransactionUndone {        transaction_id: TransactionId,    },    Reloaded,    DiffBaseChanged,    LanguageChanged,    CapabilityChanged,    Reparsed,    Saved,    FileHandleChanged,    Closed,    DirtyChanged,    DiagnosticsUpdated,} #[derive(Clone)]struct History {    next_transaction_id: TransactionId,    undo_stack: Vec<Transaction>,    redo_stack: Vec<Transaction>,    transaction_depth: usize,    group_interval: Duration,} #[derive(Clone)]struct Transaction {    id: TransactionId,    buffer_transactions: HashMap<BufferId, text::TransactionId>,    first_edit_at: Instant,    last_edit_at: Instant,    suppress_grouping: bool,} pub trait ToOffset: 'static + fmt::Debug {    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;} pub trait ToOffsetUtf16: 'static + fmt::Debug {    fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16;} pub trait ToPoint: 'static + fmt::Debug {    fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;} pub trait ToPointUtf16: 'static + fmt::Debug {    fn to_point_utf16(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16;} struct BufferState {    buffer: Model<Buffer>,    last_version: clock::Global,    last_parse_count: usize,    last_selections_update_count: usize,    last_diagnostics_update_count: usize,    last_file_update_count: usize,    last_git_diff_update_count: usize,    excerpts: Vec<Locator>,    _subscriptions: [gpui::Subscription; 2],} #[derive(Clone, Default)]pub struct MultiBufferSnapshot {    singleton: bool,    excerpts: SumTree<Excerpt>,    excerpt_ids: SumTree<ExcerptIdMapping>,    parse_count: usize,    diagnostics_update_count: usize,    trailing_excerpt_update_count: usize,    git_diff_update_count: usize,    edit_count: usize,    is_dirty: bool,    has_conflict: bool,} pub struct ExcerptBoundary {    pub id: ExcerptId,    pub row: u32,    pub buffer: BufferSnapshot,    pub range: ExcerptRange<text::Anchor>,    pub starts_new_buffer: bool,} #[derive(Clone)]struct Excerpt {    id: ExcerptId,    locator: Locator,    buffer_id: BufferId,    buffer: BufferSnapshot,    range: ExcerptRange<text::Anchor>,    max_buffer_row: u32,    text_summary: TextSummary,    has_trailing_newline: bool,} #[derive(Clone, Debug)]struct ExcerptIdMapping {    id: ExcerptId,    locator: Locator,} #[derive(Clone, Debug, Eq, PartialEq)]pub struct ExcerptRange<T> {    pub context: Range<T>,    pub primary: Option<Range<T>>,} #[derive(Clone, Debug, Default)]struct ExcerptSummary {    excerpt_id: ExcerptId,    excerpt_locator: Locator,    max_buffer_row: u32,    text: TextSummary,} #[derive(Clone)]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>>,    language_aware: bool,} pub struct MultiBufferBytes<'a> {    range: Range<usize>,    excerpts: Cursor<'a, Excerpt, usize>,    excerpt_bytes: Option<ExcerptBytes<'a>>,    chunk: &'a [u8],} pub struct ReversedMultiBufferBytes<'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: text::Bytes<'a>,    footer_height: usize,} impl MultiBuffer {    pub fn new(replica_id: ReplicaId, capability: Capability) -> Self {        Self {            snapshot: Default::default(),            buffers: Default::default(),            subscriptions: Default::default(),            singleton: false,            capability,            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),            },            title: Default::default(),        }    }     pub fn clone(&self, new_cx: &mut ModelContext<Self>) -> Self {        let mut buffers = HashMap::default();        for (buffer_id, buffer_state) in self.buffers.borrow().iter() {            buffers.insert(                *buffer_id,                BufferState {                    buffer: buffer_state.buffer.clone(),                    last_version: buffer_state.last_version.clone(),                    last_parse_count: buffer_state.last_parse_count,                    last_selections_update_count: buffer_state.last_selections_update_count,                    last_diagnostics_update_count: buffer_state.last_diagnostics_update_count,                    last_file_update_count: buffer_state.last_file_update_count,                    last_git_diff_update_count: buffer_state.last_git_diff_update_count,                    excerpts: buffer_state.excerpts.clone(),                    _subscriptions: [                        new_cx.observe(&buffer_state.buffer, |_, _, cx| cx.notify()),                        new_cx.subscribe(&buffer_state.buffer, Self::on_buffer_event),                    ],                },            );        }        Self {            snapshot: RefCell::new(self.snapshot.borrow().clone()),            buffers: RefCell::new(buffers),            subscriptions: Default::default(),            singleton: self.singleton,            capability: self.capability,            replica_id: self.replica_id,            history: self.history.clone(),            title: self.title.clone(),        }    }     pub fn with_title(mut self, title: String) -> Self {        self.title = Some(title);        self    }     pub fn read_only(&self) -> bool {        self.capability == Capability::ReadOnly    }     pub fn singleton(buffer: Model<Buffer>, cx: &mut ModelContext<Self>) -> Self {        let mut this = Self::new(buffer.read(cx).replica_id(), buffer.read(cx).capability());        this.singleton = true;        this.push_excerpts(            buffer,            [ExcerptRange {                context: text::Anchor::MIN..text::Anchor::MAX,                primary: None,            }],            cx,        );        this.snapshot.borrow_mut().singleton = true;        this    }     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<Model<Buffer>> {        if self.singleton {            return Some(                self.buffers                    .borrow()                    .values()                    .next()                    .unwrap()                    .buffer                    .clone(),            );        } else {            None        }    }     pub fn is_singleton(&self) -> bool {        self.singleton    }     pub fn subscribe(&mut self) -> Subscription {        self.subscriptions.subscribe()    }     pub fn is_dirty(&self, cx: &AppContext) -> bool {        self.read(cx).is_dirty()    }     pub fn has_conflict(&self, cx: &AppContext) -> bool {        self.read(cx).has_conflict()    }     // The `is_empty` signature doesn't match what clippy expects    #[allow(clippy::len_without_is_empty)]    pub fn len(&self, cx: &AppContext) -> usize {        self.read(cx).len()    }     pub fn is_empty(&self, cx: &AppContext) -> bool {        self.len(cx) != 0    }     pub fn symbols_containing<T: ToOffset>(        &self,        offset: T,        theme: Option<&SyntaxTheme>,        cx: &AppContext,    ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {        self.read(cx).symbols_containing(offset, theme)    }     pub fn edit<I, S, T>(        &mut self,        edits: I,        mut autoindent_mode: Option<AutoindentMode>,        cx: &mut ModelContext<Self>,    ) where        I: IntoIterator<Item = (Range<S>, T)>,        S: ToOffset,        T: Into<Arc<str>>,    {        if self.buffers.borrow().is_empty() {            return;        }         let snapshot = self.read(cx);        let edits = edits.into_iter().map(|(range, new_text)| {            let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot);            if range.start > range.end {                mem::swap(&mut range.start, &mut range.end);            }            (range, new_text)        });         if let Some(buffer) = self.as_singleton() {            return buffer.update(cx, |buffer, cx| {                buffer.edit(edits, autoindent_mode, cx);            });        }         let original_indent_columns = match &mut autoindent_mode {            Some(AutoindentMode::Block {                original_indent_columns,            }) => mem::take(original_indent_columns),            _ => Default::default(),        };         struct BufferEdit {            range: Range<usize>,            new_text: Arc<str>,            is_insertion: bool,            original_indent_column: u32,        }        let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();        let mut edited_excerpt_ids = Vec::new();        let mut cursor = snapshot.excerpts.cursor::<usize>();        for (ix, (range, new_text)) in edits.enumerate() {            let new_text: Arc<str> = new_text.into();            let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0);            cursor.seek(&range.start, Bias::Right, &());            if cursor.item().is_none() && range.start == *cursor.start() {                cursor.prev(&());            }            let start_excerpt = cursor.item().expect("start offset out of bounds");            let start_overshoot = range.start - cursor.start();            let buffer_start = start_excerpt                .range                .context                .start                .to_offset(&start_excerpt.buffer)                + start_overshoot;            edited_excerpt_ids.push(start_excerpt.id);             cursor.seek(&range.end, Bias::Right, &());            if cursor.item().is_none() && range.end == *cursor.start() {                cursor.prev(&());            }            let end_excerpt = cursor.item().expect("end offset out of bounds");            let end_overshoot = range.end - cursor.start();            let buffer_end = end_excerpt                .range                .context                .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(BufferEdit {                        range: buffer_start..buffer_end,                        new_text,                        is_insertion: true,                        original_indent_column,                    });            } else {                edited_excerpt_ids.push(end_excerpt.id);                let start_excerpt_range = buffer_start                    ..start_excerpt                        .range                        .context                        .end                        .to_offset(&start_excerpt.buffer);                let end_excerpt_range = end_excerpt                    .range                    .context                    .start                    .to_offset(&end_excerpt.buffer)                    ..buffer_end;                buffer_edits                    .entry(start_excerpt.buffer_id)                    .or_insert(Vec::new())                    .push(BufferEdit {                        range: start_excerpt_range,                        new_text: new_text.clone(),                        is_insertion: true,                        original_indent_column,                    });                buffer_edits                    .entry(end_excerpt.buffer_id)                    .or_insert(Vec::new())                    .push(BufferEdit {                        range: end_excerpt_range,                        new_text: new_text.clone(),                        is_insertion: false,                        original_indent_column,                    });                 cursor.seek(&range.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(BufferEdit {                            range: excerpt.range.context.to_offset(&excerpt.buffer),                            new_text: new_text.clone(),

Lines 1–500 of 5525.