use std::fmt::Write as _;
use crate::api::models::DictEntry;
use crate::api::{Dictionary, LinkType};
use crate::render::Context;
use crate::render::style::Palette;
use crate::render::table::{Column, render, tally};
#[must_use]
pub fn one(kind: Dictionary, entries: &[DictEntry], ctx: &Context) -> String {
let paint = ctx.painter();
let mut out = String::with_capacity(64 + entries.len() * 48);
let _ = writeln!(out, "{}", paint.paint(kind.label(), Palette::heading()));
out.push_str(&rows(kind, entries, ctx));
let _ = writeln!(
out,
"{}",
paint.paint(
&format!("shown {} of {}", entries.len(), entries.len()),
Palette::label()
)
);
out
}
#[must_use]
pub fn many(sections: &[(Dictionary, Vec<DictEntry>)], ctx: &Context) -> String {
let mut out = String::new();
for (index, (kind, entries)) in sections.iter().enumerate() {
if index > 0 {
out.push('\n');
}
out.push_str(&one(*kind, entries, ctx));
}
out
}
fn rows(kind: Dictionary, entries: &[DictEntry], ctx: &Context) -> String {
let categorised = kind == Dictionary::Statuses;
let columns: Vec<Column> = if categorised {
vec![
Column::whole("KEY", 20, Palette::key()),
Column::new("NAME", 32, anstyle::Style::new()),
Column::new("CATEGORY", 12, Palette::label()),
]
} else {
vec![
Column::whole("KEY", 20, Palette::key()),
Column::new("NAME", 32, anstyle::Style::new()),
]
};
let rows: Vec<Vec<String>> = entries
.iter()
.map(|entry| {
let mut row = vec![entry.key.clone(), entry.name.clone()];
if categorised {
row.push(entry.category.clone().unwrap_or_else(|| "-".to_owned()));
}
row
})
.collect();
render(&columns, &rows, ctx)
}
#[must_use]
pub fn link_types(types: &[LinkType], ctx: &Context) -> String {
let columns = [
Column::new("WRITE", 20, Palette::key()),
Column::new("MEANS", 26, anstyle::Style::new()),
Column::whole("TYPE", 12, Palette::label()),
];
let mut rows = Vec::with_capacity(types.len() * 2);
for kind in types {
for (outward, label) in [(true, &kind.outward), (false, &kind.inward)] {
if !outward && kind.inward == kind.outward {
continue;
}
rows.push(vec![
relationship(&kind.id, outward).unwrap_or("-").to_owned(),
label.clone().unwrap_or_else(|| "-".to_owned()),
kind.id.clone(),
]);
}
}
let mut out = render(&columns, &rows, ctx);
out.push_str(&tally(rows.len(), Some(rows.len() as u64), None, ctx));
out
}
fn relationship(type_id: &str, outward: bool) -> Option<&'static str> {
Some(match (type_id, outward) {
("relates", _) => "relates",
("depends", true) => "depends on",
("depends", false) => "is dependent by",
("subtask", true) => "is parent task for",
("subtask", false) => "is subtask for",
("duplicates", true) => "is duplicated by",
("duplicates", false) => "duplicates",
("epic", true) => "has epic",
("epic", false) => "is epic of",
_ => return None,
})
}