@@ -1,195 +1,266 @@
-use crate::{MultiBufferDimension, MultiBufferOffset, MultiBufferOffsetUtf16};
+use crate::{ExcerptSummary, MultiBufferDimension, MultiBufferOffset, MultiBufferOffsetUtf16};
-use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
+use super::{MultiBufferSnapshot, ToOffset, ToPoint};
use language::Point;
use std::{
cmp::Ordering,
ops::{Add, AddAssign, Range, Sub},
};
use sum_tree::Bias;
+use text::BufferId;
+use util::debug_panic;
/// A stable reference to a position within a [`MultiBuffer`](super::MultiBuffer).
///
/// Unlike simple offsets, anchors remain valid as the text is edited, automatically
/// adjusting to reflect insertions and deletions around them.
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
-pub struct Anchor {
- /// Identifies which excerpt within the multi-buffer this anchor belongs to.
- /// A multi-buffer can contain multiple excerpts from different buffers.
- pub excerpt_id: ExcerptId,
- /// The position within the excerpt's underlying buffer. This is a stable
- /// reference that remains valid as the buffer text is edited.
- pub text_anchor: text::Anchor,
- /// When present, indicates this anchor points into deleted text within an
- /// expanded diff hunk. The anchor references a position in the diff base
- /// (original) text rather than the current buffer text. This is used when
- /// displaying inline diffs where deleted lines are shown.
- pub diff_base_anchor: Option<text::Anchor>,
+pub enum Anchor {
+ Min,
+ Max,
+ Text {
+ /// The position within the excerpt's underlying buffer. This is a stable
+ /// reference that remains valid as the buffer text is edited.
+ timestamp: clock::Lamport,
+
+ /// The byte offset into the text inserted in the operation
+ /// at `timestamp`.
+ offset: u32,
+ /// Whether this anchor stays attached to the character *before* or *after*
+ /// the offset.
+ bias: Bias,
+ buffer_id: BufferId,
+ /// When present, indicates this anchor points into deleted text within an
+ /// expanded diff hunk. The anchor references a position in the diff base
+ /// (original) text rather than the current buffer text. This is used when
+ /// displaying inline diffs where deleted lines are shown.
+ diff_base_anchor: Option<text::Anchor>,
+ },
}
impl std::fmt::Debug for Anchor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.is_min() {
- return write!(f, "Anchor::min({:?})", self.text_anchor.buffer_id);
+ return write!(f, "Anchor::Min");
}
if self.is_max() {
- return write!(f, "Anchor::max({:?})", self.text_anchor.buffer_id);
+ return write!(f, "Anchor::Max");
}
f.debug_struct("Anchor")
- .field("excerpt_id", &self.excerpt_id)
- .field("text_anchor", &self.text_anchor)
- .field("diff_base_anchor", &self.diff_base_anchor)
+ .field("text_anchor", &self.text_anchor().unwrap())
+ .field("diff_base_anchor", &self.diff_base_anchor())
.finish()
}
}
impl Anchor {
- pub fn with_diff_base_anchor(self, diff_base_anchor: text::Anchor) -> Self {
- Self {
- diff_base_anchor: Some(diff_base_anchor),
- ..self
+ pub fn text_anchor(&self) -> Option<text::Anchor> {
+ match self {
+ Self::Min | Self::Max => None,
+ Self::Text {
+ timestamp,
+ offset,
+ bias,
+ buffer_id,
+ ..
+ } => Some(text::Anchor::new(
+ *timestamp,
+ *offset,
+ *bias,
+ Some(*buffer_id),
+ )),
}
}
- pub fn in_buffer(excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Self {
- Self {
- excerpt_id,
- text_anchor,
- diff_base_anchor: None,
+ pub fn diff_base_anchor(&self) -> Option<text::Anchor> {
+ match self {
+ Self::Min | Self::Max => None,
+ Self::Text {
+ diff_base_anchor, ..
+ } => *diff_base_anchor,
}
}
- pub fn range_in_buffer(excerpt_id: ExcerptId, range: Range<text::Anchor>) -> Range<Self> {
- Self::in_buffer(excerpt_id, range.start)..Self::in_buffer(excerpt_id, range.end)
+ pub fn with_diff_base_anchor(mut self, diff_base_anchor: text::Anchor) -> Self {
+ match &mut self {
+ Self::Min | Self::Max => {
+ debug_panic!("with_diff_base_anchor called on min or max anchor");
+ }
+ Self::Text {
+ diff_base_anchor: self_diff_base_anchor,
+ ..
+ } => {
+ *self_diff_base_anchor = Some(diff_base_anchor);
+ }
+ };
+ self
}
- pub fn min() -> Self {
- Self {
- excerpt_id: ExcerptId::min(),
- text_anchor: text::Anchor::MIN,
+ pub fn text(text_anchor: text::Anchor) -> Self {
+ let Some(buffer_id) = text_anchor.buffer_id else {
+ panic!("text_anchor must have a buffer_id");
+ };
+ Self::Text {
diff_base_anchor: None,
+ timestamp: text_anchor.timestamp(),
+ buffer_id,
+ offset: text_anchor.offset,
+ bias: text_anchor.bias,
}
}
+ pub fn range_in_buffer(range: Range<text::Anchor>) -> Range<Self> {
+ Self::text(range.start)..Self::text(range.end)
+ }
+
+ pub fn min() -> Self {
+ Self::Min
+ }
+
pub fn max() -> Self {
- Self {
- excerpt_id: ExcerptId::max(),
- text_anchor: text::Anchor::MAX,
- diff_base_anchor: None,
- }
+ Self::Max
}
pub fn is_min(&self) -> bool {
- self.excerpt_id == ExcerptId::min()
- && self.text_anchor.is_min()
- && self.diff_base_anchor.is_none()
+ matches!(self, Self::Min)
}
pub fn is_max(&self) -> bool {
- self.excerpt_id == ExcerptId::max()
- && self.text_anchor.is_max()
- && self.diff_base_anchor.is_none()
+ matches!(self, Self::Max)
}
pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
- if self == other {
- return Ordering::Equal;
- }
+ let (self_text_anchor, other_text_anchor) = match (self, other) {
+ (Anchor::Min, Anchor::Min) => return Ordering::Equal,
+ (Anchor::Max, Anchor::Max) => return Ordering::Equal,
+ (Anchor::Min, _) => return Ordering::Less,
+ (Anchor::Max, _) => return Ordering::Greater,
+ (_, Anchor::Max) => return Ordering::Less,
+ (_, Anchor::Min) => return Ordering::Greater,
+ (Anchor::Text { .. }, Anchor::Text { .. }) => {
+ (self.text_anchor().unwrap(), other.text_anchor().unwrap())
+ }
+ };
+ let self_buffer_id = self_text_anchor.buffer_id.unwrap();
+ let other_buffer_id = other_text_anchor.buffer_id.unwrap();
- let self_excerpt_id = snapshot.latest_excerpt_id(self.excerpt_id);
- let other_excerpt_id = snapshot.latest_excerpt_id(other.excerpt_id);
+ let Some(self_path_key) = snapshot.path_keys.get(&self_buffer_id) else {
+ panic!("path key was never set for buffer_id")
+ };
+ let Some(other_path_key) = snapshot.path_keys.get(&other_buffer_id) else {
+ panic!("path key was never set for buffer_id")
+ };
- let excerpt_id_cmp = self_excerpt_id.cmp(&other_excerpt_id, snapshot);
- if excerpt_id_cmp.is_ne() {
- return excerpt_id_cmp;
+ if self_path_key.cmp(other_path_key) != Ordering::Equal {
+ return self_path_key.cmp(other_path_key);
}
- if self_excerpt_id == ExcerptId::max()
- && self.text_anchor.is_max()
- && self.text_anchor.is_max()
- && self.diff_base_anchor.is_none()
- && other.diff_base_anchor.is_none()
- {
+
+ // in the case that you removed the buffer contianing self,
+ // and added the buffer containing other with the same path key
+ if self_buffer_id != other_buffer_id {
+ return self_buffer_id.cmp(&other_buffer_id);
+ }
+
+ let Some(buffer) = snapshot.buffer_for_path(&self_path_key) else {
return Ordering::Equal;
+ };
+ let text_cmp = self_text_anchor.cmp(&other_text_anchor, buffer);
+ if text_cmp != Ordering::Equal {
+ return text_cmp;
}
- if let Some(excerpt) = snapshot.excerpt(self_excerpt_id) {
- let text_cmp = self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer);
- if text_cmp.is_ne() {
- return text_cmp;
- }
- if (self.diff_base_anchor.is_some() || other.diff_base_anchor.is_some())
- && let Some(base_text) = snapshot
- .diffs
- .get(&excerpt.buffer_id)
- .map(|diff| diff.base_text())
- {
- let self_anchor = self.diff_base_anchor.filter(|a| a.is_valid(base_text));
- let other_anchor = other.diff_base_anchor.filter(|a| a.is_valid(base_text));
- return match (self_anchor, other_anchor) {
- (Some(a), Some(b)) => a.cmp(&b, base_text),
- (Some(_), None) => match other.text_anchor.bias {
- Bias::Left => Ordering::Greater,
- Bias::Right => Ordering::Less,
- },
- (None, Some(_)) => match self.text_anchor.bias {
- Bias::Left => Ordering::Less,
- Bias::Right => Ordering::Greater,
- },
- (None, None) => Ordering::Equal,
- };
- }
+
+ if (self.diff_base_anchor().is_some() || other.diff_base_anchor().is_some())
+ && let Some(base_text) = snapshot
+ .diffs
+ .get(&self_buffer_id)
+ .map(|diff| diff.base_text())
+ {
+ let self_anchor = self.diff_base_anchor().filter(|a| a.is_valid(base_text));
+ let other_anchor = other.diff_base_anchor().filter(|a| a.is_valid(base_text));
+ return match (self_anchor, other_anchor) {
+ (Some(a), Some(b)) => a.cmp(&b, base_text),
+ (Some(_), None) => match other_text_anchor.bias {
+ Bias::Left => Ordering::Greater,
+ Bias::Right => Ordering::Less,
+ },
+ (None, Some(_)) => match self_text_anchor.bias {
+ Bias::Left => Ordering::Less,
+ Bias::Right => Ordering::Greater,
+ },
+ (None, None) => Ordering::Equal,
+ };
}
+
Ordering::Equal
}
pub fn bias(&self) -> Bias {
- self.text_anchor.bias
+ match self {
+ Anchor::Min => Bias::Left,
+ Anchor::Max => Bias::Right,
+ Anchor::Text { bias, .. } => *bias,
+ }
}
pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
- if self.text_anchor.bias != Bias::Left
- && let Some(excerpt) = snapshot.excerpt(self.excerpt_id)
- {
- return Self {
- excerpt_id: excerpt.id,
- text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
- diff_base_anchor: self.diff_base_anchor.map(|a| {
- if let Some(base_text) = snapshot
- .diffs
- .get(&excerpt.buffer_id)
- .map(|diff| diff.base_text())
- && a.is_valid(&base_text)
+ match self {
+ Anchor::Min => *self,
+ Anchor::Max => snapshot.anchor_before(snapshot.max_point()),
+ Anchor::Text {
+ bias, buffer_id, ..
+ } => {
+ if *bias == Bias::Left {
+ return *self;
+ }
+ let Some(buffer) = snapshot.buffer_for_id(*buffer_id) else {
+ return *self;
+ };
+ let text_anchor = self.text_anchor().unwrap().bias_left(&buffer);
+ let ret = Self::text(text_anchor);
+ if let Some(diff_base_anchor) = self.diff_base_anchor() {
+ if let Some(diff) = snapshot.diffs.get(&buffer_id)
+ && diff_base_anchor.is_valid(&diff.base_text())
{
- return a.bias_left(base_text);
+ ret.with_diff_base_anchor(diff_base_anchor.bias_left(diff.base_text()))
+ } else {
+ ret.with_diff_base_anchor(diff_base_anchor)
}
- a
- }),
- };
+ } else {
+ ret
+ }
+ }
}
- *self
}
pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
- if self.text_anchor.bias != Bias::Right
- && let Some(excerpt) = snapshot.excerpt(self.excerpt_id)
- {
- return Self {
- excerpt_id: excerpt.id,
- text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
- diff_base_anchor: self.diff_base_anchor.map(|a| {
- if let Some(base_text) = snapshot
- .diffs
- .get(&excerpt.buffer_id)
- .map(|diff| diff.base_text())
- && a.is_valid(&base_text)
+ match self {
+ Anchor::Min => *self,
+ Anchor::Max => snapshot.anchor_after(Point::zero()),
+ Anchor::Text {
+ bias, buffer_id, ..
+ } => {
+ if *bias == Bias::Right {
+ return *self;
+ }
+ let Some(buffer) = snapshot.buffer_for_id(*buffer_id) else {
+ return *self;
+ };
+ let text_anchor = self.text_anchor().unwrap().bias_right(&buffer);
+ let ret = Self::text(text_anchor);
+ if let Some(diff_base_anchor) = self.diff_base_anchor() {
+ if let Some(diff) = snapshot.diffs.get(&buffer_id)
+ && diff_base_anchor.is_valid(&diff.base_text())
{
- return a.bias_right(base_text);
+ ret.with_diff_base_anchor(diff_base_anchor.bias_right(diff.base_text()))
+ } else {
+ ret.with_diff_base_anchor(diff_base_anchor)
}
- a
- }),
- };
+ } else {
+ ret
+ }
+ }
}
- *self
}
pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
@@ -206,16 +277,35 @@ impl Anchor {
}
pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool {
- if self.is_min() || self.is_max() {
- true
- } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
- (self.text_anchor == excerpt.range.context.start
- || self.text_anchor == excerpt.range.context.end
- || self.text_anchor.is_valid(&excerpt.buffer))
- && excerpt.contains(self)
- } else {
- false
- }
+ let Some(text_anchor) = self.text_anchor() else {
+ return true;
+ };
+ let Some(buffer_id) = text_anchor.buffer_id else {
+ debug_panic!("missing buffer_id for anchor");
+ return false;
+ };
+
+ let Some(target) = snapshot.anchor_seek_target(*self) else {
+ return false;
+ };
+ let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>(());
+ cursor.seek(&target, Bias::Left);
+ let Some(excerpt) = cursor.item() else {
+ return false;
+ };
+ excerpt.buffer.remote_id() == buffer_id
+ && excerpt
+ .range
+ .context
+ .start
+ .cmp(&text_anchor, &excerpt.buffer)
+ .is_le()
+ && excerpt
+ .range
+ .context
+ .end
+ .cmp(&text_anchor, &excerpt.buffer)
+ .is_ge()
}
}
@@ -15,7 +15,7 @@ use buffer_diff::{
};
use clock::ReplicaId;
use collections::{BTreeMap, Bound, HashMap, HashSet};
-use gpui::{App, Context, Entity, EntityId, EventEmitter};
+use gpui::{App, Context, Entity, EventEmitter};
use itertools::Itertools;
use language::{
AutoindentMode, BracketMatch, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability,
@@ -36,7 +36,8 @@ use std::{
any::type_name,
borrow::Cow,
cell::{Cell, OnceCell, Ref, RefCell},
- cmp, fmt,
+ cmp::{self, Ordering},
+ fmt,
future::Future,
io,
iter::{self, FromIterator},
@@ -54,7 +55,6 @@ use text::{
subscription::{Subscription, Topic},
};
use theme::SyntaxTheme;
-use util::post_inc;
use ztracing::instrument;
pub use self::path_key::{PathExcerptInsertResult, PathKey};
@@ -65,9 +65,6 @@ 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>
@@ -77,10 +74,6 @@ pub struct MultiBuffer {
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>,
@@ -96,22 +89,23 @@ pub struct MultiBuffer {
buffer_changed_since_sync: Rc<Cell<bool>>,
}
+pub struct ExcerptInfo {
+ path_key: PathKey,
+ buffer_id: BufferId,
+ range: ExcerptRange<text::Anchor>,
+}
+
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
- ExcerptsAdded {
+ BufferUpdated {
buffer: Entity<Buffer>,
- predecessor: ExcerptId,
- excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
+ path_key: PathKey,
+ ranges: Vec<Range<text::Anchor>>,
},
- ExcerptsRemoved {
- ids: Vec<ExcerptId>,
+ BuffersRemoved {
removed_buffer_ids: Vec<BufferId>,
},
- ExcerptsExpanded {
- ids: Vec<ExcerptId>,
- },
- ExcerptsEdited {
- excerpt_ids: Vec<ExcerptId>,
+ BuffersEdited {
buffer_ids: Vec<BufferId>,
},
DiffHunksToggled,
@@ -140,8 +134,6 @@ pub struct MultiBufferDiffHunk {
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).
@@ -162,8 +154,8 @@ impl MultiBufferDiffHunk {
}
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);
+ let start = Anchor::text(self.buffer_range.start);
+ let end = Anchor::text(self.buffer_range.end);
start..end
}
}
@@ -513,10 +505,9 @@ pub trait ToPoint: 'static + fmt::Debug {
struct BufferState {
buffer: Entity<Buffer>,
+ path_key: PathKey,
last_version: RefCell<clock::Global>,
last_non_text_state_update_count: Cell<usize>,
- // Note, any changes to this field value require updating snapshot.buffer_locators as well
- excerpts: Vec<Locator>,
_subscriptions: [gpui::Subscription; 2],
}
@@ -620,11 +611,9 @@ impl DiffState {
#[derive(Clone, Default)]
pub struct MultiBufferSnapshot {
excerpts: SumTree<Excerpt>,
- buffer_locators: TreeMap<BufferId, Arc<[Locator]>>,
+ path_keys: TreeMap<BufferId, PathKey>,
diffs: TreeMap<BufferId, DiffStateSnapshot>,
diff_transforms: SumTree<DiffTransform>,
- excerpt_ids: SumTree<ExcerptIdMapping>,
- replaced_excerpts: Arc<HashMap<ExcerptId, ExcerptId>>,
non_text_state_update_count: usize,
edit_count: usize,
is_dirty: bool,
@@ -639,24 +628,12 @@ pub struct MultiBufferSnapshot {
show_headers: bool,
}
-// follower: None
-// - BufferContent(Some)
-// - BufferContent(None)
-// - DeletedHunk
-//
-// follower: Some
-// - BufferContent(Some)
-// - BufferContent(None)
-
#[derive(Debug, Clone)]
enum DiffTransform {
- // RealText
BufferContent {
summary: MBTextSummary,
- // modified_hunk_info
inserted_hunk_info: Option<DiffTransformHunkInfo>,
},
- // ExpandedHunkText
DeletedHunk {
summary: TextSummary,
buffer_id: BufferId,
@@ -668,7 +645,7 @@ enum DiffTransform {
#[derive(Clone, Copy, Debug)]
struct DiffTransformHunkInfo {
- excerpt_id: ExcerptId,
+ buffer_id: BufferId,
hunk_start_anchor: text::Anchor,
hunk_secondary_status: DiffHunkSecondaryStatus,
is_logically_deleted: bool,
@@ -678,30 +655,28 @@ impl Eq for DiffTransformHunkInfo {}
impl PartialEq for DiffTransformHunkInfo {
fn eq(&self, other: &DiffTransformHunkInfo) -> bool {
- self.excerpt_id == other.excerpt_id && self.hunk_start_anchor == other.hunk_start_anchor
+ self.buffer_id == other.buffer_id && self.hunk_start_anchor == other.hunk_start_anchor
}
}
impl std::hash::Hash for DiffTransformHunkInfo {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- self.excerpt_id.hash(state);
+ self.buffer_id.hash(state);
self.hunk_start_anchor.hash(state);
}
}
#[derive(Clone)]
-pub struct ExcerptInfo {
- pub id: ExcerptId,
+pub struct ExcerptBoundaryInfo {
pub buffer: Arc<BufferSnapshot>,
pub buffer_id: BufferId,
pub range: ExcerptRange<text::Anchor>,
pub end_row: MultiBufferRow,
}
-impl std::fmt::Debug for ExcerptInfo {
+impl std::fmt::Debug for ExcerptBoundaryInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(type_name::<Self>())
- .field("id", &self.id)
.field("buffer_id", &self.buffer_id)
.field("path", &self.buffer.file().map(|f| f.path()))
.field("range", &self.range)
@@ -712,8 +687,8 @@ impl std::fmt::Debug for ExcerptInfo {
/// A boundary between `Excerpt`s in a [`MultiBuffer`]
#[derive(Debug)]
pub struct ExcerptBoundary {
- pub prev: Option<ExcerptInfo>,
- pub next: ExcerptInfo,
+ pub prev: Option<ExcerptBoundaryInfo>,
+ pub next: ExcerptBoundaryInfo,
/// The row in the `MultiBuffer` where the boundary is located
pub row: MultiBufferRow,
}
@@ -727,13 +702,13 @@ impl ExcerptBoundary {
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ExpandInfo {
pub direction: ExpandExcerptDirection,
- pub excerpt_id: ExcerptId,
+ pub excerpt_range: Range<text::Anchor>,
}
-#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct RowInfo {
pub buffer_id: Option<BufferId>,
pub buffer_row: Option<u32>,
@@ -745,22 +720,19 @@ pub struct RowInfo {
/// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`].
#[derive(Clone)]
-struct Excerpt {
- /// The unique identifier for this excerpt
- id: ExcerptId,
+pub(crate) struct Excerpt {
/// The location of the excerpt in the [`MultiBuffer`]
- locator: Locator,
- /// The buffer being excerpted
- buffer_id: BufferId,
+ pub(crate) path_key: PathKey,
/// A snapshot of the buffer being excerpted
- buffer: Arc<BufferSnapshot>,
+ pub(crate) buffer: Arc<BufferSnapshot>,
/// The range of the buffer to be shown in the excerpt
- range: ExcerptRange<text::Anchor>,
+ pub(crate) range: ExcerptRange<text::Anchor>,
+
/// The last row in the excerpted slice of the buffer
- max_buffer_row: BufferRow,
+ pub(crate) max_buffer_row: BufferRow,
/// A summary of the text in the excerpt
- text_summary: TextSummary,
- has_trailing_newline: bool,
+ pub(crate) text_summary: TextSummary,
+ pub(crate) has_trailing_newline: bool,
}
/// A public view into an `Excerpt` in a [`MultiBuffer`].
@@ -779,12 +751,6 @@ pub struct MultiBufferExcerpt<'a> {
buffer_offset: BufferOffset,
}
-#[derive(Clone, Debug)]
-struct ExcerptIdMapping {
- id: ExcerptId,
- locator: Locator,
-}
-
/// A range of text from a single [`Buffer`], to be shown as an `Excerpt`.
/// These ranges are relative to the buffer itself
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
@@ -805,16 +771,34 @@ impl<T: Clone> ExcerptRange<T> {
}
}
-#[derive(Clone, Debug, Default)]
+impl ExcerptRange<text::Anchor> {
+ pub fn contains(&self, t: &text::Anchor, snapshot: &BufferSnapshot) -> bool {
+ self.context.start.cmp(t, snapshot).is_le() && self.context.end.cmp(t, snapshot).is_ge()
+ }
+}
+
+#[derive(Clone, Debug)]
pub struct ExcerptSummary {
- excerpt_id: ExcerptId,
- /// The location of the last [`Excerpt`] being summarized
- excerpt_locator: Locator,
+ path_key: PathKey,
+ /// End of the excerpt
+ max_anchor: text::Anchor,
widest_line_number: u32,
text: MBTextSummary,
count: usize,
}
+impl ExcerptSummary {
+ pub fn min() -> Self {
+ ExcerptSummary {
+ path_key: PathKey::min(),
+ max_anchor: text::Anchor::MIN,
+ widest_line_number: 0,
+ text: MBTextSummary::default(),
+ count: 0,
+ }
+ }
+}
+
#[derive(Debug, Clone)]
pub struct DiffTransformSummary {
input: MBTextSummary,
@@ -1066,7 +1050,6 @@ struct MultiBufferRegion<'a, MBD, BD> {
}
struct ExcerptChunks<'a> {
- excerpt_id: ExcerptId,
content_chunks: BufferChunks<'a>,
has_footer: bool,
}
@@ -1077,7 +1060,6 @@ struct BufferEdit {
new_text: Arc<str>,
is_insertion: bool,
original_indent_column: Option<u32>,
- excerpt_id: ExcerptId,
}
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -1180,8 +1162,6 @@ impl MultiBuffer {
singleton: false,
capability,
title: None,
- excerpts_by_path: Default::default(),
- paths_by_excerpt: Default::default(),
buffer_changed_since_sync: Default::default(),
history: History::default(),
}
@@ -1198,11 +1178,11 @@ impl MultiBuffer {
*buffer_id,
BufferState {
buffer: buffer_state.buffer.clone(),
+ path_key: buffer_state.path_key.clone(),
last_version: buffer_state.last_version.clone(),
last_non_text_state_update_count: buffer_state
.last_non_text_state_update_count
.clone(),
- 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),
@@ -1217,8 +1197,6 @@ impl MultiBuffer {
Self {
snapshot: RefCell::new(self.snapshot.borrow().clone()),
buffers,
- excerpts_by_path: Default::default(),
- paths_by_excerpt: Default::default(),
diffs: diff_bases,
subscriptions: Default::default(),
singleton: self.singleton,
@@ -1366,7 +1344,7 @@ impl MultiBuffer {
_ => Default::default(),
};
- let (buffer_edits, edited_excerpt_ids) = MultiBuffer::convert_edits_to_buffer_edits(
+ let buffer_edits = MultiBuffer::convert_edits_to_buffer_edits(
edits,
this.snapshot.get_mut(),
&original_indent_columns,
@@ -1387,14 +1365,12 @@ impl MultiBuffer {
mut new_text,
mut is_insertion,
original_indent_column,
- excerpt_id,
}) = edits.next()
{
while let Some(BufferEdit {
range: next_range,
is_insertion: next_is_insertion,
new_text: next_new_text,
- excerpt_id: next_excerpt_id,
..
}) = edits.peek()
{
@@ -1407,9 +1383,7 @@ impl MultiBuffer {
if should_coalesce {
range.end = cmp::max(next_range.end, range.end);
is_insertion |= *next_is_insertion;
- if excerpt_id == *next_excerpt_id {
- new_text = format!("{new_text}{next_new_text}").into();
- }
+ new_text = format!("{new_text}{next_new_text}").into();
edits.next();
} else {
break;
@@ -1457,10 +1431,7 @@ impl MultiBuffer {
})
}
- cx.emit(Event::ExcerptsEdited {
- excerpt_ids: edited_excerpt_ids,
- buffer_ids,
- });
+ cx.emit(Event::BuffersEdited { buffer_ids });
}
}
@@ -1468,9 +1439,8 @@ impl MultiBuffer {
edits: Vec<(Range<MultiBufferOffset>, Arc<str>)>,
snapshot: &MultiBufferSnapshot,
original_indent_columns: &[Option<u32>],
- ) -> (HashMap<BufferId, Vec<BufferEdit>>, Vec<ExcerptId>) {
+ ) -> HashMap<BufferId, Vec<BufferEdit>> {
let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();
- let mut edited_excerpt_ids = Vec::new();
let mut cursor = snapshot.cursor::<MultiBufferOffset, BufferOffset>();
for (ix, (range, new_text)) in edits.into_iter().enumerate() {
let original_indent_column = original_indent_columns.get(ix).copied().flatten();
@@ -1515,11 +1485,10 @@ impl MultiBuffer {
let buffer_end =
(end_region.buffer_range.start + end_overshoot).min(end_region.buffer_range.end);
- if start_region.excerpt.id == end_region.excerpt.id {
+ if start_region.excerpt == end_region.excerpt {
if start_region.buffer.capability == Capability::ReadWrite
&& start_region.is_main_buffer
{
- edited_excerpt_ids.push(start_region.excerpt.id);
buffer_edits
.entry(start_region.buffer.remote_id())
.or_default()
@@ -1528,7 +1497,6 @@ impl MultiBuffer {
new_text,
is_insertion: true,
original_indent_column,
- excerpt_id: start_region.excerpt.id,
});
}
} else {
@@ -1537,7 +1505,6 @@ impl MultiBuffer {
if start_region.buffer.capability == Capability::ReadWrite
&& start_region.is_main_buffer
{
- edited_excerpt_ids.push(start_region.excerpt.id);
buffer_edits
.entry(start_region.buffer.remote_id())
.or_default()
@@ -1546,14 +1513,11 @@ impl MultiBuffer {
new_text: new_text.clone(),
is_insertion: true,
original_indent_column,
- excerpt_id: start_region.excerpt.id,
});
}
- let excerpt_id = end_region.excerpt.id;
if end_region.buffer.capability == Capability::ReadWrite
&& end_region.is_main_buffer
{
- edited_excerpt_ids.push(excerpt_id);
buffer_edits
.entry(end_region.buffer.remote_id())
.or_default()
@@ -1562,18 +1526,17 @@ impl MultiBuffer {
new_text: new_text.clone(),
is_insertion: false,
original_indent_column,
- excerpt_id,
});
}
+ let end_region_excerpt = end_region.excerpt.clone();
cursor.seek(&range.start);
cursor.next_excerpt();
while let Some(region) = cursor.region() {
- if region.excerpt.id == excerpt_id {
+ if region.excerpt == &end_region_excerpt {
break;
}
if region.buffer.capability == Capability::ReadWrite && region.is_main_buffer {
- edited_excerpt_ids.push(region.excerpt.id);
buffer_edits
.entry(region.buffer.remote_id())
.or_default()
@@ -1582,14 +1545,13 @@ impl MultiBuffer {
new_text: new_text.clone(),
is_insertion: false,
original_indent_column,
- excerpt_id: region.excerpt.id,
});
}
cursor.next_excerpt();
}
}
}
- (buffer_edits, edited_excerpt_ids)
+ buffer_edits
}
pub fn autoindent_ranges<I, S>(&mut self, ranges: I, cx: &mut Context<Self>)
@@ -1621,7 +1583,7 @@ impl MultiBuffer {
edits: Vec<(Range<MultiBufferOffset>, Arc<str>)>,
cx: &mut Context<MultiBuffer>,
) {
- let (buffer_edits, edited_excerpt_ids) =
+ let buffer_edits =
MultiBuffer::convert_edits_to_buffer_edits(edits, this.snapshot.get_mut(), &[]);
let mut buffer_ids = Vec::new();
@@ -1645,10 +1607,7 @@ impl MultiBuffer {
})
}
- cx.emit(Event::ExcerptsEdited {
- excerpt_ids: edited_excerpt_ids,
- buffer_ids,
- });
+ cx.emit(Event::BuffersEdited { buffer_ids });
}
}
@@ -1662,25 +1621,33 @@ impl MultiBuffer {
let mut selections_by_buffer: HashMap<BufferId, Vec<Selection<text::Anchor>>> =
Default::default();
let snapshot = self.read(cx);
- let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(());
+ let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>(());
for selection in selections {
- let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id);
- let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id);
+ let Some(start) = snapshot.anchor_seek_target(selection.start) else {
+ continue;
+ };
+ let Some(end) = snapshot.anchor_seek_target(selection.end) else {
+ continue;
+ };
- cursor.seek(&Some(start_locator), Bias::Left);
+ cursor.seek(&start, Bias::Left);
while let Some(excerpt) = cursor.item()
- && excerpt.locator <= *end_locator
+ && sum_tree::SeekTarget::cmp(&end, &cursor.position, ()).is_gt()
{
- let mut start = excerpt.range.context.start;
- let mut end = excerpt.range.context.end;
- if excerpt.id == selection.start.excerpt_id {
- start = selection.start.text_anchor;
- }
- if excerpt.id == selection.end.excerpt_id {
- end = selection.end.text_anchor;
- }
+ let start = text::Anchor::max(
+ &excerpt.range.context.start,
+ &selection.start.text_anchor().unwrap_or(text::Anchor::MIN),
+ &excerpt.buffer,
+ )
+ .clone();
+ let end = text::Anchor::min(
+ &excerpt.range.context.end,
+ &selection.end.text_anchor().unwrap_or(text::Anchor::MAX),
+ &excerpt.buffer,
+ )
+ .clone();
selections_by_buffer
- .entry(excerpt.buffer_id)
+ .entry(excerpt.buffer.remote_id())
.or_default()
.push(Selection {
id: selection.id,
@@ -1702,25 +1669,9 @@ impl MultiBuffer {
}
}
- for (buffer_id, mut selections) in selections_by_buffer {
+ for (buffer_id, selections) in selections_by_buffer {
self.buffers[&buffer_id].buffer.update(cx, |buffer, cx| {
- selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer));
- let mut selections = selections.into_iter().peekable();
- let merged_selections = Arc::from_iter(iter::from_fn(|| {
- let mut selection = selections.next()?;
- while let Some(next_selection) = selections.peek() {
- if selection.end.cmp(&next_selection.start, buffer).is_ge() {
- let next_selection = selections.next().unwrap();
- if next_selection.end.cmp(&selection.end, buffer).is_ge() {
- selection.end = next_selection.end;
- }
- } else {
- break;
- }
- }
- Some(selection)
- }));
- buffer.set_active_selections(merged_selections, line_mode, cursor_shape, cx);
+ buffer.set_active_selections(selections.into(), line_mode, cursor_shape, cx);
});
}
}
@@ -1759,175 +1710,11 @@ impl MultiBuffer {
(merged_ranges, counts)
}
- pub fn insert_excerpts_after<O>(
- &mut self,
- prev_excerpt_id: ExcerptId,
- buffer: Entity<Buffer>,
- ranges: impl IntoIterator<Item = ExcerptRange<O>>,
- cx: &mut Context<Self>,
- ) -> Vec<ExcerptId>
- where
- O: text::ToOffset,
- {
- let mut ids = Vec::new();
- let mut next_excerpt_id =
- if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() {
- last_entry.id.0 + 1
- } else {
- 1
- };
- self.insert_excerpts_with_ids_after(
- prev_excerpt_id,
- buffer,
- ranges.into_iter().map(|range| {
- let id = ExcerptId(post_inc(&mut next_excerpt_id));
- ids.push(id);
- (id, range)
- }),
- cx,
- );
- ids
- }
-
- pub fn insert_excerpts_with_ids_after<O>(
- &mut self,
- prev_excerpt_id: ExcerptId,
- buffer: Entity<Buffer>,
- ranges: impl IntoIterator<Item = (ExcerptId, ExcerptRange<O>)>,
- cx: &mut Context<Self>,
- ) where
- O: text::ToOffset,
- {
- assert_eq!(self.history.transaction_depth(), 0);
- let mut ranges = ranges.into_iter().peekable();
- if ranges.peek().is_none() {
- return Default::default();
- }
-
- self.sync_mut(cx);
-
- let buffer_snapshot = buffer.read(cx).snapshot();
- let buffer_id = buffer_snapshot.remote_id();
-
- let buffer_state = self.buffers.entry(buffer_id).or_insert_with(|| {
- self.buffer_changed_since_sync.replace(true);
- buffer.update(cx, |buffer, _| {
- buffer.record_changes(Rc::downgrade(&self.buffer_changed_since_sync));
- });
- BufferState {
- last_version: RefCell::new(buffer_snapshot.version().clone()),
- last_non_text_state_update_count: Cell::new(
- buffer_snapshot.non_text_state_update_count(),
- ),
- excerpts: Default::default(),
- _subscriptions: [
- cx.observe(&buffer, |_, _, cx| cx.notify()),
- cx.subscribe(&buffer, Self::on_buffer_event),
- ],
- buffer: buffer.clone(),
- }
- });
-
- let mut snapshot = self.snapshot.get_mut();
-
- let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone();
- let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids);
- let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(());
- let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right);
- prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone();
-
- let edit_start = ExcerptDimension(new_excerpts.summary().text.len);
- new_excerpts.update_last(
- |excerpt| {
- excerpt.has_trailing_newline = true;
- },
- (),
- );
-
- let next_locator = if let Some(excerpt) = cursor.item() {
- excerpt.locator.clone()
- } else {
- Locator::max()
- };
-
- let mut excerpts = Vec::new();
- let buffer_snapshot = Arc::new(buffer_snapshot);
- while let Some((id, range)) = ranges.next() {
- let locator = Locator::between(&prev_locator, &next_locator);
- if let Err(ix) = buffer_state.excerpts.binary_search(&locator) {
- buffer_state.excerpts.insert(ix, locator.clone());
- }
- let range = ExcerptRange {
- context: buffer_snapshot.anchor_before(&range.context.start)
- ..buffer_snapshot.anchor_after(&range.context.end),
- primary: buffer_snapshot.anchor_before(&range.primary.start)
- ..buffer_snapshot.anchor_after(&range.primary.end),
- };
- excerpts.push((id, range.clone()));
- let excerpt = Excerpt::new(
- id,
- locator.clone(),
- buffer_id,
- buffer_snapshot.clone(),
- range,
- ranges.peek().is_some() || cursor.item().is_some(),
- );
- new_excerpts.push(excerpt, ());
- prev_locator = locator.clone();
-
- if let Some(last_mapping_entry) = new_excerpt_ids.last() {
- assert!(id > last_mapping_entry.id, "excerpt ids must be increasing");
- }
- new_excerpt_ids.push(ExcerptIdMapping { id, locator }, ());
- }
- snapshot
- .buffer_locators
- .insert(buffer_id, buffer_state.excerpts.iter().cloned().collect());
-
- let edit_end = ExcerptDimension(new_excerpts.summary().text.len);
-
- let suffix = cursor.suffix();
- let changed_trailing_excerpt = suffix.is_empty();
- new_excerpts.append(suffix, ());
- drop(cursor);
- snapshot.excerpts = new_excerpts;
- snapshot.excerpt_ids = new_excerpt_ids;
- if changed_trailing_excerpt {
- snapshot.trailing_excerpt_update_count += 1;
- }
-
- let edits = Self::sync_diff_transforms(
- &mut snapshot,
- vec![Edit {
- old: edit_start..edit_start,
- new: edit_start..edit_end,
- }],
- DiffChangeKind::BufferEdited,
- );
- if !edits.is_empty() {
- self.subscriptions.publish(edits);
- }
-
- cx.emit(Event::Edited {
- edited_buffer: None,
- });
- cx.emit(Event::ExcerptsAdded {
- buffer,
- predecessor: prev_excerpt_id,
- excerpts,
- });
- cx.notify();
- }
-
pub fn clear(&mut self, cx: &mut Context<Self>) {
self.sync_mut(cx);
- let ids = self.excerpt_ids();
let removed_buffer_ids = std::mem::take(&mut self.buffers).into_keys().collect();
- self.excerpts_by_path.clear();
- self.paths_by_excerpt.clear();
let MultiBufferSnapshot {
excerpts,
- buffer_locators,
diffs: _,
diff_transforms: _,
non_text_state_update_count: _,
@@ -1937,15 +1724,13 @@ impl MultiBuffer {
has_conflict,
has_inverted_diff,
singleton: _,
- excerpt_ids: _,
- replaced_excerpts,
trailing_excerpt_update_count,
all_diff_hunks_expanded: _,
show_deleted_hunks: _,
use_extended_diff_range: _,
show_headers: _,
+ path_keys: _,
} = self.snapshot.get_mut();
- buffer_locators.clear();
let start = ExcerptDimension(MultiBufferOffset::ZERO);
let prev_len = ExcerptDimension(excerpts.summary().text.len);
*excerpts = Default::default();
@@ -1954,10 +1739,6 @@ impl MultiBuffer {
*has_deleted_file = false;
*has_conflict = false;
*has_inverted_diff = false;
- match Arc::get_mut(replaced_excerpts) {
- Some(replaced_excerpts) => replaced_excerpts.clear(),
- None => *replaced_excerpts = Default::default(),
- }
let edits = Self::sync_diff_transforms(
self.snapshot.get_mut(),
@@ -1973,10 +1754,7 @@ impl MultiBuffer {
cx.emit(Event::Edited {
edited_buffer: None,
});
- cx.emit(Event::ExcerptsRemoved {
- ids,
- removed_buffer_ids,
- });
+ cx.emit(Event::BuffersRemoved { removed_buffer_ids });
cx.notify();
}
@@ -1985,21 +1763,22 @@ impl MultiBuffer {
&self,
buffer_id: BufferId,
cx: &App,
- ) -> Vec<(ExcerptId, ExcerptRange<text::Anchor>)> {
+ ) -> Vec<ExcerptRange<text::Anchor>> {
let mut excerpts = Vec::new();
let snapshot = self.read(cx);
- let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(());
- if let Some(locators) = snapshot.buffer_locators.get(&buffer_id) {
- for locator in &**locators {
- cursor.seek_forward(&Some(locator), Bias::Left);
- if let Some(excerpt) = cursor.item()
- && excerpt.locator == *locator
- {
- excerpts.push((excerpt.id, excerpt.range.clone()));
- }
- }
- }
+ let Some(path_key) = snapshot.path_keys.get(&buffer_id).cloned() else {
+ return excerpts;
+ };
+
+ let mut cursor = snapshot.excerpts.cursor::<PathKey>(());
+ cursor.seek_forward(&path_key, Bias::Left);
+ while let Some(item) = cursor.item()
+ && item.path_key == path_key
+ {
+ excerpts.push(item.range.clone());
+ cursor.next()
+ }
excerpts
}
@@ -2007,84 +1786,67 @@ impl MultiBuffer {
let snapshot = self.read(cx);
let mut excerpts = snapshot
.excerpts
- .cursor::<Dimensions<Option<&Locator>, ExcerptPoint>>(());
+ .cursor::<Dimensions<PathKey, ExcerptPoint>>(());
let mut diff_transforms = snapshot
.diff_transforms
.cursor::<Dimensions<ExcerptPoint, OutputDimension<Point>>>(());
diff_transforms.next();
- let locators = snapshot
- .buffer_locators
- .get(&buffer_id)
- .into_iter()
- .flat_map(|v| &**v);
let mut result = Vec::new();
- for locator in locators {
- excerpts.seek_forward(&Some(locator), Bias::Left);
- if let Some(excerpt) = excerpts.item()
- && excerpt.locator == *locator
- {
- let excerpt_start = excerpts.start().1;
- let excerpt_end = excerpt_start + excerpt.text_summary.lines;
+ let Some(path_key) = snapshot.path_keys.get(&buffer_id) else {
+ return result;
+ };
- diff_transforms.seek_forward(&excerpt_start, Bias::Left);
- let overshoot = excerpt_start - diff_transforms.start().0;
- let start = diff_transforms.start().1 + overshoot;
+ while let Some(excerpt) = excerpts.item()
+ && &excerpt.path_key == path_key
+ {
+ let excerpt_start = excerpts.start().1;
+ let excerpt_end = excerpt_start + excerpt.text_summary.lines;
- diff_transforms.seek_forward(&excerpt_end, Bias::Right);
- let overshoot = excerpt_end - diff_transforms.start().0;
- let end = diff_transforms.start().1 + overshoot;
+ diff_transforms.seek_forward(&excerpt_start, Bias::Left);
+ let overshoot = excerpt_start - diff_transforms.start().0;
+ let start = diff_transforms.start().1 + overshoot;
- result.push(start.0..end.0)
- }
+ diff_transforms.seek_forward(&excerpt_end, Bias::Right);
+ let overshoot = excerpt_end - diff_transforms.start().0;
+ let end = diff_transforms.start().1 + overshoot;
+
+ result.push(start.0..end.0);
+ excerpts.next()
}
result
}
+ // todo!() this seems bogus
pub fn excerpt_buffer_ids(&self) -> Vec<BufferId> {
self.snapshot
.borrow()
.excerpts
.iter()
- .map(|entry| entry.buffer_id)
+ .map(|entry| entry.buffer.remote_id())
.collect()
}
- pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
- let snapshot = self.snapshot.borrow();
- let mut ids = Vec::with_capacity(snapshot.excerpts.summary().count);
- ids.extend(snapshot.excerpts.iter().map(|entry| entry.id));
- ids
- }
-
- pub fn excerpt_containing(
- &self,
- position: impl ToOffset,
- cx: &App,
- ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
+ pub fn excerpt_containing(&self, position: impl ToOffset, cx: &App) -> Option<ExcerptInfo> {
let snapshot = self.read(cx);
let offset = position.to_offset(&snapshot);
let mut cursor = snapshot.cursor::<MultiBufferOffset, BufferOffset>();
cursor.seek(&offset);
- cursor
- .excerpt()
- .or_else(|| snapshot.excerpts.last())
- .map(|excerpt| {
- (
- excerpt.id,
- self.buffers.get(&excerpt.buffer_id).unwrap().buffer.clone(),
- excerpt.range.context.clone(),
- )
- })
+ let excerpt = cursor.excerpt().or(snapshot.excerpts.last())?;
+ Some(ExcerptInfo {
+ path_key: excerpt.path_key.clone(),
+ buffer_id: excerpt.buffer.remote_id(),
+ range: excerpt.range.clone(),
+ })
}
pub fn buffer_for_anchor(&self, anchor: Anchor, cx: &App) -> Option<Entity<Buffer>> {
- if let Some(buffer_id) = anchor.text_anchor.buffer_id {
- self.buffer(buffer_id)
- } else {
- let (_, buffer, _) = self.excerpt_containing(anchor, cx)?;
- Some(buffer)
- }
+ let buffer_id = match anchor {
+ Anchor::Min => self.snapshot(cx).excerpts.first()?.buffer.remote_id(),
+ Anchor::Max => self.snapshot(cx).excerpts.last()?.buffer.remote_id(),
+ Anchor::Text { buffer_id, .. } => buffer_id,
+ };
+ self.buffer(buffer_id)
}
// If point is at the end of the buffer, the last excerpt is returned
@@ -2106,15 +1868,10 @@ impl MultiBuffer {
&self,
point: T,
cx: &App,
- ) -> Option<(Entity<Buffer>, Point, ExcerptId)> {
+ ) -> Option<(Entity<Buffer>, Point)> {
let snapshot = self.read(cx);
- let (buffer, point, is_main_buffer) =
- snapshot.point_to_buffer_point(point.to_point(&snapshot))?;
- Some((
- self.buffers.get(&buffer.remote_id())?.buffer.clone(),
- point,
- is_main_buffer,
- ))
+ let (buffer, point) = snapshot.point_to_buffer_point(point.to_point(&snapshot))?;
+ Some((self.buffers.get(&buffer.remote_id())?.buffer.clone(), point))
}
pub fn buffer_point_to_anchor(
@@ -2126,25 +1883,22 @@ impl MultiBuffer {
) -> Option<Anchor> {
let mut found = None;
let snapshot = buffer.read(cx).snapshot();
- for (excerpt_id, range) in self.excerpts_for_buffer(snapshot.remote_id(), cx) {
+ for range in self.excerpts_for_buffer(snapshot.remote_id(), cx) {
let start = range.context.start.to_point(&snapshot);
let end = range.context.end.to_point(&snapshot);
if start <= point && point < end {
- found = Some((snapshot.clip_point(point, Bias::Left), excerpt_id));
+ found = Some(snapshot.clip_point(point, Bias::Left));
break;
}
if point < start {
- found = Some((start, excerpt_id));
+ found = Some(start);
}
if point > end {
- found = Some((end, excerpt_id));
+ found = Some(end);
}
}
- found.map(|(point, excerpt_id)| {
- let text_anchor = snapshot.anchor_after(point);
- Anchor::in_buffer(excerpt_id, text_anchor)
- })
+ Some(Anchor::text(snapshot.anchor_after(found?)))
}
pub fn buffer_anchor_to_anchor(