Remove empty line when collapsing diagnostics (#39459)

Closes #39028

Fixed empty lines appearing when collapsing files with diagnostic
messages in the diagnostics panel.

Added a flag to track when processing a `FoldedBuffer` and skip
`Near/Below` blocks (diagnostic messages) that immediately follow it.
This prevents diagnostics from rendering as empty lines when their file
is collapsed.

Before:
<img width="1489" height="429" alt="before"
src="https://github.com/user-attachments/assets/5e233290-1f6e-403c-a6b3-a65107586d01"
/>

After:
<img width="981" height="270" alt="after"
src="https://github.com/user-attachments/assets/a877b651-6b7f-4441-805c-38ea41e73a18"
/>

Release Notes:
- Fixed empty lines when collapsing files with diagnostics in the
diagnostics panel
This commit is contained in:
Vinicius da Motta
2025-10-07 16:38:35 +00:00
committed by GitHub
parent ded73c9d56
commit f9a2724a8b
@@ -689,6 +689,7 @@ impl BlockMap {
// For each of these blocks, insert a new isomorphic transform preceding the block,
// and then insert the block itself.
let mut just_processed_folded_buffer = false;
for (block_placement, block) in blocks_in_edit.drain(..) {
let mut summary = TransformSummary {
input_rows: 0,
@@ -701,8 +702,12 @@ impl BlockMap {
match block_placement {
BlockPlacement::Above(position) => {
rows_before_block = position.0 - new_transforms.summary().input_rows;
just_processed_folded_buffer = false;
}
BlockPlacement::Near(position) | BlockPlacement::Below(position) => {
if just_processed_folded_buffer {
continue;
}
if position.0 + 1 < new_transforms.summary().input_rows {
continue;
}
@@ -711,6 +716,7 @@ impl BlockMap {
BlockPlacement::Replace(range) => {
rows_before_block = range.start().0 - new_transforms.summary().input_rows;
summary.input_rows = range.end().0 - range.start().0 + 1;
just_processed_folded_buffer = matches!(block, Block::FoldedBuffer { .. });
}
}
@@ -3566,6 +3572,96 @@ mod tests {
assert_eq!(blocks_snapshot.text(), "abc\n\ndef\nghi\njkl\nmno");
}
#[gpui::test]
fn test_folded_buffer_with_near_blocks(cx: &mut gpui::TestAppContext) {
cx.update(init_test);
let text = "line 1\nline 2\nline 3";
let buffer = cx.update(|cx| {
MultiBuffer::build_multi([(text, vec![Point::new(0, 0)..Point::new(2, 6)])], cx)
});
let buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx));
let buffer_ids = buffer_snapshot
.excerpts()
.map(|(_, buffer_snapshot, _)| buffer_snapshot.remote_id())
.dedup()
.collect::<Vec<_>>();
assert_eq!(buffer_ids.len(), 1);
let buffer_id = buffer_ids[0];
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
let (_, wrap_snapshot) =
cx.update(|cx| WrapMap::new(tab_snapshot, font("Helvetica"), px(14.0), None, cx));
let mut block_map = BlockMap::new(wrap_snapshot.clone(), 1, 1);
let mut writer = block_map.write(wrap_snapshot.clone(), Patch::default());
writer.insert(vec![BlockProperties {
style: BlockStyle::Fixed,
placement: BlockPlacement::Near(buffer_snapshot.anchor_after(Point::new(0, 0))),
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
}]);
let blocks_snapshot = block_map.read(wrap_snapshot.clone(), Patch::default());
assert_eq!(blocks_snapshot.text(), "\nline 1\n\nline 2\nline 3");
let mut writer = block_map.write(wrap_snapshot.clone(), Patch::default());
buffer.read_with(cx, |buffer, cx| {
writer.fold_buffers([buffer_id], buffer, cx);
});
let blocks_snapshot = block_map.read(wrap_snapshot, Patch::default());
assert_eq!(blocks_snapshot.text(), "");
}
#[gpui::test]
fn test_folded_buffer_with_near_blocks_on_last_line(cx: &mut gpui::TestAppContext) {
cx.update(init_test);
let text = "line 1\nline 2\nline 3\nline 4";
let buffer = cx.update(|cx| {
MultiBuffer::build_multi([(text, vec![Point::new(0, 0)..Point::new(3, 6)])], cx)
});
let buffer_snapshot = cx.update(|cx| buffer.read(cx).snapshot(cx));
let buffer_ids = buffer_snapshot
.excerpts()
.map(|(_, buffer_snapshot, _)| buffer_snapshot.remote_id())
.dedup()
.collect::<Vec<_>>();
assert_eq!(buffer_ids.len(), 1);
let buffer_id = buffer_ids[0];
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
let (_, wrap_snapshot) =
cx.update(|cx| WrapMap::new(tab_snapshot, font("Helvetica"), px(14.0), None, cx));
let mut block_map = BlockMap::new(wrap_snapshot.clone(), 1, 1);
let mut writer = block_map.write(wrap_snapshot.clone(), Patch::default());
writer.insert(vec![BlockProperties {
style: BlockStyle::Fixed,
placement: BlockPlacement::Near(buffer_snapshot.anchor_after(Point::new(3, 6))),
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
}]);
let blocks_snapshot = block_map.read(wrap_snapshot.clone(), Patch::default());
assert_eq!(blocks_snapshot.text(), "\nline 1\nline 2\nline 3\nline 4\n");
let mut writer = block_map.write(wrap_snapshot.clone(), Patch::default());
buffer.read_with(cx, |buffer, cx| {
writer.fold_buffers([buffer_id], buffer, cx);
});
let blocks_snapshot = block_map.read(wrap_snapshot, Patch::default());
assert_eq!(blocks_snapshot.text(), "");
}
fn init_test(cx: &mut gpui::App) {
let settings = SettingsStore::test(cx);
cx.set_global(settings);