Skip to content

Commit

Permalink
Allow folding buffers inside multi buffers (zed-industries#22046)
Browse files Browse the repository at this point in the history
Closes zed-industries#4925


https://github.com/user-attachments/assets/e7b87375-893f-41ae-a2d9-d501499e40d1


Allows to fold any buffer inside multi buffers, either by clicking the
chevron icon on the header, or by using
`editor::Fold`/`editor::UnfoldLines`/`editor::ToggleFold`/`editor::FoldAll`
and `editor::UnfoldAll` actions inside the multi buffer (those were noop
there before).

Every fold has a fake line inside it, so it's possible to navigate into
that via the keyboard and unfold it with the corresponding editor
action.

The state is synchronized with the outline panel state: any fold inside
multi buffer folds the corresponding file entry; any file entry fold
inside the outline panel folds the corresponding buffer inside the multi
buffer, any directory fold inside the outline panel folds the
corresponding buffers inside the multi buffer for each nested file entry
in the panel.


Release Notes:

- Added a possibility to fold buffers inside multi buffers

---------

Co-authored-by: Antonio Scandurra <[email protected]>
Co-authored-by: Max Brunsfeld <[email protected]>
Co-authored-by: Cole Miller <[email protected]>
  • Loading branch information
4 people authored Dec 15, 2024
1 parent f64fced commit af50261
Show file tree
Hide file tree
Showing 9 changed files with 2,397 additions and 585 deletions.
1 change: 1 addition & 0 deletions crates/diagnostics/src/diagnostics_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,7 @@ fn editor_blocks(
.ok()?
}

Block::FoldedBuffer { .. } => FILE_HEADER.into(),
Block::ExcerptBoundary {
starts_new_buffer, ..
} => {
Expand Down
48 changes: 40 additions & 8 deletions crates/editor/src/display_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ impl DisplayMap {
let start = buffer_snapshot.anchor_before(range.start);
let end = buffer_snapshot.anchor_after(range.end);
BlockProperties {
placement: BlockPlacement::Replace(start..end),
placement: BlockPlacement::Replace(start..=end),
render,
height,
style,
Expand Down Expand Up @@ -336,6 +336,38 @@ impl DisplayMap {
block_map.remove_intersecting_replace_blocks(offset_ranges, inclusive);
}

pub fn fold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut ModelContext<Self>) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
let (snapshot, edits) = self.fold_map.read(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 mut block_map = self.block_map.write(snapshot, edits);
block_map.fold_buffer(buffer_id, self.buffer.read(cx), cx)
}

pub fn unfold_buffer(&mut self, buffer_id: language::BufferId, cx: &mut ModelContext<Self>) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let edits = self.buffer_subscription.consume().into_inner();
let tab_size = Self::tab_size(&self.buffer, cx);
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
let (snapshot, edits) = self.fold_map.read(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 mut block_map = self.block_map.write(snapshot, edits);
block_map.unfold_buffer(buffer_id, self.buffer.read(cx), cx)
}

pub(crate) fn buffer_folded(&self, buffer_id: language::BufferId) -> bool {
self.block_map.folded_buffers.contains(&buffer_id)
}

pub fn insert_creases(
&mut self,
creases: impl IntoIterator<Item = Crease<Anchor>>,
Expand Down Expand Up @@ -712,7 +744,11 @@ impl DisplaySnapshot {
}
}

pub fn next_line_boundary(&self, mut point: MultiBufferPoint) -> (Point, DisplayPoint) {
pub fn next_line_boundary(
&self,
mut point: MultiBufferPoint,
) -> (MultiBufferPoint, DisplayPoint) {
let original_point = point;
loop {
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
let mut fold_point = self.fold_snapshot.to_fold_point(inlay_point, Bias::Right);
Expand All @@ -723,7 +759,7 @@ impl DisplaySnapshot {
let mut display_point = self.point_to_display_point(point, Bias::Right);
*display_point.column_mut() = self.line_len(display_point.row());
let next_point = self.display_point_to_point(display_point, Bias::Right);
if next_point == point {
if next_point == point || original_point == point || original_point == next_point {
return (point, display_point);
}
point = next_point;
Expand Down Expand Up @@ -1081,10 +1117,6 @@ impl DisplaySnapshot {
|| self.fold_snapshot.is_line_folded(buffer_row)
}

pub fn is_line_replaced(&self, buffer_row: MultiBufferRow) -> bool {
self.block_snapshot.is_line_replaced(buffer_row)
}

pub fn is_block_line(&self, display_row: DisplayRow) -> bool {
self.block_snapshot.is_block_line(BlockRow(display_row.0))
}
Expand Down Expand Up @@ -2231,7 +2263,7 @@ pub mod tests {
[BlockProperties {
placement: BlockPlacement::Replace(
buffer_snapshot.anchor_before(Point::new(1, 2))
..buffer_snapshot.anchor_after(Point::new(2, 3)),
..=buffer_snapshot.anchor_after(Point::new(2, 3)),
),
height: 4,
style: BlockStyle::Fixed,
Expand Down
Loading

0 comments on commit af50261

Please sign in to comment.