use ratatui::{
style::Style,
text::{Line, Span},
};
use crate::github::detail::PrDetail;
use crate::theme::Palette;
use crate::ui::glyphs;
use crate::ui::util::{humanize_delta, section_header, truncate};
const SHA_COLS: usize = 8;
const AUTHOR_COLS: usize = 13;
const AGE_COLS: usize = 9;
const ADDS_COLS: usize = 6;
const DELS_COLS: usize = 5;
const CURSOR_COLS: usize = 2;
const CI_COLS: usize = 2;
const DROP_STATS_BELOW: usize = 60;
const DROP_CI_BELOW: usize = 60;
const DROP_AGE_BELOW: usize = 50;
pub(super) fn build_commits(
detail: &PrDetail,
p: &Palette,
cursor: Option<usize>,
) -> (Vec<Line<'static>>, Vec<(u16, u16)>) {
if detail.commits.is_empty() {
return (Vec::new(), Vec::new());
}
let avail: usize = 80;
let show_stats = avail >= DROP_STATS_BELOW;
let show_ci = avail >= DROP_CI_BELOW;
let show_age = avail >= DROP_AGE_BELOW;
let mut fixed = CURSOR_COLS + SHA_COLS + AUTHOR_COLS;
if show_ci {
fixed += CI_COLS;
}
if show_age {
fixed += AGE_COLS;
}
if show_stats {
fixed += ADDS_COLS + DELS_COLS;
}
let headline_cols = avail.saturating_sub(fixed).max(10);
let count = detail.commits.len();
let mut lines: Vec<Line<'static>> = Vec::with_capacity(count + 2);
lines.push(section_header(&format!("COMMITS ({count})"), p));
lines.push(Line::from(""));
for (row_idx, commit) in detail.commits.iter().enumerate() {
let is_cursor = cursor.is_some_and(|c| c == row_idx);
let mut spans: Vec<Span<'static>> = Vec::with_capacity(9);
let indicator = if is_cursor { "\u{25b6} " } else { " " }; let indicator_style =
if is_cursor { Style::default().fg(p.accent) } else { Style::default() };
spans.push(Span::styled(indicator.to_owned(), indicator_style));
let sha_style =
if is_cursor { Style::default().fg(p.accent) } else { Style::default().fg(p.muted) };
spans.push(Span::styled(format!("{:<7} ", commit.short_sha), sha_style));
let headline = truncate(&commit.headline, headline_cols);
let headline_padded = format!("{headline:<headline_cols$} ");
spans.push(Span::styled(headline_padded, Style::default().fg(p.foreground)));
let author_trunc = truncate(&commit.author, 11);
spans.push(Span::styled(format!("@{author_trunc:<11} "), Style::default().fg(p.dim)));
if show_ci {
let (glyph_char, role) = glyphs::ci_glyph(commit.check_state, false);
let color = p.color_for(role);
spans.push(Span::styled(format!("{glyph_char} "), Style::default().fg(color)));
}
if show_age {
let age = humanize_delta(&commit.committed_at);
spans.push(Span::styled(format!("{age:<8} "), Style::default().fg(p.dim)));
}
if show_stats {
spans.push(Span::styled(
format!("+{:<5}", commit.additions),
Style::default().fg(p.git_new),
));
spans.push(Span::styled(
format!("-{:<5}", commit.deletions),
Style::default().fg(p.danger),
));
}
lines.push(Line::from(spans));
}
if count >= 100 {
lines.push(Line::from(""));
lines.push(Line::from(Span::styled(
" Showing last 100 commits \u{2014} older commits not loaded",
Style::default().fg(p.muted),
)));
}
(lines, Vec::new())
}