From 506570a73ac7d363f8500ea0cf4d0d27f6782b08 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Mon, 16 Feb 2026 14:34:16 +0100 Subject: [PATCH] git_graph: Add resizable commit view support (#49171) This PR add support for resizable commit view, so you can increase the commit view width by hand. https://github.com/user-attachments/assets/47b3d165-1d5b-4c5c-b36d-dc007d62fd43 Before you mark this PR as ready for review, make sure that you have: - [x] Added a solid test coverage and/or screenshots from doing manual testing - [x] Done a self-review taking into account security and performance aspects - [x] Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Release Notes: - N/A (no release notes since it's behind a feature flag) --- crates/git_graph/src/git_graph.rs | 108 ++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/crates/git_graph/src/git_graph.rs b/crates/git_graph/src/git_graph.rs index d81e3e02c0e4b16a5d42fe2c71a04ed3bce8a304..a6a713a6ff4eda78a930af7db586184839cf7f87 100644 --- a/crates/git_graph/src/git_graph.rs +++ b/crates/git_graph/src/git_graph.rs @@ -7,10 +7,11 @@ use git::{ }; use git_ui::{commit_tooltip::CommitAvatar, commit_view::CommitView}; use gpui::{ - AnyElement, App, Bounds, ClipboardItem, Context, Corner, DefiniteLength, ElementId, Entity, - EventEmitter, FocusHandle, Focusable, FontWeight, Hsla, InteractiveElement, ParentElement, - PathBuilder, Pixels, Point, Render, ScrollStrategy, ScrollWheelEvent, SharedString, Styled, - Subscription, Task, WeakEntity, Window, actions, anchored, deferred, point, px, + AnyElement, App, Bounds, ClickEvent, ClipboardItem, Context, Corner, DefiniteLength, + DragMoveEvent, ElementId, Entity, EventEmitter, FocusHandle, Focusable, FontWeight, Hsla, + InteractiveElement, ParentElement, PathBuilder, Pixels, Point, Render, ScrollStrategy, + ScrollWheelEvent, SharedString, Styled, Subscription, Task, WeakEntity, Window, actions, + anchored, deferred, point, px, }; use menu::{SelectNext, SelectPrevious}; use project::{ @@ -36,6 +37,53 @@ const COMMIT_CIRCLE_STROKE_WIDTH: Pixels = px(1.5); const LANE_WIDTH: Pixels = px(16.0); const LEFT_PADDING: Pixels = px(12.0); const LINE_WIDTH: Pixels = px(1.5); +const RESIZE_HANDLE_WIDTH: f32 = 8.0; + +struct DraggedSplitHandle; + +pub struct SplitState { + left_ratio: f32, + visible_left_ratio: f32, +} + +impl SplitState { + pub fn new() -> Self { + Self { + left_ratio: 1.0, + visible_left_ratio: 1.0, + } + } + + pub fn right_ratio(&self) -> f32 { + 1.0 - self.visible_left_ratio + } + + fn on_drag_move( + &mut self, + drag_event: &DragMoveEvent, + _window: &mut Window, + _cx: &mut Context, + ) { + let drag_position = drag_event.event.position; + let bounds = drag_event.bounds; + let bounds_width = bounds.right() - bounds.left(); + + let min_ratio = 0.1; + let max_ratio = 0.9; + + let new_ratio = (drag_position.x - bounds.left()) / bounds_width; + self.visible_left_ratio = new_ratio.clamp(min_ratio, max_ratio); + } + + fn commit_ratio(&mut self) { + self.left_ratio = self.visible_left_ratio; + } + + fn on_double_click(&mut self) { + self.left_ratio = 1.0; + self.visible_left_ratio = 1.0; + } +} actions!( git_graph, @@ -598,6 +646,7 @@ pub struct GitGraph { selected_commit_diff: Option, _commit_diff_task: Option>, _load_task: Option>, + commit_details_split_state: Entity, } impl GitGraph { @@ -688,6 +737,7 @@ impl GitGraph { selected_commit_diff: None, log_source, log_order, + commit_details_split_state: cx.new(|_cx| SplitState::new()), } } @@ -1087,6 +1137,9 @@ impl GitGraph { .border_l_1() .border_color(cx.theme().colors().border) .bg(cx.theme().colors().surface_background) + .flex_basis(DefiniteLength::Fraction( + self.commit_details_split_state.read(cx).right_ratio(), + )) .child( v_flex() .p_3() @@ -1535,6 +1588,40 @@ impl GitGraph { cx.notify(); } } + + fn render_commit_view_resize_handle( + &self, + _window: &mut Window, + cx: &mut Context, + ) -> AnyElement { + div() + .id("commit-view-split-resize-container") + .relative() + .h_full() + .flex_shrink_0() + .w(px(1.)) + .bg(cx.theme().colors().border_variant) + .child( + div() + .id("commit-view-split-resize-handle") + .absolute() + .left(px(-RESIZE_HANDLE_WIDTH / 2.0)) + .w(px(RESIZE_HANDLE_WIDTH)) + .h_full() + .cursor_col_resize() + .block_mouse_except_scroll() + .on_click(cx.listener(|this, event: &ClickEvent, _window, cx| { + if event.click_count() >= 2 { + this.commit_details_split_state.update(cx, |state, _| { + state.on_double_click(); + }); + } + cx.stop_propagation(); + })) + .on_drag(DraggedSplitHandle, |_, _, _, cx| cx.new(|_| gpui::Empty)), + ) + .into_any_element() + } } impl Render for GitGraph { @@ -1671,8 +1758,19 @@ impl Render for GitGraph { ), ) }) + .on_drag_move::(cx.listener(|this, event, window, cx| { + this.commit_details_split_state.update(cx, |state, cx| { + state.on_drag_move(event, window, cx); + }); + })) + .on_drop::(cx.listener(|this, _event, _window, cx| { + this.commit_details_split_state.update(cx, |state, _cx| { + state.commit_ratio(); + }); + })) .when(self.selected_entry_idx.is_some(), |this| { - this.child(self.render_commit_detail_panel(window, cx)) + this.child(self.render_commit_view_resize_handle(window, cx)) + .child(self.render_commit_detail_panel(window, cx)) }) };