Scrollbar markers enhancements (#9080)

Several improvements in how various markers are displayed in the editor
scrollbar, as described in #9070, if you're ok with the proposal:
- Scrollbar has three columns:
  - 1st is for git markers
  - 2nd is for selections and search resulta highlightings
  - 3rd is for diagnostics
- Height of all markers is scaled, but there's a minimal allowed height
of 2px.
- Right border removed from both the scrollbar and thumb to make more
room for markers.

Release Notes:

- Improved scrollbar markers visualization (#9070).
This commit is contained in:
Andrew Lygin 2024-03-14 00:05:43 +03:00 committed by GitHub
parent b65aa7e2a7
commit 6ae5274954
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -2167,12 +2167,16 @@ impl EditorElement {
top: Pixels::ZERO, top: Pixels::ZERO,
right: Pixels::ZERO, right: Pixels::ZERO,
bottom: Pixels::ZERO, bottom: Pixels::ZERO,
left: px(1.), left: ScrollbarLayout::BORDER_WIDTH,
}, },
cx.theme().colors().scrollbar_track_border, cx.theme().colors().scrollbar_track_border,
)); ));
let scrollbar_settings = EditorSettings::get_global(cx).scrollbar; let scrollbar_settings = EditorSettings::get_global(cx).scrollbar;
let is_singleton = self.editor.read(cx).is_singleton(cx); let is_singleton = self.editor.read(cx).is_singleton(cx);
let left = scrollbar_layout.hitbox.left();
let right = scrollbar_layout.hitbox.right();
let column_width =
px(((right - left - ScrollbarLayout::BORDER_WIDTH).0 / 3.0).floor());
if is_singleton && scrollbar_settings.selections { if is_singleton && scrollbar_settings.selections {
let start_anchor = Anchor::min(); let start_anchor = Anchor::min();
let end_anchor = Anchor::max(); let end_anchor = Anchor::max();
@ -2184,26 +2188,18 @@ impl EditorElement {
&layout.position_map.snapshot, &layout.position_map.snapshot,
50000, 50000,
); );
let left_x = left + ScrollbarLayout::BORDER_WIDTH + column_width;
let right_x = left_x + column_width;
for range in background_ranges { for range in background_ranges {
let start_y = scrollbar_layout.y_for_row(range.start().row() as f32); let (start_y, end_y) =
let mut end_y = scrollbar_layout.y_for_row(range.end().row() as f32); scrollbar_layout.ys_for_marker(range.start().row(), range.end().row());
if end_y - start_y < px(1.) { let bounds =
end_y = start_y + px(1.); Bounds::from_corners(point(left_x, start_y), point(right_x, end_y));
}
let bounds = Bounds::from_corners(
point(scrollbar_layout.hitbox.left(), start_y),
point(scrollbar_layout.hitbox.right(), end_y),
);
cx.paint_quad(quad( cx.paint_quad(quad(
bounds, bounds,
Corners::default(), Corners::default(),
cx.theme().status().info, cx.theme().status().info,
Edges { Edges::default(),
top: Pixels::ZERO,
right: px(1.),
bottom: Pixels::ZERO,
left: px(1.),
},
cx.theme().colors().scrollbar_thumb_border, cx.theme().colors().scrollbar_thumb_border,
)); ));
} }
@ -2215,68 +2211,49 @@ impl EditorElement {
&layout.position_map.snapshot, &layout.position_map.snapshot,
cx.theme().colors(), cx.theme().colors(),
); );
let left_x = left + ScrollbarLayout::BORDER_WIDTH + column_width;
let right_x = left_x + column_width;
for hunk in selection_ranges { for hunk in selection_ranges {
let start_display = Point::new(hunk.0.start.row(), 0) let start_display = Point::new(hunk.0.start.row(), 0)
.to_display_point(&layout.position_map.snapshot.display_snapshot); .to_display_point(&layout.position_map.snapshot.display_snapshot);
let end_display = Point::new(hunk.0.end.row(), 0) let end_display = Point::new(hunk.0.end.row(), 0)
.to_display_point(&layout.position_map.snapshot.display_snapshot); .to_display_point(&layout.position_map.snapshot.display_snapshot);
let start_y = scrollbar_layout.y_for_row(start_display.row() as f32); let (start_y, end_y) =
let mut end_y = if hunk.0.start == hunk.0.end { scrollbar_layout.ys_for_marker(start_display.row(), end_display.row());
scrollbar_layout.y_for_row((end_display.row() + 1) as f32) let bounds =
} else { Bounds::from_corners(point(left_x, start_y), point(right_x, end_y));
scrollbar_layout.y_for_row(end_display.row() as f32)
};
if end_y - start_y < px(1.) {
end_y = start_y + px(1.);
}
let bounds = Bounds::from_corners(
point(scrollbar_layout.hitbox.left(), start_y),
point(scrollbar_layout.hitbox.right(), end_y),
);
cx.paint_quad(quad( cx.paint_quad(quad(
bounds, bounds,
Corners::default(), Corners::default(),
cx.theme().status().info, cx.theme().status().info,
Edges { Edges::default(),
top: Pixels::ZERO,
right: px(1.),
bottom: Pixels::ZERO,
left: px(1.),
},
cx.theme().colors().scrollbar_thumb_border, cx.theme().colors().scrollbar_thumb_border,
)); ));
} }
} }
if is_singleton && scrollbar_settings.git_diff { if is_singleton && scrollbar_settings.git_diff {
let left_x = left + ScrollbarLayout::BORDER_WIDTH;
let right_x = left_x + column_width;
for hunk in layout for hunk in layout
.position_map .position_map
.snapshot .snapshot
.buffer_snapshot .buffer_snapshot
.git_diff_hunks_in_range(0..layout.max_row) .git_diff_hunks_in_range(0..layout.max_row)
{ {
let start_display = Point::new(hunk.associated_range.start, 0) let start_display_row = Point::new(hunk.associated_range.start, 0)
.to_display_point(&layout.position_map.snapshot.display_snapshot); .to_display_point(&layout.position_map.snapshot.display_snapshot)
let end_display = Point::new(hunk.associated_range.end, 0) .row();
.to_display_point(&layout.position_map.snapshot.display_snapshot); let mut end_display_row = Point::new(hunk.associated_range.end, 0)
let start_y = scrollbar_layout.y_for_row(start_display.row() as f32); .to_display_point(&layout.position_map.snapshot.display_snapshot)
let mut end_y = if hunk.associated_range.start == hunk.associated_range.end .row();
{ if end_display_row != start_display_row {
scrollbar_layout.y_for_row((end_display.row() + 1) as f32) end_display_row -= 1;
} else {
scrollbar_layout.y_for_row(end_display.row() as f32)
};
if end_y - start_y < px(1.) {
end_y = start_y + px(1.);
} }
let bounds = Bounds::from_corners( let (start_y, end_y) =
point(scrollbar_layout.hitbox.left(), start_y), scrollbar_layout.ys_for_marker(start_display_row, end_display_row);
point(scrollbar_layout.hitbox.right(), end_y), let bounds =
); Bounds::from_corners(point(left_x, start_y), point(right_x, end_y));
let color = match hunk.status() { let color = match hunk.status() {
DiffHunkStatus::Added => cx.theme().status().created, DiffHunkStatus::Added => cx.theme().status().created,
DiffHunkStatus::Modified => cx.theme().status().modified, DiffHunkStatus::Modified => cx.theme().status().modified,
@ -2286,12 +2263,7 @@ impl EditorElement {
bounds, bounds,
Corners::default(), Corners::default(),
color, color,
Edges { Edges::default(),
top: Pixels::ZERO,
right: px(1.),
bottom: Pixels::ZERO,
left: px(1.),
},
cx.theme().colors().scrollbar_thumb_border, cx.theme().colors().scrollbar_thumb_border,
)); ));
} }
@ -2315,6 +2287,7 @@ impl EditorElement {
std::cmp::Reverse(diagnostic.diagnostic.severity) std::cmp::Reverse(diagnostic.diagnostic.severity)
}); });
let left_x = left + ScrollbarLayout::BORDER_WIDTH + 2.0 * column_width;
for diagnostic in diagnostics { for diagnostic in diagnostics {
let start_display = diagnostic let start_display = diagnostic
.range .range
@ -2324,21 +2297,10 @@ impl EditorElement {
.range .range
.end .end
.to_display_point(&layout.position_map.snapshot.display_snapshot); .to_display_point(&layout.position_map.snapshot.display_snapshot);
let start_y = scrollbar_layout.y_for_row(start_display.row() as f32); let (start_y, end_y) =
let mut end_y = if diagnostic.range.start == diagnostic.range.end { scrollbar_layout.ys_for_marker(start_display.row(), end_display.row());
scrollbar_layout.y_for_row((end_display.row() + 1) as f32) let bounds =
} else { Bounds::from_corners(point(left_x, start_y), point(right, end_y));
scrollbar_layout.y_for_row(end_display.row() as f32)
};
if end_y - start_y < px(1.) {
end_y = start_y + px(1.);
}
let bounds = Bounds::from_corners(
point(scrollbar_layout.hitbox.left(), start_y),
point(scrollbar_layout.hitbox.right(), end_y),
);
let color = match diagnostic.diagnostic.severity { let color = match diagnostic.diagnostic.severity {
DiagnosticSeverity::ERROR => cx.theme().status().error, DiagnosticSeverity::ERROR => cx.theme().status().error,
DiagnosticSeverity::WARNING => cx.theme().status().warning, DiagnosticSeverity::WARNING => cx.theme().status().warning,
@ -2349,12 +2311,7 @@ impl EditorElement {
bounds, bounds,
Corners::default(), Corners::default(),
color, color,
Edges { Edges::default(),
top: Pixels::ZERO,
right: px(1.),
bottom: Pixels::ZERO,
left: px(1.),
},
cx.theme().colors().scrollbar_thumb_border, cx.theme().colors().scrollbar_thumb_border,
)); ));
} }
@ -2366,9 +2323,9 @@ impl EditorElement {
cx.theme().colors().scrollbar_thumb_background, cx.theme().colors().scrollbar_thumb_background,
Edges { Edges {
top: Pixels::ZERO, top: Pixels::ZERO,
right: px(1.), right: Pixels::ZERO,
bottom: Pixels::ZERO, bottom: Pixels::ZERO,
left: px(1.), left: ScrollbarLayout::BORDER_WIDTH,
}, },
cx.theme().colors().scrollbar_thumb_border, cx.theme().colors().scrollbar_thumb_border,
)); ));
@ -3466,6 +3423,9 @@ struct ScrollbarLayout {
} }
impl ScrollbarLayout { impl ScrollbarLayout {
const BORDER_WIDTH: Pixels = px(1.0);
const MIN_MARKER_HEIGHT: Pixels = px(2.0);
fn thumb_bounds(&self) -> Bounds<Pixels> { fn thumb_bounds(&self) -> Bounds<Pixels> {
let thumb_top = self.y_for_row(self.visible_row_range.start) - self.first_row_y_offset; let thumb_top = self.y_for_row(self.visible_row_range.start) - self.first_row_y_offset;
let thumb_bottom = self.y_for_row(self.visible_row_range.end) + self.first_row_y_offset; let thumb_bottom = self.y_for_row(self.visible_row_range.end) + self.first_row_y_offset;
@ -3478,6 +3438,15 @@ impl ScrollbarLayout {
fn y_for_row(&self, row: f32) -> Pixels { fn y_for_row(&self, row: f32) -> Pixels {
self.hitbox.top() + self.first_row_y_offset + row * self.row_height self.hitbox.top() + self.first_row_y_offset + row * self.row_height
} }
fn ys_for_marker(&self, start_row: u32, end_row: u32) -> (Pixels, Pixels) {
let start_y = self.y_for_row(start_row as f32);
let mut end_y = self.y_for_row((end_row + 1) as f32);
if end_y - start_y < Self::MIN_MARKER_HEIGHT {
end_y = start_y + Self::MIN_MARKER_HEIGHT;
}
(start_y, end_y)
}
} }
struct FoldLayout { struct FoldLayout {