From d8d822092d85fd1829d7dde04c99c07b1df66db1 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:43:15 +0800 Subject: [PATCH] chore(scm): reserve the graph and commit-detail mount points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both land in panel.rs — the history section below the file list, the detail body in place of it — and both are being written in parallel. Landing the two call sites and their stub modules up front keeps them from colliding over the same function. The detail body replaces the working tree's rather than sitting beside it, so the two can never be on screen each claiming to be the file list. The history section sits outside the scroller: it pages, and sharing a scroll region would mean scrolling back past hundreds of commits to reach the message box. --- src/ui/scm/detail.rs | 27 +++++++++++++++++++++++++++ src/ui/scm/graph.rs | 32 ++++++++++++++++++++++++++++++++ src/ui/scm/mod.rs | 4 ++++ src/ui/scm/panel.rs | 31 +++++++++++++++++++++++++------ src/ui/scm/state.rs | 1 + 5 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 src/ui/scm/detail.rs create mode 100644 src/ui/scm/graph.rs diff --git a/src/ui/scm/detail.rs b/src/ui/scm/detail.rs new file mode 100644 index 00000000..ea6c972a --- /dev/null +++ b/src/ui/scm/detail.rs @@ -0,0 +1,27 @@ +//! One commit, in the panel's own body. +//! +//! Replacing the body rather than opening a third kind of container: the +//! panel already knows how to draw a list of changed files, and the only +//! things a commit adds above it are its message and who wrote it. The file +//! rows are the same rows, minus the buttons — nothing here should be able to +//! drift from what the working tree shows. +//! +//! The patch itself still goes to the full-screen overlay. 260px is not a +//! place to read a diff. + +use gpui::{AnyElement, Context}; + +use crate::ui::app::Tty7App; +use crate::ui::scm::state::CommitDetailView; + +impl Tty7App { + /// The commit detail body, shown in place of the file groups. + pub(crate) fn render_commit_detail( + &mut self, + _detail: &CommitDetailView, + _window: &mut gpui::Window, + _cx: &mut Context, + ) -> Option { + None + } +} diff --git a/src/ui/scm/graph.rs b/src/ui/scm/graph.rs new file mode 100644 index 00000000..93384dfd --- /dev/null +++ b/src/ui/scm/graph.rs @@ -0,0 +1,32 @@ +//! The history section at the foot of the panel. +//! +//! Its job is shape, not text. 260px leaves room for roughly 26 characters +//! beside the lanes, and this repository's commit subjects run to a median of +//! 64 — so what a reader gets here is where the branches are, where they +//! merged, which refs sit where, and how recently anything moved. Reading a +//! message is the commit detail view's job, one click away. +//! +//! That is also VS Code's own reading of a sidebar graph, and it is why the +//! conventional-commit prefix is lifted out into a chip rather than left to +//! eat half the line. + +use gpui::{AnyElement, Context}; + +use crate::ui::app::Tty7App; +use crate::ui::scm::state::RepoKey; + +impl Tty7App { + /// The history section, when it is expanded and has something to draw. + /// + /// Sits below the file list as its own scroll region rather than at the + /// end of one: the graph pages, and sharing a scroller would mean scrolling + /// back past hundreds of commits to reach the message box. + pub(crate) fn render_graph_section( + &mut self, + _repo: &RepoKey, + _window: &mut gpui::Window, + _cx: &mut Context, + ) -> Option { + None + } +} diff --git a/src/ui/scm/mod.rs b/src/ui/scm/mod.rs index fa2944c1..ff6da7c7 100644 --- a/src/ui/scm/mod.rs +++ b/src/ui/scm/mod.rs @@ -8,6 +8,10 @@ // `relative_time` has no row to date yet, and `status_rank` is the file tree's // to use. Both allows come off with the step that wires them up. pub(crate) mod actions; +#[allow(dead_code)] +pub(crate) mod detail; +#[allow(dead_code)] +pub(crate) mod graph; pub(crate) mod panel; #[allow(dead_code)] pub(crate) mod path; diff --git a/src/ui/scm/panel.rs b/src/ui/scm/panel.rs index 56b0eecf..b1c331a0 100644 --- a/src/ui/scm/panel.rs +++ b/src/ui/scm/panel.rs @@ -169,16 +169,23 @@ impl Tty7App { pinned.extend(naming); pinned.push(commit); pinned.push(buttons); - let body = if status.is_clean() { - self.panel_empty( + // A commit's detail replaces the working tree's, so the two can never + // be on screen claiming to be the same thing. + let detail = self.scm.detail.clone(); + let body = match detail + .as_ref() + .and_then(|d| self.render_commit_detail(d, window, cx)) + { + Some(body) => body, + None if status.is_clean() => self.panel_empty( t(L10nKey::PanelNoChanges), Some(t(L10nKey::PanelNoChangesHint)), cx, - ) - } else { - self.scm_groups(&repo, &status, cx) + ), + None => self.scm_groups(&repo, &status, cx), }; - self.scm_shell_with(title, pinned, body) + let history = self.render_graph_section(&repo, window, cx); + self.scm_shell_full(title, pinned, body, history) } /// The repository line: which branch, how far from its upstream, and one @@ -762,6 +769,17 @@ impl Tty7App { title: AnyElement, pinned: Vec, body: AnyElement, + ) -> AnyElement { + self.scm_shell_full(title, pinned, body, None) + } + + /// …and `footer` is the history section, which scrolls on its own. + fn scm_shell_full( + &self, + title: AnyElement, + pinned: Vec, + body: AnyElement, + footer: Option, ) -> AnyElement { let scroller = div() .id("panel-scm-body") @@ -780,6 +798,7 @@ impl Tty7App { scroller, &self.scm.scroll, )) + .children(footer) .into_any_element() } diff --git a/src/ui/scm/state.rs b/src/ui/scm/state.rs index ac11544c..96880939 100644 --- a/src/ui/scm/state.rs +++ b/src/ui/scm/state.rs @@ -174,6 +174,7 @@ pub(crate) struct GraphState { /// touched. A file-level diff is not shown here — that opens the full-screen /// overlay, because 260px cannot render a diff and pretending otherwise would /// mean inventing a third kind of container. +#[derive(Clone, PartialEq, Eq, Debug)] pub(crate) struct CommitDetailView { pub(crate) repo: RepoKey, pub(crate) oid: String,