8514 lines · 302.7 KB · Rust
RawDownload
mod anchor;#[cfg(test)]mod multi_buffer_tests;mod path_key;mod transaction; use self::transaction::History; pub use anchor::{Anchor, AnchorRangeExt}; use anyhow::{Result, anyhow};use buffer_diff::{    BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffChanged, DiffHunk,    DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind,};use clock::ReplicaId;use collections::{BTreeMap, Bound, HashMap, HashSet};use gpui::{App, Context, Entity, EntityId, EventEmitter};use itertools::Itertools;use language::{    AutoindentMode, BracketMatch, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability,    CharClassifier, CharKind, CharScopeContext, Chunk, CursorShape, DiagnosticEntryRef, File,    IndentGuideSettings, IndentSize, Language, LanguageScope, OffsetRangeExt, OffsetUtf16, Outline,    OutlineItem, Point, PointUtf16, Selection, TextDimension, TextObject, ToOffset as _,    ToPoint as _, TransactionId, TreeSitterOptions, Unclipped,    language_settings::{LanguageSettings, language_settings},}; #[cfg(any(test, feature = "test-support"))]use gpui::AppContext as _; use rope::DimensionPair;use smallvec::SmallVec;use smol::future::yield_now;use std::{    any::type_name,    borrow::Cow,    cell::{Cell, OnceCell, Ref, RefCell},    cmp, fmt,    future::Future,    io,    iter::{self, FromIterator},    mem,    ops::{self, Add, AddAssign, ControlFlow, Range, RangeBounds, Sub, SubAssign},    rc::Rc,    str,    sync::{Arc, OnceLock},    time::Duration,};use sum_tree::{Bias, Cursor, Dimension, Dimensions, SumTree, TreeMap};use text::{    BufferId, Edit, LineIndent, TextSummary,    locator::Locator,    subscription::{Subscription, Topic},};use theme::SyntaxTheme;use util::post_inc;use ztracing::instrument; pub use self::path_key::PathKey; pub static EXCERPT_CONTEXT_LINES: OnceLock<fn(&App) -> u32> = OnceLock::new(); pub fn excerpt_context_lines(cx: &App) -> u32 {    EXCERPT_CONTEXT_LINES.get().map(|f| f(cx)).unwrap_or(2)} #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]pub struct ExcerptId(u32); /// One or more [`Buffers`](Buffer) being edited in a single view.////// See <https://zed.dev/features#multi-buffers>pub struct MultiBuffer {    /// A snapshot of the [`Excerpt`]s in the MultiBuffer.    /// Use [`MultiBuffer::snapshot`] to get a up-to-date snapshot.    snapshot: RefCell<MultiBufferSnapshot>,    /// Contains the state of the buffers being edited    buffers: BTreeMap<BufferId, BufferState>,    /// Mapping from path keys to their excerpts.    excerpts_by_path: BTreeMap<PathKey, Vec<ExcerptId>>,    /// Mapping from excerpt IDs to their path key.    paths_by_excerpt: HashMap<ExcerptId, PathKey>,    /// Mapping from buffer IDs to their diff states    diffs: HashMap<BufferId, DiffState>,    subscriptions: Topic<MultiBufferOffset>,    /// If true, the multi-buffer only contains a single [`Buffer`] and a single [`Excerpt`]    singleton: bool,    /// The history of the multi-buffer.    history: History,    /// The explicit title of the multi-buffer.    /// If `None`, it will be derived from the underlying path or content.    title: Option<String>,    /// The writing capability of the multi-buffer.    capability: Capability,    buffer_changed_since_sync: Rc<Cell<bool>>,} #[derive(Clone, Debug, PartialEq, Eq)]pub enum Event {    ExcerptsAdded {        buffer: Entity<Buffer>,        predecessor: ExcerptId,        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,    },    ExcerptsRemoved {        ids: Vec<ExcerptId>,        removed_buffer_ids: Vec<BufferId>,    },    ExcerptsExpanded {        ids: Vec<ExcerptId>,    },    ExcerptsEdited {        excerpt_ids: Vec<ExcerptId>,        buffer_ids: Vec<BufferId>,    },    DiffHunksToggled,    Edited {        edited_buffer: Option<Entity<Buffer>>,    },    TransactionUndone {        transaction_id: TransactionId,    },    Reloaded,    LanguageChanged(BufferId, bool),    Reparsed(BufferId),    Saved,    FileHandleChanged,    DirtyChanged,    DiagnosticsUpdated,    BufferDiffChanged,} /// A diff hunk, representing a range of consequent lines in a multibuffer.#[derive(Debug, Clone, PartialEq, Eq)]pub struct MultiBufferDiffHunk {    /// The row range in the multibuffer where this diff hunk appears.    pub row_range: Range<MultiBufferRow>,    /// The buffer ID that this hunk belongs to.    pub buffer_id: BufferId,    /// The range of the underlying buffer that this hunk corresponds to.    pub buffer_range: Range<text::Anchor>,    /// The excerpt that contains the diff hunk.    pub excerpt_id: ExcerptId,    /// The range within the buffer's diff base that this hunk corresponds to.    pub diff_base_byte_range: Range<BufferOffset>,    /// The status of this hunk (added/modified/deleted and secondary status).    pub status: DiffHunkStatus,    /// The word diffs for this hunk.    pub word_diffs: Vec<Range<MultiBufferOffset>>,} impl MultiBufferDiffHunk {    pub fn status(&self) -> DiffHunkStatus {        self.status    }     pub fn is_created_file(&self) -> bool {        self.diff_base_byte_range == (BufferOffset(0)..BufferOffset(0))            && self.buffer_range.start.is_min()            && self.buffer_range.end.is_max()    }     pub fn multi_buffer_range(&self) -> Range<Anchor> {        let start = Anchor::in_buffer(self.excerpt_id, self.buffer_range.start);        let end = Anchor::in_buffer(self.excerpt_id, self.buffer_range.end);        start..end    }} pub type MultiBufferPoint = Point;type ExcerptOffset = ExcerptDimension<MultiBufferOffset>;type ExcerptPoint = ExcerptDimension<Point>; #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, Hash, serde::Deserialize)]#[serde(transparent)]pub struct MultiBufferRow(pub u32); impl MultiBufferRow {    pub const MIN: Self = Self(0);    pub const MAX: Self = Self(u32::MAX);} impl ops::Add<usize> for MultiBufferRow {    type Output = Self;     fn add(self, rhs: usize) -> Self::Output {        MultiBufferRow(self.0 + rhs as u32)    }} pub trait MultiBufferDimension: 'static + Copy + Default + std::fmt::Debug {    type TextDimension: TextDimension;    fn from_summary(summary: &MBTextSummary) -> Self;     fn add_text_dim(&mut self, summary: &Self::TextDimension);     fn add_mb_text_summary(&mut self, summary: &MBTextSummary);} // todo(lw): MultiBufferPointimpl MultiBufferDimension for Point {    type TextDimension = Point;    fn from_summary(summary: &MBTextSummary) -> Self {        summary.lines    }     fn add_text_dim(&mut self, other: &Self::TextDimension) {        *self += *other;    }     fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {        *self += summary.lines;    }} // todo(lw): MultiBufferPointUtf16impl MultiBufferDimension for PointUtf16 {    type TextDimension = PointUtf16;    fn from_summary(summary: &MBTextSummary) -> Self {        summary.lines_utf16()    }     fn add_text_dim(&mut self, other: &Self::TextDimension) {        *self += *other;    }     fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {        *self += summary.lines_utf16();    }} #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, Hash, serde::Deserialize)]pub struct MultiBufferOffset(pub usize); impl fmt::Display for MultiBufferOffset {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        write!(f, "{}", self.0)    }} impl rand::distr::uniform::SampleUniform for MultiBufferOffset {    type Sampler = MultiBufferOffsetUniformSampler;} pub struct MultiBufferOffsetUniformSampler {    sampler: rand::distr::uniform::UniformUsize,} impl rand::distr::uniform::UniformSampler for MultiBufferOffsetUniformSampler {    type X = MultiBufferOffset;     fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, rand::distr::uniform::Error>    where        B1: rand::distr::uniform::SampleBorrow<Self::X> + Sized,        B2: rand::distr::uniform::SampleBorrow<Self::X> + Sized,    {        let low = *low_b.borrow();        let high = *high_b.borrow();        let sampler = rand::distr::uniform::UniformUsize::new(low.0, high.0);        sampler.map(|sampler| MultiBufferOffsetUniformSampler { sampler })    }     #[inline] // if the range is constant, this helps LLVM to do the    // calculations at compile-time.    fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, rand::distr::uniform::Error>    where        B1: rand::distr::uniform::SampleBorrow<Self::X> + Sized,        B2: rand::distr::uniform::SampleBorrow<Self::X> + Sized,    {        let low = *low_b.borrow();        let high = *high_b.borrow();        let sampler = rand::distr::uniform::UniformUsize::new_inclusive(low.0, high.0);        sampler.map(|sampler| MultiBufferOffsetUniformSampler { sampler })    }     fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Self::X {        MultiBufferOffset(self.sampler.sample(rng))    }}impl MultiBufferDimension for MultiBufferOffset {    type TextDimension = usize;    fn from_summary(summary: &MBTextSummary) -> Self {        summary.len    }     fn add_text_dim(&mut self, other: &Self::TextDimension) {        self.0 += *other;    }     fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {        *self += summary.len;    }}impl MultiBufferDimension for MultiBufferOffsetUtf16 {    type TextDimension = OffsetUtf16;    fn from_summary(summary: &MBTextSummary) -> Self {        MultiBufferOffsetUtf16(summary.len_utf16)    }     fn add_text_dim(&mut self, other: &Self::TextDimension) {        self.0 += *other;    }     fn add_mb_text_summary(&mut self, summary: &MBTextSummary) {        self.0 += summary.len_utf16;    }} #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, Hash, serde::Deserialize)]pub struct BufferOffset(pub usize); impl TextDimension for BufferOffset {    fn from_text_summary(summary: &TextSummary) -> Self {        BufferOffset(usize::from_text_summary(summary))    }    fn from_chunk(chunk: rope::ChunkSlice) -> Self {        BufferOffset(usize::from_chunk(chunk))    }    fn add_assign(&mut self, other: &Self) {        TextDimension::add_assign(&mut self.0, &other.0);    }}impl<'a> sum_tree::Dimension<'a, rope::ChunkSummary> for BufferOffset {    fn zero(cx: ()) -> Self {        BufferOffset(<usize as sum_tree::Dimension<'a, rope::ChunkSummary>>::zero(cx))    }     fn add_summary(&mut self, summary: &'a rope::ChunkSummary, cx: ()) {        usize::add_summary(&mut self.0, summary, cx);    }} impl Sub for BufferOffset {    type Output = usize;     fn sub(self, other: BufferOffset) -> Self::Output {        self.0 - other.0    }} impl AddAssign<DimensionPair<usize, Point>> for BufferOffset {    fn add_assign(&mut self, other: DimensionPair<usize, Point>) {        self.0 += other.key;    }} impl language::ToPoint for BufferOffset {    fn to_point(&self, snapshot: &text::BufferSnapshot) -> Point {        self.0.to_point(snapshot)    }} impl language::ToPointUtf16 for BufferOffset {    fn to_point_utf16(&self, snapshot: &text::BufferSnapshot) -> PointUtf16 {        self.0.to_point_utf16(snapshot)    }} impl language::ToOffset for BufferOffset {    fn to_offset(&self, snapshot: &text::BufferSnapshot) -> usize {        self.0.to_offset(snapshot)    }} impl language::ToOffsetUtf16 for BufferOffset {    fn to_offset_utf16(&self, snapshot: &text::BufferSnapshot) -> OffsetUtf16 {        self.0.to_offset_utf16(snapshot)    }} #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]pub struct MultiBufferOffsetUtf16(pub OffsetUtf16); impl ops::Add<usize> for MultiBufferOffsetUtf16 {    type Output = MultiBufferOffsetUtf16;     fn add(self, rhs: usize) -> Self::Output {        MultiBufferOffsetUtf16(OffsetUtf16(self.0.0 + rhs))    }} impl ops::Add<OffsetUtf16> for MultiBufferOffsetUtf16 {    type Output = Self;     fn add(self, rhs: OffsetUtf16) -> Self::Output {        MultiBufferOffsetUtf16(self.0 + rhs)    }} impl AddAssign<OffsetUtf16> for MultiBufferOffsetUtf16 {    fn add_assign(&mut self, rhs: OffsetUtf16) {        self.0 += rhs;    }} impl AddAssign<usize> for MultiBufferOffsetUtf16 {    fn add_assign(&mut self, rhs: usize) {        self.0.0 += rhs;    }} impl Sub for MultiBufferOffsetUtf16 {    type Output = OffsetUtf16;     fn sub(self, other: MultiBufferOffsetUtf16) -> Self::Output {        self.0 - other.0    }} impl Sub<OffsetUtf16> for MultiBufferOffsetUtf16 {    type Output = MultiBufferOffsetUtf16;     fn sub(self, other: OffsetUtf16) -> Self::Output {        MultiBufferOffsetUtf16(self.0 - other)    }} #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]pub struct BufferOffsetUtf16(pub OffsetUtf16); impl MultiBufferOffset {    const ZERO: Self = Self(0);    pub fn saturating_sub(self, other: MultiBufferOffset) -> usize {        self.0.saturating_sub(other.0)    }    pub fn saturating_sub_usize(self, other: usize) -> MultiBufferOffset {        MultiBufferOffset(self.0.saturating_sub(other))    }} impl ops::Sub for MultiBufferOffset {    type Output = usize;     fn sub(self, other: MultiBufferOffset) -> Self::Output {        self.0 - other.0    }} impl ops::Sub<usize> for MultiBufferOffset {    type Output = Self;     fn sub(self, other: usize) -> Self::Output {        MultiBufferOffset(self.0 - other)    }} impl ops::SubAssign<usize> for MultiBufferOffset {    fn sub_assign(&mut self, other: usize) {        self.0 -= other;    }} impl ops::Add<usize> for BufferOffset {    type Output = Self;     fn add(self, rhs: usize) -> Self::Output {        BufferOffset(self.0 + rhs)    }} impl ops::AddAssign<usize> for BufferOffset {    fn add_assign(&mut self, other: usize) {        self.0 += other;    }} impl ops::Add<usize> for MultiBufferOffset {    type Output = Self;     fn add(self, rhs: usize) -> Self::Output {        MultiBufferOffset(self.0 + rhs)    }} impl ops::AddAssign<usize> for MultiBufferOffset {    fn add_assign(&mut self, other: usize) {        self.0 += other;    }} impl ops::Add<isize> for MultiBufferOffset {    type Output = Self;     fn add(self, rhs: isize) -> Self::Output {        MultiBufferOffset((self.0 as isize + rhs) as usize)    }} impl ops::Add for MultiBufferOffset {    type Output = Self;     fn add(self, rhs: MultiBufferOffset) -> Self::Output {        MultiBufferOffset(self.0 + rhs.0)    }} impl ops::AddAssign<MultiBufferOffset> for MultiBufferOffset {    fn add_assign(&mut self, other: MultiBufferOffset) {        self.0 += other.0;

Lines 1–500 of 8514.