use super::*;
pub fn pr_commits(
page: &mut Page,
pr: &PrRef,
d: &PrDetail,
activity: Fetched<'_, PrActivity>,
now: u64,
) {
pr_summary(page, pr, d, now);
let Some(a) = activity.show(page, "commits") else {
return;
};
commit_rows(page, &pr.repo, Some(pr), &a.commits, now);
}
pub(super) fn commit_rows(
page: &mut Page,
repo: &RepoId,
pr: Option<&PrRef>,
commits: &impl Rows<CommitInfo>,
now: u64,
) {
let rest = match (commits.rest(), commits.rows().first()) {
(Rest::OnGitHub(n), Some(oldest)) => {
let earlier = url::commits(repo, &oldest.oid, "");
let text = format!("… {n} earlier {}", noun(n, "commit"));
item(page, earlier, |page, link| {
page.wrapped(vec![Seg::linked(text, Role::Link, link)], 2, Frame::None);
});
Rest::All
}
(rest, _) => rest,
};
let mut current_day = String::new();
for c in commits.rows() {
let date = day(&c.date);
if date == current_day {
page.box_rule();
} else {
if !current_day.is_empty() {
page.box_bottom();
}
page.box_top(
vec![Seg::new(format!("◷ Commits on {date}"), Role::Meta)],
Vec::new(),
);
current_day = date;
}
let commit = match pr {
Some(pr) => url::pull_tab(pr, &format!("commits/{}", c.oid)),
None => url::commit(repo, &c.oid),
};
item(page, commit, |page, link| {
page.box_line(
vec![Seg::linked(c.headline.clone(), Role::Strong, link)],
vec![Seg::new(crate::ui::text::short_sha(&c.oid), Role::Code)],
0,
);
let who = c.author.name();
let committed = format!("{who} committed {}", time::ago_iso(&c.date, now));
body(page, vec![Seg::new(committed, Role::Meta)]);
});
}
if !current_day.is_empty() {
rest_row(page, commits.rows().len(), rest);
page.box_bottom();
}
}
pub fn commit_history(
page: &mut Page,
repo: &RepoId,
rev: &str,
path: &str,
history: Fetched<'_, Results<CommitInfo>>,
now: u64,
) {
let mut title = vec![Seg::new("Commits", Role::Title)];
let at = if path.is_empty() {
format!(" {rev}")
} else {
format!(" {rev} · {path}")
};
title.push(Seg::new(at, Role::Meta));
page.wrapped(title, 0, Frame::None);
page.blank();
let Some(h) = history.show(page, "commits") else {
return;
};
if h.items.is_empty() {
empty_box(page, Seg::new("◷ Commits", Role::Meta), "No commits here.");
return;
}
commit_rows(page, repo, None, h, now);
}
pub struct PrCommitAt {
pub n: u64,
pub of: u64,
pub pr: String,
pub number: u64,
pub previous: Option<String>,
pub next: Option<String>,
}
pub fn pr_commit_nav(page: &mut Page, at: &PrCommitAt) {
let pr = link_seg(page, format!("#{}", at.number), at.pr.clone(), Role::Link);
let mut segs = vec![
Seg::new(format!("Commit {} of {} in ", at.n, at.of), Role::Meta),
pr,
];
for (label, url) in [("‹ Previous", &at.previous), ("Next ›", &at.next)] {
segs.push(Seg::new(" ", Role::Meta));
segs.push(match url {
Some(url) => link_seg(page, label, url.clone(), Role::Link),
None => Seg::new(label, Role::Meta),
});
}
page.line(segs);
page.blank();
}
pub fn commit(page: &mut Page, repo: &RepoId, d: &CommitDetail, files: &str, now: u64) {
page.wrapped(
vec![Seg::new(d.headline.clone(), Role::Title)],
0,
Frame::None,
);
if !d.body.is_empty() {
page.blank();
let base = LinkBase::new(repo, &d.oid, "");
markdown::render(page, &d.body, Some(&base), Frame::None);
}
page.blank();
let mut who = vec![
person_seg(page, &d.author, Role::Strong),
Seg::new(
format!(" authored {}", time::ago_iso(&d.authored_at, now)),
Role::Meta,
),
];
if let Some(committer) = &d.committer {
who.push(Seg::new(" · ", Role::Meta));
who.push(person_seg(page, committer, Role::Strong));
who.push(Seg::new(
format!(" committed {}", time::ago_iso(&d.committed_at, now)),
Role::Meta,
));
}
match d.verified {
Some(true) => who.extend([space(), chip("Verified", Bg::SuccessContainer)]),
Some(false) => who.extend([space(), chip("Unverified", Bg::ErrorContainer)]),
None => {}
}
page.wrapped(who, 0, Frame::None);
let mut ids = vec![Seg::new(
format!("commit {}", crate::ui::text::short_sha(&d.oid)),
Role::Meta,
)];
if !d.parents.is_empty() {
let noun = if d.parents.total() == 1 {
"parent"
} else {
"parents"
};
ids.push(Seg::new(format!(" · {noun} "), Role::Meta));
for (i, parent) in d.parents.iter().enumerate() {
if i > 0 {
ids.push(Seg::new(" + ", Role::Meta));
}
let short = crate::ui::text::short_sha(parent);
ids.push(link_seg(page, short, url::commit(repo, parent), Role::Code));
}
more_chips(&mut ids, &d.parents);
}
page.wrapped(ids, 0, Frame::None);
page.blank();
page.box_top(vec![Seg::new("± Files changed", Role::Meta)], Vec::new());
item(page, files, |page, link| {
let what = match d.changed_files {
Some(n) => plural(n, "file"),
None => "Files".to_owned(),
};
let mut segs = vec![Seg::linked(what, Role::Link, link), space()];
segs.extend(changes(d.additions, d.deletions));
page.box_line(segs, vec![Seg::new("↵ show the diff", Role::Meta)], 0);
});
page.box_bottom();
}