Skip to content

Commit

Permalink
Remove multi-buffer excerpt arrows at start/end of files.
Browse files Browse the repository at this point in the history
Co-Authored-By: Cole <[email protected]>
  • Loading branch information
ConradIrwin and cole-miller committed Feb 22, 2025
1 parent 3e75a66 commit 3ea0cd7
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 94 deletions.
1 change: 0 additions & 1 deletion crates/editor/src/display_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,6 @@ impl DisplaySnapshot {
.blocks_in_range(rows.start.0..rows.end.0)
.map(|(row, block)| (DisplayRow(row), block))
}

pub fn sticky_header_excerpt(&self, row: DisplayRow) -> Option<StickyHeaderExcerpt<'_>> {
self.block_snapshot.sticky_header_excerpt(row.0)
}
Expand Down
137 changes: 77 additions & 60 deletions crates/editor/src/display_map/block_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,15 @@ pub enum Block {
first_excerpt: ExcerptInfo,
prev_excerpt: Option<ExcerptInfo>,
height: u32,
show_excerpt_controls: bool,
excerpt_controls_before: bool,
},
ExcerptBoundary {
prev_excerpt: Option<ExcerptInfo>,
next_excerpt: Option<ExcerptInfo>,
height: u32,
starts_new_buffer: bool,
show_excerpt_controls: bool,
excerpt_controls_before: bool,
excerpt_controls_after: bool,
},
}

Expand Down Expand Up @@ -362,24 +363,29 @@ impl Debug for Block {
first_excerpt,
prev_excerpt,
height,
show_excerpt_controls,
excerpt_controls_before,
} => f
.debug_struct("FoldedBuffer")
.field("first_excerpt", &first_excerpt)
.field("prev_excerpt", prev_excerpt)
.field("height", height)
.field("show_excerpt_controls", show_excerpt_controls)
.field("excerpt_controls_before", excerpt_controls_before)
.finish(),
Self::ExcerptBoundary {
starts_new_buffer,
next_excerpt,
prev_excerpt,
..
excerpt_controls_before,
excerpt_controls_after,
height,
} => f
.debug_struct("ExcerptBoundary")
.field("prev_excerpt", prev_excerpt)
.field("next_excerpt", next_excerpt)
.field("height", height)
.field("starts_new_buffer", starts_new_buffer)
.field("excerpt_controls_before", excerpt_controls_before)
.field("excerpt_controls_after", excerpt_controls_after)
.finish(),
}
}
Expand Down Expand Up @@ -772,9 +778,12 @@ impl BlockMap {
.filter(|prev| !folded_buffers.contains(&prev.buffer_id));

let mut height = 0;
if prev_excerpt.is_some() {
if show_excerpt_controls {
let mut excerpt_controls_before = false;
let mut excerpt_controls_after = false;
if let Some(prev_excerpt) = &prev_excerpt {
if show_excerpt_controls && !prev_excerpt.ends_at_end {
height += excerpt_footer_height;
excerpt_controls_before = true;
}
}

Expand Down Expand Up @@ -810,21 +819,25 @@ impl BlockMap {
Block::FoldedBuffer {
prev_excerpt,
height: height + buffer_header_height,
show_excerpt_controls,
excerpt_controls_before,
first_excerpt,
},
));
}
}

if excerpt_boundary.next.is_some() {
if let Some(next_excerpt) = &excerpt_boundary.next {
if new_buffer_id.is_some() {
height += buffer_header_height;
if show_excerpt_controls {
if show_excerpt_controls && !next_excerpt.starts_at_start {
height += excerpt_header_height;
excerpt_controls_after = true;
}
} else {
height += excerpt_header_height;
if show_excerpt_controls && !next_excerpt.starts_at_start {
height += excerpt_header_height;
excerpt_controls_after = true;
}
}
}

Expand All @@ -843,7 +856,8 @@ impl BlockMap {
next_excerpt: excerpt_boundary.next,
height,
starts_new_buffer: new_buffer_id.is_some(),
show_excerpt_controls,
excerpt_controls_before,
excerpt_controls_after,
},
))
})
Expand Down Expand Up @@ -1413,59 +1427,62 @@ impl BlockSnapshot {

pub fn sticky_header_excerpt(&self, top_row: u32) -> Option<StickyHeaderExcerpt<'_>> {
let mut cursor = self.transforms.cursor::<BlockRow>(&());
cursor.seek(&BlockRow(top_row), Bias::Left, &());
let seek_target = (top_row + 1).min(self.max_point().row);
cursor.seek(&BlockRow(seek_target), Bias::Left, &());

while let Some(transform) = cursor.item() {
let start = cursor.start().0;
let end = cursor.end(&()).0;

match &transform.block {
Some(Block::ExcerptBoundary {
prev_excerpt,
next_excerpt,
starts_new_buffer,
show_excerpt_controls,
..
}) => {
let matches_start = if *show_excerpt_controls && prev_excerpt.is_some() {
start < top_row
} else {
start <= top_row
};

if matches_start && top_row <= end {
return next_excerpt.as_ref().map(|excerpt| StickyHeaderExcerpt {
next_buffer_row: None,
next_excerpt_controls_present: *show_excerpt_controls,
excerpt,
});
}
let Some(Block::ExcerptBoundary {
prev_excerpt,
next_excerpt,
excerpt_controls_before,
..
}) = &transform.block
else {
cursor.prev(&());
continue;
};

let next_buffer_row = if *starts_new_buffer { Some(end) } else { None };
let matches_start = if *excerpt_controls_before && prev_excerpt.is_some() {
start < top_row
} else {
start <= top_row
};

return prev_excerpt.as_ref().map(|excerpt| StickyHeaderExcerpt {
excerpt,
next_buffer_row,
next_excerpt_controls_present: *show_excerpt_controls,
});
}
Some(Block::FoldedBuffer {
prev_excerpt: Some(excerpt),
..
}) if top_row <= start => {
return Some(StickyHeaderExcerpt {
next_buffer_row: Some(end),
next_excerpt_controls_present: false,
excerpt,
});
}
Some(Block::FoldedBuffer { .. }) | Some(Block::Custom(_)) | None => {}
if !matches_start {
cursor.prev(&());
continue;
}

// This is needed to iterate past None / FoldedBuffer / Custom blocks. For FoldedBuffer,
// if scrolled slightly past the header of a folded block, the next block is needed for
// the sticky header.
let mut end = None;
cursor.next(&());
while let Some(transform) = cursor.item() {
match &transform.block {
Some(Block::FoldedBuffer {
excerpt_controls_before,
..
})
| Some(Block::ExcerptBoundary {
starts_new_buffer: true,
excerpt_controls_before,
..
}) => {
if *excerpt_controls_before {
end = Some(cursor.start().0 + 1);
} else {
end = Some(cursor.start().0);
}
break;
}
_ => {
cursor.next(&());
}
}
}
return next_excerpt.as_ref().map(|excerpt| StickyHeaderExcerpt {
max_row: end,
excerpt,
});
}

None
Expand Down Expand Up @@ -1753,10 +1770,10 @@ impl<'a> BlockChunks<'a> {
}
}

#[derive(Debug)]
pub struct StickyHeaderExcerpt<'a> {
pub excerpt: &'a ExcerptInfo,
pub next_excerpt_controls_present: bool,
pub next_buffer_row: Option<u32>,
pub max_row: Option<u32>,
}

impl<'a> Iterator for BlockChunks<'a> {
Expand Down Expand Up @@ -2993,7 +3010,7 @@ mod tests {
let mut block_map = BlockMap::new(wrap_snapshot.clone(), true, 2, 1, 1);
let blocks_snapshot = block_map.read(wrap_snapshot.clone(), Patch::default());

assert_eq!(blocks_snapshot.text(), "\n\n\n111\n");
assert_eq!(blocks_snapshot.text(), "\n\n111");

let mut writer = block_map.write(wrap_snapshot.clone(), Patch::default());
buffer.read_with(cx, |buffer, cx| {
Expand Down
31 changes: 11 additions & 20 deletions crates/editor/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2547,14 +2547,15 @@ impl EditorElement {
Block::FoldedBuffer {
first_excerpt,
prev_excerpt,
show_excerpt_controls,
excerpt_controls_before,
height,
..
} => {
let selected = selected_buffer_ids.contains(&first_excerpt.buffer_id);
let mut result = v_flex().id(block_id).w_full();

if let Some(prev_excerpt) = prev_excerpt {
if *show_excerpt_controls {
if *excerpt_controls_before {
result = result.child(self.render_expand_excerpt_control(
block_id,
ExpandExcerptDirection::Down,
Expand Down Expand Up @@ -2582,15 +2583,16 @@ impl EditorElement {
Block::ExcerptBoundary {
prev_excerpt,
next_excerpt,
show_excerpt_controls,
excerpt_controls_before,
excerpt_controls_after,
height,
starts_new_buffer,
} => {
let color = cx.theme().colors().clone();
let mut result = v_flex().id(block_id).w_full();

if let Some(prev_excerpt) = prev_excerpt {
if *show_excerpt_controls {
if *excerpt_controls_before {
result = result.child(self.render_expand_excerpt_control(
block_id,
ExpandExcerptDirection::Down,
Expand Down Expand Up @@ -2623,7 +2625,7 @@ impl EditorElement {
.child(div().h(FILE_HEADER_HEIGHT as f32 * window.line_height()));
}

if *show_excerpt_controls {
if *excerpt_controls_after {
result = result.child(self.render_expand_excerpt_control(
block_id,
ExpandExcerptDirection::Up,
Expand All @@ -2634,7 +2636,7 @@ impl EditorElement {
));
}
} else {
if *show_excerpt_controls {
if *excerpt_controls_after {
result = result.child(
h_flex()
.relative()
Expand Down Expand Up @@ -3162,11 +3164,7 @@ impl EditorElement {
#[allow(clippy::too_many_arguments)]
fn layout_sticky_buffer_header(
&self,
StickyHeaderExcerpt {
excerpt,
next_excerpt_controls_present,
next_buffer_row,
}: StickyHeaderExcerpt<'_>,
StickyHeaderExcerpt { excerpt, max_row }: StickyHeaderExcerpt<'_>,
scroll_position: f32,
line_height: Pixels,
snapshot: &EditorSnapshot,
Expand Down Expand Up @@ -3208,16 +3206,9 @@ impl EditorElement {

let mut origin = hitbox.origin;

if let Some(next_buffer_row) = next_buffer_row {
if let Some(max_row) = max_row {
// Push up the sticky header when the excerpt is getting close to the top of the viewport

let mut max_row = next_buffer_row - FILE_HEADER_HEIGHT * 2;

if next_excerpt_controls_present {
max_row -= MULTI_BUFFER_EXCERPT_HEADER_HEIGHT;
}

let offset = scroll_position - max_row as f32;
let offset = scroll_position - (max_row - FILE_HEADER_HEIGHT) as f32;

if offset > 0.0 {
origin.y -= Pixels(offset) * line_height;
Expand Down
1 change: 1 addition & 0 deletions crates/editor/src/movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,7 @@ mod tests {
let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));

assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
assert_eq!(snapshot.text(), "\nabc\ndefg\n\n\nhijkl\nmn");

let col_2_x = snapshot
.x_for_display_point(DisplayPoint::new(DisplayRow(2), 2), &text_layout_details);
Expand Down
Loading

0 comments on commit 3ea0cd7

Please sign in to comment.