commit view: Fix layout shift while loading commit (#44548)

Fixes a few cases where the commit view would layout shift as the diff
loaded. This was caused by:
- Adding the commit message buffer after all the diff files
- Using the gutter dimensions from the last frame for the avatar spacing

Release Notes:

- commit view: Fix layout shift while loading commit

---------

Co-authored-by: MrSubidubi <dev@bahn.sh>
This commit is contained in:
Agus Zubiaga
2025-12-10 15:01:49 +00:00
committed by GitHub
co-authored by MrSubidubi
parent dd431631b4
commit 21f7e6a9e6
10 changed files with 316 additions and 308 deletions
+73 -60
View File
@@ -1,9 +1,7 @@
use anyhow::{Context as _, Result};
use buffer_diff::{BufferDiff, BufferDiffSnapshot};
use editor::display_map::{BlockPlacement, BlockProperties, BlockStyle};
use editor::{
Editor, EditorEvent, ExcerptId, ExcerptRange, MultiBuffer, multibuffer_context_lines,
};
use editor::{Editor, EditorEvent, ExcerptRange, MultiBuffer, multibuffer_context_lines};
use git::repository::{CommitDetails, CommitDiff, RepoPath};
use git::{GitHostingProviderRegistry, GitRemote, parse_git_remote_url};
use gpui::{
@@ -13,7 +11,7 @@ use gpui::{
};
use language::{
Anchor, Buffer, Capability, DiskState, File, LanguageRegistry, LineEnding, OffsetRangeExt as _,
ReplicaId, Rope, TextBuffer,
Point, ReplicaId, Rope, TextBuffer,
};
use multi_buffer::PathKey;
use project::{Project, WorktreeId, git_store::Repository};
@@ -70,6 +68,7 @@ struct GitBlob {
display_name: Arc<str>,
}
const COMMIT_MESSAGE_SORT_PREFIX: u64 = 0;
const FILE_NAMESPACE_SORT_PREFIX: u64 = 1;
impl CommitView {
@@ -147,6 +146,32 @@ impl CommitView {
) -> Self {
let language_registry = project.read(cx).languages().clone();
let multibuffer = cx.new(|_| MultiBuffer::new(Capability::ReadOnly));
let message_buffer = cx.new(|cx| {
let mut buffer = Buffer::local(commit.message.clone(), cx);
buffer.set_capability(Capability::ReadOnly, cx);
buffer
});
multibuffer.update(cx, |multibuffer, cx| {
let snapshot = message_buffer.read(cx).snapshot();
let full_range = Point::zero()..snapshot.max_point();
let range = ExcerptRange {
context: full_range.clone(),
primary: full_range,
};
multibuffer.set_excerpt_ranges_for_path(
PathKey::with_sort_prefix(
COMMIT_MESSAGE_SORT_PREFIX,
RelPath::unix("commit message").unwrap().into(),
),
message_buffer.clone(),
&snapshot,
vec![range],
cx,
)
});
let editor = cx.new(|cx| {
let mut editor =
Editor::for_multibuffer(multibuffer.clone(), Some(project.clone()), window, cx);
@@ -154,9 +179,38 @@ impl CommitView {
editor.disable_inline_diagnostics();
editor.set_show_breakpoints(false, cx);
editor.set_expand_all_diff_hunks(cx);
editor.disable_header_for_buffer(message_buffer.read(cx).remote_id(), cx);
editor.disable_indent_guides_for_buffer(message_buffer.read(cx).remote_id(), cx);
editor.insert_blocks(
[BlockProperties {
placement: BlockPlacement::Above(editor::Anchor::min()),
height: Some(1),
style: BlockStyle::Sticky,
render: Arc::new(|_| gpui::Empty.into_any_element()),
priority: 0,
}]
.into_iter()
.chain(
editor
.buffer()
.read(cx)
.buffer_anchor_to_anchor(&message_buffer, Anchor::MAX, cx)
.map(|anchor| BlockProperties {
placement: BlockPlacement::Below(anchor),
height: Some(1),
style: BlockStyle::Sticky,
render: Arc::new(|_| gpui::Empty.into_any_element()),
priority: 0,
}),
),
None,
cx,
);
editor
});
let commit_sha = Arc::<str>::from(commit.sha.as_ref());
let first_worktree_id = project
@@ -166,7 +220,6 @@ impl CommitView {
.map(|worktree| worktree.read(cx).id());
let repository_clone = repository.clone();
let commit_message = commit.message.clone();
cx.spawn(async move |this, cx| {
for file in commit_diff.files {
@@ -228,59 +281,6 @@ impl CommitView {
})?;
}
let message_buffer = cx.new(|cx| {
let mut buffer = Buffer::local(commit_message, cx);
buffer.set_capability(Capability::ReadOnly, cx);
buffer
})?;
this.update(cx, |this, cx| {
this.multibuffer.update(cx, |multibuffer, cx| {
let range = ExcerptRange {
context: Anchor::MIN..Anchor::MAX,
primary: Anchor::MIN..Anchor::MAX,
};
multibuffer.insert_excerpts_after(
ExcerptId::min(),
message_buffer.clone(),
[range],
cx,
)
});
this.editor.update(cx, |editor, cx| {
editor.disable_header_for_buffer(message_buffer.read(cx).remote_id(), cx);
editor
.disable_indent_guides_for_buffer(message_buffer.read(cx).remote_id(), cx);
editor.insert_blocks(
[BlockProperties {
placement: BlockPlacement::Above(editor::Anchor::min()),
height: Some(1),
style: BlockStyle::Sticky,
render: Arc::new(|_| gpui::Empty.into_any_element()),
priority: 0,
}]
.into_iter()
.chain(
editor
.buffer()
.read(cx)
.buffer_anchor_to_anchor(&message_buffer, Anchor::MAX, cx)
.map(|anchor| BlockProperties {
placement: BlockPlacement::Below(anchor),
height: Some(1),
style: BlockStyle::Sticky,
render: Arc::new(|_| gpui::Empty.into_any_element()),
priority: 0,
}),
),
None,
cx,
)
});
})?;
anyhow::Ok(())
})
.detach();
@@ -417,12 +417,23 @@ impl CommitView {
None
};
let gutter_width = self.editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(window, cx);
let style = editor.style(cx);
let font_id = window.text_system().resolve_font(&style.text.font());
let font_size = style.text.font_size.to_pixels(window.rem_size());
snapshot
.gutter_dimensions(font_id, font_size, style, window, cx)
.full_width()
});
h_flex()
.border_b_1()
.border_color(cx.theme().colors().border_variant)
.w_full()
.child(
h_flex()
.w(self.editor.read(cx).last_gutter_dimensions().full_width())
.w(gutter_width)
.justify_center()
.child(self.render_commit_avatar(&commit.sha, rems_from_px(48.), window, cx)),
)
@@ -1011,7 +1022,9 @@ impl Render for CommitView {
.size_full()
.bg(cx.theme().colors().editor_background)
.child(self.render_header(window, cx))
.child(div().flex_grow().child(self.editor.clone()))
.when(!self.editor.read(cx).is_empty(cx), |this| {
this.child(div().flex_grow().child(self.editor.clone()))
})
}
}