From 3426a28c482a9f4ba2b60a96aefff048fe661120 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 8 Jul 2026 16:21:22 +0200 Subject: [PATCH] feat: show local branch count in the Repos table A repo that keeps several branches (e.g. one theme per branch) only ever showed its checked-out branch, hiding that the others exist. The Repos table now renders the active branch plus `+N` for the other local branches (cyan when >1), the BRANCH column widened to fit, and `vulp status` prints "(+N more local)". The full list stays in the detail Branches tab; RepoSummary.branch_count is in --json too. --- src/cli_cmds/workspace.rs | 3 ++- src/hub/tabs_tables.rs | 12 ++++++++++-- src/status/mod.rs | 8 +++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/cli_cmds/workspace.rs b/src/cli_cmds/workspace.rs index 0ce0d69..b215fe4 100644 --- a/src/cli_cmds/workspace.rs +++ b/src/cli_cmds/workspace.rs @@ -92,7 +92,8 @@ pub fn status(cfg: &AppConfig, json: bool, repo: &str) -> Result<()> { } println!("name: {}", r.name); println!("path: {}", r.path.display()); - println!("branch: {}", r.branch); + println!("branch: {}{}", r.branch, + if r.branch_count > 1 { format!(" (+{} more local)", r.branch_count - 1) } else { String::new() }); println!("dirty: {}", r.is_dirty); println!("ahead: {}", r.ahead); println!("behind: {}", r.behind); diff --git a/src/hub/tabs_tables.rs b/src/hub/tabs_tables.rs index 2a3a364..14ccf15 100644 --- a/src/hub/tabs_tables.rs +++ b/src/hub/tabs_tables.rs @@ -78,6 +78,14 @@ pub fn render_repos_table(f: &mut Frame, state: &HubState, area: Rect) { }; let stars_str = r.stars.map(|s| format!("{}", s)).unwrap_or_else(|| "—".into()); let stars_col = if r.stars.is_some() { Color::Yellow } else { Color::DarkGray }; + // Active branch, plus `+N` when the repo keeps other local + // branches (e.g. a theme per branch) — so the count is visible + // without opening the Branches tab. + let branch_cell = if r.branch_count > 1 { + format!("{} +{}", r.branch.chars().take(9).collect::(), r.branch_count - 1) + } else { + r.branch.chars().take(13).collect::() + }; let is_pinned = state.pins.contains(&r.path); let prefix = match (is_pinned, r.bookmarked) { (true, true) => "◆★", @@ -89,7 +97,7 @@ pub fn render_repos_table(f: &mut Frame, state: &HubState, area: Rect) { Some(Row::new(vec![ Cell::from(format!("{} {}", if is_cur { "▶" } else { " " }, if is_sel { "[✓]" } else { "[ ]" })).style(check_sty), Cell::from(format!("{}{}{}", prefix, if is_external { "⧉ " } else { "" }, r.name)).style(Style::default().fg(name_col)), - Cell::from(r.branch.chars().take(9).collect::()), + Cell::from(branch_cell).style(Style::default().fg(if r.branch_count > 1 { Color::Cyan } else { Color::Reset })), Cell::from(proj_name.chars().take(21).collect::()).style(Style::default().fg(proj_color)), Cell::from(vis).style(match vis { "public" => Style::default().fg(Color::Green), "private" => Style::default().fg(Color::Yellow), _ => Style::default().fg(Color::DarkGray) }), Cell::from(r.last_commit_age.clone()).style(Style::default().fg(age_color(r.last_commit_ts))), @@ -107,7 +115,7 @@ pub fn render_repos_table(f: &mut Frame, state: &HubState, area: Rect) { let widths = [ Constraint::Length(6), Constraint::Fill(1), - Constraint::Length(10), + Constraint::Length(14), Constraint::Length(22), Constraint::Length(9), Constraint::Length(9), diff --git a/src/status/mod.rs b/src/status/mod.rs index 2199488..e71e624 100644 --- a/src/status/mod.rs +++ b/src/status/mod.rs @@ -28,6 +28,10 @@ pub struct RepoSummary { pub last_commit_ts: i64, pub last_tag: Option, pub visibility: Option, + /// Number of local branches. Surfaced in the Repos table as `+N` next to + /// the active branch so a repo that keeps several branches (e.g. one theme + /// per branch) shows its branch count at a glance, not just the checkout. + pub branch_count: usize, pub owner: Option, // parsed from git remote URL /// The provider-side repo name parsed from the git remote URL — not /// necessarily the local folder name (see `parse_repo_name_from_url`). @@ -404,6 +408,8 @@ pub fn repo_summary(path: &Path) -> Result { let owner = extract_owner(&repo); let remote_repo_name = extract_remote_repo_name(&repo); + let branch_count = repo.branches(Some(git2::BranchType::Local)) + .map(|bs| bs.count()).unwrap_or(0); let has_license = detect_license(path); let t_lang = std::time::Instant::now(); @@ -431,7 +437,7 @@ pub fn repo_summary(path: &Path) -> Result { Ok(RepoSummary { name, path: path.to_path_buf(), branch, ahead, behind, is_dirty, last_commit_msg: msg, last_commit_age: age, last_commit_ts: ts, - last_tag, visibility: None, owner, remote_repo_name, has_license, lang, bookmarked: false, + last_tag, visibility: None, branch_count, owner, remote_repo_name, has_license, lang, bookmarked: false, stars: None, open_issues: None, open_prs: None, stash_count, ci_status: None, dependabot_open: None, deploy_status: None,