use std::path::PathBuf;
use super::RepoEntry;
use crate::git::status::RepoStatus;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum AttentionCell {
Stash,
Worktree,
Ahead,
Behind,
DirtySub,
UnpushedSub,
FetchWarn,
}
pub(super) fn attention_cells(
status: &RepoStatus,
stash_expanded: bool,
worktree_expanded: bool,
) -> Vec<(String, AttentionCell)> {
let mut cells = Vec::new();
if !status.stashes.is_empty() {
let icon = if stash_expanded {
"\u{25bc}"
} else {
"\u{25b6}"
};
cells.push((
format!("{icon}${}", status.stash_count()),
AttentionCell::Stash,
));
}
if !status.worktree_info.is_empty() {
let icon = if worktree_expanded {
"\u{25bc}"
} else {
"\u{25b6}"
};
cells.push((
format!("{icon}{}", status.worktree_info.len()),
AttentionCell::Worktree,
));
}
if status.ahead > 0 {
cells.push((format!("\u{2191}{}", status.ahead), AttentionCell::Ahead));
}
if status.behind > 0 {
cells.push((format!("\u{2193}{}", status.behind), AttentionCell::Behind));
}
if status.has_dirty_submodules {
cells.push(("\u{25c8}".to_string(), AttentionCell::DirtySub));
}
if status.has_unpushed_submodules {
cells.push(("\u{21e1}".to_string(), AttentionCell::UnpushedSub));
}
if status.fetch_failed {
cells.push(("\u{26a0}".to_string(), AttentionCell::FetchWarn));
}
cells
}
pub(super) fn packed_width(cells: &[(String, AttentionCell)]) -> u16 {
let glyphs: u16 = cells
.iter()
.map(|(text, _)| text.chars().count() as u16)
.sum();
glyphs + cells.len().saturating_sub(1) as u16
}
pub(super) fn is_default_branch(branch: &str) -> bool {
branch == "main" || branch == "master"
}
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
pub(super) struct RowLayout {
pub(super) name_col: u16,
pub(super) branch_col: u16,
}
impl RowLayout {
pub(super) fn branch_x(&self) -> u16 {
2 + self.name_col + 1
}
pub(super) fn attention_x(&self) -> u16 {
self.branch_x()
+ if self.branch_col > 0 {
self.branch_col + 1
} else {
0
}
}
}
pub(super) fn row_layout(
repos: &[RepoEntry],
live_panes: &[(String, PathBuf)],
inner_width: u16,
) -> RowLayout {
let mut l = RowLayout::default();
let widest_name = repos
.iter()
.map(|r| r.display.chars().count() as u16)
.max()
.unwrap_or(0);
let mut tail_max: u16 = 0;
for entry in repos {
let live = crate::session::liveness::is_live(&entry.path, live_panes);
let mut tail = u16::from(live);
if let Some(status) = entry.status.as_ref() {
l.branch_col = l.branch_col.max(status.branch.chars().count() as u16);
let attention = packed_width(&attention_cells(status, false, false));
if attention > 0 {
tail += attention + u16::from(tail > 0);
}
if !status.files.is_empty() {
let count = 2 + status.files.len().to_string().len() as u16;
tail += count + u16::from(tail > 0);
}
}
tail_max = tail_max.max(tail);
}
l.branch_col = l.branch_col.min(inner_width / 3);
let reserved = if l.branch_col > 0 {
l.branch_col + 1
} else {
0
} + tail_max;
l.name_col = widest_name
.min(inner_width.saturating_sub(2 + 1 + reserved))
.max(1);
l
}