use ratatui::style::{Color, Modifier, Style};
use ratatui::text::Span;
use crate::interactive::session_prompt::StatusView;
use crate::interactive::tui::wrap::cell_width;
use super::super::super::theme::{accent, secondary};
pub(super) const SEGMENT_SEP: &str = " · ";
pub(super) struct BarWords {
pub name: String,
pub plus_n: Option<String>,
pub model: String,
pub mode: Option<String>,
pub tasks: Option<String>,
}
pub(super) fn bar_words(view: &StatusView) -> BarWords {
BarWords {
name: view.profile.clone(),
plus_n: (!view.included.is_empty()).then(|| format!(" +{}", view.included.len())),
model: view.model.clone(),
mode: (view.agent_mode != "build").then(|| view.agent_mode.clone()),
tasks: view.task_summary.clone(),
}
}
#[derive(Clone, Copy)]
pub(super) struct BarFit {
pub plus_n: bool,
pub model: bool,
pub mode: bool,
pub tasks: bool,
pub hint: bool,
}
pub(super) fn full_fit(words: &BarWords) -> BarFit {
BarFit {
plus_n: words.plus_n.is_some(),
model: true,
mode: words.mode.is_some(),
tasks: words.tasks.is_some(),
hint: true,
}
}
fn piece(keep: bool, text: Option<&str>) -> usize {
match (keep, text) {
(true, Some(text)) => cell_width(SEGMENT_SEP) + cell_width(text),
_ => 0,
}
}
fn width_for(words: &BarWords, keep: BarFit, hint_width: usize) -> usize {
cell_width(&name_text(words, keep.plus_n))
+ piece(keep.model, Some(&words.model))
+ piece(keep.mode, words.mode.as_deref())
+ piece(keep.tasks, words.tasks.as_deref())
+ if keep.hint { 1 + hint_width } else { 0 }
}
pub(super) fn segments_width(words: &BarWords, mut keep: BarFit) -> usize {
keep.hint = false;
width_for(words, keep, 0)
}
pub(super) fn fit_bar(words: &BarWords, hint_width: usize, width: usize) -> BarFit {
let mut keep = full_fit(words);
while width_for(words, keep, hint_width) > width {
if keep.tasks {
keep.tasks = false;
} else if keep.mode {
keep.mode = false;
} else if keep.plus_n {
keep.plus_n = false;
} else if keep.model {
keep.model = false;
} else if keep.hint {
keep.hint = false;
} else {
break; }
}
keep
}
fn name_text(words: &BarWords, keep_plus_n: bool) -> String {
match (keep_plus_n, &words.plus_n) {
(true, Some(suffix)) => format!("{}{suffix}", words.name),
_ => words.name.clone(),
}
}
pub(super) fn bar_spans(words: &BarWords, keep: BarFit, bg: Color) -> Vec<Span<'static>> {
let base = Style::default().bg(bg);
let push = |spans: &mut Vec<Span<'static>>, keep: bool, text: Option<&str>| {
if keep && let Some(text) = text {
spans.push(Span::styled(
format!("{SEGMENT_SEP}{text}"),
base.fg(secondary()),
));
}
};
let mut spans = vec![Span::styled(
name_text(words, keep.plus_n),
base.fg(accent()).add_modifier(Modifier::BOLD),
)];
push(&mut spans, keep.model, Some(&words.model));
push(&mut spans, keep.mode, words.mode.as_deref());
push(&mut spans, keep.tasks, words.tasks.as_deref());
spans
}