From e202981f0caf06b4fe1d6b1c0c19a911f538b15c Mon Sep 17 00:00:00 2001 From: Evan Simkowitz Date: Thu, 19 Jun 2025 04:24:06 -0700 Subject: [PATCH] editor: Scale minimap width to editor width (#32317) --- assets/settings/default.json | 4 +- crates/editor/src/editor_settings.rs | 14 ++++++ crates/editor/src/element.rs | 74 ++++++++++++++++++++-------- 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 4ad39e0977..ecf8b896c4 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -435,7 +435,9 @@ // 1. `null` to inherit the editor `current_line_highlight` setting (default) // 2. "line" or "all" to highlight the current line in the minimap. // 3. "gutter" or "none" to not highlight the current line in the minimap. - "current_line_highlight": null + "current_line_highlight": null, + // Maximum number of columns to display in the minimap. + "max_width_columns": 80 }, // Enable middle-click paste on Linux. "middle_click_paste": true, diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 68f4c2afb8..f2cb41793c 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -1,3 +1,6 @@ +use core::num; +use std::num::NonZeroU32; + use gpui::App; use language::CursorShape; use project::project_settings::DiagnosticSeverity; @@ -150,6 +153,7 @@ pub struct Minimap { pub thumb: MinimapThumb, pub thumb_border: MinimapThumbBorder, pub current_line_highlight: Option, + pub max_width_columns: num::NonZeroU32, } impl Minimap { @@ -632,6 +636,11 @@ pub struct MinimapContent { /// /// Default: inherits editor line highlights setting pub current_line_highlight: Option>, + + /// Maximum number of columns to display in the minimap. + /// + /// Default: 80 + pub max_width_columns: Option, } /// Forcefully enable or disable the scrollbar for each axis @@ -854,6 +863,8 @@ impl Settings for EditorSettings { let mut minimap = MinimapContent::default(); let minimap_enabled = vscode.read_bool("editor.minimap.enabled").unwrap_or(true); let autohide = vscode.read_bool("editor.minimap.autohide"); + let mut max_width_columns: Option = None; + vscode.u32_setting("editor.minimap.maxColumn", &mut max_width_columns); if minimap_enabled { if let Some(false) = autohide { minimap.show = Some(ShowMinimap::Always); @@ -863,6 +874,9 @@ impl Settings for EditorSettings { } else { minimap.show = Some(ShowMinimap::Never); } + if let Some(max_width_columns) = max_width_columns { + minimap.max_width_columns = NonZeroU32::new(max_width_columns); + } vscode.enum_setting( "editor.minimap.showSlider", diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 429b1a6739..afefc32e4a 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -16,9 +16,9 @@ use crate::{ HighlightedChunk, ToDisplayPoint, }, editor_settings::{ - CurrentLineHighlight, DocumentColorsRenderMode, DoubleClickInMultibuffer, MinimapThumb, - MinimapThumbBorder, ScrollBeyondLastLine, ScrollbarAxes, ScrollbarDiagnostics, ShowMinimap, - ShowScrollbar, + CurrentLineHighlight, DocumentColorsRenderMode, DoubleClickInMultibuffer, Minimap, + MinimapThumb, MinimapThumbBorder, ScrollBeyondLastLine, ScrollbarAxes, + ScrollbarDiagnostics, ShowMinimap, ShowScrollbar, }, git::blame::{BlameRenderer, GitBlame, GlobalBlameRenderer}, hover_popover::{ @@ -1908,6 +1908,40 @@ impl EditorElement { text_style.line_height_in_pixels(rem_size) } + fn get_minimap_width( + &self, + minimap_settings: &Minimap, + scrollbars_shown: bool, + text_width: Pixels, + em_width: Pixels, + font_size: Pixels, + rem_size: Pixels, + cx: &App, + ) -> Option { + if minimap_settings.show == ShowMinimap::Auto && !scrollbars_shown { + return None; + } + + let minimap_font_size = self.editor.read_with(cx, |editor, cx| { + editor.minimap().map(|minimap_editor| { + minimap_editor + .read(cx) + .text_style_refinement + .as_ref() + .and_then(|refinement| refinement.font_size) + .unwrap_or(MINIMAP_FONT_SIZE) + }) + })?; + + let minimap_em_width = em_width * (minimap_font_size.to_pixels(rem_size) / font_size); + + let minimap_width = (text_width * MinimapLayout::MINIMAP_WIDTH_PCT) + .min(minimap_em_width * minimap_settings.max_width_columns.get() as f32); + + (minimap_width >= minimap_em_width * MinimapLayout::MINIMAP_MIN_WIDTH_COLUMNS) + .then_some(minimap_width) + } + fn prepaint_crease_toggles( &self, crease_toggles: &mut [Option], @@ -7829,9 +7863,10 @@ impl Element for EditorElement { }); let style = self.style.clone(); + let rem_size = window.rem_size(); let font_id = window.text_system().resolve_font(&style.text.font()); - let font_size = style.text.font_size.to_pixels(window.rem_size()); - let line_height = style.text.line_height_in_pixels(window.rem_size()); + let font_size = style.text.font_size.to_pixels(rem_size); + let line_height = style.text.line_height_in_pixels(rem_size); let em_width = window.text_system().em_width(font_id, font_size).unwrap(); let em_advance = window.text_system().em_advance(font_id, font_size).unwrap(); let glyph_grid_cell = size(em_advance, line_height); @@ -7859,27 +7894,21 @@ impl Element for EditorElement { .then_some(style.scrollbar_width) .unwrap_or_default(); let minimap_width = self - .editor - .read(cx) - .minimap() - .is_some() - .then(|| match settings.minimap.show { - ShowMinimap::Auto => { - scrollbars_shown.then_some(MinimapLayout::MINIMAP_WIDTH) - } - _ => Some(MinimapLayout::MINIMAP_WIDTH), - }) - .flatten() - .filter(|minimap_width| { - text_width - vertical_scrollbar_width - *minimap_width > *minimap_width - }) + .get_minimap_width( + &settings.minimap, + scrollbars_shown, + text_width, + em_width, + font_size, + rem_size, + cx, + ) .unwrap_or_default(); let right_margin = minimap_width + vertical_scrollbar_width; let editor_width = text_width - gutter_dimensions.margin - 2 * em_width - right_margin; - let editor_margins = EditorMargins { gutter: gutter_dimensions, right: right_margin, @@ -9474,7 +9503,10 @@ struct MinimapLayout { } impl MinimapLayout { - const MINIMAP_WIDTH: Pixels = px(100.); + /// The minimum width of the minimap in columns. If the minimap is smaller than this, it will be hidden. + const MINIMAP_MIN_WIDTH_COLUMNS: f32 = 20.; + /// The minimap width as a percentage of the editor width. + const MINIMAP_WIDTH_PCT: f32 = 0.15; /// Calculates the scroll top offset the minimap editor has to have based on the /// current scroll progress. fn calculate_minimap_top_offset(