editor: Add minimap (#26893)

## Overview

This PR adds the minimap feature to the Zed editor, closely following
the [design from Visual Studio
Code](https://code.visualstudio.com/docs/getstarted/userinterface#_minimap).
When configured, a second instance of the editor will appear to the left
of the scrollbar. This instance is not interactive and it has a slimmed
down set of annotations, but it is otherwise just a zoomed-out version
of the main editor instance. A thumb shows the line boundaries of the
main viewport, as well as the progress through the document. Clicking on
a section of code in the minimap will jump the editor to that code.
Dragging the thumb will act like the scrollbar, moving sequentially
through the document.

![screenshot of Zed with three editors open and the minimap enabled,
showing the
slider](https://github.com/user-attachments/assets/4178d23a-a5ea-4e38-b871-06dd2a8f9560)

## New settings

This adds a `minimap` section to the editor settings with the following
keys:

### `show`

When to show the minimap in the editor.
This setting can take three values:
1. Show the minimap if the editor's scrollbar is visible: `"auto"`
2. Always show the minimap: `"always"`
3. Never show the minimap: `"never"` (default)

### `thumb`

When to show the minimap thumb.
This setting can take two values:
1. Show the minimap thumb if the mouse is over the minimap: `"hover"`
2. Always show the minimap thumb: `"always"` (default)

### `width`

The width of the minimap in pixels.

Default: `100`

### `font_size`

The font size of the minimap in pixels.

Default: `2`

## Providing feedback

In order to keep the PR focused on development updates, please use the
discussion thread for feature suggestions and usability feedback: #26894


## Features left to add

- [x] fix scrolling performance
- [x] user settings for enable/disable, width, text size, etc.
- [x] show overview of visible lines in minimap
- [x] clicking on minimap should navigate to the corresponding section
of code
- ~[ ] more prominent highlighting in the minimap editor~
- ~[ ] override scrollbar auto setting to always when minimap is set to
always show~

Release Notes:

- Added minimap for high-level overview and quick navigation of editor
contents.

---------

Co-authored-by: MrSubidubi <dev@bahn.sh>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
Evan Simkowitz 2025-05-07 13:11:09 -07:00 committed by GitHub
parent 902931fdfc
commit 607a9445fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 1083 additions and 216 deletions

View file

@ -31,7 +31,7 @@ use crate::{
};
pub use block_map::{
Block, BlockChunks as DisplayChunks, BlockContext, BlockId, BlockMap, BlockPlacement,
BlockPoint, BlockProperties, BlockRows, BlockStyle, CustomBlockId, RenderBlock,
BlockPoint, BlockProperties, BlockRows, BlockStyle, CustomBlockId, EditorMargins, RenderBlock,
StickyHeaderExcerpt,
};
use block_map::{BlockRow, BlockSnapshot};
@ -258,6 +258,7 @@ impl DisplayMap {
height: Some(height),
style,
priority,
render_in_minimap: true,
}
}),
);
@ -950,16 +951,17 @@ impl DisplaySnapshot {
diagnostic_highlight.fade_out = Some(editor_style.unnecessary_code_fade);
}
if let Some(severity) = chunk.diagnostic_severity {
// Omit underlines for HINT/INFO diagnostics on 'unnecessary' code.
if severity <= DiagnosticSeverity::WARNING || !chunk.is_unnecessary {
let diagnostic_color = super::diagnostic_style(severity, &editor_style.status);
diagnostic_highlight.underline = Some(UnderlineStyle {
color: Some(diagnostic_color),
thickness: 1.0.into(),
wavy: true,
});
}
// Omit underlines for HINT/INFO diagnostics on 'unnecessary' code.
if let Some(severity) = chunk.diagnostic_severity.filter(|severity| {
editor_style.show_underlines
&& (!chunk.is_unnecessary || *severity <= DiagnosticSeverity::WARNING)
}) {
let diagnostic_color = super::diagnostic_style(severity, &editor_style.status);
diagnostic_highlight.underline = Some(UnderlineStyle {
color: Some(diagnostic_color),
thickness: 1.0.into(),
wavy: true,
});
}
if let Some(highlight_style) = highlight_style.as_mut() {
@ -1613,6 +1615,7 @@ pub mod tests {
height: Some(height),
render: Arc::new(|_| div().into_any()),
priority,
render_in_minimap: true,
}
})
.collect::<Vec<_>>();
@ -1975,6 +1978,7 @@ pub mod tests {
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}],
cx,
);
@ -2170,6 +2174,7 @@ pub mod tests {
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
placement: BlockPlacement::Below(
@ -2179,6 +2184,7 @@ pub mod tests {
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
],
cx,
@ -2284,6 +2290,7 @@ pub mod tests {
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}],
cx,
)
@ -2358,6 +2365,7 @@ pub mod tests {
style: BlockStyle::Fixed,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}],
cx,
);