From 09ace088ac574124a260215bc5c4695566766784 Mon Sep 17 00:00:00 2001 From: Finn Evers Date: Sun, 11 May 2025 17:54:57 +0200 Subject: [PATCH] editor: Prevent vertical scrollbar from overlapping with buffer headers (#30477) Closes #16993 This PR fixes an issue where the vertical editor scrollbar was overlaying with buffer headers. I fixed this by reserving space for the scrollbar as needed which is provided by the recently introduced `right_margin`. Most of the diff consists of moving the `EditorMargins` creation out of `render_block`, as the right margin is stored in this struct and moving this out reduces the length of the parameter list of `render_blocks` by one. I thought of this to be a small but nice side effect. When it comes to the dividers, I decided against these considering the margin as well, since it felt a bit off. However, I can see arguments for these also considering the margins. I did include an image for comparison in the list below. Happy to change this should it be preferred the other way around. | `main` | ![main](https://github.com/user-attachments/assets/1148a553-cf66-4ef7-b81a-9595e9b42308) | | --- | --- | | PR | ![PR](https://github.com/user-attachments/assets/811c8385-0596-427f-8d09-f800cc8d7285) | | Fix with shortened divider | ![pr_line_shortened](https://github.com/user-attachments/assets/9938e27f-17a5-460f-99cf-47d1fab234ed) | Release Notes: - Ensured that the vertical editor scrollbar no longer overlaps with buffer headers. --- crates/editor/src/element.rs | 63 ++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 58c9b41434108fd92dad872d3b3154aabd67927c..df77ee0f5047c8848656c7750ec07e26567da996 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -2882,8 +2882,7 @@ impl EditorElement { text_x: Pixels, rows: &Range, line_layouts: &[LineWithInvisibles], - gutter_dimensions: &GutterDimensions, - right_margin: Pixels, + editor_margins: &EditorMargins, line_height: Pixels, em_width: Pixels, text_hitbox: &Hitbox, @@ -2943,11 +2942,6 @@ impl EditorElement { }) .is_ok(); - let margins = EditorMargins { - gutter: *gutter_dimensions, - right: right_margin, - }; - div() .size_full() .children( @@ -2956,7 +2950,7 @@ impl EditorElement { window, app: cx, anchor_x, - margins: &margins, + margins: editor_margins, line_height, em_width, block_id, @@ -2975,7 +2969,7 @@ impl EditorElement { .. } => { let selected = selected_buffer_ids.contains(&first_excerpt.buffer_id); - let result = v_flex().id(block_id).w_full(); + let result = v_flex().id(block_id).w_full().pr(editor_margins.right); let jump_data = header_jump_data(snapshot, block_row_start, *height, first_excerpt); result @@ -3006,8 +3000,10 @@ impl EditorElement { if sticky_header_excerpt_id != Some(excerpt.id) { let selected = selected_buffer_ids.contains(&excerpt.buffer_id); - result = result.child(self.render_buffer_header( - excerpt, false, selected, false, jump_data, window, cx, + result = result.child(div().pr(editor_margins.right).child( + self.render_buffer_header( + excerpt, false, selected, false, jump_data, window, cx, + ), )); } else { result = @@ -3054,7 +3050,7 @@ impl EditorElement { if let Some((x_target, line_width)) = x_position { let margin = em_width * 2; if line_width + final_size.width + margin - < editor_width + gutter_dimensions.full_width() + < editor_width + editor_margins.gutter.full_width() && !row_block_types.contains_key(&(row - 1)) && element_height_in_lines == 1 { @@ -3064,10 +3060,10 @@ impl EditorElement { element_height_in_lines = 0; row_block_types.insert(row, is_block); } else { - let max_offset = - editor_width + gutter_dimensions.full_width() - final_size.width; + let max_offset = editor_width + editor_margins.gutter.full_width() + - final_size.width; let min_offset = (x_target + em_width - final_size.width) - .max(gutter_dimensions.full_width()); + .max(editor_margins.gutter.full_width()); x_offset = x_target.min(max_offset).max(min_offset); } } @@ -3283,8 +3279,7 @@ impl EditorElement { text_hitbox: &Hitbox, editor_width: Pixels, scroll_width: &mut Pixels, - gutter_dimensions: &GutterDimensions, - right_margin: Pixels, + editor_margins: &EditorMargins, em_width: Pixels, text_x: Pixels, line_height: Pixels, @@ -3324,8 +3319,7 @@ impl EditorElement { text_x, &rows, line_layouts, - gutter_dimensions, - right_margin, + editor_margins, line_height, em_width, text_hitbox, @@ -3363,7 +3357,7 @@ impl EditorElement { .size .width .max(fixed_block_max_width) - .max(gutter_dimensions.width + *scroll_width) + .max(editor_margins.gutter.width + *scroll_width) .into(), (BlockStyle::Fixed, _) => unreachable!(), }; @@ -3382,8 +3376,7 @@ impl EditorElement { text_x, &rows, line_layouts, - gutter_dimensions, - right_margin, + editor_margins, line_height, em_width, text_hitbox, @@ -3423,7 +3416,7 @@ impl EditorElement { .size .width .max(fixed_block_max_width) - .max(gutter_dimensions.width + *scroll_width), + .max(editor_margins.gutter.width + *scroll_width), ), BlockStyle::Sticky => AvailableSpace::Definite(hitbox.size.width), }; @@ -3437,8 +3430,7 @@ impl EditorElement { text_x, &rows, line_layouts, - gutter_dimensions, - right_margin, + editor_margins, line_height, em_width, text_hitbox, @@ -3470,7 +3462,8 @@ impl EditorElement { } if resized_blocks.is_empty() { - *scroll_width = (*scroll_width).max(fixed_block_max_width - gutter_dimensions.width); + *scroll_width = + (*scroll_width).max(fixed_block_max_width - editor_margins.gutter.width); Ok((blocks, row_block_types)) } else { Err(resized_blocks) @@ -3523,6 +3516,7 @@ impl EditorElement { StickyHeaderExcerpt { excerpt }: StickyHeaderExcerpt<'_>, scroll_position: f32, line_height: Pixels, + right_margin: Pixels, snapshot: &EditorSnapshot, hitbox: &Hitbox, selected_buffer_ids: &Vec, @@ -3541,11 +3535,13 @@ impl EditorElement { let selected = selected_buffer_ids.contains(&excerpt.buffer_id); + let available_width = hitbox.bounds.size.width - right_margin; + let mut header = v_flex() .relative() .child( div() - .w(hitbox.bounds.size.width) + .w(available_width) .h(FILE_HEADER_HEIGHT as f32 * line_height) .bg(linear_gradient( 0., @@ -3582,7 +3578,7 @@ impl EditorElement { } let size = size( - AvailableSpace::Definite(hitbox.size.width), + AvailableSpace::Definite(available_width), AvailableSpace::MinContent, ); @@ -7177,9 +7173,14 @@ impl Element for EditorElement { let editor_width = text_width - gutter_dimensions.margin - 2 * em_width - right_margin; + let editor_margins = EditorMargins { + gutter: gutter_dimensions, + right: right_margin, + }; + // Offset the content_bounds from the text_bounds by the gutter margin (which // is roughly half a character wide) to make hit testing work more like how we want. - let content_offset = point(gutter_dimensions.margin, Pixels::ZERO); + let content_offset = point(editor_margins.gutter.margin, Pixels::ZERO); let editor_content_width = editor_width - content_offset.x; @@ -7635,8 +7636,7 @@ impl Element for EditorElement { &text_hitbox, editor_width, &mut scroll_width, - &gutter_dimensions, - right_margin, + &editor_margins, em_width, gutter_dimensions.full_width(), line_height, @@ -7665,6 +7665,7 @@ impl Element for EditorElement { sticky_header_excerpt, scroll_position.y, line_height, + right_margin, &snapshot, &hitbox, &selected_buffer_ids,