
This pull request introduces the ability to add flaps, custom foldable regions whose first foldable line can be associated with: - A toggle in the gutter - A trailer showed at the end of the line, before the inline blame information https://github.com/zed-industries/zed/assets/482957/c53a9148-f31a-4743-af64-18afa73c404c To achieve this, we changed `FoldMap::fold` to accept a piece of text to display when the range is folded. We use this capability in flaps to avoid displaying the ellipsis character. We want to use this new API in the assistant to fold context while still giving visual cues as to what that context is. Release Notes: - N/A --------- Co-authored-by: Nathan Sobo <nathan@zed.dev> Co-authored-by: Mikayla <mikayla@zed.dev> Co-authored-by: Max <max@zed.dev>
148 lines
4.3 KiB
Rust
148 lines
4.3 KiB
Rust
use crate::{
|
|
locator::Locator, BufferId, BufferSnapshot, Point, PointUtf16, TextDimension, ToOffset,
|
|
ToPoint, ToPointUtf16,
|
|
};
|
|
use std::{cmp::Ordering, fmt::Debug, ops::Range};
|
|
use sum_tree::Bias;
|
|
|
|
/// A timestamped position in a buffer
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)]
|
|
pub struct Anchor {
|
|
pub timestamp: clock::Lamport,
|
|
/// The byte offset in the buffer
|
|
pub offset: usize,
|
|
/// Describes which character the anchor is biased towards
|
|
pub bias: Bias,
|
|
pub buffer_id: Option<BufferId>,
|
|
}
|
|
|
|
impl Anchor {
|
|
pub const MIN: Self = Self {
|
|
timestamp: clock::Lamport::MIN,
|
|
offset: usize::MIN,
|
|
bias: Bias::Left,
|
|
buffer_id: None,
|
|
};
|
|
|
|
pub const MAX: Self = Self {
|
|
timestamp: clock::Lamport::MAX,
|
|
offset: usize::MAX,
|
|
bias: Bias::Right,
|
|
buffer_id: None,
|
|
};
|
|
|
|
pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
|
|
let fragment_id_comparison = if self.timestamp == other.timestamp {
|
|
Ordering::Equal
|
|
} else {
|
|
buffer
|
|
.fragment_id_for_anchor(self)
|
|
.cmp(buffer.fragment_id_for_anchor(other))
|
|
};
|
|
|
|
fragment_id_comparison
|
|
.then_with(|| self.offset.cmp(&other.offset))
|
|
.then_with(|| self.bias.cmp(&other.bias))
|
|
}
|
|
|
|
pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
|
|
if self.cmp(other, buffer).is_le() {
|
|
*self
|
|
} else {
|
|
*other
|
|
}
|
|
}
|
|
|
|
pub fn max(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
|
|
if self.cmp(other, buffer).is_ge() {
|
|
*self
|
|
} else {
|
|
*other
|
|
}
|
|
}
|
|
|
|
pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
|
|
if bias == Bias::Left {
|
|
self.bias_left(buffer)
|
|
} else {
|
|
self.bias_right(buffer)
|
|
}
|
|
}
|
|
|
|
pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor {
|
|
if self.bias == Bias::Left {
|
|
*self
|
|
} else {
|
|
buffer.anchor_before(self)
|
|
}
|
|
}
|
|
|
|
pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor {
|
|
if self.bias == Bias::Right {
|
|
*self
|
|
} else {
|
|
buffer.anchor_after(self)
|
|
}
|
|
}
|
|
|
|
pub fn summary<D>(&self, content: &BufferSnapshot) -> D
|
|
where
|
|
D: TextDimension,
|
|
{
|
|
content.summary_for_anchor(self)
|
|
}
|
|
|
|
/// Returns true when the [`Anchor`] is located inside a visible fragment.
|
|
pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool {
|
|
if *self == Anchor::MIN || *self == Anchor::MAX {
|
|
true
|
|
} else if self.buffer_id != Some(buffer.remote_id) {
|
|
false
|
|
} else {
|
|
let fragment_id = buffer.fragment_id_for_anchor(self);
|
|
let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>();
|
|
fragment_cursor.seek(&Some(fragment_id), Bias::Left, &None);
|
|
fragment_cursor
|
|
.item()
|
|
.map_or(false, |fragment| fragment.visible)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait OffsetRangeExt {
|
|
fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize>;
|
|
fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point>;
|
|
fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16>;
|
|
}
|
|
|
|
impl<T> OffsetRangeExt for Range<T>
|
|
where
|
|
T: ToOffset,
|
|
{
|
|
fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize> {
|
|
self.start.to_offset(snapshot)..self.end.to_offset(snapshot)
|
|
}
|
|
|
|
fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point> {
|
|
self.start.to_offset(snapshot).to_point(snapshot)
|
|
..self.end.to_offset(snapshot).to_point(snapshot)
|
|
}
|
|
|
|
fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16> {
|
|
self.start.to_offset(snapshot).to_point_utf16(snapshot)
|
|
..self.end.to_offset(snapshot).to_point_utf16(snapshot)
|
|
}
|
|
}
|
|
|
|
pub trait AnchorRangeExt {
|
|
fn cmp(&self, b: &Range<Anchor>, buffer: &BufferSnapshot) -> Ordering;
|
|
}
|
|
|
|
impl AnchorRangeExt for Range<Anchor> {
|
|
fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Ordering {
|
|
match self.start.cmp(&other.start, buffer) {
|
|
Ordering::Equal => other.end.cmp(&self.end, buffer),
|
|
ord => ord,
|
|
}
|
|
}
|
|
}
|