use cadmpeg_registry::{
dialect_provenance, dialect_table, format_rows, DialectProvenance, DialectTableError,
InputCatalog, RegistryLoadError,
};
pub(crate) fn print_formats(inputs: &InputCatalog) -> Result<(), RegistryLoadError> {
println!("FORMAT READ WRITE EXTENSIONS");
for row in format_rows(inputs) {
println!(
"{:<10} {:<6} {:<6} {}",
row.id,
"yes",
yes_no(row.write()?),
row.extensions.join(", ")
);
}
println!();
println!("`cadmpeg dialects [FORMAT]` lists the dialects of each format.");
Ok(())
}
const fn yes_no(value: bool) -> &'static str {
if value {
"yes"
} else {
"no"
}
}
pub(crate) fn print_dialects(format: Option<&str>) -> Result<(), DialectTableError> {
for (index, section) in dialect_table(format)?.iter().enumerate() {
if index > 0 {
println!();
}
let name = §ion.format;
match section.catalog {
Some(catalog) if !catalog.is_empty() => {
let default = catalog
.default()
.map_or("none", |(_, target)| target.id.as_str());
println!("{name} (write targets in this build; default {default})");
}
Some(_) => println!("{name} (this build writes it, with no dialect catalog)"),
None => println!("{name} (no encoder in this build)"),
}
println!(
" DIALECT READ WRITE TITLE"
);
for row in §ion.rows {
let is_target = section
.catalog
.is_some_and(|catalog| catalog.iter().any(|target| target.id == row.id));
println!(
" {:<34} {:<24} {:<24} {}",
row.id.as_str(),
row.disposition.read,
if is_target {
format!("{} (target)", row.disposition.write)
} else {
row.disposition.write.to_string()
},
row.title
);
}
}
Ok(())
}
pub(crate) fn dialect_lines(
dialects: Option<&cadmpeg_core::dialect::DialectLayers>,
) -> Result<Vec<String>, RegistryLoadError> {
let Some(dialects) = dialects else {
return Ok(Vec::new());
};
let DialectProvenance {
id,
read,
write_targets,
} = dialect_provenance(dialects)?;
let id = id.as_str().to_owned();
let mut clauses = Vec::new();
if let Some(read) = read {
clauses.push(format!("read {read}"));
}
if !write_targets.is_empty() {
let targets = write_targets
.iter()
.map(|target| suffix(target.id.as_str()))
.collect::<Vec<_>>()
.join(", ");
clauses.push(format!("write targets {targets}"));
}
let primary = if clauses.is_empty() {
format!("dialect: {id}")
} else {
format!("dialect: {id} — {}", clauses.join(", "))
};
Ok(std::iter::once(primary)
.chain(
dialects
.iter()
.skip(1)
.map(|layer| format!("dialect: {}", layer.dialect())),
)
.collect())
}
fn suffix(id: &str) -> &str {
id.split_once(':').map_or(id, |(_, rest)| rest)
}
#[cfg(test)]
mod tests {
use super::dialect_lines;
#[cfg(feature = "rhino")]
#[test]
fn the_provenance_line_joins_the_match_the_registry_and_the_catalog() {
use cadmpeg_core::dialect::{DialectLayers, DialectMatch};
let dialects = DialectLayers::of(DialectMatch::admitted(cadmpeg_core::dialect_id!(
"rhino:archive-50"
)));
let lines = dialect_lines(Some(&dialects)).expect("embedded registry loads");
let line = &lines[0];
assert!(line.starts_with("dialect: rhino:archive-50 — "), "{line}");
assert!(line.contains("read "), "{line}");
assert!(line.contains("write targets archive-50"), "{line}");
assert!(line.contains("archive-80"), "{line}");
}
#[test]
fn no_dialects_is_no_line() {
assert!(dialect_lines(None)
.expect("embedded registry loads")
.is_empty());
}
#[test]
fn every_classified_layer_gets_a_human_line() {
use cadmpeg_core::dialect::{DialectLayers, DialectMatch};
let dialects = DialectLayers::of(DialectMatch::admitted(cadmpeg_core::dialect_id!(
"sldprt:2024"
)))
.with(DialectMatch::admitted(cadmpeg_core::dialect_id!(
"acis:sat-32"
)))
.expect("distinct dialect layer keys");
assert_eq!(
dialect_lines(Some(&dialects))
.expect("embedded registry loads")
.len(),
2
);
assert_eq!(
dialect_lines(Some(&dialects)).expect("embedded registry loads")[1],
"dialect: acis:sat-32"
);
}
}