Detailed changes
@@ -111,6 +111,7 @@ use ui::{SharedString, px};
use unicode_segmentation::UnicodeSegmentation;
use ztracing::instrument;
+use std::cell::RefCell;
use std::{
any::TypeId,
borrow::Cow,
@@ -228,39 +229,34 @@ pub struct DisplayMap {
lsp_folding_crease_ids: HashMap<BufferId, Vec<CreaseId>>,
}
-// test change
-
pub(crate) struct Companion {
rhs_display_map_id: EntityId,
- rhs_folded_buffers: HashSet<BufferId>,
rhs_buffer_to_lhs_buffer: HashMap<BufferId, BufferId>,
lhs_buffer_to_rhs_buffer: HashMap<BufferId, BufferId>,
rhs_excerpt_to_lhs_excerpt: HashMap<ExcerptId, ExcerptId>,
lhs_excerpt_to_rhs_excerpt: HashMap<ExcerptId, ExcerptId>,
rhs_rows_to_lhs_rows: ConvertMultiBufferRows,
lhs_rows_to_rhs_rows: ConvertMultiBufferRows,
- rhs_custom_blocks_to_lhs_custom_blocks: HashMap<CustomBlockId, CustomBlockId>,
- lhs_custom_blocks_to_rhs_custom_blocks: HashMap<CustomBlockId, CustomBlockId>,
+ rhs_custom_block_to_balancing_block: RefCell<HashMap<CustomBlockId, CustomBlockId>>,
+ lhs_custom_block_to_balancing_block: RefCell<HashMap<CustomBlockId, CustomBlockId>>,
}
impl Companion {
pub(crate) fn new(
rhs_display_map_id: EntityId,
- rhs_folded_buffers: HashSet<BufferId>,
rhs_rows_to_lhs_rows: ConvertMultiBufferRows,
lhs_rows_to_rhs_rows: ConvertMultiBufferRows,
) -> Self {
Self {
rhs_display_map_id,
- rhs_folded_buffers,
rhs_buffer_to_lhs_buffer: Default::default(),
lhs_buffer_to_rhs_buffer: Default::default(),
rhs_excerpt_to_lhs_excerpt: Default::default(),
lhs_excerpt_to_rhs_excerpt: Default::default(),
rhs_rows_to_lhs_rows,
lhs_rows_to_rhs_rows,
- rhs_custom_blocks_to_lhs_custom_blocks: Default::default(),
- lhs_custom_blocks_to_rhs_custom_blocks: Default::default(),
+ rhs_custom_block_to_balancing_block: Default::default(),
+ lhs_custom_block_to_balancing_block: Default::default(),
}
}
@@ -268,37 +264,17 @@ impl Companion {
self.rhs_display_map_id == display_map_id
}
- pub(crate) fn companion_custom_block_to_custom_block(
+ pub(crate) fn custom_block_to_balancing_block(
&self,
display_map_id: EntityId,
- ) -> &HashMap<CustomBlockId, CustomBlockId> {
+ ) -> &RefCell<HashMap<CustomBlockId, CustomBlockId>> {
if self.is_rhs(display_map_id) {
- &self.lhs_custom_blocks_to_rhs_custom_blocks
+ &self.rhs_custom_block_to_balancing_block
} else {
- &self.rhs_custom_blocks_to_lhs_custom_blocks
+ &self.lhs_custom_block_to_balancing_block
}
}
- pub(crate) fn add_custom_block_mapping(
- &mut self,
- lhs_id: CustomBlockId,
- rhs_id: CustomBlockId,
- ) {
- self.lhs_custom_blocks_to_rhs_custom_blocks
- .insert(lhs_id, rhs_id);
- self.rhs_custom_blocks_to_lhs_custom_blocks
- .insert(rhs_id, lhs_id);
- }
-
- pub(crate) fn remove_custom_block_mapping(
- &mut self,
- lhs_id: &CustomBlockId,
- rhs_id: &CustomBlockId,
- ) {
- self.lhs_custom_blocks_to_rhs_custom_blocks.remove(lhs_id);
- self.rhs_custom_blocks_to_lhs_custom_blocks.remove(rhs_id);
- }
-
pub(crate) fn convert_rows_to_companion(
&self,
display_map_id: EntityId,
@@ -342,6 +318,34 @@ impl Companion {
excerpt.patch.edit_for_old_position(point).new
}
+ pub(crate) fn convert_point_to_companion(
+ &self,
+ display_map_id: EntityId,
+ our_snapshot: &MultiBufferSnapshot,
+ companion_snapshot: &MultiBufferSnapshot,
+ point: MultiBufferPoint,
+ ) -> Range<MultiBufferPoint> {
+ let (excerpt_map, convert_fn) = if self.is_rhs(display_map_id) {
+ (&self.rhs_excerpt_to_lhs_excerpt, self.rhs_rows_to_lhs_rows)
+ } else {
+ (&self.lhs_excerpt_to_rhs_excerpt, self.lhs_rows_to_rhs_rows)
+ };
+
+ let excerpt = convert_fn(
+ excerpt_map,
+ companion_snapshot,
+ our_snapshot,
+ (Bound::Included(point), Bound::Included(point)),
+ )
+ .into_iter()
+ .next();
+
+ let Some(excerpt) = excerpt else {
+ return Point::zero()..companion_snapshot.max_point();
+ };
+ excerpt.patch.edit_for_old_position(point).new
+ }
+
pub(crate) fn companion_excerpt_to_excerpt(
&self,
display_map_id: EntityId,
@@ -468,59 +472,41 @@ impl DisplayMap {
}
}
+ // TODO(split-diff) figure out how to free the LHS from having to build a block map before this is called
pub(crate) fn set_companion(
&mut self,
- companion: Option<(WeakEntity<DisplayMap>, Entity<Companion>)>,
+ companion: Option<(Entity<DisplayMap>, Entity<Companion>)>,
cx: &mut Context<Self>,
) {
+ let this = cx.weak_entity();
+ // Reverting to no companion, recompute the block map to clear spacers
+ // and balancing blocks.
let Some((companion_display_map, companion)) = companion else {
- self.companion = None;
+ let Some((_, companion)) = self.companion.take() else {
+ return;
+ };
let (snapshot, edits) = self.sync_through_wrap(cx);
let edits = edits.compose([text::Edit {
old: WrapRow(0)..snapshot.max_point().row(),
new: WrapRow(0)..snapshot.max_point().row(),
}]);
- self.block_map.read(snapshot, edits, None);
+ self.block_map.write(snapshot, edits, None).remove(
+ companion
+ .read(cx)
+ .lhs_custom_block_to_balancing_block
+ .borrow()
+ .values()
+ .copied()
+ .collect(),
+ );
return;
};
-
- // Second call to set_companion doesn't need to do anything
- if companion_display_map
- .update(cx, |companion_dm, _| companion_dm.companion.is_none())
- .unwrap_or(true)
- {
- self.companion = Some((companion_display_map, companion));
- return;
- }
-
- let rhs_display_map_id = companion.read(cx).rhs_display_map_id;
- if self.entity_id != rhs_display_map_id {
- let buffer_mapping = companion
- .read(cx)
- .buffer_to_companion_buffer(rhs_display_map_id);
- self.block_map.folded_buffers = companion
- .read(cx)
- .rhs_folded_buffers
- .iter()
- .filter_map(|id| buffer_mapping.get(id).copied())
- .collect();
- }
+ assert_eq!(self.entity_id, companion.read(cx).rhs_display_map_id);
let snapshot = self.unfold_intersecting([Anchor::min()..Anchor::max()], true, cx);
- self.companion = Some((companion_display_map.clone(), companion));
-
- let companion_wrap_data = companion_display_map
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok();
- let companion = self.companion.as_ref().map(|(_, c)| c.read(cx));
- let companion_view =
- companion_wrap_data
- .as_ref()
- .zip(companion)
- .map(|((snapshot, edits), companion)| {
- CompanionView::new(self.entity_id, snapshot, edits, companion)
- });
+ let (companion_wrap_snapshot, companion_wrap_edits) =
+ companion_display_map.update(cx, |dm, cx| dm.sync_through_wrap(cx));
let edits = Patch::new(
[text::Edit {
@@ -530,58 +516,64 @@ impl DisplayMap {
.into_iter()
.collect(),
);
- self.block_map
- .read(snapshot.clone(), edits.clone(), companion_view);
-
- if let Some((companion_dm, _)) = &self.companion {
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- let their_companion_ref = dm.companion.as_ref().map(|(_, c)| c);
- dm.block_map.read(
- companion_snapshot,
- companion_edits,
- their_companion_ref.map(|c| {
- CompanionView::new(dm.entity_id, &snapshot, &edits, c.read(cx))
- }),
- );
- }
- });
- }
- }
+ let reader = self.block_map.read(
+ snapshot.clone(),
+ edits.clone(),
+ Some(CompanionView::new(
+ self.entity_id,
+ &companion_wrap_snapshot,
+ &companion_wrap_edits,
+ companion.read(cx),
+ )),
+ );
- pub(crate) fn sync_custom_blocks_into_companion(&mut self, cx: &mut Context<Self>) {
- if self.companion.is_none() {
- return;
- }
+ companion_display_map.update(cx, |companion_display_map, cx| {
+ for my_buffer in self.folded_buffers() {
+ let their_buffer = companion
+ .read(cx)
+ .rhs_buffer_to_lhs_buffer
+ .get(my_buffer)
+ .unwrap();
+ companion_display_map
+ .block_map
+ .folded_buffers
+ .insert(*their_buffer);
+ }
+ for block in reader.blocks {
+ let Some(their_block) = block_map::balancing_block(
+ &block.properties(),
+ snapshot.buffer(),
+ companion_wrap_snapshot.buffer(),
+ self.entity_id,
+ companion.read(cx),
+ ) else {
+ continue;
+ };
+ let their_id = companion_display_map
+ .block_map
+ .insert_block_raw(their_block, companion_wrap_snapshot.buffer());
+ companion.update(cx, |companion, _cx| {
+ companion
+ .custom_block_to_balancing_block(self.entity_id)
+ .borrow_mut()
+ .insert(block.id, their_id);
+ });
+ }
+ companion_display_map.block_map.read(
+ companion_wrap_snapshot,
+ companion_wrap_edits,
+ Some(CompanionView::new(
+ companion_display_map.entity_id,
+ &snapshot,
+ &edits,
+ companion.read(cx),
+ )),
+ );
+ companion_display_map.companion = Some((this, companion.clone()));
+ });
- let (self_wrap_snapshot, _) = self.sync_through_wrap(cx);
- let (companion_dm, companion) = self
- .companion
- .as_ref()
- .expect("companion must exist at this point");
-
- companion
- .update(cx, |companion, cx| {
- companion_dm.update(cx, |dm, cx| {
- let (companion_snapshot, _) = dm.sync_through_wrap(cx);
- // Sync existing custom blocks to the companion
- for block in self
- .block_map
- .read(self_wrap_snapshot.clone(), Patch::default(), None)
- .blocks
- {
- dm.block_map.insert_custom_block_into_companion(
- self.entity_id,
- &companion_snapshot,
- block,
- self_wrap_snapshot.buffer_snapshot(),
- companion,
- )
- }
- })
- })
- .ok();
+ self.companion = Some((companion_display_map.downgrade(), companion));
}
pub(crate) fn companion(&self) -> Option<&Entity<Companion>> {
@@ -612,6 +604,40 @@ impl DisplayMap {
.update(cx, |map, cx| map.sync(snapshot, edits, cx))
}
+ fn with_synced_companion_mut<R>(
+ display_map_id: EntityId,
+ companion: &Option<(WeakEntity<DisplayMap>, Entity<Companion>)>,
+ cx: &mut App,
+ callback: impl FnOnce(Option<CompanionViewMut<'_>>, &mut App) -> R,
+ ) -> R {
+ let Some((companion_display_map, companion)) = companion else {
+ return callback(None, cx);
+ };
+ let Some(companion_display_map) = companion_display_map.upgrade() else {
+ return callback(None, cx);
+ };
+ companion_display_map.update(cx, |companion_display_map, cx| {
+ let (companion_wrap_snapshot, companion_wrap_edits) =
+ companion_display_map.sync_through_wrap(cx);
+ companion_display_map
+ .buffer
+ .update(cx, |companion_multibuffer, cx| {
+ companion.update(cx, |companion, cx| {
+ let companion_view = CompanionViewMut::new(
+ display_map_id,
+ companion_display_map.entity_id,
+ &companion_wrap_snapshot,
+ &companion_wrap_edits,
+ companion_multibuffer,
+ companion,
+ &mut companion_display_map.block_map,
+ );
+ callback(Some(companion_view), cx)
+ })
+ })
+ })
+ }
+
#[instrument(skip_all)]
pub fn snapshot(&mut self, cx: &mut Context<Self>) -> DisplaySnapshot {
let (self_wrap_snapshot, self_wrap_edits) = self.sync_through_wrap(cx);
@@ -729,29 +755,13 @@ impl DisplayMap {
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
- let companion_wrap_data = self.companion.as_ref().and_then(|(companion_dm, _)| {
- companion_dm
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok()
- });
-
let (snapshot, edits) = self.inlay_map.sync(buffer_snapshot.clone(), edits);
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
- let (snapshot, edits) = self
+ let (_snapshot, _edits) = self
.wrap_map
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
- {
- let companion_ref = self.companion.as_ref().map(|(_, c)| c.read(cx));
- let companion_view = companion_wrap_data.as_ref().zip(companion_ref).map(
- |((snapshot, edits), companion)| {
- CompanionView::new(self.entity_id, snapshot, edits, companion)
- },
- );
- self.block_map.read(snapshot, edits, companion_view);
- }
-
let inline = creases.iter().filter_map(|crease| {
if let Crease::Inline {
range, placeholder, ..
@@ -765,13 +775,10 @@ impl DisplayMap {
let (snapshot, edits) = fold_map.fold(inline);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
- let (self_new_wrap_snapshot, self_new_wrap_edits) = self
+ let (snapshot, edits) = self
.wrap_map
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
- let (self_wrap_snapshot, self_wrap_edits) =
- (self_new_wrap_snapshot.clone(), self_new_wrap_edits.clone());
-
let blocks = creases
.into_iter()
.filter_map(|crease| {
@@ -807,53 +814,7 @@ impl DisplayMap {
}
});
- if let Some((companion_dm, companion)) = self.companion.as_ref()
- && let Some((snapshot, edits)) = companion_wrap_data.as_ref()
- {
- companion_dm
- .update(cx, |dm, cx| {
- companion.update(cx, |companion, _| {
- self.block_map
- .write(
- self_new_wrap_snapshot,
- self_new_wrap_edits,
- Some(CompanionViewMut::new(
- self.entity_id,
- snapshot,
- edits,
- companion,
- &mut dm.block_map,
- )),
- )
- .insert(blocks);
- })
- })
- .ok();
- } else {
- self.block_map
- .write(self_new_wrap_snapshot, self_new_wrap_edits, None)
- .insert(blocks);
- };
-
- if let Some((companion_dm, _)) = &self.companion {
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- let their_companion_ref = dm.companion.as_ref().map(|(_, c)| c.read(cx));
- dm.block_map.read(
- companion_snapshot,
- companion_edits,
- their_companion_ref.map(|c| {
- CompanionView::new(
- dm.entity_id,
- &self_wrap_snapshot,
- &self_wrap_edits,
- c,
- )
- }),
- );
- }
- });
- }
+ self.block_map.write(snapshot, edits, None).insert(blocks);
}
/// Removes any folds with the given ranges.
@@ -868,28 +829,13 @@ impl DisplayMap {
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
- let companion_wrap_data = self.companion.as_ref().and_then(|(companion_dm, _)| {
- companion_dm
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok()
- });
-
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
let (snapshot, edits) = self
.wrap_map
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
-
- {
- let companion_ref = self.companion.as_ref().map(|(_, c)| c.read(cx));
- let companion_view = companion_wrap_data.as_ref().zip(companion_ref).map(
- |((snapshot, edits), companion)| {
- CompanionView::new(self.entity_id, snapshot, edits, companion)
- },
- );
- self.block_map.read(snapshot, edits, companion_view);
- }
+ self.block_map.read(snapshot, edits, None);
let (snapshot, edits) = fold_map.remove_folds(ranges, type_id);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
@@ -897,53 +843,8 @@ impl DisplayMap {
.wrap_map
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
- let (self_wrap_snapshot, self_wrap_edits) =
- (self_new_wrap_snapshot.clone(), self_new_wrap_edits.clone());
-
- if let Some((companion_dm, companion)) = self.companion.as_ref()
- && let Some((snapshot, edits)) = companion_wrap_data.as_ref()
- {
- companion_dm
- .update(cx, |dm, cx| {
- companion.update(cx, |companion, _| {
- self.block_map.write(
- self_new_wrap_snapshot,
- self_new_wrap_edits,
- Some(CompanionViewMut::new(
- self.entity_id,
- snapshot,
- edits,
- companion,
- &mut dm.block_map,
- )),
- );
- })
- })
- .ok();
- } else {
- self.block_map
- .write(self_new_wrap_snapshot, self_new_wrap_edits, None);
- }
-
- if let Some((companion_dm, _)) = &self.companion {
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- let their_companion_ref = dm.companion.as_ref().map(|(_, c)| c.read(cx));
- dm.block_map.read(
- companion_snapshot,
- companion_edits,
- their_companion_ref.map(|c| {
- CompanionView::new(
- dm.entity_id,
- &self_wrap_snapshot,
- &self_wrap_edits,
- c,
- )
- }),
- );
- }
- });
- }
+ self.block_map
+ .write(self_new_wrap_snapshot, self_new_wrap_edits, None);
}
/// Removes any folds whose ranges intersect any of the given ranges.
@@ -962,28 +863,13 @@ impl DisplayMap {
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
- let companion_wrap_data = self.companion.as_ref().and_then(|(companion_dm, _)| {
- companion_dm
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok()
- });
-
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
let (snapshot, edits) = self
.wrap_map
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
-
- {
- let companion_ref = self.companion.as_ref().map(|(_, c)| c.read(cx));
- let companion_view = companion_wrap_data.as_ref().zip(companion_ref).map(
- |((snapshot, edits), companion)| {
- CompanionView::new(self.entity_id, snapshot, edits, companion)
- },
- );
- self.block_map.read(snapshot, edits, companion_view);
- }
+ self.block_map.read(snapshot, edits, None);
let (snapshot, edits) =
fold_map.unfold_intersecting(offset_ranges.iter().cloned(), inclusive);
@@ -992,56 +878,9 @@ impl DisplayMap {
.wrap_map
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
- let (self_wrap_snapshot, self_wrap_edits) =
- (self_new_wrap_snapshot.clone(), self_new_wrap_edits.clone());
-
- if let Some((companion_dm, companion)) = self.companion.as_ref()
- && let Some((snapshot, edits)) = companion_wrap_data.as_ref()
- {
- companion_dm
- .update(cx, |dm, cx| {
- companion.update(cx, |companion, _| {
- self.block_map
- .write(
- self_new_wrap_snapshot.clone(),
- self_new_wrap_edits,
- Some(CompanionViewMut::new(
- self.entity_id,
- snapshot,
- edits,
- companion,
- &mut dm.block_map,
- )),
- )
- .remove_intersecting_replace_blocks(offset_ranges, inclusive);
- })
- })
- .ok();
- } else {
- self.block_map
- .write(self_new_wrap_snapshot.clone(), self_new_wrap_edits, None)
- .remove_intersecting_replace_blocks(offset_ranges, inclusive);
- }
-
- if let Some((companion_dm, _)) = &self.companion {
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- let their_companion_ref = dm.companion.as_ref().map(|(_, c)| c.read(cx));
- dm.block_map.read(
- companion_snapshot,
- companion_edits,
- their_companion_ref.map(|c| {
- CompanionView::new(
- dm.entity_id,
- &self_wrap_snapshot,
- &self_wrap_edits,
- c,
- )
- }),
- );
- }
- });
- }
+ self.block_map
+ .write(self_new_wrap_snapshot.clone(), self_new_wrap_edits, None)
+ .remove_intersecting_replace_blocks(offset_ranges, inclusive);
self_new_wrap_snapshot
}
@@ -1049,160 +888,35 @@ impl DisplayMap {
#[instrument(skip_all)]
pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
let (self_wrap_snapshot, self_wrap_edits) = self.sync_through_wrap(cx);
+ self.block_map
+ .write(self_wrap_snapshot, self_wrap_edits, None)
+ .disable_header_for_buffer(buffer_id);
+ }
- let companion_wrap_data = self.companion.as_ref().and_then(|(companion_dm, _)| {
- companion_dm
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok()
- });
-
- if let Some((companion_dm, companion)) = self.companion.as_ref()
- && let Some((snapshot, edits)) = companion_wrap_data.as_ref()
- {
- companion_dm
- .update(cx, |dm, cx| {
- companion.update(cx, |companion, _| {
- self.block_map
- .write(
- self_wrap_snapshot.clone(),
- self_wrap_edits.clone(),
- Some(CompanionViewMut::new(
- self.entity_id,
- snapshot,
- edits,
- companion,
- &mut dm.block_map,
- )),
- )
- .disable_header_for_buffer(buffer_id);
- })
- })
- .ok();
- } else {
- self.block_map
- .write(self_wrap_snapshot.clone(), self_wrap_edits.clone(), None)
- .disable_header_for_buffer(buffer_id);
- }
-
- if let Some((companion_dm, _)) = &self.companion {
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- let their_companion_ref = dm.companion.as_ref().map(|(_, c)| c.read(cx));
- dm.block_map.read(
- companion_snapshot,
- companion_edits,
- their_companion_ref.map(|c| {
- CompanionView::new(
- dm.entity_id,
- &self_wrap_snapshot,
- &self_wrap_edits,
- c,
- )
- }),
- );
- }
- });
- }
- }
-
- #[instrument(skip_all)]
- pub fn fold_buffers(
- &mut self,
- buffer_ids: impl IntoIterator<Item = language::BufferId>,
- cx: &mut App,
- ) {
- let buffer_ids: Vec<_> = buffer_ids.into_iter().collect();
-
- if let Some((_, companion_entity)) = &self.companion {
- companion_entity.update(cx, |companion, _| {
- if self.entity_id == companion.rhs_display_map_id {
- companion
- .rhs_folded_buffers
- .extend(buffer_ids.iter().copied());
- } else {
- let rhs_ids = buffer_ids
- .iter()
- .filter_map(|id| companion.lhs_buffer_to_rhs_buffer.get(id).copied());
- companion.rhs_folded_buffers.extend(rhs_ids);
- }
- });
- }
+ #[instrument(skip_all)]
+ pub fn fold_buffers(
+ &mut self,
+ buffer_ids: impl IntoIterator<Item = language::BufferId>,
+ cx: &mut App,
+ ) {
+ let buffer_ids: Vec<_> = buffer_ids.into_iter().collect();
let (self_wrap_snapshot, self_wrap_edits) = self.sync_through_wrap(cx);
- let companion_wrap_data = self.companion.as_ref().and_then(|(companion_dm, _)| {
- companion_dm
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok()
- });
-
- if let Some((companion_dm, companion)) = self.companion.as_ref()
- && let Some((snapshot, edits)) = companion_wrap_data.as_ref()
- {
- companion_dm
- .update(cx, |dm, cx| {
- companion.update(cx, |companion, cx| {
- self.block_map
- .write(
- self_wrap_snapshot.clone(),
- self_wrap_edits.clone(),
- Some(CompanionViewMut::new(
- self.entity_id,
- snapshot,
- edits,
- companion,
- &mut dm.block_map,
- )),
- )
- .fold_buffers(buffer_ids.iter().copied(), self.buffer.read(cx), cx);
- })
- })
- .ok();
- } else {
- self.block_map
- .write(self_wrap_snapshot.clone(), self_wrap_edits.clone(), None)
- .fold_buffers(buffer_ids.iter().copied(), self.buffer.read(cx), cx);
- }
-
- if let Some((companion_dm, companion_entity)) = &self.companion {
- let buffer_mapping = companion_entity
- .read(cx)
- .buffer_to_companion_buffer(self.entity_id);
- let their_buffer_ids: Vec<_> = buffer_ids
- .iter()
- .filter_map(|id| buffer_mapping.get(id).copied())
- .collect();
-
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- if let Some((_, their_companion)) = dm.companion.as_ref() {
- their_companion.update(cx, |their_companion, cx| {
- let mut block_map = dm.block_map.write(
- companion_snapshot,
- companion_edits,
- Some(CompanionViewMut::new(
- dm.entity_id,
- &self_wrap_snapshot,
- &self_wrap_edits,
- their_companion,
- &mut self.block_map,
- )),
- );
- if !their_buffer_ids.is_empty() {
- block_map.fold_buffers(their_buffer_ids, dm.buffer.read(cx), cx);
- }
- })
- } else {
- let mut block_map =
- dm.block_map
- .write(companion_snapshot, companion_edits, None);
- if !their_buffer_ids.is_empty() {
- block_map.fold_buffers(their_buffer_ids, dm.buffer.read(cx), cx);
- }
- }
- }
- });
- }
+ Self::with_synced_companion_mut(
+ self.entity_id,
+ &self.companion,
+ cx,
+ |companion_view, cx| {
+ self.block_map
+ .write(
+ self_wrap_snapshot.clone(),
+ self_wrap_edits.clone(),
+ companion_view,
+ )
+ .fold_buffers(buffer_ids.iter().copied(), self.buffer.read(cx), cx);
+ },
+ )
}
#[instrument(skip_all)]
@@ -1213,97 +927,22 @@ impl DisplayMap {
) {
let buffer_ids: Vec<_> = buffer_ids.into_iter().collect();
- if let Some((_, companion_entity)) = &self.companion {
- companion_entity.update(cx, |companion, _| {
- if self.entity_id == companion.rhs_display_map_id {
- for id in &buffer_ids {
- companion.rhs_folded_buffers.remove(id);
- }
- } else {
- for id in &buffer_ids {
- if let Some(rhs_id) = companion.lhs_buffer_to_rhs_buffer.get(id) {
- companion.rhs_folded_buffers.remove(rhs_id);
- }
- }
- }
- });
- }
-
let (self_wrap_snapshot, self_wrap_edits) = self.sync_through_wrap(cx);
- let companion_wrap_data = self.companion.as_ref().and_then(|(companion_dm, _)| {
- companion_dm
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok()
- });
-
- if let Some((companion_dm, companion)) = self.companion.as_ref()
- && let Some((snapshot, edits)) = companion_wrap_data.as_ref()
- {
- companion_dm
- .update(cx, |dm, cx| {
- companion.update(cx, |companion, cx| {
- self.block_map
- .write(
- self_wrap_snapshot.clone(),
- self_wrap_edits.clone(),
- Some(CompanionViewMut::new(
- self.entity_id,
- snapshot,
- edits,
- companion,
- &mut dm.block_map,
- )),
- )
- .unfold_buffers(buffer_ids.iter().copied(), self.buffer.read(cx), cx);
- })
- })
- .ok();
- } else {
- self.block_map
- .write(self_wrap_snapshot.clone(), self_wrap_edits.clone(), None)
- .unfold_buffers(buffer_ids.iter().copied(), self.buffer.read(cx), cx);
- }
-
- if let Some((companion_dm, companion_entity)) = &self.companion {
- let buffer_mapping = companion_entity
- .read(cx)
- .buffer_to_companion_buffer(self.entity_id);
- let their_buffer_ids: Vec<_> = buffer_ids
- .iter()
- .filter_map(|id| buffer_mapping.get(id).copied())
- .collect();
-
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- if let Some((_, their_companion)) = dm.companion.as_ref() {
- their_companion.update(cx, |their_companion, cx| {
- let mut block_map = dm.block_map.write(
- companion_snapshot,
- companion_edits,
- Some(CompanionViewMut::new(
- dm.entity_id,
- &self_wrap_snapshot,
- &self_wrap_edits,
- their_companion,
- &mut self.block_map,
- )),
- );
- if !their_buffer_ids.is_empty() {
- block_map.unfold_buffers(their_buffer_ids, dm.buffer.read(cx), cx);
- }
- })
- } else {
- let mut block_map =
- dm.block_map
- .write(companion_snapshot, companion_edits, None);
- if !their_buffer_ids.is_empty() {
- block_map.unfold_buffers(their_buffer_ids, dm.buffer.read(cx), cx);
- }
- }
- }
- });
- }
+ Self::with_synced_companion_mut(
+ self.entity_id,
+ &self.companion,
+ cx,
+ |companion_view, cx| {
+ self.block_map
+ .write(
+ self_wrap_snapshot.clone(),
+ self_wrap_edits.clone(),
+ companion_view,
+ )
+ .unfold_buffers(buffer_ids.iter().copied(), self.buffer.read(cx), cx);
+ },
+ )
}
#[instrument(skip_all)]
@@ -1419,122 +1058,40 @@ impl DisplayMap {
cx: &mut Context<Self>,
) -> Vec<CustomBlockId> {
let (self_wrap_snapshot, self_wrap_edits) = self.sync_through_wrap(cx);
-
- let companion_wrap_data = self.companion.as_ref().and_then(|(companion_dm, _)| {
- companion_dm
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok()
- });
-
- let result = if let Some((companion_dm, companion)) = self.companion.as_ref()
- && let Some((snapshot, edits)) = companion_wrap_data.as_ref()
- {
- companion_dm
- .update(cx, |dm, cx| {
- companion.update(cx, |companion, _| {
- self.block_map
- .write(
- self_wrap_snapshot.clone(),
- self_wrap_edits.clone(),
- Some(CompanionViewMut::new(
- self.entity_id,
- snapshot,
- edits,
- companion,
- &mut dm.block_map,
- )),
- )
- .insert(blocks)
- })
- })
- .ok()
- .expect("success inserting blocks with companion")
- } else {
- self.block_map
- .write(self_wrap_snapshot.clone(), self_wrap_edits.clone(), None)
- .insert(blocks)
- };
-
- if let Some((companion_dm, _)) = &self.companion {
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- let their_companion_ref = dm.companion.as_ref().map(|(_, c)| c.read(cx));
- dm.block_map.read(
- companion_snapshot,
- companion_edits,
- their_companion_ref.map(|c| {
- CompanionView::new(
- dm.entity_id,
- &self_wrap_snapshot,
- &self_wrap_edits,
- c,
- )
- }),
- );
- }
- });
- }
-
- result
+ Self::with_synced_companion_mut(
+ self.entity_id,
+ &self.companion,
+ cx,
+ |companion_view, _cx| {
+ self.block_map
+ .write(
+ self_wrap_snapshot.clone(),
+ self_wrap_edits.clone(),
+ companion_view,
+ )
+ .insert(blocks)
+ },
+ )
}
#[instrument(skip_all)]
pub fn resize_blocks(&mut self, heights: HashMap<CustomBlockId, u32>, cx: &mut Context<Self>) {
let (self_wrap_snapshot, self_wrap_edits) = self.sync_through_wrap(cx);
- let companion_wrap_data = self.companion.as_ref().and_then(|(companion_dm, _)| {
- companion_dm
- .update(cx, |dm, cx| dm.sync_through_wrap(cx))
- .ok()
- });
-
- if let Some((companion_dm, companion)) = self.companion.as_ref()
- && let Some((snapshot, edits)) = companion_wrap_data.as_ref()
- {
- companion_dm
- .update(cx, |dm, cx| {
- companion.update(cx, |companion, _| {
- self.block_map
- .write(
- self_wrap_snapshot.clone(),
- self_wrap_edits.clone(),
- Some(CompanionViewMut::new(
- self.entity_id,
- snapshot,
- edits,
- companion,
- &mut dm.block_map,
- )),
- )
- .resize(heights);
- })
- })
- .ok();
- } else {
- self.block_map
- .write(self_wrap_snapshot.clone(), self_wrap_edits.clone(), None)
- .resize(heights);
- }
-
- if let Some((companion_dm, _)) = &self.companion {
- let _ = companion_dm.update(cx, |dm, cx| {
- if let Some((companion_snapshot, companion_edits)) = companion_wrap_data {
- let their_companion_ref = dm.companion.as_ref().map(|(_, c)| c.read(cx));
- dm.block_map.read(
- companion_snapshot,
- companion_edits,
- their_companion_ref.map(|c| {
- CompanionView::new(
- dm.entity_id,
- &self_wrap_snapshot,
- &self_wrap_edits,
- c,
- )
- }),
- );
- }
- });
- }
+ Self::with_synced_companion_mut(
+ self.entity_id,
+ &self.companion,
+ cx,
+ |companion_view, _cx| {
+ self.block_map
+ .write(
+ self_wrap_snapshot.clone(),
+ self_wrap_edits.clone(),
+ companion_view,
+ )
+ .resize(heights);
+ },
+ )
}
#[instrument(skip_all)]
@@ -27,7 +27,7 @@ use std::{
};
use sum_tree::{Bias, ContextLessSummary, Dimensions, SumTree, TreeMap};
use text::{BufferId, Edit};
-use ui::ElementId;
+use ui::{ElementId, IntoElement};
const NEWLINES: &[u8; rope::Chunk::MASK_BITS] = &[b'\n'; _];
const BULLETS: &[u8; rope::Chunk::MASK_BITS] = &[b'*'; _];
@@ -57,20 +57,17 @@ pub struct BlockMapWriter<'a> {
companion: Option<BlockMapWriterCompanion<'a>>,
}
-struct BlockMapWriterCompanion<'a>(CompanionViewMut<'a>);
-
-impl<'a> Deref for BlockMapWriterCompanion<'a> {
- type Target = CompanionViewMut<'a>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
+/// Auxiliary data needed when modifying a BlockMap whose parent DisplayMap has a companion.
+struct BlockMapWriterCompanion<'a> {
+ display_map_id: EntityId,
+ companion_wrap_snapshot: WrapSnapshot,
+ companion: &'a Companion,
+ inverse: Option<BlockMapInverseWriter<'a>>,
}
-impl<'a> DerefMut for BlockMapWriterCompanion<'a> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
+struct BlockMapInverseWriter<'a> {
+ companion_multibuffer: &'a MultiBuffer,
+ companion_writer: Box<BlockMapWriter<'a>>,
}
#[derive(Clone)]
@@ -527,23 +524,23 @@ pub struct BlockRows<'a> {
#[derive(Clone, Copy)]
pub struct CompanionView<'a> {
- entity_id: EntityId,
- wrap_snapshot: &'a WrapSnapshot,
- wrap_edits: &'a WrapPatch,
+ display_map_id: EntityId,
+ companion_wrap_snapshot: &'a WrapSnapshot,
+ companion_wrap_edits: &'a WrapPatch,
companion: &'a Companion,
}
impl<'a> CompanionView<'a> {
pub(crate) fn new(
- entity_id: EntityId,
- wrap_snapshot: &'a WrapSnapshot,
- wrap_edits: &'a WrapPatch,
+ display_map_id: EntityId,
+ companion_wrap_snapshot: &'a WrapSnapshot,
+ companion_wrap_edits: &'a WrapPatch,
companion: &'a Companion,
) -> Self {
Self {
- entity_id,
- wrap_snapshot,
- wrap_edits,
+ display_map_id,
+ companion_wrap_snapshot,
+ companion_wrap_edits,
companion,
}
}
@@ -552,9 +549,9 @@ impl<'a> CompanionView<'a> {
impl<'a> From<CompanionViewMut<'a>> for CompanionView<'a> {
fn from(view_mut: CompanionViewMut<'a>) -> Self {
Self {
- entity_id: view_mut.entity_id,
- wrap_snapshot: view_mut.wrap_snapshot,
- wrap_edits: view_mut.wrap_edits,
+ display_map_id: view_mut.display_map_id,
+ companion_wrap_snapshot: view_mut.companion_wrap_snapshot,
+ companion_wrap_edits: view_mut.companion_wrap_edits,
companion: view_mut.companion,
}
}
@@ -563,36 +560,42 @@ impl<'a> From<CompanionViewMut<'a>> for CompanionView<'a> {
impl<'a> From<&'a CompanionViewMut<'a>> for CompanionView<'a> {
fn from(view_mut: &'a CompanionViewMut<'a>) -> Self {
Self {
- entity_id: view_mut.entity_id,
- wrap_snapshot: view_mut.wrap_snapshot,
- wrap_edits: view_mut.wrap_edits,
+ display_map_id: view_mut.display_map_id,
+ companion_wrap_snapshot: view_mut.companion_wrap_snapshot,
+ companion_wrap_edits: view_mut.companion_wrap_edits,
companion: view_mut.companion,
}
}
}
pub struct CompanionViewMut<'a> {
- entity_id: EntityId,
- wrap_snapshot: &'a WrapSnapshot,
- wrap_edits: &'a WrapPatch,
- companion: &'a mut Companion,
- block_map: &'a mut BlockMap,
+ display_map_id: EntityId,
+ companion_display_map_id: EntityId,
+ companion_wrap_snapshot: &'a WrapSnapshot,
+ companion_wrap_edits: &'a WrapPatch,
+ companion_multibuffer: &'a MultiBuffer,
+ companion_block_map: &'a mut BlockMap,
+ companion: &'a Companion,
}
impl<'a> CompanionViewMut<'a> {
pub(crate) fn new(
- entity_id: EntityId,
- wrap_snapshot: &'a WrapSnapshot,
- wrap_edits: &'a WrapPatch,
- companion: &'a mut Companion,
- block_map: &'a mut BlockMap,
+ display_map_id: EntityId,
+ companion_display_map_id: EntityId,
+ companion_wrap_snapshot: &'a WrapSnapshot,
+ companion_wrap_edits: &'a WrapPatch,
+ companion_multibuffer: &'a MultiBuffer,
+ companion: &'a Companion,
+ companion_block_map: &'a mut BlockMap,
) -> Self {
Self {
- entity_id,
- wrap_snapshot,
- wrap_edits,
+ display_map_id,
+ companion_display_map_id,
+ companion_wrap_snapshot,
+ companion_wrap_edits,
+ companion_multibuffer,
companion,
- block_map,
+ companion_block_map,
}
}
}
@@ -659,16 +662,76 @@ impl BlockMap {
) -> BlockMapWriter<'a> {
self.sync(
&wrap_snapshot,
- edits,
+ edits.clone(),
companion_view.as_ref().map(CompanionView::from),
);
- *self.wrap_snapshot.borrow_mut() = wrap_snapshot;
+ *self.wrap_snapshot.borrow_mut() = wrap_snapshot.clone();
+ let companion = if let Some(companion_view) = companion_view {
+ companion_view.companion_block_map.sync(
+ companion_view.companion_wrap_snapshot,
+ companion_view.companion_wrap_edits.clone(),
+ Some(CompanionView::new(
+ companion_view.companion_display_map_id,
+ &wrap_snapshot,
+ &edits,
+ companion_view.companion,
+ )),
+ );
+ *companion_view
+ .companion_block_map
+ .wrap_snapshot
+ .borrow_mut() = companion_view.companion_wrap_snapshot.clone();
+ Some(BlockMapWriterCompanion {
+ display_map_id: companion_view.display_map_id,
+ companion_wrap_snapshot: companion_view.companion_wrap_snapshot.clone(),
+ companion: companion_view.companion,
+ inverse: Some(BlockMapInverseWriter {
+ companion_multibuffer: companion_view.companion_multibuffer,
+ companion_writer: Box::new(BlockMapWriter {
+ block_map: companion_view.companion_block_map,
+ companion: Some(BlockMapWriterCompanion {
+ display_map_id: companion_view.companion_display_map_id,
+ companion_wrap_snapshot: wrap_snapshot,
+ companion: companion_view.companion,
+ inverse: None,
+ }),
+ }),
+ }),
+ })
+ } else {
+ None
+ };
BlockMapWriter {
block_map: self,
- companion: companion_view.map(BlockMapWriterCompanion),
+ companion,
}
}
+ pub(crate) fn insert_block_raw(
+ &mut self,
+ block: BlockProperties<Anchor>,
+ buffer: &MultiBufferSnapshot,
+ ) -> CustomBlockId {
+ let id = CustomBlockId(self.next_block_id.fetch_add(1, SeqCst));
+ let block_ix = match self
+ .custom_blocks
+ .binary_search_by(|probe| probe.placement.cmp(&block.placement, &buffer))
+ {
+ Ok(ix) | Err(ix) => ix,
+ };
+ let new_block = Arc::new(CustomBlock {
+ id,
+ placement: block.placement.clone(),
+ height: block.height,
+ style: block.style,
+ render: Arc::new(Mutex::new(block.render.clone())),
+ priority: block.priority,
+ });
+ self.custom_blocks.insert(block_ix, new_block.clone());
+ self.custom_blocks_by_id.insert(id, new_block);
+ id
+ }
+
#[ztracing::instrument(skip_all, fields(edits = ?edits))]
fn sync(
&self,
@@ -697,10 +760,10 @@ impl BlockMap {
// Pull in companion edits to ensure we recompute spacers in ranges that have changed in the companion.
if let Some(CompanionView {
- wrap_snapshot: companion_new_snapshot,
- wrap_edits: companion_edits,
+ companion_wrap_snapshot: companion_new_snapshot,
+ companion_wrap_edits: companion_edits,
companion,
- entity_id: display_map_id,
+ display_map_id,
..
}) = companion_view
{
@@ -962,9 +1025,9 @@ impl BlockMap {
));
if let Some(CompanionView {
- wrap_snapshot: companion_snapshot,
+ companion_wrap_snapshot: companion_snapshot,
companion,
- entity_id: display_map_id,
+ display_map_id,
..
}) = companion_view
{
@@ -1469,55 +1532,6 @@ impl BlockMap {
_ => false,
});
}
-
- pub(crate) fn insert_custom_block_into_companion(
- &mut self,
- entity_id: EntityId,
- snapshot: &WrapSnapshot,
- block: &CustomBlock,
- companion_snapshot: &MultiBufferSnapshot,
- companion: &mut Companion,
- ) {
- let their_anchor = block.placement.start();
- let their_point = their_anchor.to_point(companion_snapshot);
- let my_patches = companion.convert_rows_to_companion(
- entity_id,
- snapshot.buffer_snapshot(),
- companion_snapshot,
- (Bound::Included(their_point), Bound::Included(their_point)),
- );
- let my_excerpt = my_patches
- .first()
- .expect("at least one companion excerpt exists");
- let my_range = my_excerpt.patch.edit_for_old_position(their_point).new;
- let my_point = my_range.start;
- let anchor = snapshot.buffer_snapshot().anchor_before(my_point);
- let height = block.height.unwrap_or(1);
- let new_block = BlockProperties {
- placement: BlockPlacement::Above(anchor),
- height: Some(height),
- style: BlockStyle::Sticky,
- render: Arc::new(move |cx| {
- crate::EditorElement::render_spacer_block(
- cx.block_id,
- cx.height,
- cx.line_height,
- cx.window,
- cx.app,
- )
- }),
- priority: 0,
- };
- log::debug!("Inserting matching companion custom block: {block:#?} => {new_block:#?}");
- let new_block_id = self
- .write(snapshot.clone(), Patch::default(), None)
- .insert([new_block])[0];
- if companion.is_rhs(entity_id) {
- companion.add_custom_block_mapping(block.id, new_block_id);
- } else {
- companion.add_custom_block_mapping(new_block_id, block.id);
- }
- }
}
#[ztracing::instrument(skip(tree, wrap_snapshot))]
@@ -1629,6 +1643,63 @@ impl BlockMapReader<'_> {
}
}
+pub(crate) fn balancing_block(
+ my_block: &BlockProperties<Anchor>,
+ my_snapshot: &MultiBufferSnapshot,
+ their_snapshot: &MultiBufferSnapshot,
+ my_display_map_id: EntityId,
+ companion: &Companion,
+) -> Option<BlockProperties<Anchor>> {
+ let my_anchor = my_block.placement.start();
+ let my_point = my_anchor.to_point(&my_snapshot);
+ let their_range = companion.convert_point_to_companion(
+ my_display_map_id,
+ my_snapshot,
+ their_snapshot,
+ my_point,
+ );
+ let their_anchor = their_snapshot.anchor_at(their_range.start, my_anchor.bias());
+ let their_placement = match my_block.placement {
+ BlockPlacement::Above(_) => BlockPlacement::Above(their_anchor),
+ BlockPlacement::Below(_) => {
+ if their_range.is_empty() {
+ BlockPlacement::Above(their_anchor)
+ } else {
+ BlockPlacement::Below(their_anchor)
+ }
+ }
+ // Not supported for balancing
+ BlockPlacement::Near(_) | BlockPlacement::Replace(_) => return None,
+ };
+ Some(BlockProperties {
+ placement: their_placement,
+ height: my_block.height,
+ style: BlockStyle::Sticky,
+ render: Arc::new(move |cx| {
+ crate::EditorElement::render_spacer_block(
+ cx.block_id,
+ cx.height,
+ cx.line_height,
+ cx.window,
+ cx.app,
+ )
+ }),
+ priority: my_block.priority,
+ })
+}
+
+impl BlockMapWriterCompanion<'_> {
+ fn companion_view(&self) -> CompanionView<'_> {
+ static EMPTY_PATCH: Patch<WrapRow> = Patch::empty();
+ CompanionView {
+ display_map_id: self.display_map_id,
+ companion_wrap_snapshot: &self.companion_wrap_snapshot,
+ companion_wrap_edits: &EMPTY_PATCH,
+ companion: self.companion,
+ }
+ }
+}
+
impl BlockMapWriter<'_> {
#[ztracing::instrument(skip_all)]
pub fn insert(
@@ -1638,20 +1709,21 @@ impl BlockMapWriter<'_> {
let blocks = blocks.into_iter();
let mut ids = Vec::with_capacity(blocks.size_hint().1.unwrap_or(0));
let mut edits = Patch::default();
- let wrap_snapshot = &*self.block_map.wrap_snapshot.borrow();
+ let wrap_snapshot = self.block_map.wrap_snapshot.borrow().clone();
let buffer = wrap_snapshot.buffer_snapshot();
let mut previous_wrap_row_range: Option<Range<WrapRow>> = None;
+ let mut companion_blocks = Vec::new();
for block in blocks {
if let BlockPlacement::Replace(_) = &block.placement {
debug_assert!(block.height.unwrap() > 0);
}
- let id = CustomBlockId(self.block_map.next_block_id.fetch_add(1, SeqCst));
+ let id = self.block_map.insert_block_raw(block.clone(), &buffer);
ids.push(id);
- let start = block.placement.start().to_point(buffer);
- let end = block.placement.end().to_point(buffer);
+ let start = block.placement.start().to_point(&buffer);
+ let end = block.placement.end().to_point(&buffer);
let start_wrap_row = wrap_snapshot.make_wrap_point(start, Bias::Left).row();
let end_wrap_row = wrap_snapshot.make_wrap_point(end, Bias::Left).row();
@@ -1669,44 +1741,18 @@ impl BlockMapWriter<'_> {
});
(range.start, range.end)
};
- let block_ix = match self
- .block_map
- .custom_blocks
- .binary_search_by(|probe| probe.placement.cmp(&block.placement, buffer))
- {
- Ok(ix) | Err(ix) => ix,
- };
- let new_block = Arc::new(CustomBlock {
- id,
- placement: block.placement.clone(),
- height: block.height,
- render: Arc::new(Mutex::new(block.render)),
- style: block.style,
- priority: block.priority,
- });
- self.block_map
- .custom_blocks
- .insert(block_ix, new_block.clone());
- self.block_map
- .custom_blocks_by_id
- .insert(id, new_block.clone());
// Insert a matching custom block in the companion (if any)
- if let Some(CompanionViewMut {
- entity_id: their_entity_id,
- wrap_snapshot: their_snapshot,
- block_map: their_block_map,
- companion,
- ..
- }) = self.companion.as_deref_mut()
+ if let Some(companion) = &mut self.companion
+ && companion.inverse.is_some()
{
- their_block_map.insert_custom_block_into_companion(
- *their_entity_id,
- their_snapshot,
- &new_block,
- buffer,
- companion,
- );
+ companion_blocks.extend(balancing_block(
+ &block,
+ &buffer,
+ companion.companion_wrap_snapshot.buffer(),
+ companion.display_map_id,
+ companion.companion,
+ ));
}
edits = edits.compose([Edit {
@@ -1715,31 +1761,36 @@ impl BlockMapWriter<'_> {
}]);
}
- let default_patch = Patch::default();
self.block_map.sync(
- wrap_snapshot,
+ &wrap_snapshot,
edits,
- self.companion.as_deref().map(
- |CompanionViewMut {
- entity_id,
- wrap_snapshot,
- companion,
- ..
- }| {
- CompanionView::new(*entity_id, wrap_snapshot, &default_patch, companion)
- },
- ),
+ self.companion
+ .as_ref()
+ .map(BlockMapWriterCompanion::companion_view),
);
+
+ if let Some(companion) = &mut self.companion
+ && let Some(inverse) = &mut companion.inverse
+ {
+ let companion_ids = inverse.companion_writer.insert(companion_blocks);
+ companion
+ .companion
+ .custom_block_to_balancing_block(companion.display_map_id)
+ .borrow_mut()
+ .extend(ids.iter().copied().zip(companion_ids));
+ }
+
ids
}
#[ztracing::instrument(skip_all)]
pub fn resize(&mut self, mut heights: HashMap<CustomBlockId, u32>) {
- let wrap_snapshot = &*self.block_map.wrap_snapshot.borrow();
+ let wrap_snapshot = self.block_map.wrap_snapshot.borrow().clone();
let buffer = wrap_snapshot.buffer_snapshot();
let mut edits = Patch::default();
let mut last_block_buffer_row = None;
+ let mut companion_heights = HashMap::default();
for block in &mut self.block_map.custom_blocks {
if let Some(new_height) = heights.remove(&block.id) {
if let BlockPlacement::Replace(_) = &block.placement {
@@ -1761,6 +1812,18 @@ impl BlockMapWriter<'_> {
.custom_blocks_by_id
.insert(block.id, new_block);
+ if let Some(companion) = &self.companion
+ && companion.inverse.is_some()
+ && let Some(companion_block_id) = companion
+ .companion
+ .custom_block_to_balancing_block(companion.display_map_id)
+ .borrow()
+ .get(&block.id)
+ .copied()
+ {
+ companion_heights.insert(companion_block_id, new_height);
+ }
+
let start_row = block.placement.start().to_point(buffer).row;
let end_row = block.placement.end().to_point(buffer).row;
if last_block_buffer_row != Some(end_row) {
@@ -1785,21 +1848,18 @@ impl BlockMapWriter<'_> {
}
}
- let default_patch = Patch::default();
self.block_map.sync(
- wrap_snapshot,
+ &wrap_snapshot,
edits,
- self.companion.as_deref().map(
- |CompanionViewMut {
- entity_id,
- wrap_snapshot,
- companion,
- ..
- }| {
- CompanionView::new(*entity_id, wrap_snapshot, &default_patch, companion)
- },
- ),
+ self.companion
+ .as_ref()
+ .map(BlockMapWriterCompanion::companion_view),
);
+ if let Some(companion) = &mut self.companion
+ && let Some(inverse) = &mut companion.inverse
+ {
+ inverse.companion_writer.resize(companion_heights);
+ }
}
#[ztracing::instrument(skip_all)]
@@ -1809,6 +1869,7 @@ impl BlockMapWriter<'_> {
let mut edits = Patch::default();
let mut last_block_buffer_row = None;
let mut previous_wrap_row_range: Option<Range<WrapRow>> = None;
+ let mut companion_block_ids: HashSet<CustomBlockId> = HashSet::default();
self.block_map.custom_blocks.retain(|block| {
if block_ids.contains(&block.id) {
let start = block.placement.start().to_point(buffer);
@@ -1837,6 +1898,18 @@ impl BlockMapWriter<'_> {
new: start_row..end_row,
})
}
+ if let Some(companion) = &self.companion
+ && companion.inverse.is_some()
+ {
+ companion_block_ids.extend(
+ companion
+ .companion
+ .custom_block_to_balancing_block(companion.display_map_id)
+ .borrow()
+ .get(&block.id)
+ .copied(),
+ );
+ }
false
} else {
true
@@ -1846,51 +1919,23 @@ impl BlockMapWriter<'_> {
.custom_blocks_by_id
.retain(|id, _| !block_ids.contains(id));
- if let Some(CompanionViewMut {
- entity_id: their_entity_id,
- wrap_snapshot: their_snapshot,
- companion,
- block_map: their_block_map,
- ..
- }) = self.companion.as_deref_mut()
- {
- let their_block_ids: HashSet<_> = block_ids
- .iter()
- .filter_map(|my_block_id| {
- let mapping = companion.companion_custom_block_to_custom_block(*their_entity_id);
- let their_block_id =
- mapping.get(my_block_id)?;
- log::debug!("Removing custom block in the companion with id {their_block_id:?} for mine {my_block_id:?}");
- Some(*their_block_id)
- })
- .collect();
- for (lhs_id, rhs_id) in block_ids.iter().zip(their_block_ids.iter()) {
- if !companion.is_rhs(*their_entity_id) {
- companion.remove_custom_block_mapping(lhs_id, rhs_id);
- } else {
- companion.remove_custom_block_mapping(rhs_id, lhs_id);
- }
- }
- their_block_map
- .write(their_snapshot.clone(), Patch::default(), None)
- .remove(their_block_ids);
- }
-
- let default_patch = Patch::default();
self.block_map.sync(
wrap_snapshot,
edits,
- self.companion.as_deref().map(
- |CompanionViewMut {
- entity_id,
- wrap_snapshot,
- companion,
- ..
- }| {
- CompanionView::new(*entity_id, wrap_snapshot, &default_patch, companion)
- },
- ),
+ self.companion
+ .as_ref()
+ .map(BlockMapWriterCompanion::companion_view),
);
+ if let Some(companion) = &mut self.companion
+ && let Some(inverse) = &mut companion.inverse
+ {
+ companion
+ .companion
+ .custom_block_to_balancing_block(companion.display_map_id)
+ .borrow_mut()
+ .retain(|id, _| !block_ids.contains(&id));
+ inverse.companion_writer.remove(companion_block_ids);
+ }
}
#[ztracing::instrument(skip_all)]
@@ -1947,6 +1992,7 @@ impl BlockMapWriter<'_> {
cx: &App,
) {
let mut ranges = Vec::new();
+ let mut companion_buffer_ids = HashSet::default();
for buffer_id in buffer_ids {
if fold {
self.block_map.folded_buffers.insert(buffer_id);
@@ -1954,6 +2000,17 @@ impl BlockMapWriter<'_> {
self.block_map.folded_buffers.remove(&buffer_id);
}
ranges.extend(multi_buffer.excerpt_ranges_for_buffer(buffer_id, cx));
+ if let Some(companion) = &self.companion
+ && companion.inverse.is_some()
+ {
+ companion_buffer_ids.extend(
+ companion
+ .companion
+ .buffer_to_companion_buffer(companion.display_map_id)
+ .get(&buffer_id)
+ .copied(),
+ )
+ }
}
ranges.sort_unstable_by_key(|range| range.start);
@@ -1971,21 +2028,23 @@ impl BlockMapWriter<'_> {
});
}
- let default_patch = Patch::default();
self.block_map.sync(
&wrap_snapshot,
- edits,
- self.companion.as_deref().map(
- |CompanionViewMut {
- entity_id,
- wrap_snapshot,
- companion,
- ..
- }| {
- CompanionView::new(*entity_id, wrap_snapshot, &default_patch, companion)
- },
- ),
+ edits.clone(),
+ self.companion
+ .as_ref()
+ .map(BlockMapWriterCompanion::companion_view),
);
+ if let Some(companion) = &mut self.companion
+ && let Some(inverse) = &mut companion.inverse
+ {
+ inverse.companion_writer.fold_or_unfold_buffers(
+ fold,
+ companion_buffer_ids,
+ inverse.companion_multibuffer,
+ cx,
+ );
+ }
}
#[ztracing::instrument(skip_all)]
@@ -2696,6 +2755,19 @@ impl CustomBlock {
pub fn style(&self) -> BlockStyle {
self.style
}
+
+ pub fn properties(&self) -> BlockProperties<Anchor> {
+ BlockProperties {
+ placement: self.placement.clone(),
+ height: self.height,
+ style: self.style,
+ render: Arc::new(|_| {
+ // Not used
+ gpui::Empty.into_any_element()
+ }),
+ priority: self.priority,
+ }
+ }
}
impl Debug for CustomBlock {
@@ -4534,7 +4606,6 @@ mod tests {
let companion = cx.new(|_| {
let mut c = Companion::new(
rhs_entity_id,
- Default::default(),
convert_rhs_rows_to_lhs,
convert_lhs_rows_to_rhs,
);
@@ -634,11 +634,8 @@ impl SplittableEditor {
.collect()
};
- let rhs_folded_buffers = rhs_display_map.read(cx).folded_buffers().clone();
-
let mut companion = Companion::new(
rhs_display_map_id,
- rhs_folded_buffers,
convert_rhs_rows_to_lhs,
convert_lhs_rows_to_rhs,
);
@@ -659,13 +656,7 @@ impl SplittableEditor {
let companion = cx.new(|_| companion);
rhs_display_map.update(cx, |dm, cx| {
- dm.set_companion(Some((lhs_display_map.downgrade(), companion.clone())), cx);
- });
- lhs_display_map.update(cx, |dm, cx| {
- dm.set_companion(Some((rhs_display_map.downgrade(), companion)), cx);
- });
- rhs_display_map.update(cx, |dm, cx| {
- dm.sync_custom_blocks_into_companion(cx);
+ dm.set_companion(Some((lhs_display_map, companion.clone())), cx);
});
let shared_scroll_anchor = self
@@ -2017,7 +2008,7 @@ mod tests {
use std::sync::Arc;
use buffer_diff::BufferDiff;
- use collections::HashSet;
+ use collections::{HashMap, HashSet};
use fs::FakeFs;
use gpui::Element as _;
use gpui::{AppContext as _, Entity, Pixels, VisualTestContext};
@@ -2039,6 +2030,7 @@ mod tests {
async fn init_test(
cx: &mut gpui::TestAppContext,
soft_wrap: SoftWrap,
+ style: DiffViewStyle,
) -> (Entity<SplittableEditor>, &mut VisualTestContext) {
cx.update(|cx| {
let store = SettingsStore::test(cx);
@@ -2055,26 +2047,22 @@ mod tests {
multibuffer
});
let editor = cx.new_window_entity(|window, cx| {
- let mut editor = SplittableEditor::new(
- DiffViewStyle::Stacked,
+ let editor = SplittableEditor::new(
+ style,
rhs_multibuffer.clone(),
project.clone(),
workspace,
window,
cx,
);
- editor.split(&Default::default(), window, cx);
editor.rhs_editor.update(cx, |editor, cx| {
editor.set_soft_wrap_mode(soft_wrap, cx);
});
- editor
- .lhs
- .as_ref()
- .unwrap()
- .editor
- .update(cx, |editor, cx| {
+ if let Some(lhs) = &editor.lhs {
+ lhs.editor.update(cx, |editor, cx| {
editor.set_soft_wrap_mode(soft_wrap, cx);
});
+ }
editor
});
(editor, cx)
@@ -2144,7 +2132,7 @@ mod tests {
async fn test_random_split_editor(mut rng: StdRng, cx: &mut gpui::TestAppContext) {
use rand::prelude::*;
- let (editor, cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, cx) = init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let operations = std::env::var("OPERATIONS")
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
@@ -2228,7 +2216,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaa
@@ -2357,7 +2346,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text1 = "
aaa
@@ -2515,7 +2505,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaa
@@ -2634,7 +2625,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaa
@@ -2763,7 +2755,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaa
@@ -2888,7 +2881,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaa
@@ -3001,7 +2995,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let text = "aaaa bbbb cccc dddd eeee ffff";
@@ -3069,7 +3064,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaaa bbbb cccc dddd eeee ffff
@@ -3131,7 +3127,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaaa bbbb cccc dddd eeee ffff
@@ -3200,7 +3197,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let text = "
aaaa bbbb cccc dddd eeee ffff
@@ -3312,7 +3310,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let (buffer1, diff1) = buffer_with_diff("xxx\nyyy", "xxx\nyyy", &mut cx);
@@ -3416,7 +3415,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaa
@@ -3498,7 +3498,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "aaaa bbbb cccc dddd eeee ffff\n";
@@ -3577,7 +3578,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaa
@@ -3699,7 +3701,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "";
let current_text = "
@@ -3775,7 +3778,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
aaa
@@ -3870,7 +3874,7 @@ mod tests {
use gpui::size;
use rope::Point;
- let (editor, mut cx) = init_test(cx, SoftWrap::None).await;
+ let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::SideBySide).await;
let long_line = "x".repeat(200);
let mut lines: Vec<String> = (0..50).map(|i| format!("line {i}")).collect();
@@ -3953,7 +3957,8 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::EditorWidth).await;
+ let (editor, mut cx) =
+ init_test(cx, SoftWrap::EditorWidth, DiffViewStyle::SideBySide).await;
let base_text = "
first line
@@ -4083,7 +4088,7 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::None).await;
+ let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::SideBySide).await;
let base_text = "
bbb
@@ -4163,10 +4168,9 @@ mod tests {
let lhs_block_id = lhs_editor.read_with(cx, |lhs_editor, cx| {
let display_map = lhs_editor.display_map.read(cx);
let companion = display_map.companion().unwrap().read(cx);
- let mapping = companion.companion_custom_block_to_custom_block(
- rhs_editor.read(cx).display_map.entity_id(),
- );
- *mapping.get(&block_ids[0]).unwrap()
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
+ *mapping.borrow().get(&block_ids[0]).unwrap()
});
cx.update(|_, cx| {
@@ -4231,7 +4235,7 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::None).await;
+ let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::SideBySide).await;
let base_text = "
bbb
@@ -4324,12 +4328,11 @@ mod tests {
let (lhs_block_id_1, lhs_block_id_2) = lhs_editor.read_with(cx, |lhs_editor, cx| {
let display_map = lhs_editor.display_map.read(cx);
let companion = display_map.companion().unwrap().read(cx);
- let mapping = companion.companion_custom_block_to_custom_block(
- rhs_editor.read(cx).display_map.entity_id(),
- );
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
(
- *mapping.get(&block_ids[0]).unwrap(),
- *mapping.get(&block_ids[1]).unwrap(),
+ *mapping.borrow().get(&block_ids[0]).unwrap(),
+ *mapping.borrow().get(&block_ids[1]).unwrap(),
)
});
@@ -4414,10 +4417,9 @@ mod tests {
let lhs_block_id_2 = lhs_editor.read_with(cx, |lhs_editor, cx| {
let display_map = lhs_editor.display_map.read(cx);
let companion = display_map.companion().unwrap().read(cx);
- let mapping = companion.companion_custom_block_to_custom_block(
- rhs_editor.read(cx).display_map.entity_id(),
- );
- *mapping.get(&block_ids[1]).unwrap()
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
+ *mapping.borrow().get(&block_ids[1]).unwrap()
});
cx.update(|_, cx| {
@@ -4455,7 +4457,7 @@ mod tests {
use rope::Point;
use unindent::Unindent as _;
- let (editor, mut cx) = init_test(cx, SoftWrap::None).await;
+ let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::SideBySide).await;
let base_text = "
bbb
@@ -4559,12 +4561,11 @@ mod tests {
let (lhs_block_id_1, lhs_block_id_2) = lhs_editor.read_with(cx, |lhs_editor, cx| {
let display_map = lhs_editor.display_map.read(cx);
let companion = display_map.companion().unwrap().read(cx);
- let mapping = companion.companion_custom_block_to_custom_block(
- rhs_editor.read(cx).display_map.entity_id(),
- );
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
(
- *mapping.get(&block_ids[0]).unwrap(),
- *mapping.get(&block_ids[1]).unwrap(),
+ *mapping.borrow().get(&block_ids[0]).unwrap(),
+ *mapping.borrow().get(&block_ids[1]).unwrap(),
)
});
@@ -4649,10 +4650,9 @@ mod tests {
let lhs_block_id_2 = lhs_editor.read_with(cx, |lhs_editor, cx| {
let display_map = lhs_editor.display_map.read(cx);
let companion = display_map.companion().unwrap().read(cx);
- let mapping = companion.companion_custom_block_to_custom_block(
- rhs_editor.read(cx).display_map.entity_id(),
- );
- *mapping.get(&block_ids[1]).unwrap()
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
+ *mapping.borrow().get(&block_ids[1]).unwrap()
});
cx.update(|_, cx| {
@@ -4711,10 +4711,9 @@ mod tests {
let lhs_block_id_3 = lhs_editor.read_with(cx, |lhs_editor, cx| {
let display_map = lhs_editor.display_map.read(cx);
let companion = display_map.companion().unwrap().read(cx);
- let mapping = companion.companion_custom_block_to_custom_block(
- rhs_editor.read(cx).display_map.entity_id(),
- );
- *mapping.get(&new_block_ids[0]).unwrap()
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
+ *mapping.borrow().get(&new_block_ids[0]).unwrap()
});
cx.update(|_, cx| {
@@ -4777,4 +4776,629 @@ mod tests {
&mut cx,
);
}
+
+ #[gpui::test]
+ async fn test_buffer_folding_sync(cx: &mut gpui::TestAppContext) {
+ use rope::Point;
+ use unindent::Unindent as _;
+
+ let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::Stacked).await;
+
+ let base_text1 = "
+ aaa
+ bbb
+ ccc"
+ .unindent();
+ let current_text1 = "
+ aaa
+ bbb
+ ccc"
+ .unindent();
+
+ let base_text2 = "
+ ddd
+ eee
+ fff"
+ .unindent();
+ let current_text2 = "
+ ddd
+ eee
+ fff"
+ .unindent();
+
+ let (buffer1, diff1) = buffer_with_diff(&base_text1, ¤t_text1, &mut cx);
+ let (buffer2, diff2) = buffer_with_diff(&base_text2, ¤t_text2, &mut cx);
+
+ let buffer1_id = buffer1.read_with(cx, |buffer, _| buffer.remote_id());
+ let buffer2_id = buffer2.read_with(cx, |buffer, _| buffer.remote_id());
+
+ editor.update(cx, |editor, cx| {
+ let path1 = PathKey::for_buffer(&buffer1, cx);
+ editor.set_excerpts_for_path(
+ path1,
+ buffer1.clone(),
+ vec![Point::new(0, 0)..buffer1.read(cx).max_point()],
+ 0,
+ diff1.clone(),
+ cx,
+ );
+ let path2 = PathKey::for_buffer(&buffer2, cx);
+ editor.set_excerpts_for_path(
+ path2,
+ buffer2.clone(),
+ vec![Point::new(0, 0)..buffer2.read(cx).max_point()],
+ 1,
+ diff2.clone(),
+ cx,
+ );
+ });
+
+ cx.run_until_parked();
+
+ editor.update(cx, |editor, cx| {
+ editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ rhs_editor.fold_buffer(buffer1_id, cx);
+ });
+ });
+
+ cx.run_until_parked();
+
+ let rhs_buffer1_folded = editor.read_with(cx, |editor, cx| {
+ editor.rhs_editor.read(cx).is_buffer_folded(buffer1_id, cx)
+ });
+ assert!(
+ rhs_buffer1_folded,
+ "buffer1 should be folded in rhs before split"
+ );
+
+ editor.update_in(cx, |editor, window, cx| {
+ editor.split(&Default::default(), window, cx);
+ });
+
+ cx.run_until_parked();
+
+ let (rhs_editor, lhs_editor) = editor.read_with(cx, |editor, _cx| {
+ (
+ editor.rhs_editor.clone(),
+ editor.lhs.as_ref().unwrap().editor.clone(),
+ )
+ });
+
+ let rhs_buffer1_folded =
+ rhs_editor.read_with(cx, |editor, cx| editor.is_buffer_folded(buffer1_id, cx));
+ assert!(
+ rhs_buffer1_folded,
+ "buffer1 should be folded in rhs after split"
+ );
+
+ let base_buffer1_id = diff1.read_with(cx, |diff, cx| diff.base_text(cx).remote_id());
+ let lhs_buffer1_folded = lhs_editor.read_with(cx, |editor, cx| {
+ editor.is_buffer_folded(base_buffer1_id, cx)
+ });
+ assert!(
+ lhs_buffer1_folded,
+ "buffer1 should be folded in lhs after split"
+ );
+
+ assert_split_content(
+ &editor,
+ "
+ § <no file>
+ § -----
+ § <no file>
+ § -----
+ ddd
+ eee
+ fff"
+ .unindent(),
+ "
+ § <no file>
+ § -----
+ § <no file>
+ § -----
+ ddd
+ eee
+ fff"
+ .unindent(),
+ &mut cx,
+ );
+
+ editor.update(cx, |editor, cx| {
+ editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ rhs_editor.fold_buffer(buffer2_id, cx);
+ });
+ });
+
+ cx.run_until_parked();
+
+ let rhs_buffer2_folded =
+ rhs_editor.read_with(cx, |editor, cx| editor.is_buffer_folded(buffer2_id, cx));
+ assert!(rhs_buffer2_folded, "buffer2 should be folded in rhs");
+
+ let base_buffer2_id = diff2.read_with(cx, |diff, cx| diff.base_text(cx).remote_id());
+ let lhs_buffer2_folded = lhs_editor.read_with(cx, |editor, cx| {
+ editor.is_buffer_folded(base_buffer2_id, cx)
+ });
+ assert!(lhs_buffer2_folded, "buffer2 should be folded in lhs");
+
+ let rhs_buffer1_still_folded =
+ rhs_editor.read_with(cx, |editor, cx| editor.is_buffer_folded(buffer1_id, cx));
+ assert!(
+ rhs_buffer1_still_folded,
+ "buffer1 should still be folded in rhs"
+ );
+
+ let lhs_buffer1_still_folded = lhs_editor.read_with(cx, |editor, cx| {
+ editor.is_buffer_folded(base_buffer1_id, cx)
+ });
+ assert!(
+ lhs_buffer1_still_folded,
+ "buffer1 should still be folded in lhs"
+ );
+
+ assert_split_content(
+ &editor,
+ "
+ § <no file>
+ § -----
+ § <no file>
+ § -----"
+ .unindent(),
+ "
+ § <no file>
+ § -----
+ § <no file>
+ § -----"
+ .unindent(),
+ &mut cx,
+ );
+ }
+
+ #[gpui::test]
+ async fn test_custom_block_in_middle_of_added_hunk(cx: &mut gpui::TestAppContext) {
+ use rope::Point;
+ use unindent::Unindent as _;
+
+ let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::SideBySide).await;
+
+ let base_text = "
+ ddd
+ eee
+ "
+ .unindent();
+ let current_text = "
+ aaa
+ bbb
+ ccc
+ ddd
+ eee
+ "
+ .unindent();
+
+ let (buffer, diff) = buffer_with_diff(&base_text, ¤t_text, &mut cx);
+
+ editor.update(cx, |editor, cx| {
+ let path = PathKey::for_buffer(&buffer, cx);
+ editor.set_excerpts_for_path(
+ path,
+ buffer.clone(),
+ vec![Point::new(0, 0)..buffer.read(cx).max_point()],
+ 0,
+ diff.clone(),
+ cx,
+ );
+ });
+
+ cx.run_until_parked();
+
+ assert_split_content(
+ &editor,
+ "
+ § <no file>
+ § -----
+ aaa
+ bbb
+ ccc
+ ddd
+ eee"
+ .unindent(),
+ "
+ § <no file>
+ § -----
+ § spacer
+ § spacer
+ § spacer
+ ddd
+ eee"
+ .unindent(),
+ &mut cx,
+ );
+
+ let block_ids = editor.update(cx, |splittable_editor, cx| {
+ splittable_editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ let snapshot = rhs_editor.buffer().read(cx).snapshot(cx);
+ let anchor = snapshot.anchor_before(Point::new(2, 0));
+ rhs_editor.insert_blocks(
+ [BlockProperties {
+ placement: BlockPlacement::Above(anchor),
+ height: Some(1),
+ style: BlockStyle::Fixed,
+ render: Arc::new(|_| div().into_any()),
+ priority: 0,
+ }],
+ None,
+ cx,
+ )
+ })
+ });
+
+ let rhs_editor = editor.read_with(cx, |editor, _| editor.rhs_editor.clone());
+ let lhs_editor =
+ editor.read_with(cx, |editor, _| editor.lhs.as_ref().unwrap().editor.clone());
+
+ cx.update(|_, cx| {
+ set_block_content_for_tests(&rhs_editor, block_ids[0], cx, |_| {
+ "custom block".to_string()
+ });
+ });
+
+ let lhs_block_id = lhs_editor.read_with(cx, |lhs_editor, cx| {
+ let display_map = lhs_editor.display_map.read(cx);
+ let companion = display_map.companion().unwrap().read(cx);
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
+ *mapping.borrow().get(&block_ids[0]).unwrap()
+ });
+
+ cx.update(|_, cx| {
+ set_block_content_for_tests(&lhs_editor, lhs_block_id, cx, |_| {
+ "custom block".to_string()
+ });
+ });
+
+ cx.run_until_parked();
+
+ assert_split_content(
+ &editor,
+ "
+ § <no file>
+ § -----
+ aaa
+ bbb
+ § custom block
+ ccc
+ ddd
+ eee"
+ .unindent(),
+ "
+ § <no file>
+ § -----
+ § spacer
+ § spacer
+ § spacer
+ § custom block
+ ddd
+ eee"
+ .unindent(),
+ &mut cx,
+ );
+
+ editor.update(cx, |splittable_editor, cx| {
+ splittable_editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ rhs_editor.remove_blocks(HashSet::from_iter(block_ids), None, cx);
+ });
+ });
+
+ cx.run_until_parked();
+
+ assert_split_content(
+ &editor,
+ "
+ § <no file>
+ § -----
+ aaa
+ bbb
+ ccc
+ ddd
+ eee"
+ .unindent(),
+ "
+ § <no file>
+ § -----
+ § spacer
+ § spacer
+ § spacer
+ ddd
+ eee"
+ .unindent(),
+ &mut cx,
+ );
+ }
+
+ #[gpui::test]
+ async fn test_custom_block_below_in_middle_of_added_hunk(cx: &mut gpui::TestAppContext) {
+ use rope::Point;
+ use unindent::Unindent as _;
+
+ let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::SideBySide).await;
+
+ let base_text = "
+ ddd
+ eee
+ "
+ .unindent();
+ let current_text = "
+ aaa
+ bbb
+ ccc
+ ddd
+ eee
+ "
+ .unindent();
+
+ let (buffer, diff) = buffer_with_diff(&base_text, ¤t_text, &mut cx);
+
+ editor.update(cx, |editor, cx| {
+ let path = PathKey::for_buffer(&buffer, cx);
+ editor.set_excerpts_for_path(
+ path,
+ buffer.clone(),
+ vec![Point::new(0, 0)..buffer.read(cx).max_point()],
+ 0,
+ diff.clone(),
+ cx,
+ );
+ });
+
+ cx.run_until_parked();
+
+ assert_split_content(
+ &editor,
+ "
+ § <no file>
+ § -----
+ aaa
+ bbb
+ ccc
+ ddd
+ eee"
+ .unindent(),
+ "
+ § <no file>
+ § -----
+ § spacer
+ § spacer
+ § spacer
+ ddd
+ eee"
+ .unindent(),
+ &mut cx,
+ );
+
+ let block_ids = editor.update(cx, |splittable_editor, cx| {
+ splittable_editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ let snapshot = rhs_editor.buffer().read(cx).snapshot(cx);
+ let anchor = snapshot.anchor_after(Point::new(1, 3));
+ rhs_editor.insert_blocks(
+ [BlockProperties {
+ placement: BlockPlacement::Below(anchor),
+ height: Some(1),
+ style: BlockStyle::Fixed,
+ render: Arc::new(|_| div().into_any()),
+ priority: 0,
+ }],
+ None,
+ cx,
+ )
+ })
+ });
+
+ let rhs_editor = editor.read_with(cx, |editor, _| editor.rhs_editor.clone());
+ let lhs_editor =
+ editor.read_with(cx, |editor, _| editor.lhs.as_ref().unwrap().editor.clone());
+
+ cx.update(|_, cx| {
+ set_block_content_for_tests(&rhs_editor, block_ids[0], cx, |_| {
+ "custom block".to_string()
+ });
+ });
+
+ let lhs_block_id = lhs_editor.read_with(cx, |lhs_editor, cx| {
+ let display_map = lhs_editor.display_map.read(cx);
+ let companion = display_map.companion().unwrap().read(cx);
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
+ *mapping.borrow().get(&block_ids[0]).unwrap()
+ });
+
+ cx.update(|_, cx| {
+ set_block_content_for_tests(&lhs_editor, lhs_block_id, cx, |_| {
+ "custom block".to_string()
+ });
+ });
+
+ cx.run_until_parked();
+
+ assert_split_content(
+ &editor,
+ "
+ § <no file>
+ § -----
+ aaa
+ bbb
+ § custom block
+ ccc
+ ddd
+ eee"
+ .unindent(),
+ "
+ § <no file>
+ § -----
+ § spacer
+ § spacer
+ § spacer
+ § custom block
+ ddd
+ eee"
+ .unindent(),
+ &mut cx,
+ );
+
+ editor.update(cx, |splittable_editor, cx| {
+ splittable_editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ rhs_editor.remove_blocks(HashSet::from_iter(block_ids), None, cx);
+ });
+ });
+
+ cx.run_until_parked();
+
+ assert_split_content(
+ &editor,
+ "
+ § <no file>
+ § -----
+ aaa
+ bbb
+ ccc
+ ddd
+ eee"
+ .unindent(),
+ "
+ § <no file>
+ § -----
+ § spacer
+ § spacer
+ § spacer
+ ddd
+ eee"
+ .unindent(),
+ &mut cx,
+ );
+ }
+
+ #[gpui::test]
+ async fn test_custom_block_resize_syncs_balancing_block(cx: &mut gpui::TestAppContext) {
+ use rope::Point;
+ use unindent::Unindent as _;
+
+ let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::SideBySide).await;
+
+ let base_text = "
+ bbb
+ ccc
+ "
+ .unindent();
+ let current_text = "
+ aaa
+ bbb
+ ccc
+ "
+ .unindent();
+
+ let (buffer, diff) = buffer_with_diff(&base_text, ¤t_text, &mut cx);
+
+ editor.update(cx, |editor, cx| {
+ let path = PathKey::for_buffer(&buffer, cx);
+ editor.set_excerpts_for_path(
+ path,
+ buffer.clone(),
+ vec![Point::new(0, 0)..buffer.read(cx).max_point()],
+ 0,
+ diff.clone(),
+ cx,
+ );
+ });
+
+ cx.run_until_parked();
+
+ let block_ids = editor.update(cx, |splittable_editor, cx| {
+ splittable_editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ let snapshot = rhs_editor.buffer().read(cx).snapshot(cx);
+ let anchor = snapshot.anchor_before(Point::new(2, 0));
+ rhs_editor.insert_blocks(
+ [BlockProperties {
+ placement: BlockPlacement::Above(anchor),
+ height: Some(1),
+ style: BlockStyle::Fixed,
+ render: Arc::new(|_| div().into_any()),
+ priority: 0,
+ }],
+ None,
+ cx,
+ )
+ })
+ });
+
+ let rhs_editor = editor.read_with(cx, |editor, _| editor.rhs_editor.clone());
+ let lhs_editor =
+ editor.read_with(cx, |editor, _| editor.lhs.as_ref().unwrap().editor.clone());
+
+ let lhs_block_id = lhs_editor.read_with(cx, |lhs_editor, cx| {
+ let display_map = lhs_editor.display_map.read(cx);
+ let companion = display_map.companion().unwrap().read(cx);
+ let mapping = companion
+ .custom_block_to_balancing_block(rhs_editor.read(cx).display_map.entity_id());
+ *mapping.borrow().get(&block_ids[0]).unwrap()
+ });
+
+ cx.run_until_parked();
+
+ let get_block_height = |editor: &Entity<crate::Editor>,
+ block_id: crate::CustomBlockId,
+ cx: &mut VisualTestContext| {
+ editor.update_in(cx, |editor, window, cx| {
+ let snapshot = editor.snapshot(window, cx);
+ snapshot
+ .block_for_id(crate::BlockId::Custom(block_id))
+ .map(|block| block.height())
+ })
+ };
+
+ assert_eq!(
+ get_block_height(&rhs_editor, block_ids[0], &mut cx),
+ Some(1)
+ );
+ assert_eq!(
+ get_block_height(&lhs_editor, lhs_block_id, &mut cx),
+ Some(1)
+ );
+
+ editor.update(cx, |splittable_editor, cx| {
+ splittable_editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ let mut heights = HashMap::default();
+ heights.insert(block_ids[0], 3);
+ rhs_editor.resize_blocks(heights, None, cx);
+ });
+ });
+
+ cx.run_until_parked();
+
+ assert_eq!(
+ get_block_height(&rhs_editor, block_ids[0], &mut cx),
+ Some(3)
+ );
+ assert_eq!(
+ get_block_height(&lhs_editor, lhs_block_id, &mut cx),
+ Some(3)
+ );
+
+ editor.update(cx, |splittable_editor, cx| {
+ splittable_editor.rhs_editor.update(cx, |rhs_editor, cx| {
+ let mut heights = HashMap::default();
+ heights.insert(block_ids[0], 5);
+ rhs_editor.resize_blocks(heights, None, cx);
+ });
+ });
+
+ cx.run_until_parked();
+
+ assert_eq!(
+ get_block_height(&rhs_editor, block_ids[0], &mut cx),
+ Some(5)
+ );
+ assert_eq!(
+ get_block_height(&lhs_editor, lhs_block_id, &mut cx),
+ Some(5)
+ );
+ }
}
@@ -240,6 +240,9 @@ pub fn editor_content_with_blocks_and_size(
first_excerpt,
height,
} => {
+ while lines.len() <= row.0 as usize {
+ lines.push(String::new());
+ }
lines[row.0 as usize].push_str(&cx.update(|_, cx| {
format!(
"§ {}",
@@ -251,15 +254,24 @@ pub fn editor_content_with_blocks_and_size(
)
}));
for row in row.0 + 1..row.0 + height {
+ while lines.len() <= row as usize {
+ lines.push(String::new());
+ }
lines[row as usize].push_str("§ -----");
}
}
Block::ExcerptBoundary { height, .. } => {
for row in row.0..row.0 + height {
+ while lines.len() <= row as usize {
+ lines.push(String::new());
+ }
lines[row as usize].push_str("§ -----");
}
}
Block::BufferHeader { excerpt, height } => {
+ while lines.len() <= row.0 as usize {
+ lines.push(String::new());
+ }
lines[row.0 as usize].push_str(&cx.update(|_, cx| {
format!(
"§ {}",
@@ -271,6 +283,9 @@ pub fn editor_content_with_blocks_and_size(
)
}));
for row in row.0 + 1..row.0 + height {
+ while lines.len() <= row as usize {
+ lines.push(String::new());
+ }
lines[row as usize].push_str("§ -----");
}
}
@@ -11,6 +11,10 @@ impl<T> Patch<T>
where
T: 'static + Clone + Copy + Ord + Default,
{
+ pub const fn empty() -> Self {
+ Self(Vec::new())
+ }
+
pub fn new(edits: Vec<Edit<T>>) -> Self {
#[cfg(debug_assertions)]
{