git blame gutter: Use smallest possible space (#18145)

Before:
![screenshot-2024-09-26-15 00
20@2x](https://github.com/user-attachments/assets/f6706325-5bef-404e-a0b4-63a5121969fa)

After:

![screenshot-2024-09-26-15 02
24@2x](https://github.com/user-attachments/assets/739d0831-0b4a-457f-917e-10f3a662e74d)


Release Notes:

- Improved the git blame gutter to take up only the space required to
display the longest git author name in the current file.

---------

Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
This commit is contained in:
Thorsten Ball 2024-09-26 15:47:14 +02:00 committed by GitHub
parent 1a4f9b2891
commit 7eea1a6f51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 65 additions and 22 deletions

View file

@ -663,7 +663,7 @@ pub struct EditorSnapshot {
show_git_diff_gutter: Option<bool>,
show_code_actions: Option<bool>,
show_runnables: Option<bool>,
render_git_blame_gutter: bool,
git_blame_gutter_max_author_length: Option<usize>,
pub display_snapshot: DisplaySnapshot,
pub placeholder_text: Option<Arc<str>>,
is_focused: bool,
@ -673,7 +673,7 @@ pub struct EditorSnapshot {
gutter_hovered: bool,
}
const GIT_BLAME_GUTTER_WIDTH_CHARS: f32 = 53.;
const GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED: usize = 20;
#[derive(Default, Debug, Clone, Copy)]
pub struct GutterDimensions {
@ -2211,6 +2211,19 @@ impl Editor {
}
pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
let git_blame_gutter_max_author_length = self
.render_git_blame_gutter(cx)
.then(|| {
if let Some(blame) = self.blame.as_ref() {
let max_author_length =
blame.update(cx, |blame, cx| blame.max_author_length(cx));
Some(max_author_length)
} else {
None
}
})
.flatten();
EditorSnapshot {
mode: self.mode,
show_gutter: self.show_gutter,
@ -2218,7 +2231,7 @@ impl Editor {
show_git_diff_gutter: self.show_git_diff_gutter,
show_code_actions: self.show_code_actions,
show_runnables: self.show_runnables,
render_git_blame_gutter: self.render_git_blame_gutter(cx),
git_blame_gutter_max_author_length,
display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
scroll_anchor: self.scroll_manager.anchor(),
ongoing_scroll: self.scroll_manager.ongoing_scroll(),
@ -12989,9 +13002,19 @@ impl EditorSnapshot {
let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
let git_blame_entries_width = self
.render_git_blame_gutter
.then_some(em_width * GIT_BLAME_GUTTER_WIDTH_CHARS);
let git_blame_entries_width =
self.git_blame_gutter_max_author_length
.map(|max_author_length| {
// Length of the author name, but also space for the commit hash,
// the spacing and the timestamp.
let max_char_count = max_author_length
.min(GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED)
+ 7 // length of commit sha
+ 14 // length of max relative timestamp ("60 minutes ago")
+ 4; // gaps and margins
em_advance * max_char_count
});
let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
left_padding += if show_code_actions || show_runnables {

View file

@ -21,7 +21,7 @@ use crate::{
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown,
PageUp, Point, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint,
CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
CURSORS_VISIBLE_FOR, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
};
use client::ParticipantIndex;
use collections::{BTreeMap, HashMap};
@ -1445,7 +1445,7 @@ impl EditorElement {
AvailableSpace::MaxContent
};
let scroll_top = scroll_position.y * line_height;
let start_x = em_width * 1;
let start_x = em_width;
let mut last_used_color: Option<(PlayerColor, Oid)> = None;
@ -4228,7 +4228,7 @@ fn render_blame_entry(
let short_commit_id = blame_entry.sha.display_short();
let author_name = blame_entry.author.as_deref().unwrap_or("<no name>");
let name = util::truncate_and_trailoff(author_name, 20);
let name = util::truncate_and_trailoff(author_name, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED);
let details = blame.read(cx).details_for_entry(&blame_entry);
@ -4240,22 +4240,21 @@ fn render_blame_entry(
h_flex()
.w_full()
.justify_between()
.font_family(style.text.font().family)
.line_height(style.text.line_height)
.id(("blame", ix))
.children([
div()
.text_color(sha_color.cursor)
.child(short_commit_id)
.mr_2(),
div()
.w_full()
.h_flex()
.justify_between()
.text_color(cx.theme().status().hint)
.child(name)
.child(relative_timestamp),
])
.text_color(cx.theme().status().hint)
.pr_2()
.gap_2()
.child(
h_flex()
.items_center()
.gap_2()
.child(div().text_color(sha_color.cursor).child(short_commit_id))
.child(name),
)
.child(relative_timestamp)
.on_mouse_down(MouseButton::Right, {
let blame_entry = blame_entry.clone();
let details = details.clone();

View file

@ -207,6 +207,27 @@ impl GitBlame {
})
}
pub fn max_author_length(&mut self, cx: &mut ModelContext<Self>) -> usize {
self.sync(cx);
let mut max_author_length = 0;
for entry in self.entries.iter() {
let author_len = entry
.blame
.as_ref()
.and_then(|entry| entry.author.as_ref())
.map(|author| author.len());
if let Some(author_len) = author_len {
if author_len > max_author_length {
max_author_length = author_len;
}
}
}
max_author_length
}
pub fn blur(&mut self, _: &mut ModelContext<Self>) {
self.focused = false;
}