Use replace blocks for patches (#20605)
Release Notes: - N/A --------- Co-authored-by: Max <max@zed.dev> Co-authored-by: Richard <richard@zed.dev>
This commit is contained in:
co-authored by
Max
Richard
parent
96deabfb78
commit
92613a8904
@@ -7,7 +7,7 @@ use collections::{Bound, HashMap, HashSet};
|
||||
use gpui::{AnyElement, EntityId, Pixels, WindowContext};
|
||||
use language::{Chunk, Patch, Point};
|
||||
use multi_buffer::{
|
||||
Anchor, ExcerptId, ExcerptInfo, MultiBufferRow, MultiBufferSnapshot, ToPoint as _,
|
||||
Anchor, ExcerptId, ExcerptInfo, MultiBufferRow, MultiBufferSnapshot, ToOffset, ToPoint as _,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
@@ -77,7 +77,7 @@ pub struct BlockRow(pub(super) u32);
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
struct WrapRow(u32);
|
||||
|
||||
pub type RenderBlock = Box<dyn Send + FnMut(&mut BlockContext) -> AnyElement>;
|
||||
pub type RenderBlock = Arc<dyn Send + Sync + Fn(&mut BlockContext) -> AnyElement>;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum BlockPlacement<T> {
|
||||
@@ -352,6 +352,13 @@ impl Block {
|
||||
Block::ExcerptBoundary { next_excerpt, .. } => next_excerpt.is_none(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_replacement(&self) -> bool {
|
||||
match self {
|
||||
Block::Custom(block) => matches!(block.placement, BlockPlacement::Replace(_)),
|
||||
Block::ExcerptBoundary { .. } => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Block {
|
||||
@@ -1119,6 +1126,64 @@ impl<'a> BlockMapWriter<'a> {
|
||||
.retain(|id, _| !block_ids.contains(id));
|
||||
self.0.sync(wrap_snapshot, edits);
|
||||
}
|
||||
|
||||
pub fn remove_intersecting_replace_blocks<T>(
|
||||
&mut self,
|
||||
ranges: impl IntoIterator<Item = Range<T>>,
|
||||
inclusive: bool,
|
||||
) where
|
||||
T: ToOffset,
|
||||
{
|
||||
let wrap_snapshot = self.0.wrap_snapshot.borrow();
|
||||
let mut blocks_to_remove = HashSet::default();
|
||||
for range in ranges {
|
||||
let range = range.start.to_offset(wrap_snapshot.buffer_snapshot())
|
||||
..range.end.to_offset(wrap_snapshot.buffer_snapshot());
|
||||
for block in self.blocks_intersecting_buffer_range(range, inclusive) {
|
||||
if matches!(block.placement, BlockPlacement::Replace(_)) {
|
||||
blocks_to_remove.insert(block.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(wrap_snapshot);
|
||||
self.remove(blocks_to_remove);
|
||||
}
|
||||
|
||||
fn blocks_intersecting_buffer_range(
|
||||
&self,
|
||||
range: Range<usize>,
|
||||
inclusive: bool,
|
||||
) -> &[Arc<CustomBlock>] {
|
||||
let wrap_snapshot = self.0.wrap_snapshot.borrow();
|
||||
let buffer = wrap_snapshot.buffer_snapshot();
|
||||
let start_block_ix = match self.0.custom_blocks.binary_search_by(|probe| {
|
||||
probe
|
||||
.end()
|
||||
.to_offset(buffer)
|
||||
.cmp(&range.start)
|
||||
.then(if inclusive {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Less
|
||||
})
|
||||
}) {
|
||||
Ok(ix) | Err(ix) => ix,
|
||||
};
|
||||
let end_block_ix = match self.0.custom_blocks.binary_search_by(|probe| {
|
||||
probe
|
||||
.start()
|
||||
.to_offset(buffer)
|
||||
.cmp(&range.end)
|
||||
.then(if inclusive {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
})
|
||||
}) {
|
||||
Ok(ix) | Err(ix) => ix,
|
||||
};
|
||||
&self.0.custom_blocks[start_block_ix..end_block_ix]
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockSnapshot {
|
||||
@@ -1298,6 +1363,21 @@ impl BlockSnapshot {
|
||||
cursor.item().map_or(false, |t| t.block.is_some())
|
||||
}
|
||||
|
||||
pub(super) fn is_line_replaced(&self, row: MultiBufferRow) -> bool {
|
||||
let wrap_point = self
|
||||
.wrap_snapshot
|
||||
.make_wrap_point(Point::new(row.0, 0), Bias::Left);
|
||||
let mut cursor = self.transforms.cursor::<(WrapRow, BlockRow)>(&());
|
||||
cursor.seek(&WrapRow(wrap_point.row()), Bias::Right, &());
|
||||
cursor.item().map_or(false, |transform| {
|
||||
if let Some(Block::Custom(block)) = transform.block.as_ref() {
|
||||
matches!(block.placement, BlockPlacement::Replace(_))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, point: BlockPoint, bias: Bias) -> BlockPoint {
|
||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&());
|
||||
cursor.seek(&BlockRow(point.row), Bias::Right, &());
|
||||
@@ -1515,7 +1595,7 @@ impl<'a> Iterator for BlockChunks<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Iterator for BlockBufferRows<'a> {
|
||||
type Item = Option<BlockRow>;
|
||||
type Item = Option<u32>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.started {
|
||||
@@ -1538,16 +1618,25 @@ impl<'a> Iterator for BlockBufferRows<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if self.transforms.item()?.block.is_none() {
|
||||
let transform = self.transforms.item()?;
|
||||
if transform
|
||||
.block
|
||||
.as_ref()
|
||||
.map_or(true, |block| block.is_replacement())
|
||||
{
|
||||
self.input_buffer_rows.seek(self.transforms.start().1 .0);
|
||||
}
|
||||
}
|
||||
|
||||
let transform = self.transforms.item()?;
|
||||
if transform.block.is_some() {
|
||||
Some(None)
|
||||
if let Some(block) = transform.block.as_ref() {
|
||||
if block.is_replacement() && self.transforms.start().0 == self.output_row {
|
||||
Some(self.input_buffer_rows.next().unwrap())
|
||||
} else {
|
||||
Some(None)
|
||||
}
|
||||
} else {
|
||||
Some(self.input_buffer_rows.next().unwrap().map(BlockRow))
|
||||
Some(self.input_buffer_rows.next().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1709,21 +1798,21 @@ mod tests {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Above(buffer_snapshot.anchor_after(Point::new(1, 0))),
|
||||
height: 1,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Above(buffer_snapshot.anchor_after(Point::new(1, 2))),
|
||||
height: 2,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Below(buffer_snapshot.anchor_after(Point::new(3, 3))),
|
||||
height: 3,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
]);
|
||||
@@ -1821,10 +1910,7 @@ mod tests {
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.buffer_rows(BlockRow(0))
|
||||
.map(|row| row.map(|r| r.0))
|
||||
.collect::<Vec<_>>(),
|
||||
snapshot.buffer_rows(BlockRow(0)).collect::<Vec<_>>(),
|
||||
&[
|
||||
Some(0),
|
||||
None,
|
||||
@@ -1960,21 +2046,21 @@ mod tests {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Above(buffer_snapshot.anchor_after(Point::new(1, 0))),
|
||||
height: 1,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Above(buffer_snapshot.anchor_after(Point::new(1, 2))),
|
||||
height: 2,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Below(buffer_snapshot.anchor_after(Point::new(3, 3))),
|
||||
height: 3,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
]);
|
||||
@@ -2062,14 +2148,14 @@ mod tests {
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Above(buffer_snapshot.anchor_after(Point::new(1, 12))),
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
height: 1,
|
||||
priority: 0,
|
||||
},
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Below(buffer_snapshot.anchor_after(Point::new(1, 1))),
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
height: 1,
|
||||
priority: 0,
|
||||
},
|
||||
@@ -2109,7 +2195,7 @@ mod tests {
|
||||
..buffer_snapshot.anchor_before(Point::new(3, 1)),
|
||||
),
|
||||
height: 4,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
}]);
|
||||
|
||||
@@ -2162,14 +2248,14 @@ mod tests {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Above(buffer_snapshot.anchor_after(Point::new(1, 3))),
|
||||
height: 1,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Below(buffer_snapshot.anchor_after(Point::new(6, 2))),
|
||||
height: 1,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
]);
|
||||
@@ -2183,21 +2269,21 @@ mod tests {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Below(buffer_snapshot.anchor_after(Point::new(1, 3))),
|
||||
height: 1,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Above(buffer_snapshot.anchor_after(Point::new(2, 1))),
|
||||
height: 1,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
BlockProperties {
|
||||
style: BlockStyle::Fixed,
|
||||
placement: BlockPlacement::Above(buffer_snapshot.anchor_after(Point::new(6, 1))),
|
||||
height: 1,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
},
|
||||
]);
|
||||
@@ -2302,7 +2388,7 @@ mod tests {
|
||||
style: BlockStyle::Fixed,
|
||||
placement,
|
||||
height,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
}
|
||||
})
|
||||
@@ -2321,7 +2407,7 @@ mod tests {
|
||||
placement: props.placement.clone(),
|
||||
height: props.height,
|
||||
style: props.style,
|
||||
render: Box::new(|_| div().into_any()),
|
||||
render: Arc::new(|_| div().into_any()),
|
||||
priority: 0,
|
||||
}));
|
||||
}
|
||||
@@ -2409,6 +2495,7 @@ mod tests {
|
||||
let mut expected_buffer_rows = Vec::new();
|
||||
let mut expected_text = String::new();
|
||||
let mut expected_block_positions = Vec::new();
|
||||
let mut expected_replaced_buffer_rows = HashSet::default();
|
||||
let input_text = wraps_snapshot.text();
|
||||
|
||||
// Loop over the input lines, creating (N - 1) empty lines for
|
||||
@@ -2422,6 +2509,9 @@ mod tests {
|
||||
let mut block_row = 0;
|
||||
while let Some((wrap_row, input_line)) = input_text_lines.next() {
|
||||
let wrap_row = wrap_row as u32;
|
||||
let multibuffer_row = wraps_snapshot
|
||||
.to_point(WrapPoint::new(wrap_row, 0), Bias::Left)
|
||||
.row;
|
||||
|
||||
// Create empty lines for the above block
|
||||
while let Some((placement, block)) = sorted_blocks_iter.peek() {
|
||||
@@ -2451,30 +2541,33 @@ mod tests {
|
||||
{
|
||||
if wrap_row >= replace_range.start.0 {
|
||||
is_in_replace_block = true;
|
||||
|
||||
if wrap_row == replace_range.start.0 {
|
||||
expected_buffer_rows.push(input_buffer_rows[multibuffer_row as usize]);
|
||||
}
|
||||
|
||||
if wrap_row == replace_range.end.0 {
|
||||
expected_block_positions.push((block_row, block.id()));
|
||||
if block.height() > 0 {
|
||||
let text = "\n".repeat((block.height() - 1) as usize);
|
||||
if block_row > 0 {
|
||||
expected_text.push('\n');
|
||||
}
|
||||
expected_text.push_str(&text);
|
||||
for _ in 0..block.height() {
|
||||
expected_buffer_rows.push(None);
|
||||
}
|
||||
block_row += block.height();
|
||||
let text = "\n".repeat((block.height() - 1) as usize);
|
||||
if block_row > 0 {
|
||||
expected_text.push('\n');
|
||||
}
|
||||
expected_text.push_str(&text);
|
||||
|
||||
for _ in 1..block.height() {
|
||||
expected_buffer_rows.push(None);
|
||||
}
|
||||
block_row += block.height();
|
||||
|
||||
sorted_blocks_iter.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !is_in_replace_block {
|
||||
let buffer_row = input_buffer_rows[wraps_snapshot
|
||||
.to_point(WrapPoint::new(wrap_row, 0), Bias::Left)
|
||||
.row as usize];
|
||||
|
||||
if is_in_replace_block {
|
||||
expected_replaced_buffer_rows.insert(MultiBufferRow(multibuffer_row));
|
||||
} else {
|
||||
let buffer_row = input_buffer_rows[multibuffer_row as usize];
|
||||
let soft_wrapped = wraps_snapshot
|
||||
.to_tab_point(WrapPoint::new(wrap_row, 0))
|
||||
.column()
|
||||
@@ -2543,9 +2636,10 @@ mod tests {
|
||||
assert_eq!(
|
||||
blocks_snapshot
|
||||
.buffer_rows(BlockRow(start_row as u32))
|
||||
.map(|row| row.map(|r| r.0))
|
||||
.collect::<Vec<_>>(),
|
||||
&expected_buffer_rows[start_row..]
|
||||
&expected_buffer_rows[start_row..],
|
||||
"incorrect buffer_rows starting at row {:?}",
|
||||
start_row
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2666,6 +2760,16 @@ mod tests {
|
||||
block_point.column += c.len_utf8() as u32;
|
||||
}
|
||||
}
|
||||
|
||||
for buffer_row in 0..=buffer_snapshot.max_point().row {
|
||||
let buffer_row = MultiBufferRow(buffer_row);
|
||||
assert_eq!(
|
||||
blocks_snapshot.is_line_replaced(buffer_row),
|
||||
expected_replaced_buffer_rows.contains(&buffer_row),
|
||||
"incorrect is_line_replaced({:?})",
|
||||
buffer_row
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ use collections::HashMap;
|
||||
use gpui::{AnyElement, IntoElement};
|
||||
use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToPoint};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{cmp::Ordering, ops::Range, sync::Arc};
|
||||
use std::{cmp::Ordering, fmt::Debug, ops::Range, sync::Arc};
|
||||
use sum_tree::{Bias, SeekTarget, SumTree};
|
||||
use text::Point;
|
||||
use ui::{IconName, SharedString, WindowContext};
|
||||
|
||||
use crate::FoldPlaceholder;
|
||||
use crate::{BlockStyle, FoldPlaceholder, RenderBlock};
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct CreaseId(usize);
|
||||
@@ -45,15 +45,15 @@ impl CreaseSnapshot {
|
||||
&'a self,
|
||||
row: MultiBufferRow,
|
||||
snapshot: &'a MultiBufferSnapshot,
|
||||
) -> Option<&'a Crease> {
|
||||
) -> Option<&'a Crease<Anchor>> {
|
||||
let start = snapshot.anchor_before(Point::new(row.0, 0));
|
||||
let mut cursor = self.creases.cursor::<ItemSummary>(snapshot);
|
||||
cursor.seek(&start, Bias::Left, snapshot);
|
||||
while let Some(item) = cursor.item() {
|
||||
match Ord::cmp(&item.crease.range.start.to_point(snapshot).row, &row.0) {
|
||||
match Ord::cmp(&item.crease.range().start.to_point(snapshot).row, &row.0) {
|
||||
Ordering::Less => cursor.next(snapshot),
|
||||
Ordering::Equal => {
|
||||
if item.crease.range.start.is_valid(snapshot) {
|
||||
if item.crease.range().start.is_valid(snapshot) {
|
||||
return Some(&item.crease);
|
||||
} else {
|
||||
cursor.next(snapshot);
|
||||
@@ -69,7 +69,7 @@ impl CreaseSnapshot {
|
||||
&'a self,
|
||||
range: Range<MultiBufferRow>,
|
||||
snapshot: &'a MultiBufferSnapshot,
|
||||
) -> impl 'a + Iterator<Item = &'a Crease> {
|
||||
) -> impl 'a + Iterator<Item = &'a Crease<Anchor>> {
|
||||
let start = snapshot.anchor_before(Point::new(range.start.0, 0));
|
||||
let mut cursor = self.creases.cursor::<ItemSummary>(snapshot);
|
||||
cursor.seek(&start, Bias::Left, snapshot);
|
||||
@@ -77,8 +77,9 @@ impl CreaseSnapshot {
|
||||
std::iter::from_fn(move || {
|
||||
while let Some(item) = cursor.item() {
|
||||
cursor.next(snapshot);
|
||||
let crease_start = item.crease.range.start.to_point(snapshot);
|
||||
let crease_end = item.crease.range.end.to_point(snapshot);
|
||||
let crease_range = item.crease.range();
|
||||
let crease_start = crease_range.start.to_point(snapshot);
|
||||
let crease_end = crease_range.end.to_point(snapshot);
|
||||
if crease_end.row > range.end.0 {
|
||||
continue;
|
||||
}
|
||||
@@ -99,8 +100,9 @@ impl CreaseSnapshot {
|
||||
|
||||
cursor.next(snapshot);
|
||||
while let Some(item) = cursor.item() {
|
||||
let start_point = item.crease.range.start.to_point(snapshot);
|
||||
let end_point = item.crease.range.end.to_point(snapshot);
|
||||
let crease_range = item.crease.range();
|
||||
let start_point = crease_range.start.to_point(snapshot);
|
||||
let end_point = crease_range.end.to_point(snapshot);
|
||||
results.push((item.id, start_point..end_point));
|
||||
cursor.next(snapshot);
|
||||
}
|
||||
@@ -123,12 +125,22 @@ type RenderTrailerFn =
|
||||
Arc<dyn Send + Sync + Fn(MultiBufferRow, bool, &mut WindowContext) -> AnyElement>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Crease {
|
||||
pub range: Range<Anchor>,
|
||||
pub placeholder: FoldPlaceholder,
|
||||
pub render_toggle: RenderToggleFn,
|
||||
pub render_trailer: RenderTrailerFn,
|
||||
pub metadata: Option<CreaseMetadata>,
|
||||
pub enum Crease<T> {
|
||||
Inline {
|
||||
range: Range<T>,
|
||||
placeholder: FoldPlaceholder,
|
||||
render_toggle: Option<RenderToggleFn>,
|
||||
render_trailer: Option<RenderTrailerFn>,
|
||||
metadata: Option<CreaseMetadata>,
|
||||
},
|
||||
Block {
|
||||
range: Range<T>,
|
||||
block_height: u32,
|
||||
block_style: BlockStyle,
|
||||
render_block: RenderBlock,
|
||||
block_priority: usize,
|
||||
render_toggle: Option<RenderToggleFn>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Metadata about a [`Crease`], that is used for serialization.
|
||||
@@ -138,9 +150,30 @@ pub struct CreaseMetadata {
|
||||
pub label: SharedString,
|
||||
}
|
||||
|
||||
impl Crease {
|
||||
pub fn new<RenderToggle, ToggleElement, RenderTrailer, TrailerElement>(
|
||||
range: Range<Anchor>,
|
||||
impl<T> Crease<T> {
|
||||
pub fn simple(range: Range<T>, placeholder: FoldPlaceholder) -> Self {
|
||||
Crease::Inline {
|
||||
range,
|
||||
placeholder,
|
||||
render_toggle: None,
|
||||
render_trailer: None,
|
||||
metadata: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block(range: Range<T>, height: u32, style: BlockStyle, render: RenderBlock) -> Self {
|
||||
Self::Block {
|
||||
range,
|
||||
block_height: height,
|
||||
block_style: style,
|
||||
render_block: render,
|
||||
block_priority: 0,
|
||||
render_toggle: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inline<RenderToggle, ToggleElement, RenderTrailer, TrailerElement>(
|
||||
range: Range<T>,
|
||||
placeholder: FoldPlaceholder,
|
||||
render_toggle: RenderToggle,
|
||||
render_trailer: RenderTrailer,
|
||||
@@ -164,37 +197,76 @@ impl Crease {
|
||||
+ 'static,
|
||||
TrailerElement: IntoElement,
|
||||
{
|
||||
Crease {
|
||||
Crease::Inline {
|
||||
range,
|
||||
placeholder,
|
||||
render_toggle: Arc::new(move |row, folded, toggle, cx| {
|
||||
render_toggle: Some(Arc::new(move |row, folded, toggle, cx| {
|
||||
render_toggle(row, folded, toggle, cx).into_any_element()
|
||||
}),
|
||||
render_trailer: Arc::new(move |row, folded, cx| {
|
||||
})),
|
||||
render_trailer: Some(Arc::new(move |row, folded, cx| {
|
||||
render_trailer(row, folded, cx).into_any_element()
|
||||
}),
|
||||
})),
|
||||
metadata: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_metadata(mut self, metadata: CreaseMetadata) -> Self {
|
||||
self.metadata = Some(metadata);
|
||||
self
|
||||
pub fn with_metadata(self, metadata: CreaseMetadata) -> Self {
|
||||
match self {
|
||||
Crease::Inline {
|
||||
range,
|
||||
placeholder,
|
||||
render_toggle,
|
||||
render_trailer,
|
||||
..
|
||||
} => Crease::Inline {
|
||||
range,
|
||||
placeholder,
|
||||
render_toggle,
|
||||
render_trailer,
|
||||
metadata: Some(metadata),
|
||||
},
|
||||
Crease::Block { .. } => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn range(&self) -> &Range<T> {
|
||||
match self {
|
||||
Crease::Inline { range, .. } => range,
|
||||
Crease::Block { range, .. } => range,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Crease {
|
||||
impl<T> std::fmt::Debug for Crease<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Crease")
|
||||
.field("range", &self.range)
|
||||
.finish()
|
||||
match self {
|
||||
Crease::Inline {
|
||||
range, metadata, ..
|
||||
} => f
|
||||
.debug_struct("Crease::Inline")
|
||||
.field("range", range)
|
||||
.field("metadata", metadata)
|
||||
.finish_non_exhaustive(),
|
||||
Crease::Block {
|
||||
range,
|
||||
block_height,
|
||||
..
|
||||
} => f
|
||||
.debug_struct("Crease::Block")
|
||||
.field("range", range)
|
||||
.field("height", block_height)
|
||||
.finish_non_exhaustive(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct CreaseItem {
|
||||
id: CreaseId,
|
||||
crease: Crease,
|
||||
crease: Crease<Anchor>,
|
||||
}
|
||||
|
||||
impl CreaseMap {
|
||||
@@ -204,7 +276,7 @@ impl CreaseMap {
|
||||
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
creases: impl IntoIterator<Item = Crease>,
|
||||
creases: impl IntoIterator<Item = Crease<Anchor>>,
|
||||
snapshot: &MultiBufferSnapshot,
|
||||
) -> Vec<CreaseId> {
|
||||
let mut new_ids = Vec::new();
|
||||
@@ -212,11 +284,12 @@ impl CreaseMap {
|
||||
let mut new_creases = SumTree::new(snapshot);
|
||||
let mut cursor = self.snapshot.creases.cursor::<ItemSummary>(snapshot);
|
||||
for crease in creases {
|
||||
new_creases.append(cursor.slice(&crease.range, Bias::Left, snapshot), snapshot);
|
||||
let crease_range = crease.range().clone();
|
||||
new_creases.append(cursor.slice(&crease_range, Bias::Left, snapshot), snapshot);
|
||||
|
||||
let id = self.next_id;
|
||||
self.next_id.0 += 1;
|
||||
self.id_to_range.insert(id, crease.range.clone());
|
||||
self.id_to_range.insert(id, crease_range);
|
||||
new_creases.push(CreaseItem { crease, id }, snapshot);
|
||||
new_ids.push(id);
|
||||
}
|
||||
@@ -293,7 +366,7 @@ impl sum_tree::Item for CreaseItem {
|
||||
|
||||
fn summary(&self, _cx: &MultiBufferSnapshot) -> Self::Summary {
|
||||
ItemSummary {
|
||||
range: self.crease.range.clone(),
|
||||
range: self.crease.range().clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,13 +399,13 @@ mod test {
|
||||
|
||||
// Insert creases
|
||||
let creases = [
|
||||
Crease::new(
|
||||
Crease::inline(
|
||||
snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(1, 5)),
|
||||
FoldPlaceholder::test(),
|
||||
|_row, _folded, _toggle, _cx| div(),
|
||||
|_row, _folded, _cx| div(),
|
||||
),
|
||||
Crease::new(
|
||||
Crease::inline(
|
||||
snapshot.anchor_before(Point::new(3, 0))..snapshot.anchor_after(Point::new(3, 5)),
|
||||
FoldPlaceholder::test(),
|
||||
|_row, _folded, _toggle, _cx| div(),
|
||||
@@ -372,19 +445,19 @@ mod test {
|
||||
let mut crease_map = CreaseMap::new(&snapshot);
|
||||
|
||||
let creases = [
|
||||
Crease::new(
|
||||
Crease::inline(
|
||||
snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(1, 5)),
|
||||
FoldPlaceholder::test(),
|
||||
|_row, _folded, _toggle, _cx| div(),
|
||||
|_row, _folded, _cx| div(),
|
||||
),
|
||||
Crease::new(
|
||||
Crease::inline(
|
||||
snapshot.anchor_before(Point::new(3, 0))..snapshot.anchor_after(Point::new(3, 5)),
|
||||
FoldPlaceholder::test(),
|
||||
|_row, _folded, _toggle, _cx| div(),
|
||||
|_row, _folded, _cx| div(),
|
||||
),
|
||||
Crease::new(
|
||||
Crease::inline(
|
||||
snapshot.anchor_before(Point::new(5, 0))..snapshot.anchor_after(Point::new(5, 5)),
|
||||
FoldPlaceholder::test(),
|
||||
|_row, _folded, _toggle, _cx| div(),
|
||||
@@ -402,12 +475,12 @@ mod test {
|
||||
let range = MultiBufferRow(2)..MultiBufferRow(5);
|
||||
let creases: Vec<_> = crease_snapshot.creases_in_range(range, &snapshot).collect();
|
||||
assert_eq!(creases.len(), 1);
|
||||
assert_eq!(creases[0].range.start.to_point(&snapshot).row, 3);
|
||||
assert_eq!(creases[0].range().start.to_point(&snapshot).row, 3);
|
||||
|
||||
let range = MultiBufferRow(0)..MultiBufferRow(2);
|
||||
let creases: Vec<_> = crease_snapshot.creases_in_range(range, &snapshot).collect();
|
||||
assert_eq!(creases.len(), 1);
|
||||
assert_eq!(creases[0].range.start.to_point(&snapshot).row, 1);
|
||||
assert_eq!(creases[0].range().start.to_point(&snapshot).row, 1);
|
||||
|
||||
let range = MultiBufferRow(6)..MultiBufferRow(7);
|
||||
let creases: Vec<_> = crease_snapshot.creases_in_range(range, &snapshot).collect();
|
||||
|
||||
Reference in New Issue
Block a user