From 5210d9e8b4947a6769bbf928d612eb4b42d4d562 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 17 Mar 2025 22:26:27 -0600 Subject: [PATCH] Tidier multibuffer (#26954) Makes multibuffer headers less close to the top of the file. Moves multibuffer line numbers one em to the right to make space for the expand excerpt button on large line numbers. Release Notes: - N/A --------- Co-authored-by: Danilo Leal --- crates/editor/src/editor.rs | 15 +++++++--- crates/editor/src/element.rs | 54 ++++++++++++++++++++++-------------- 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index b4efca5779e4c829c2a42fe98e1d1b2880fc8acc..dfcdf109e61764d8ce8c2e7bf24a1cc451ae9e31 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -211,6 +211,7 @@ pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration: pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction"; pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict"; +pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4; const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers { alt: true, @@ -17618,7 +17619,7 @@ impl EditorSnapshot { .unwrap_or(gutter_settings.line_numbers); let line_gutter_width = if show_line_numbers { // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines. - let min_width_for_number_on_gutter = em_advance * 4.0; + let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32; max_line_number_width.max(min_width_for_number_on_gutter) } else { 0.0.into() @@ -17647,8 +17648,12 @@ impl EditorSnapshot { em_advance * max_char_count }); + let is_singleton = self.buffer_snapshot.is_singleton(); + let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO); - left_padding += if show_code_actions || show_runnables { + left_padding += if !is_singleton { + em_width * 4.0 + } else if show_code_actions || show_runnables { em_width * 3.0 } else if show_git_gutter && show_line_numbers { em_width * 2.0 @@ -17658,9 +17663,11 @@ impl EditorSnapshot { px(0.) }; - let right_padding = if gutter_settings.folds && show_line_numbers { + let shows_folds = is_singleton && gutter_settings.folds; + + let right_padding = if shows_folds && show_line_numbers { em_width * 4.0 - } else if gutter_settings.folds { + } else if shows_folds || (!is_singleton && show_line_numbers) { em_width * 3.0 } else if show_line_numbers { em_width diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 2ae8fc5cb25610afd014ac00bba7fd6775bc8637..9abdaca114cd5b6ed83097100658d0717261081c 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -23,7 +23,7 @@ use crate::{ InlineCompletion, JumpData, LineDown, LineHighlight, LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, SelectedTextHighlight, Selection, SoftWrap, StickyHeaderExcerpt, ToPoint, ToggleFold, COLUMNAR_SELECTION_MODIFIERS, CURSORS_VISIBLE_FOR, - FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, + FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MIN_LINE_NUMBER_DIGITS, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, }; use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind}; @@ -2119,9 +2119,11 @@ impl EditorElement { }) } - fn layout_excerpt_gutter( + fn layout_expand_toggles( &self, gutter_hitbox: &Hitbox, + gutter_dimensions: GutterDimensions, + em_width: Pixels, line_height: Pixels, scroll_position: gpui::Point, buffer_rows: &[RowInfo], @@ -2130,19 +2132,17 @@ impl EditorElement { ) -> Vec)>> { let editor_font_size = self.style.text.font_size.to_pixels(window.rem_size()) * 1.2; - let icon_size = editor_font_size.round(); - let button_h_padding = ((icon_size - px(1.0)) / 2.0).round() - px(2.0); - let scroll_top = scroll_position.y * line_height; - let max_line_number_length = 1 + self + let max_line_number_length = self .editor .read(cx) .buffer() .read(cx) .snapshot(cx) .widest_line_number() - .ilog10(); + .ilog10() + + 1; let elements = buffer_rows .into_iter() @@ -2159,20 +2159,27 @@ impl EditorElement { ExpandExcerptDirection::UpAndDown => IconName::ExpandVertical, }; + let git_gutter_width = Self::gutter_strip_width(line_height); + let available_width = gutter_dimensions.left_padding - git_gutter_width; + let editor = self.editor.clone(); - let is_wide = max_line_number_length > 3 + let is_wide = max_line_number_length >= MIN_LINE_NUMBER_DIGITS && row_info .buffer_row - .is_some_and(|row| (row + 1).ilog10() + 1 == max_line_number_length); + .is_some_and(|row| (row + 1).ilog10() + 1 == max_line_number_length) + || gutter_dimensions.right_padding == px(0.); + + let width = if is_wide { + available_width - px(2.) + } else { + available_width + em_width - px(2.) + }; let toggle = IconButton::new(("expand", ix), icon_name) .icon_color(Color::Custom(cx.theme().colors().editor_line_number)) .selected_icon_color(Color::Custom(cx.theme().colors().editor_foreground)) .icon_size(IconSize::Custom(rems(editor_font_size / window.rem_size()))) - .width((icon_size + button_h_padding * 2).into()) - .when(is_wide, |el| { - el.width((icon_size + button_h_padding).into()) - }) + .width(width.into()) .on_click(move |_, _, cx| { editor.update(cx, |editor, cx| { editor.expand_excerpt(excerpt_id, direction, cx); @@ -2185,7 +2192,7 @@ impl EditorElement { .into_any_element(); let position = point( - px(1.), + git_gutter_width + px(1.), ix as f32 * line_height - (scroll_top % line_height) + px(1.), ); let origin = gutter_hitbox.origin + position; @@ -2709,7 +2716,7 @@ impl EditorElement { for_excerpt: &ExcerptInfo, is_folded: bool, is_selected: bool, - _is_sticky: bool, + is_sticky: bool, jump_data: JumpData, window: &mut Window, cx: &mut App, @@ -2744,8 +2751,7 @@ impl EditorElement { let colors = cx.theme().colors(); div() - .px_2() - .pt_2() + .p_1() .w_full() .h(FILE_HEADER_HEIGHT as f32 * window.line_height()) .child( @@ -2756,7 +2762,7 @@ impl EditorElement { .pl_0p5() .pr_5() .rounded_sm() - // .when(is_sticky, |el| el.shadow_md()) + .when(is_sticky, |el| el.shadow_md()) .border_1() .map(|div| { let border_color = if is_selected @@ -2784,7 +2790,7 @@ impl EditorElement { ButtonLike::new("toggle-buffer-fold") .style(ui::ButtonStyle::Transparent) .size(ButtonSize::Large) - .width(px(30.).into()) + .width(px(24.).into()) .children(toggle_chevron_icon) .tooltip({ let focus_handle = focus_handle.clone(); @@ -4413,6 +4419,10 @@ impl EditorElement { }); } + fn gutter_strip_width(line_height: Pixels) -> Pixels { + (0.275 * line_height).floor() + } + fn diff_hunk_bounds( snapshot: &EditorSnapshot, line_height: Pixels, @@ -4421,7 +4431,7 @@ impl EditorElement { ) -> Bounds { let scroll_position = snapshot.scroll_position(); let scroll_top = scroll_position.y * line_height; - let gutter_strip_width = (0.275 * line_height).floor(); + let gutter_strip_width = Self::gutter_strip_width(line_height); match hunk { DisplayDiffHunk::Folded { display_row, .. } => { @@ -6887,8 +6897,10 @@ impl Element for EditorElement { let mut expand_toggles = window.with_element_namespace("expand_toggles", |window| { - self.layout_excerpt_gutter( + self.layout_expand_toggles( &gutter_hitbox, + gutter_dimensions, + em_width, line_height, scroll_position, &row_infos,