use crate::style::{self, Stream};
pub(crate) struct PlanItem {
pub(crate) verb: &'static str,
pub(crate) path: String,
pub(crate) what: String,
pub(crate) sub: Vec<(String, String)>,
}
impl PlanItem {
pub(crate) fn new(
verb: &'static str,
path: impl Into<String>,
what: impl Into<String>,
) -> PlanItem {
PlanItem {
verb,
path: path.into(),
what: what.into(),
sub: Vec::new(),
}
}
pub(crate) fn with_sub(
mut self,
label: impl Into<String>,
value: impl Into<String>,
) -> PlanItem {
self.sub.push((label.into(), value.into()));
self
}
}
pub(crate) fn heading(stream: Stream, cmd: &str, here: &std::path::Path) -> String {
format!(
"{} will, in {}:\n\n",
style::bold(stream, cmd),
style::dim(stream, &here.display().to_string())
)
}
pub(crate) fn render_items(stream: Stream, items: &[PlanItem]) -> String {
let verb_width = items.iter().map(|i| i.verb.len()).max().unwrap_or(0);
let path_width = items.iter().map(|i| i.path.len()).max().unwrap_or(0);
let sub_label_width = items
.iter()
.flat_map(|i| i.sub.iter().map(|(label, _)| label.len()))
.max()
.unwrap_or(0);
let sub_indent = " ".repeat(2 + verb_width + 2);
let mut s = String::new();
for item in items {
s.push_str(" ");
s.push_str(&style::verb(stream, item.verb));
s.push_str(&" ".repeat(verb_width - item.verb.len() + 2));
s.push_str(&style::path(stream, &item.path));
s.push_str(&" ".repeat(path_width - item.path.len() + 2));
s.push_str(&item.what);
s.push('\n');
for (label, value) in &item.sub {
let line = format!(
"{label}{} {value}",
" ".repeat(sub_label_width - label.len())
);
s.push_str(&sub_indent);
s.push_str(&style::dim(stream, &line));
s.push('\n');
}
}
s
}