diff --git a/radicle-cli/examples/rad-patch.md b/radicle-cli/examples/rad-patch.md index 260acb04..d90c97f2 100644 --- a/radicle-cli/examples/rad-patch.md +++ b/radicle-cli/examples/rad-patch.md @@ -51,14 +51,16 @@ $ rad patch ``` ``` $ rad patch show 191a14e520f2eeff7c0e3ee0a5523c5217eecb89 -╭──────────────────────────────────────────────────────────────────╮ -│ Title Define power requirements │ -│ Patch 191a14e520f2eeff7c0e3ee0a5523c5217eecb89 │ -│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │ -│ Status open │ -│ │ -│ See details. │ -╰──────────────────────────────────────────────────────────────────╯ +╭─────────────────────────────────────────────────────────────────────────────────────────╮ +│ Title Define power requirements │ +│ Patch 191a14e520f2eeff7c0e3ee0a5523c5217eecb89 │ +│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │ +│ Status open │ +│ │ +│ See details. │ +├─────────────────────────────────────────────────────────────────────────────────────────┤ +│ ● opened by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) 3 months ago │ +╰─────────────────────────────────────────────────────────────────────────────────────────╯ commit 3e674d1a1df90807e934f9ae5da2591dd6848a33 Author: radicle diff --git a/radicle-cli/examples/workflow/4-patching-contributor.md b/radicle-cli/examples/workflow/4-patching-contributor.md index 2ba404c1..1fd40246 100644 --- a/radicle-cli/examples/workflow/4-patching-contributor.md +++ b/radicle-cli/examples/workflow/4-patching-contributor.md @@ -49,14 +49,16 @@ $ rad patch │ ● opened by did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (you) 3 months ago │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ $ rad patch show a07ef7743a32a2e902672ea3526d1db6ee08108a -╭──────────────────────────────────────────────────────────────────╮ -│ Title Define power requirements │ -│ Patch a07ef7743a32a2e902672ea3526d1db6ee08108a │ -│ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │ -│ Status open │ -│ │ -│ See details. │ -╰──────────────────────────────────────────────────────────────────╯ +╭─────────────────────────────────────────────────────────────────────────────────────────╮ +│ Title Define power requirements │ +│ Patch a07ef7743a32a2e902672ea3526d1db6ee08108a │ +│ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │ +│ Status open │ +│ │ +│ See details. │ +├─────────────────────────────────────────────────────────────────────────────────────────┤ +│ ● opened by did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (you) 3 months ago │ +╰─────────────────────────────────────────────────────────────────────────────────────────╯ commit 3e674d1a1df90807e934f9ae5da2591dd6848a33 Author: radicle diff --git a/radicle-cli/src/commands/patch.rs b/radicle-cli/src/commands/patch.rs index a15f7f95..80f10400 100644 --- a/radicle-cli/src/commands/patch.rs +++ b/radicle-cli/src/commands/patch.rs @@ -215,7 +215,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { } Operation::Show { patch_id } => { let patch_id = patch_id.resolve(&repository.backend)?; - show::run(&repository, &workdir, &patch_id)?; + show::run(&profile, &repository, &workdir, &patch_id)?; } Operation::Update { ref patch_id, diff --git a/radicle-cli/src/commands/patch/common.rs b/radicle-cli/src/commands/patch/common.rs index 8de35791..d588dc74 100644 --- a/radicle-cli/src/commands/patch/common.rs +++ b/radicle-cli/src/commands/patch/common.rs @@ -96,7 +96,7 @@ pub fn pretty_sync_status( /// For example ' (branch1[, branch2])'. pub fn pretty_commit_version( revision_oid: &Oid, - repo: &Option, + repo: Option<&git::raw::Repository>, ) -> anyhow::Result { let oid = term::format::secondary(term::format::oid(*revision_oid)); let mut line = term::Line::new(oid); diff --git a/radicle-cli/src/commands/patch/list.rs b/radicle-cli/src/commands/patch/list.rs index 01757f75..5a4d8c8d 100644 --- a/radicle-cli/src/commands/patch/list.rs +++ b/radicle-cli/src/commands/patch/list.rs @@ -1,6 +1,6 @@ use anyhow::anyhow; -use radicle::cob::patch::{Patch, PatchId, Patches, Verdict}; +use radicle::cob::patch::{Patch, PatchId, Patches, Revision, Verdict}; use radicle::git; use radicle::prelude::*; use radicle::profile::Profile; @@ -40,65 +40,82 @@ pub fn run( } for (id, patch) in &mut own { - print(&me, id, patch, &workdir, repository)?; + widget(&me, id, patch, workdir.as_ref(), repository)?.print(); } for (id, patch) in &mut other { - print(profile.id(), id, patch, &workdir, repository)?; + widget(profile.id(), id, patch, workdir.as_ref(), repository)?.print(); } Ok(()) } -/// Print patch details. -fn print( +pub fn header( + patch_id: &PatchId, + patch: &Patch, + workdir: Option<&git::raw::Repository>, + repository: &Repository, + revision: &Revision, +) -> anyhow::Result { + let target_head = common::patch_merge_target_oid(patch.target(), repository)?; + let header = term::Line::spaced([ + term::format::bold(patch.title()).into(), + term::format::highlight(term::format::cob(patch_id)).into(), + term::format::dim(format!("R{}", patch.version())).into(), + ]) + .space() + .extend(common::pretty_commit_version(&revision.head(), workdir)?) + .space() + .extend(common::pretty_sync_status( + repository.raw(), + revision.head().into(), + target_head, + )?); + + Ok(header) +} + +/// Patch widget. +pub fn widget<'a>( whoami: &PublicKey, patch_id: &PatchId, patch: &Patch, - workdir: &Option, + workdir: Option<&git::raw::Repository>, repository: &Repository, -) -> anyhow::Result<()> { - let target_head = common::patch_merge_target_oid(patch.target(), repository)?; +) -> anyhow::Result> { + let (_, revision) = patch + .latest() + .ok_or_else(|| anyhow!("patch is malformed: no revisions found"))?; + let header = header(patch_id, patch, workdir, repository, revision)?; + let mut widget = term::VStack::default() + .child(header) + .divider() + .border(Some(term::colors::FAINT)); + for line in timeline(whoami, patch_id, patch, repository)? { + widget.push(line); + } + Ok(widget) +} + +pub fn timeline( + whoami: &PublicKey, + patch_id: &PatchId, + patch: &Patch, + repository: &Repository, +) -> anyhow::Result> { let you = patch.author().id().as_key() == whoami; - let mut author_info = term::Line::spaced([ + let mut open = term::Line::spaced([ term::format::positive("●").into(), term::format::default("opened by").into(), term::format::tertiary(patch.author().id()).into(), ]); if you { - author_info.push(term::Label::space()); - author_info.push(term::format::primary("(you)")); + open.push(term::Label::space()); + open.push(term::format::primary("(you)")); } - author_info.push(term::Label::space()); - author_info.push(term::format::dim(term::format::timestamp( - &patch.timestamp(), - ))); + let mut timeline = vec![(patch.timestamp(), open)]; - let (_, revision) = patch - .latest() - .ok_or_else(|| anyhow!("patch is malformed: no revisions found"))?; - let mut widget = term::VStack::default() - .child( - term::Line::spaced([ - term::format::bold(patch.title()).into(), - term::format::highlight(term::format::cob(patch_id)).into(), - term::format::dim(format!("R{}", patch.version())).into(), - ]) - .space() - .extend(common::pretty_commit_version(&revision.head(), workdir)?) - .space() - .extend(common::pretty_sync_status( - repository.raw(), - revision.head().into(), - target_head, - )?), - ) - .divider() - .child(author_info) - .border(Some(term::colors::FAINT)); - - let mut timeline = Vec::new(); for (revision_id, revision) in patch.revisions() { // Don't show an "update" line for the first revision. if **revision_id != **patch_id { @@ -176,12 +193,12 @@ fn print( } timeline.sort_by_key(|(t, _)| *t); + let mut lines = Vec::new(); for (time, mut line) in timeline.into_iter() { line.push(term::Label::space()); line.push(term::format::dim(term::format::timestamp(&time))); - widget.push(line); + lines.push(line); } - widget.print(); - Ok(()) + Ok(lines) } diff --git a/radicle-cli/src/commands/patch/show.rs b/radicle-cli/src/commands/patch/show.rs index c3c95f69..d9005703 100644 --- a/radicle-cli/src/commands/patch/show.rs +++ b/radicle-cli/src/commands/patch/show.rs @@ -35,11 +35,13 @@ fn show_patch_diff( } pub fn run( - storage: &Repository, + profile: &Profile, + stored: &Repository, + // TODO: Should be optional. workdir: &git::raw::Repository, patch_id: &PatchId, ) -> anyhow::Result<()> { - let patches = patch::Patches::open(storage)?; + let patches = patch::Patches::open(stored)?; let Some(patch) = patches.get(patch_id)? else { anyhow::bail!("Patch `{patch_id}` not found"); }; @@ -66,7 +68,7 @@ pub fn run( ]); let description = patch.description().trim(); - let meta = VStack::default() + let mut widget = VStack::default() .border(Some(term::colors::FAINT)) .child(attrs) .children(if !description.is_empty() { @@ -76,12 +78,16 @@ pub fn run( ] } else { vec![] - }); + }) + .divider(); - meta.print(); + for line in list::timeline(profile.id(), patch_id, &patch, stored)? { + widget.push(line); + } + widget.print(); term::blank(); - show_patch_diff(&patch, storage, workdir)?; + show_patch_diff(&patch, stored, workdir)?; term::blank(); Ok(())