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,