Show excerpt dividers in without_headers multibuffers (#36647)

Release Notes:

- Fixed diff cards in agent threads not showing dividers between
disjoint edited regions.
This commit is contained in:
Cole Miller 2025-08-21 09:23:56 -04:00 committed by Joseph T. Lyons
parent 7f95310020
commit ca67e0658a
3 changed files with 122 additions and 84 deletions

View file

@ -290,7 +290,10 @@ pub enum Block {
ExcerptBoundary { ExcerptBoundary {
excerpt: ExcerptInfo, excerpt: ExcerptInfo,
height: u32, height: u32,
starts_new_buffer: bool, },
BufferHeader {
excerpt: ExcerptInfo,
height: u32,
}, },
} }
@ -303,27 +306,37 @@ impl Block {
.. ..
} => BlockId::ExcerptBoundary(next_excerpt.id), } => BlockId::ExcerptBoundary(next_excerpt.id),
Block::FoldedBuffer { first_excerpt, .. } => BlockId::FoldedBuffer(first_excerpt.id), Block::FoldedBuffer { first_excerpt, .. } => BlockId::FoldedBuffer(first_excerpt.id),
Block::BufferHeader {
excerpt: next_excerpt,
..
} => BlockId::ExcerptBoundary(next_excerpt.id),
} }
} }
pub fn has_height(&self) -> bool { pub fn has_height(&self) -> bool {
match self { match self {
Block::Custom(block) => block.height.is_some(), Block::Custom(block) => block.height.is_some(),
Block::ExcerptBoundary { .. } | Block::FoldedBuffer { .. } => true, Block::ExcerptBoundary { .. }
| Block::FoldedBuffer { .. }
| Block::BufferHeader { .. } => true,
} }
} }
pub fn height(&self) -> u32 { pub fn height(&self) -> u32 {
match self { match self {
Block::Custom(block) => block.height.unwrap_or(0), Block::Custom(block) => block.height.unwrap_or(0),
Block::ExcerptBoundary { height, .. } | Block::FoldedBuffer { height, .. } => *height, Block::ExcerptBoundary { height, .. }
| Block::FoldedBuffer { height, .. }
| Block::BufferHeader { height, .. } => *height,
} }
} }
pub fn style(&self) -> BlockStyle { pub fn style(&self) -> BlockStyle {
match self { match self {
Block::Custom(block) => block.style, Block::Custom(block) => block.style,
Block::ExcerptBoundary { .. } | Block::FoldedBuffer { .. } => BlockStyle::Sticky, Block::ExcerptBoundary { .. }
| Block::FoldedBuffer { .. }
| Block::BufferHeader { .. } => BlockStyle::Sticky,
} }
} }
@ -332,6 +345,7 @@ impl Block {
Block::Custom(block) => matches!(block.placement, BlockPlacement::Above(_)), Block::Custom(block) => matches!(block.placement, BlockPlacement::Above(_)),
Block::FoldedBuffer { .. } => false, Block::FoldedBuffer { .. } => false,
Block::ExcerptBoundary { .. } => true, Block::ExcerptBoundary { .. } => true,
Block::BufferHeader { .. } => true,
} }
} }
@ -340,6 +354,7 @@ impl Block {
Block::Custom(block) => matches!(block.placement, BlockPlacement::Near(_)), Block::Custom(block) => matches!(block.placement, BlockPlacement::Near(_)),
Block::FoldedBuffer { .. } => false, Block::FoldedBuffer { .. } => false,
Block::ExcerptBoundary { .. } => false, Block::ExcerptBoundary { .. } => false,
Block::BufferHeader { .. } => false,
} }
} }
@ -351,6 +366,7 @@ impl Block {
), ),
Block::FoldedBuffer { .. } => false, Block::FoldedBuffer { .. } => false,
Block::ExcerptBoundary { .. } => false, Block::ExcerptBoundary { .. } => false,
Block::BufferHeader { .. } => false,
} }
} }
@ -359,6 +375,7 @@ impl Block {
Block::Custom(block) => matches!(block.placement, BlockPlacement::Replace(_)), Block::Custom(block) => matches!(block.placement, BlockPlacement::Replace(_)),
Block::FoldedBuffer { .. } => true, Block::FoldedBuffer { .. } => true,
Block::ExcerptBoundary { .. } => false, Block::ExcerptBoundary { .. } => false,
Block::BufferHeader { .. } => false,
} }
} }
@ -367,6 +384,7 @@ impl Block {
Block::Custom(_) => false, Block::Custom(_) => false,
Block::FoldedBuffer { .. } => true, Block::FoldedBuffer { .. } => true,
Block::ExcerptBoundary { .. } => true, Block::ExcerptBoundary { .. } => true,
Block::BufferHeader { .. } => true,
} }
} }
@ -374,9 +392,8 @@ impl Block {
match self { match self {
Block::Custom(_) => false, Block::Custom(_) => false,
Block::FoldedBuffer { .. } => true, Block::FoldedBuffer { .. } => true,
Block::ExcerptBoundary { Block::ExcerptBoundary { .. } => false,
starts_new_buffer, .. Block::BufferHeader { .. } => true,
} => *starts_new_buffer,
} }
} }
} }
@ -393,14 +410,14 @@ impl Debug for Block {
.field("first_excerpt", &first_excerpt) .field("first_excerpt", &first_excerpt)
.field("height", height) .field("height", height)
.finish(), .finish(),
Self::ExcerptBoundary { Self::ExcerptBoundary { excerpt, height } => f
starts_new_buffer,
excerpt,
height,
} => f
.debug_struct("ExcerptBoundary") .debug_struct("ExcerptBoundary")
.field("excerpt", excerpt) .field("excerpt", excerpt)
.field("starts_new_buffer", starts_new_buffer) .field("height", height)
.finish(),
Self::BufferHeader { excerpt, height } => f
.debug_struct("BufferHeader")
.field("excerpt", excerpt)
.field("height", height) .field("height", height)
.finish(), .finish(),
} }
@ -662,13 +679,11 @@ impl BlockMap {
}), }),
); );
if buffer.show_headers() {
blocks_in_edit.extend(self.header_and_footer_blocks( blocks_in_edit.extend(self.header_and_footer_blocks(
buffer, buffer,
(start_bound, end_bound), (start_bound, end_bound),
wrap_snapshot, wrap_snapshot,
)); ));
}
BlockMap::sort_blocks(&mut blocks_in_edit); BlockMap::sort_blocks(&mut blocks_in_edit);
@ -771,7 +786,7 @@ impl BlockMap {
if self.buffers_with_disabled_headers.contains(&new_buffer_id) { if self.buffers_with_disabled_headers.contains(&new_buffer_id) {
continue; continue;
} }
if self.folded_buffers.contains(&new_buffer_id) { if self.folded_buffers.contains(&new_buffer_id) && buffer.show_headers() {
let mut last_excerpt_end_row = first_excerpt.end_row; let mut last_excerpt_end_row = first_excerpt.end_row;
while let Some(next_boundary) = boundaries.peek() { while let Some(next_boundary) = boundaries.peek() {
@ -804,20 +819,24 @@ impl BlockMap {
} }
} }
if new_buffer_id.is_some() { let starts_new_buffer = new_buffer_id.is_some();
let block = if starts_new_buffer && buffer.show_headers() {
height += self.buffer_header_height; height += self.buffer_header_height;
} else { Block::BufferHeader {
height += self.excerpt_header_height; excerpt: excerpt_boundary.next,
height,
} }
} else if excerpt_boundary.prev.is_some() {
return Some(( height += self.excerpt_header_height;
BlockPlacement::Above(WrapRow(wrap_row)),
Block::ExcerptBoundary { Block::ExcerptBoundary {
excerpt: excerpt_boundary.next, excerpt: excerpt_boundary.next,
height, height,
starts_new_buffer: new_buffer_id.is_some(), }
}, } else {
)); continue;
};
return Some((BlockPlacement::Above(WrapRow(wrap_row)), block));
} }
}) })
} }
@ -842,13 +861,25 @@ impl BlockMap {
( (
Block::ExcerptBoundary { Block::ExcerptBoundary {
excerpt: excerpt_a, .. excerpt: excerpt_a, ..
}
| Block::BufferHeader {
excerpt: excerpt_a, ..
}, },
Block::ExcerptBoundary { Block::ExcerptBoundary {
excerpt: excerpt_b, .. excerpt: excerpt_b, ..
}
| Block::BufferHeader {
excerpt: excerpt_b, ..
}, },
) => Some(excerpt_a.id).cmp(&Some(excerpt_b.id)), ) => Some(excerpt_a.id).cmp(&Some(excerpt_b.id)),
(Block::ExcerptBoundary { .. }, Block::Custom(_)) => Ordering::Less, (
(Block::Custom(_), Block::ExcerptBoundary { .. }) => Ordering::Greater, Block::ExcerptBoundary { .. } | Block::BufferHeader { .. },
Block::Custom(_),
) => Ordering::Less,
(
Block::Custom(_),
Block::ExcerptBoundary { .. } | Block::BufferHeader { .. },
) => Ordering::Greater,
(Block::Custom(block_a), Block::Custom(block_b)) => block_a (Block::Custom(block_a), Block::Custom(block_b)) => block_a
.priority .priority
.cmp(&block_b.priority) .cmp(&block_b.priority)
@ -1377,7 +1408,9 @@ impl BlockSnapshot {
while let Some(transform) = cursor.item() { while let Some(transform) = cursor.item() {
match &transform.block { match &transform.block {
Some(Block::ExcerptBoundary { excerpt, .. }) => { Some(
Block::ExcerptBoundary { excerpt, .. } | Block::BufferHeader { excerpt, .. },
) => {
return Some(StickyHeaderExcerpt { excerpt }); return Some(StickyHeaderExcerpt { excerpt });
} }
Some(block) if block.is_buffer_header() => return None, Some(block) if block.is_buffer_header() => return None,

View file

@ -2749,7 +2749,10 @@ impl EditorElement {
let mut block_offset = 0; let mut block_offset = 0;
let mut found_excerpt_header = false; let mut found_excerpt_header = false;
for (_, block) in snapshot.blocks_in_range(prev_line..row_range.start) { for (_, block) in snapshot.blocks_in_range(prev_line..row_range.start) {
if matches!(block, Block::ExcerptBoundary { .. }) { if matches!(
block,
Block::ExcerptBoundary { .. } | Block::BufferHeader { .. }
) {
found_excerpt_header = true; found_excerpt_header = true;
break; break;
} }
@ -2766,7 +2769,10 @@ impl EditorElement {
let mut block_height = 0; let mut block_height = 0;
let mut found_excerpt_header = false; let mut found_excerpt_header = false;
for (_, block) in snapshot.blocks_in_range(row_range.end..cons_line) { for (_, block) in snapshot.blocks_in_range(row_range.end..cons_line) {
if matches!(block, Block::ExcerptBoundary { .. }) { if matches!(
block,
Block::ExcerptBoundary { .. } | Block::BufferHeader { .. }
) {
found_excerpt_header = true; found_excerpt_header = true;
} }
block_height += block.height(); block_height += block.height();
@ -3452,18 +3458,29 @@ impl EditorElement {
.into_any_element() .into_any_element()
} }
Block::ExcerptBoundary { Block::ExcerptBoundary { .. } => {
excerpt,
height,
starts_new_buffer,
..
} => {
let color = cx.theme().colors().clone(); let color = cx.theme().colors().clone();
let mut result = v_flex().id(block_id).w_full(); let mut result = v_flex().id(block_id).w_full();
result = result.child(
h_flex().relative().child(
div()
.top(line_height / 2.)
.absolute()
.w_full()
.h_px()
.bg(color.border_variant),
),
);
result.into_any()
}
Block::BufferHeader { excerpt, height } => {
let mut result = v_flex().id(block_id).w_full();
let jump_data = header_jump_data(snapshot, block_row_start, *height, excerpt); let jump_data = header_jump_data(snapshot, block_row_start, *height, excerpt);
if *starts_new_buffer {
if sticky_header_excerpt_id != Some(excerpt.id) { if sticky_header_excerpt_id != Some(excerpt.id) {
let selected = selected_buffer_ids.contains(&excerpt.buffer_id); let selected = selected_buffer_ids.contains(&excerpt.buffer_id);
@ -3476,18 +3493,6 @@ impl EditorElement {
result = result =
result.child(div().h(FILE_HEADER_HEIGHT as f32 * window.line_height())); result.child(div().h(FILE_HEADER_HEIGHT as f32 * window.line_height()));
} }
} else {
result = result.child(
h_flex().relative().child(
div()
.top(line_height / 2.)
.absolute()
.w_full()
.h_px()
.bg(color.border_variant),
),
);
};
result.into_any() result.into_any()
} }
@ -5708,7 +5713,10 @@ impl EditorElement {
let end_row_in_current_excerpt = snapshot let end_row_in_current_excerpt = snapshot
.blocks_in_range(start_row..end_row) .blocks_in_range(start_row..end_row)
.find_map(|(start_row, block)| { .find_map(|(start_row, block)| {
if matches!(block, Block::ExcerptBoundary { .. }) { if matches!(
block,
Block::ExcerptBoundary { .. } | Block::BufferHeader { .. }
) {
Some(start_row) Some(start_row)
} else { } else {
None None

View file

@ -230,12 +230,12 @@ pub fn editor_content_with_blocks(editor: &Entity<Editor>, cx: &mut VisualTestCo
lines[row as usize].push_str("§ -----"); lines[row as usize].push_str("§ -----");
} }
} }
Block::ExcerptBoundary { Block::ExcerptBoundary { height, .. } => {
excerpt, for row in row.0..row.0 + height {
height, lines[row as usize].push_str("§ -----");
starts_new_buffer, }
} => { }
if starts_new_buffer { Block::BufferHeader { excerpt, height } => {
lines[row.0 as usize].push_str(&cx.update(|_, cx| { lines[row.0 as usize].push_str(&cx.update(|_, cx| {
format!( format!(
"§ {}", "§ {}",
@ -247,9 +247,6 @@ pub fn editor_content_with_blocks(editor: &Entity<Editor>, cx: &mut VisualTestCo
.to_string_lossy() .to_string_lossy()
) )
})); }));
} else {
lines[row.0 as usize].push_str("§ -----")
}
for row in row.0 + 1..row.0 + height { for row in row.0 + 1..row.0 + height {
lines[row as usize].push_str("§ -----"); lines[row as usize].push_str("§ -----");
} }